Calling an ISR from a class

I am writing an app where I’m using a number of different ports using serial to transmit but a PWM format as reply via a single pin. As part of this, I need to respond to interrupt son change on the pins.

I’ve tried to follow https://gammon.com.au/forum/?id=12983 (thanks, Nick!) in the code:

HardwareSerial serPorts[3] = { Serial1, Serial2, Serial3 };
int uartS1[] = { UART0_S1, UART1_S1, UART2_S1 };
int pinNo[] = { 1, 10, 8 };
int testPinNo[] = { 5, 6, 7 };
byte cmdCheckSum(byte[]);

class Channel
{
// Internal variables - retain private accessibility
  static Channel * instances[3];
  volatile boolean sending, receiving, waiting;
  volatile boolean pinState;
  static volatile boolean pinFlag;
  
  static void intCh0()
  {
    if (Channel::instances[0] != NULL)
      Channel::instances[0]->pinInt();
  }

  static void intCh1()
  {
    if (Channel::instances[1] != NULL)
      Channel::instances[1]->pinInt();
  }

  static void intCh2()
  {
    if (Channel::instances[2] != NULL)
      Channel::instances[2]->pinInt();
  }
  boolean resp;
  volatile boolean uartFlag, tmrFlag;
  byte message[6] = { 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0x00 };
  byte modType[4];
  byte receivedValue;
  int bitsReceived;
  volatile long currentTime;
  long t1, t2;
  long pulseStart, pulseDur;
  int modID;
  
  void intSetup(const int pinNo)
  {
    pinMode(pinNo, INPUT_PULLUP);
    switch (pinNo)
    {
      case 1: 
        attachInterrupt (pinNo, intCh0, CHANGE);
       instances[0] = this;
        break;
        
      case 10: 
        attachInterrupt (pinNo, intCh1, CHANGE);
        instances[1] = this;
        break;

      case 8: 
        attachInterrupt (pinNo, intCh2, CHANGE);
        instances[2] = this;
        break;
        
    }  // </switch(chan)>
  }  // </void intSetup(chan)>

  void pinInt()
  {
    pinState = !pinState;
    currentTime = micros();
  }

//  Variables and functions referred to outside need to be public
  public:
    HardwareSerial serPort;
    int uartStatus;
    int portPin;
    int testPin;

  void init()
    {
      sending = false;
      receiving = false;
      waiting = false;
      resp = false;
      modID = 0;
    }   //  </init()>

  void transact()
  {
    if ( !sending && !receiving && !waiting)
    {
      sending = true;
      digitalWrite(testPin, HIGH);
      serPort.begin(2400, SERIAL_8N2);
      message[5] =  cmdCheckSum(message) | modID;
      modID++;
      if (modID > 3) modID = 0;
      serPort.write(message, 6);
    }   //  </if ( !sending && !receiving && !waiting)>
    
    if ( sending)
    {
      if (uartStatus & UART_S1_TC)
      {
        sending = false;
        digitalWrite(testPin, LOW);
        receiving = true;
        bitsReceived = 0;
        receivedValue = 0;
        resp = false;
        t1 = micros();
        serPort.end();
        pinMode(portPin, INPUT_PULLUP);
      }   //  </if (uartStatus & UART_S1_TC)
    }   //  </if ( sending)>
  
    if (receiving)
    {
      t2 = micros();
      if ((t2 - t1 > 12000) && !resp)
      {
        receiving = false;
        waiting = true;
        Serial.println(" ~~ ");
      }
      if (!digitalRead(portPin) && !resp)
      {
        resp = true;
        pinFlag = false;
        pinState = 0;
        intSetup(portPin);
        bitsReceived = 0;
      }   //  </if ((!digitalRead(1) && !resp)>
  
      if (resp && pinFlag)
      {
        pinFlag = false;
        digitalWrite(testPin, pinState);
        if (pinState)
        {
          pulseStart = currentTime; 
        }
        else
        {
          pulseDur = currentTime - pulseStart;
          Serial.print(" > ");Serial.print(pulseDur);Serial.print("  ");
          if (pulseDur > 450)
          {
            receivedValue = (receivedValue >> 1) | B10000000;
          }
          else
          {
            receivedValue = (receivedValue >> 1);
          }   //  </if (pulseDur > 400)>
  
          bitsReceived++;
          if (bitsReceived > 7)
          {
            receiving = false;
            detachInterrupt(portPin);
            pinState = LOW;
            waiting = true;
            digitalWrite(testPin, pinState);
            Serial.print("  ");Serial.println(receivedValue, HEX);
            
            int modNo = (message[5] & 0x03) + 1;
            if (message[modNo] == 0xFC)
            {
              modType[modNo - 1] = receivedValue;
            }
            
            if (receivedValue == 0xFE)
            {
              message[modNo] = 0xFC;
            }
            
          }   //  </if (bitsReceived > 7)>
        }   //  </if (pinState)>
      }   //  </if (resp && pinFlag))>
    }   //  </if (receiving)>
  }   //  </void(transact()>
} ch[3];      //  </void Channel()>

void setup()
{
  for (int i = 0; i < 3; i++)
  { 
    ch[i].init();
    ch[i].serPort = serPorts[i];
    ch[i].uartStatus = uartS1[i];
    ch[i].testPin =  testPinNo[i];
    ch[i].serPort = serPorts[i];
    ch[i].serPort.begin(2400, SERIAL_8N2);
  }   //  </for (int i = 0; i < 3; i++)>
  
  for (int i = 5; i < 8; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }   //  </for (int i = 5; i < 8; i++)>
}   //  </void setup()>

void loop()
{
  for (int i = 0; i < 3; i++)
  {
    ch[i].transact();
  }   //  </for (int i = 0; i < 3; i++)>
}   //  </void loop()>

byte cmdCheckSum(byte data[])
{
  //  int dataLength = sizeof(data);
  int CS = 0;
  for (int i = 1; i < 5; i++)
  {
    CS = CS + data[i];
  }   //  </for (int i = 1; i < 5; i++)>
  CS = CS + (CS >> 8);
  CS = CS + (CS << 4);
  CS = CS & 0xF0;
  return CS;
}   //  </byte cmdCheckSum(byte data[])>

but it fails to compile with error messages:

C:\Users\bmdur\AppData\Local\Temp\arduino_build_74629\sketch\Teensy_Meccano_int_class_2811.ino.cpp.o: In function `Channel::pinInt()':

D:\Projects\Meccano\Max hax\Teensy_Meccano_int_class_2811/Teensy_Meccano_int_class_2811.ino:69: undefined reference to `Channel::instances'

D:\Projects\Meccano\Max hax\Teensy_Meccano_int_class_2811/Teensy_Meccano_int_class_2811.ino:69: undefined reference to `Channel::instances'

D:\Projects\Meccano\Max hax\Teensy_Meccano_int_class_2811/Teensy_Meccano_int_class_2811.ino:69: undefined reference to `Channel::instances'

C:\Users\bmdur\AppData\Local\Temp\arduino_build_74629\sketch\Teensy_Meccano_int_class_2811.ino.cpp.o: In function `Channel::intSetup(int)':

D:\Projects\Meccano\Max hax\Teensy_Meccano_int_class_2811/Teensy_Meccano_int_class_2811.ino:60: undefined reference to `Channel::instances'

D:\Projects\Meccano\Max hax\Teensy_Meccano_int_class_2811/Teensy_Meccano_int_class_2811.ino:60: undefined reference to `Channel::pinFlag'

collect2.exe: error: ld returned 1 exit status

Error compiling for board Teensy 3.2 / 3.1.

I’m mystified how to fix this, as there is no reference to Channel::instances in line 69, and no reference to Channel::pinFlag in line 60. Any ideas will be welcome.

Check out post number 4

Classes are incompatible with interrupts.

There are ways around this. Check out some other libraries which use interrupts, such as the Encoder library.