Using ArduinoBLE into other class

Hi to all,
I'm trying to create a class that I will use into a ino file.
I think to create this approach

#define DEBUG true
#define VERSION "1.0.0"
#define PRODUCT "My product BLE"

#include <MyDevice.h>
MyDevice firmware;

void setup() {

  firmware.Init(DEBUG, VERSION, PRODUCT;

}

void loop() {
  
  firmware.Loop();

}

My "entrypoint" class inherits several library arduino standard.

#include <Arduino.h>

#include <Common.h> //several defines
#include <Logging.h> //Logging for monitor in debug mode
#include <Setting.h> //Setting into an external EEPROM
#include <BLECommunication.h> //Proxy to semplify methods for my device (programmable kayboard...) for setting by BLE buttons of keyboard, then I will include in this class ArduinoBLE

#ifndef MyDevice_h
#define MyDevice_h

class MyDevice
{
    public:

        //Costructor
        MyDevice(void);

        //Public Methods
        void Init(bool debug, String version, String product);
        void Loop();

    private:
      
         //several code
        Logging logger;

        Setting setting;
        BLECommunication bleCommunication;
};

#endif

OK, all seems ok....
But into a BLECommunication class I try to organize calls to ArduinoBLE

#include "Arduino.h"
#include "Common.h"
#include <Logging.h>
#include <ArduinoBLE.h>

#define ROOT_UUID "9f7cc"
#define DEVICE_UUID "-9330-4f01-b991-722834129b35"
#define SERVICE_UUID ROOT_UUID "100" DEVICE_UUID

#ifndef BLECommunication_h
#define BLECommunication_h

class BLECommunication
{
public:
    //Constructor
    BLECommunication();
    //Init
    void Init(StatusDevice *rStatusDevicePtr);
    //Set
    //void Set(byte key, uint8_t * buffer);
    //Get
    // Get(byte key, uint8_t * buffer);
    //Loop
    void Loop();

private:
    //Logger
    Logging logger;

    //BLE Connections
    BLEService myDeviceService;
    BLEUnsignedLongCharacteristic buttonCharacteristic[BUTTON_COUNT];

    void initBLE();
    void characteristicWritten(BLEDevice central, BLECharacteristic characteristic);
};
#endif

my initBLE method is this

void BLECommunication::initBLE()
{
    logger.Write("Init BLE connection: ", "BLECommunication::Init");

    keyboardService = BLEService(SERVICE_UUID);

    for (byte i = 1; i <= BUTTON_COUNT; i++)
    {
        String address = ROOT_UUID + String(100 + i) + DEVICE_UUID;
        buttonCharacteristic[i] = BLEUnsignedLongCharacteristic(address, BLERead | BLEWrite);
    }

    if (!BLE.begin())
    {
        logger.WriteLine("BLE Not Connected", "");

        while (1)
            ;
    }

    //I will need to use c_str()...... BLE.setLocalName(statusDevicePtr->product);
    BLE.setAdvertisedService(keyboardService);

    for (byte i = 1; i <= BUTTON_COUNT; i++)
    {
        keyboardService.addCharacteristic(buttonCharacteristic[i]);
    }

    // add the service
    BLE.addService(keyboardService);

    for (byte i = 1; i <= BUTTON_COUNT; i++)
    {
        buttonCharacteristic[i].setEventHandler(BLEWritten, characteristicWritten);
        buttonCharacteristic[i].setValue(0);
    }

    BLE.advertise();

    logger.WriteLine("OK", "");
}

But during compiling I found this error

/BLECommunication/BLECommunication.cpp:81:82: error: invalid use of non-static member function 'void BLECommunication::characteristicWritten(BLEDevice, BLECharacteristic)'
buttonCharacteristic[i].setEventHandler(BLEWritten, characteristicWritten);

I think that the problem is that setEventHandler method requires a static method, but I am into a instance of class BLECommunication. (I think....).

my callback methods is this

void BLECommunication::characteristicWritten(BLEDevice central, BLECharacteristic characteristic)
{
    int length = characteristic.valueSize();
    uint8_t data[length];

    for (byte i = 0; i < BUTTON_COUNT; i++)
    {
        if (buttonCharacteristic[i].uuid() == characteristic.uuid())
        {
            logger.Write("Received from: ", "BLECommunication::characteristicWritten");
            logger.Write(characteristic.uuid(), "");

            buttonCharacteristic[i].readValue(data, length);

            //TODO I will write my logic

            for (byte i = 0; i < length; i++)
                logger.WriteByte(data[i]);

            logger.WriteLine("", "");
        }
    }
}

How can I solve this problem? Did I take the wrong approach?
I haven't written anything else about my device yet, but I'd like to start off on the right foot

You are likely right
The characteristicWritten() method only exists within the context of an instance and so a function pointer to this does not make any sense as the compiler would not know what context to set up to call the member function.

Do you plan to have multiple BLECommunication instances? is the class really needed?

No, only one.
I created the classes to better organize the code, could I define the BLECommunication class as static?

if you need only one, then just define this as a library of functions, the class is not needed. (it's C++, not Java, so not everything needs to be an object)

You were crystal clear, thank you very much! :slightly_smiling_face:

But....., if I need more instances, instead?
What would have been the approach?

then you need to write a function that will act as the callback and think how the callback will know which instance to pass the message onto. (keep all the instances in a list of some sort and keep track of which instance was awaiting for a callback. If more than one was waiting, then you'd be in trouble unless there is a way to tell from the message which one was the originator)

OK! Thank you for the explanation.