bertmelis / esp32ModbusRTU

modbus RTU client for ESP32
MIT License
70 stars 44 forks source link

Using in another class #17

Closed Benji1992-HU closed 4 years ago

Benji1992-HU commented 4 years ago

Hy! I want to use the esp32ModbusRTU class in my own class, but i have this error message: no suitable constructor exists to convert from "void (uint8_t serverAddress, esp32Modbus::FunctionCode fc, uint8_t *data, uint16_t length)" to "std::function<void (uint8_t, esp32Modbus::FunctionCode, uint8_t *, uint16_t)>"

My code:

.h

class parabolaCommunication
{

private:
    int _modbusRxPin;
    int _modbusTxPin;
    int _modbusDePin;

private:
    void handleModbusData(uint8_t serverAddress, esp32Modbus::FunctionCode fc, uint8_t* data, uint16_t length);
    void identifyRecievedData(int senderAddress, long int recievedData);

public:
    parabolaCommunication(int modbusRxPin, int modbusTxPin, int modbusDePin,bool serviceMode);
    bool init(esp32Modbus::MBRTUOnData handler);

};

.cpp

bool parabolaCommunication::init(esp32Modbus::MBRTUOnData handler)
{
    if(_serviceMode == false)
    {
        wifiConnect();
        client.setServer(_mqttServerAddress, _mqttServerPort);
    }
    Serial1.begin(19200,SERIAL_8N1,_modbusRxPin,_modbusTxPin,true);
    modbus.onData(handleModbusData);
    modbus.onError([](esp32Modbus::Error error) {
    Serial.printf("error: 0x%02x\n\n", static_cast<uint8_t>(error));
  });
  modbus.begin();
    return 0;
}
void parabolaCommunication::handleModbusData(uint8_t serverAddress, esp32Modbus::FunctionCode fc, uint8_t* data, uint16_t length)
{
    long int number = 0;
    int deviceAddress = serverAddress;
    number = (data[0] << 8) + data[1];
    identifyRecievedData(deviceAddress , number);
}

Can you help me?

Thanks!

bertmelis commented 4 years ago

Every class method has a "hidden" argument: the class instance. So you'll have to use std::bind to add the extra argument.

If you don't know how, let me know.

Benji1992-HU commented 4 years ago

Sorry I am new in c++ programming, I dont know what you say.

bertmelis commented 4 years ago

Your example is lacking so much information that I can only guess what you're doing.

Anyway, suppose you have a class with a private variable esp32ModbusRTU myDevice and a private function

class myClass {
// left out lot's of stuff
 private:
  void onData(uint8_t slaveId, esp32Modbus::FunctionCode fc, uint16_t addr, uint8_t* data, uint16_t len);
  esp32ModbusRTU myDevice;
};

What you don't see is that there is -simply said- an extra argument in the _onData function which is the class instance. This is not part of the function signature that can be passed to myDevice.onData(). To overcome this you can use std::bind.

so somewhere in your class (perhaps a setup()method) you have to do something like this:

myDevice.onData(std::bind(&myClass:_onData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
Benji1992-HU commented 4 years ago

The onData has only 4 argument, i corrected this. The code: .h file:

class parabolaCommunication
{

private:
    int _modbusRxPin;
    int _modbusTxPin;
    int _modbusDePin;
    const char* _mqttClientId;
    const char* _wifiSsid;
    const char* _wifiPassword;
    bool _serviceMode;
    const char* _mqttServerAddress;
    uint16_t _mqttServerPort;
    static int _modbusActualFuncCode;
    static uint8_t _modbusActualSlaveAddr;
    static uint16_t _modbusActualSlaveRegNum;

private:
    void handleModbusData(uint8_t serverAddress, esp32Modbus::FunctionCode fc, uint8_t* data, uint16_t length);
    static void identifyRecievedData(int senderAddress, long int recievedData);
    //void onData(uint8_t slaveId, esp32Modbus::FunctionCode fc, uint16_t addr, uint8_t* data, uint16_t len);

public:
    struct sensors
    {
        int deviceAddress;
        int deviceRegisterNum;
    };

public:
    parabolaCommunication(int modbusRxPin, int modbusTxPin, int modbusDePin);
    void setWifiSettings(const char* wifiSsid, const char* wifiPassword);
    void setMqttSettings(const char* mqttServerIpAddress, uint16_t mqttServerPort, const char* mqttClientId);
    bool init(String parabolaName, bool serviceMode);
    bool wifiConnect();
    void serialPrintln(int data);
    void serialPrintln(float data);
    void serialPrintln(long data);
    void serialPrintln(byte data);
    void serialPrintln(char data);
    void serialPrintln(String data);
    void modbusAction(uint8_t slaveAddress, int funcCode, uint16_t regNum, uint16_t regData);
    void getSensorValue( struct sensors sensor );
};

.cpp file:

esp32ModbusRTU modbus(&Serial1);
SemaphoreHandle_t xSerialSemaphore;
SemaphoreHandle_t xModbusSemaphore;

bool parabolaCommunication::init(String parabolaName, bool serviceMode)
{
    _serviceMode = serviceMode;

    Serial.begin(115200);
    if ( xSerialSemaphore == NULL ) 
    {
        xSerialSemaphore = xSemaphoreCreateMutex();  
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  
    }

    if(_serviceMode == false)
    {
        wifiConnect();
        client.setServer(_mqttServerAddress, _mqttServerPort);
    }else
    {   parabolaCommunication::serialPrintln("---- SERVICE MODE ----");
        SerialBT.begin(parabolaName);
    }

    Serial1.begin(19200,SERIAL_8N1,_modbusRxPin,_modbusTxPin,true);
    modbus.onData(std::bind(&parabolaCommunication::handleModbusData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
    modbus.onError([](esp32Modbus::Error error) {
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
        Serial.printf("error: 0x%02x\n\n", static_cast<uint8_t>(error));
        xSemaphoreGive( xSerialSemaphore ); 
    }
    });
    modbus.begin();
    if ( xModbusSemaphore == NULL ) 
    {
        xModbusSemaphore = xSemaphoreCreateMutex();  
    if ( ( xModbusSemaphore ) != NULL )
        xSemaphoreGive( ( xModbusSemaphore ) );  
    }
    //struct parabolaCommunication::sensors TEMP_1 = {1,0};

    return 0;
}
void parabolaCommunication::handleModbusData(uint8_t serverAddress, esp32Modbus::FunctionCode fc, uint8_t* data, uint16_t length)
{
    long int number = 0;
    int deviceAddress = serverAddress;
    number = (data[0] << 8) + data[1];
    parabolaCommunication::serialPrintln(number);
    identifyRecievedData(deviceAddress , number);
}

The compile with no error but when I send an request dont come back the answer. I think the onData function not working.

bertmelis commented 4 years ago

That's something completely different... but I still have no idea what you're doing without a main.cpp file. But please, I'm not going to debug your entire code. I'm not interested in your WiFi or MQTT code.

Benji1992-HU commented 4 years ago

I only sent the detail that concerns the library. The other part of code is work fine. In modbus slave PC tool I see the request is sent, and the slave is response to the request, but the onData handeler function is not called.

bertmelis commented 4 years ago

The code here is quite straightforward. There's not much that could be blocking, especially if you say your slave is receiving the request.

I don't have a clue about your program. Do all the semaphores get released? Is your debug printing code working? Does the onError method get called? Any object lifetime issues?

What about throwing in some debug print statements to see where is it blocking?

Benji1992-HU commented 4 years ago

I tried without using semaphores. The result is the same. the onError is working, sometimes print 0xe0 error code.