Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: Seeking ideas on using state in callbacks

  1. #1
    Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    90

    Seeking ideas on using state in callbacks

    These days, as I've been using callbacks more and more (through Arduino-style APIs, for example IntervalTimer or attachInterrupt()), it's become apparent that this programming paradigm depends on there being global state. I'm finding myself rewriting these pieces but I lose the ability to automatically upgrade my code if any of the core code changes, or having very large switch statements that assign specific ISRs, depending on which pin, etc.

    My current consternation has to do with finding out which pin triggered an edge interrupt. I can solve this in a few ways:
    1. Reimplement internal APIs that I need (yuck).
    2. Write a callback routine for every pin possibility (yuck again).
    3. ???.


    I'm seeking opinions on how to do approach #3. Following is some example code. My challenge to you is to modify the "API Section" of the program so that the ISR (could be new functions) prints the state of the associated Holder object. You aren't allowed to modify the "User Section" because that emulates calling an API.

    Code:
    // --------------
    //  API Section
    // --------------
    
    void pin_rising_isr();
    
    // Holds some state.
    class Holder {
     public:
      Holder(int state) : state_(state), risingPin_(-1) {}
    
      void setRisingPin(int pin) {
        if (pin >= CORE_NUM_DIGITAL) {
          return;
        }
        risingPin_ = pin;
        if (pin >= 0) {
          attachInterrupt(pin, pin_rising_isr, RISING);
        }
      }
    
      int state_;
      int risingPin_;
    };
    
    void pin_rising_isr() {
      Serial.println("My caller's state is: ???");
    }
    
    // --------------
    //  User Section
    // --------------
    
    Holder h1{100};
    Holder h2{200};
    
    void setup() {
      Serial.begin(115200);
      while (!Serial && millis() < 4000) {
        // Wait for Serial to initialize
      }
    
      h1.setRisingPin(2);
      h2.setRisingPin(6);
    }
    
    void loop() {
      yield();
    }

  2. #2
    Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    90
    Here's my solution for getting state into GPIO ISRs. I'm using it from a header. It's the "write a callback for every possible pin" solution.

    Code:
    #include <core_pins.h>
    
    // Holds callback information for one pin.
    struct PinCallbackInfo {
      void (*callback)(void *state);
      void *state;
    };
    
    // Each element holds a callback function along with its state.
    static volatile PinCallbackInfo pinCallbacks[CORE_NUM_DIGITAL];
    
    #define PIN_ISR(N)                                \
      static void pin##N##_isr() {                    \
        void (*f)(void *) = pinCallbacks[N].callback; \
        if (f != nullptr) {                           \
          f(pinCallbacks[N].state);                   \
        }                                             \
      }
    
    PIN_ISR(0)
    PIN_ISR(1)
    PIN_ISR(2)
    PIN_ISR(3)
    PIN_ISR(4)
    PIN_ISR(5)
    PIN_ISR(6)
    PIN_ISR(7)
    PIN_ISR(8)
    PIN_ISR(9)
    PIN_ISR(10)
    PIN_ISR(11)
    PIN_ISR(12)
    PIN_ISR(13)
    PIN_ISR(14)
    PIN_ISR(15)
    PIN_ISR(16)
    PIN_ISR(17)
    PIN_ISR(18)
    PIN_ISR(19)
    PIN_ISR(20)
    PIN_ISR(21)
    PIN_ISR(22)
    PIN_ISR(23)
    PIN_ISR(24)
    PIN_ISR(25)
    PIN_ISR(26)
    #ifndef KINETISL
    PIN_ISR(27)
    PIN_ISR(28)
    PIN_ISR(29)
    PIN_ISR(30)
    PIN_ISR(31)
    PIN_ISR(32)
    PIN_ISR(33)
    #ifdef CORE_PIN34_PORTREG
    PIN_ISR(34)
    PIN_ISR(35)
    PIN_ISR(36)
    PIN_ISR(37)
    PIN_ISR(38)
    PIN_ISR(39)
    PIN_ISR(40)
    PIN_ISR(41)
    PIN_ISR(42)
    PIN_ISR(43)
    PIN_ISR(44)
    PIN_ISR(45)
    PIN_ISR(46)
    PIN_ISR(47)
    PIN_ISR(48)
    PIN_ISR(49)
    PIN_ISR(50)
    PIN_ISR(51)
    PIN_ISR(52)
    PIN_ISR(53)
    PIN_ISR(54)
    PIN_ISR(55)
    PIN_ISR(56)
    PIN_ISR(57)
    PIN_ISR(58)
    PIN_ISR(59)
    PIN_ISR(60)
    PIN_ISR(61)
    PIN_ISR(62)
    PIN_ISR(63)
    #endif  // CORE_PIN34_PORTREG
    #endif  // !KINETISL
    
    #undef PIN_ISR
    
    // This is used to assign a function via attachInterrupt().
    static void (*pinISRs[CORE_NUM_DIGITAL])(){
        pin0_isr,
        pin1_isr,
        pin2_isr,
        pin3_isr,
        pin4_isr,
        pin5_isr,
        pin6_isr,
        pin7_isr,
        pin8_isr,
        pin9_isr,
        pin10_isr,
        pin11_isr,
        pin12_isr,
        pin13_isr,
        pin14_isr,
        pin15_isr,
        pin16_isr,
        pin17_isr,
        pin18_isr,
        pin19_isr,
        pin20_isr,
        pin21_isr,
        pin22_isr,
        pin23_isr,
        pin24_isr,
        pin25_isr,
        pin26_isr,
    #ifndef KINETISL
        pin27_isr,
        pin28_isr,
        pin29_isr,
        pin30_isr,
        pin31_isr,
        pin32_isr,
        pin33_isr,
    #ifdef CORE_PIN34_PORTREG
        pin34_isr,
        pin35_isr,
        pin36_isr,
        pin37_isr,
        pin38_isr,
        pin39_isr,
        pin40_isr,
        pin41_isr,
        pin42_isr,
        pin43_isr,
        pin44_isr,
        pin45_isr,
        pin46_isr,
        pin47_isr,
        pin48_isr,
        pin49_isr,
        pin50_isr,
        pin51_isr,
        pin52_isr,
        pin53_isr,
        pin54_isr,
        pin55_isr,
        pin56_isr,
        pin57_isr,
        pin58_isr,
        pin59_isr,
        pin60_isr,
        pin61_isr,
        pin62_isr,
        pin63_isr,
    #endif  // CORE_PIN34_PORTREG
    #endif  // !KINETISL
    };
    
    static void attachInterruptWithState(uint8_t pin,
                                         void (*callback)(void *state), void *state,
                                         int mode) {
      pinCallbacks[pin].callback = callback;
      pinCallbacks[pin].state = state;
      attachInterrupt(pin, pinISRs[pin], mode);
    }
    
    static void detachInterruptWithState(uint8_t pin) {
      pinCallbacks[pin].callback = nullptr;
      pinCallbacks[pin].state = nullptr;
      detachInterrupt(pin);
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •