BleCharacteristic initialization in a class

im trying to initialize the BleCharacteristic class in another class using initializer list.the txCharacteristic does it without problems, however the rxCharacterristic comes with errors…

#include "Particle.h"

class BLEHandler
{
private:

public:
    const char* serviceUuid = "8A500001-C5Q3-F3A3-E1R9-E50E24DOCA9E";
    const char* rxUuid      = "8A500002-C5Q3-F3A3-E1R9-E50E24DOCA9E";
    const char* txUuid      = "8A500003-C5Q3-F3A3-E1R9-E50E24DOCA9E";

    BleCharacteristic txCharacteristic{"tx", BleCharacteristicProperty::NOTIFY, txUuid, serviceUuid};
    BleCharacteristic rxCharacteristic{"rx", BleCharacteristicProperty::WRITE_WO_RSP, rxUuid, serviceUuid, onDataReceived, this};

    void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);

    BLEHandler();
    ~BLEHandler();
};
no instance of constructor "particle::BleCharacteristic::BleCharacteristic" matches the argument list -- argument types are: (const char [3], particle::BleCharacteristicProperty, const char *, const char *, void (const uint8_t *data, size_t len, const particle::BlePeerDevice &peer, void *context), BLEHandler *)

could not convert '{"rx", WRITE_WO_RSP, ((BLEHandler*)this)->BLEHandler::rxUuid, ((BLEHandler*)this)->BLEHandler::serviceUuid, ((BLEHandler*)this)->BLEHandler::onDataReceived, ((BLEHandler*)this)}' from '<brace-enclosed initializer list>' to 'particle::BleCharacteristic'

the first error shouldn’t be an error, since i can initialize it in .ino file. And a matching constructor is in the BleCharacteristic class

BleCharacteristic(const char* desc, EnumFlags<BleCharacteristicProperty> properties, T1 charUuid, T2 svcUuid, BleOnDataReceivedCallback callback = nullptr, void* context = nullptr)

im fairly new to c++ and would appreciate a solution to the problem

The problem is that the BleCharacteristic callback is a BleOnDataReceivedCallback. Unlike some other classes, this unfortunately can’t take a C++ class instance directly so you need to implement it with two member functions, one static and one not.

// In BLEHandler class definition
void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer);

static void onDataReceivedStatic(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);

// Characteristic defnition
BleCharacteristic rxCharacteristic{"rx", BleCharacteristicProperty::WRITE_WO_RSP, rxUuid, serviceUuid, onDataReceivedStatic, this};

The implementation of the static member function looks like this:

void BLEHandler::onDataReceivedStatic(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) 
{
    BLEHandler *handler = (BLEHandler *)context;
    handler->onDataReceived(data, len, peer); 
}

What you’re doing is saving a pointer to this in the context. In order to call a non-static class member you need not only the function, but which instance of it, which the onDataReceivedStatic function does by getting it from the context.

2 Likes