2

I am working on a Particle project and coming from JS so I'm challenged by callbacks in C++. I am trying to refactor my Firebase code into a reusable class and for this I need callbacks:

void setup() {
    firebase = new Firebase;
    Serial.begin(9600);
    firebase->subscribe();
    firebase->setCallback(readCallback);
}

void readCallback(JsonObject& root)
{
    r = root["r"];
    g = root["g"];
    b = root["b"];

    Serial.printlnf("Yes! r=%d g=%d b=%d d=%d", r, g, b);
}

Firebase.h:

#ifndef Firebase_h

#define Firebase_h

#include <SparkJson.h>

class Firebase {

    public:
        Firebase();

        void
            subscribe(),
            setCallback(void (*readCallback)(JsonObject& root));


    private: 
            static void getDataHandler(const char *topic, const char *data);

            void (*_readCallback)(JsonObject& root);
};

#endif

Firebase.m:

#include "Particle.h"
// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>
#include "ArduinoJson.h"
#include "Firebase.h"

Firebase::Firebase(void) {
    Serial.printlnf("Firebase instance created");
}

void Firebase::getDataHandler(const char *topic, const char *data) {
    Serial.printlnf("getDataHandler invoked");

    StaticJsonBuffer<256> jsonBuffer;
    char *mutableCopy = strdup(data);
    JsonObject& root = jsonBuffer.parseObject(mutableCopy);
    free(mutableCopy);

    Serial.printlnf("data received: %s", data);
    //  _readCallback(root);
}

void Firebase::subscribe() {
    Serial.printlnf("Firebase subscribe");
    Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);      
}

void Firebase::setCallback(void (*readCallback)(JsonObject& root))
{
    Serial.printlnf("set callback");
    _readCallback = readCallback;
}

When getDataHandler is static everything seems to work but naturally I am having trouble accessing the callback and I get:

invalid use of member 'Firebase::_readCallback' in static member function

When it's not static I get for this line:

Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);

the following error:

invalid use of non-static member function

When I try to bind it as advised here:

Particle.subscribe("hook-response/test3rdata", std::bind(&Firebase::getDataHandler,this), MY_DEVICES);

I get a mistype as Particle.subscribe does not expect a binded method:

no matching function for call to 'CloudClass::subscribe(const char [25], std::_Bind_helper::type, Spark_Subscription_Scope_TypeDef)'

Is there a way around it?

Guy
  • 12,488
  • 16
  • 79
  • 119
  • As far as my C++ understanding tells me it is some internal firmware EventHandler class: https://github.com/spark/firmware/blob/e854596ef86286a789d19018a136f41cc2fe6f8b/system/src/system_cloud.cpp void eventHandler(system_event_t event, int data, void*) { – Guy Nov 20 '17 at 16:38

1 Answers1

3

You are getting this error because std::bind returns a function object that adheres to the signature void() and not void(char const*, char const*). The reason being, that you didn't specify any placeholders for those arguments. So a quick fix would be:

std::bind(&Firebase::getDataHandler, this, std::placeholders::_1, std::placeholders::_2)

Now the bind helper expects two parameters which it will forward to the bound member function.


Having said all that, there is no reason to use std::bind if a lambda will suffice. Lambdas are in fact superior in most regards. In C++14 there's virtually no reason to use std::bind at all. And even in C++11, your use case can be dealt with by a simple lambda:

Particle.subscribe("hook-response/test3rdata", [this](char const* a, char const* b) { getDataHandler(a, b); }, MY_DEVICES);
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Awesome! Works as expected. – Guy Nov 20 '17 at 16:44
  • How does the lambda not capture this? I am having a similar issue and my compiler always stops with: `cannot convert 'MIDITransport::setUp()::' to 'SysExCallback {aka void (*)(const unsigned char*, short unsigned int, bool)}'` – ferdyyy Sep 30 '20 at 22:51
  • @fredyyy - If you have a problem, please create a [mre] and post a proper question. Comments on 3 year old posts are not the way to go. – StoryTeller - Unslander Monica Sep 30 '20 at 22:57