0

I'm writing a class, called "MQTT_interface". I need to use "callback" function in method "reconnect" of this class. I suppose that developer, will write function "callback" for himself, and if not there will be a kind of weak function with the same name ("callback") which would sent an error to console.

I have no idea is it possible or not.

I have these files:

MQTT_interface.h

class MQTT_interface : public PubSubClient
{
    public:
    MQTT_interface(Client& c, String hostname, uint16_t port = 1883);
    void reconnect(void);

    private:
    uint8_t buf[UART_MAX_TRANSFER_SIZE];
};

MQTT_interface.cpp

void MQTT_interface::reconnect() {

    while (!connected()) {
  set_server(MQTT_auth_data.mqtt0_server, MQTT_auth_data.mqtt_port);
    if (connect(MQTT::Connect(MQTT_auth_data.mqtt_uid)
                           .set_auth(MQTT_auth_data.mqtt_uid, MQTT_auth_data.mqtt_pass))) {
      Serial.println("Connected to MQTT server");
      set_callback(callback);   //here my function must be used
        subscribe(topics.mqtt_subscribe_topic); // this is our receive filter. We able to receive only these topics
        subscribe(topics.mqtt_topic_1);

      } else {
        delay(timeout);
    }
  }
}

main.cpp

// Callback function
//  Receive data from MQTT and send it to serial
uint8_t buf[UART_MAX_TRANSFER_SIZE];
void callback(const MQTT::Publish& pub) {
// Copy the payload to a new message
  //MQTT::Publish newpub("outTopic", pub.payload(), pub.payload_len());
  //client.publish(newpub);
  String start_symbol = "";
  char end_symbol = '\n';
  String div_symbol = "&";
  //Serial.println(pub.topic());
  if (pub.has_stream()) {
    int read;
    while (read = pub.payload_stream()->read(buf, UART_MAX_TRANSFER_SIZE)) {
      Serial.write(buf, read);    
    }
    pub.payload_stream()->stop();
  }

  else{
    char symbol = 1;

    String t = pub.topic();
    String m = pub.payload_string();
    String message = start_symbol + t + div_symbol + m + end_symbol;
    int str_len ;
      str_len = message.length();
      Serial.print(message);
  }
}
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • I would advice you to think in an OOP way. For that we have lambda, std::function and callable objects in general and also the good old virtual function. The base class can implement an error handler as you mentioned. "waek" functions using the linker feature are also possible, but less related to c++ at all. – Klaus Jan 10 '19 at 12:57

1 Answers1

2

Let the user give you the callback function:

class MQTT_interface
{
public:
    using reconnect_callback = void(const MQTT::Publish&);

    static void reconnect_callback_default(const MQTT::Publish&) { /* your impl */ }
    void reconnect(reconnect_callback callback = reconnect_callback_default)
    {
        callback(/*...*/);
    }
};

Live complete example:

#include <iostream>

struct example
{
    using reconnect_callback = void(int);
    static void reconnect_callback_default(int) { std::cout << "Error\n"; }
    void reconnect(reconnect_callback callback = reconnect_callback_default)
    {
        callback(42);
    }
};

int main()
{
    example e;
    e.reconnect();                                     // Error
    e.reconnect([](int n){ std::cout << n << '\n'; }); // 42
}

This can be improved in many ways. For instance, Max Langhof suggests to define reconnect_callback as a std::function so it can be a stateful functor.

YSC
  • 38,212
  • 9
  • 96
  • 149
  • 1
    Requiring a function pointer is awkward because you can't pass stateful lambdas. Just take a `std::function` imo. – Max Langhof Jan 10 '19 at 13:05
  • `std::function` might be problematic in some cases because of dynamic memory allocation it does (that wouldn't be necessary otherwise). – EmDroid Jan 10 '19 at 13:10