Search code examples
c++c++11pointersembeddedmbed

Pass pointer of a non static member function to another non static member object


NOTE: In this context, the term "ISR" is not really addressing ISR vectors. There are a lot of tricks in the drivers. One of them is handling with the interrupts generated by the radio tranceiver chip. SX1276_LoRaRadio driver has a thread that checks the actual interrupt source. This is because all these things are working on an rtos (mbed, based on RTX5) and the rtos does not allow direct access to the MCU interrupt vectors. So once PIN_X of the mcu is triggered, the thread reads the radio chip registers for the actual interrupt source.

I am developing for an ARM MCU. There is a radio tranceiver chip (sx1276) on my board. The radio chip driver requires pointers to my own ISR member functions. Thus, I have to pass the pointers of the ISR member functions to another member object (a struct that keeps the pointers) of the same class. The detailed explanation is below.

  • A low level radio driver handles with the device registers (SX1276_LoRaRadio.cpp). This is provided by the manufacturer and developed exactly for the framework I am using (mbed os). This inherits from LoRaRadio
  • An API developed by the framwork developer (arm) provides a higher level pure virtual class for abstraction (LoRaRadio.h).
  • My own radio comm stack exploits the other two in the application layer (ProtoTelecom.hpp and ProtoTelecom.cpp).

The radio has some interrupt pins which are triggered in the occurance of some events. But i can use only one of them due to how the manufacturer designed the driver. This is explained at the very beginning. The events are members of a struct:

// This is in LoRaRadio.h
typedef struct radio_events {
    /**
     * Callback when Transmission is done.
     */
    mbed::Callback<void()> tx_done;

    
    <other mbed::Callback type members>
} radio_events_t;

My ProtoTelecom.hpp looks like this:

class ProtoTelecom: public manageCommands {
public:
    explicit ProtoTelecom(LoRaRadio *Radio, tcm_Manager *tcm);
    static void OnTxDone(void);
    void nonstaticTxDone(void);

    <other corresponding ISR member functions>
private:
    static radio_events_t RadioEvents;

    <other private stuff here>
};

Then in ProtoTelecom.cpp I assign the pointers of the corresponding static member functions to the RadioEvents members:

radio_events_t ProtoTelecom::RadioEvents = {
            .tx_done = ProtoTelecom::OnTxDone,
            
             <other pointer assignments>
};

ProtoTelecom::ProtoTelecom(LoRaRadio *Radio, c_TC_Manager *tcm) : manageCommands()
{
    <other stuff goes here>

    Radio->init_radio(&RadioEvents);
}

My problem is I have to have multiple instances of ProtoRadio. However, the radio isr functions must be static because passing member function pointers inside the class itself is not allowed in c++. This simply prevents me to initialize another hw because both execute the same isr functions. So how can I pass the pointer of a non static member function to another non static member object inside the class itself? Something like this:

ProtoTelecom::ProtoTelecom(LoRaRadio *Radio, c_TC_Manager *tcm) : manageCommands()
{
    <other stuff goes here>
    RadioEvents.tx_done = nonstaticTxDone;
    Radio->init_radio(&RadioEvents);
}

I found this thread but the case is slightly different than mine and I could not manage to adapt it to my situation. The main theme of my question is the title but I know that what I am trying to achive is a bit strange and requires some tricks. So if there are other ways to achive my final goal that is also okay for me. Thanks.


Solution

  • As @Wutz stated in his third comment, the correct way is using mbed::Callback. Here is my new constructor:

    ProtoTelecom::ProtoTelecom(LoRaRadio *Radio, c_TC_Manager *tcm) : manageCommands()
    {
        this->Radio = Radio;
        this->tcm = tcm;
    
        //Inizialize the radio
        newRadioEvents.tx_done = mbed::Callback<void()>(this, &ProtoTelecom::nonstaticOnTxDone);
        newRadioEvents.tx_timeout = mbed::Callback<void()>(this, &ProtoTelecom::nonstaticOnTxTimeout);
        newRadioEvents.rx_done = mbed::Callback<void(const uint8_t *, uint16_t , int16_t , int8_t)>(this, &ProtoTelecom::nonstaticOnRxDone);
        newRadioEvents.rx_timeout = mbed::Callback<void()>(this, &ProtoTelecom::nonstaticOnRxTimeout);
        newRadioEvents.rx_error = mbed::Callback<void()>(this, &ProtoTelecom::nonstaticOnRxError);
    
        Radio->init_radio( &newRadioEvents );
        switchModem(radio_mode);
        setState(RADIO_RECEIVE);
    }
    

    The newRadioEvents is a non static instance of radio_events_t.