espressif / esp-modbus

ESP-Modbus - the officially suppported library for Modbus protocol (serial RS485 + TCP over WiFi or Ethernet).
Apache License 2.0
85 stars 46 forks source link

ModbusTCP Master and 0x108 (ESP_ERR_INVALID_RESPONSE) (IDFGH-9119) #15

Closed fink-at-trmc-dk closed 1 year ago

fink-at-trmc-dk commented 1 year ago

Hi,

I cannot for the life of me make a simple ModbusTCP Master application running. I think I have read through alle the Modbus Controller documentation, but I must have missed something.

This is the ModbusTCP class I'm using:

#include "ModbusTCP.hpp"
#include "main.hpp"
#include "esp_modbus_master.h"
#include "esp_log.h"
#include <cstdint>

static const char *TAG = "ModbusTCP";

// Enumeration of modbus slave addresses accessed by master device
enum
{
    MB_DEVICE_ADDR1 = 71, MB_SLAVE_COUNT = 1
};

// Enumeration of all supported CIDs for device
enum
{
    CID_ACT_CHARGE = 0, CID_SET_CHARGE = 1, CID_COUNT
};

/****************************************************************/
// Example Data Dictionary for Modbus parameters in 2 slaves in the segment
mb_parameter_descriptor_t device_parameters[] =
{
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length, Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
  { CID_ACT_CHARGE, "Act Charge", "A", MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 200, 2, 0, PARAM_TYPE_FLOAT, PARAM_SIZE_FLOAT, { 0, 0, 0 }, PAR_PERMS_READ },
  { CID_SET_CHARGE, "Set Charge", "A", MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1032, 2, 0, PARAM_TYPE_FLOAT, PARAM_SIZE_FLOAT, { 0, 0, 0 }, PAR_PERMS_READ },
};

/****************************************************************/
#define MB_SLAVE_COUNT 1 // Number of slaves in the segment being accessed (as defined in Data Dictionary)
/****************************************************************/

uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
const char *slave_ip_address_table[] =
{
   { "192.168.68.120" }, // Address corresponds to UID1 and set to predefined value by user
   nullptr               // end of table
};

/****************************************************************/
static esp_err_t master_init(mb_communication_info_t *comm_info)
{
    void *master_handler = nullptr;

    esp_err_t err = mbc_master_init_tcp(&master_handler);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "mb controller initialization fail.");
        return err;
    }

    err = mbc_master_setup((void*) comm_info);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "mb controller setup fail, returns(%i).", err);
        return err;
    }

    err = mbc_master_set_descriptor(&device_parameters[0], 2);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "mb controller set descriptor fail, returns(%i).", err);
        return err;
    }

    err = mbc_master_start();
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "mb controller start fail, returns(%i).", err);
        return err;
    }

    vTaskDelay(200);
    return err;
}

/****************************************************************/

void ModbusTCP::Task(void*parameters)
{
    xEventGroupWaitBits(application_event_group, WIFI_CONNECTED_BIT, false, true, portMAX_DELAY);

    mb_communication_info_t comm_info =
    {
            .ip_mode = MB_MODE_TCP,                   // Port communication mode
            .ip_port = 1502,
            .ip_addr_type = MB_IPV4,  // version of IP protocol
            .ip_addr = (void*) slave_ip_address_table, // assign table of IP addresses
            .ip_netif_ptr = esp_netif_ptr // Initializes externally
            };

    ESP_ERROR_CHECK(master_init(&comm_info));

    while (true)
    {

        const mb_parameter_descriptor_t* param_descriptor = NULL;
        float temp_data[2] = {0}; // temporary buffer to hold maximum CID size
        uint8_t type = 0;

        for (std::uint8_t cid = 0; cid < CID_COUNT; cid++)
        {
            // Get the information for characteristic cid from data dictionary
            esp_err_t err = mbc_master_get_cid_info(cid, &param_descriptor);
            if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
            {
                err = mbc_master_get_parameter(param_descriptor->cid,
                        (char*) param_descriptor->param_key, (uint8_t*) temp_data,
                        &type);
                if (err == ESP_OK)
                {
                    ESP_LOGI(TAG,
                            "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
                            param_descriptor->cid,
                            (char*)param_descriptor->param_key,
                            (char*)param_descriptor->param_units,
                            *(uint32_t*)temp_data);
                }
                else
                {
                    ESP_LOGE(TAG,
                            "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
                            param_descriptor->cid,
                            (char*)param_descriptor->param_key, (int)err,
                            (char*)esp_err_to_name(err));
                }
            }
            else
            {
                ESP_LOGE(TAG, "Could not get information for characteristic %d.",
                        cid);
            }

        }

        vTaskDelay(2000);
    }
}

I'm testing up against diagslave.exe, which shows the master connecting, but then nothing more happens. Starting the master simulator up reveals that the disagslave is working just fine.

In the ESP32 terminal it can be seen that it connects to the slave alright, but then disconnects.

I (3606) WiFi: got ip:192.168.68.114
I (3606) WiFi: connected to ap 
I (3606) Sntp: Initializing SNTP
I (3616) Sntp: server 0: pool.ntp.org
I (7386) wifi:<ba-add>idx:1 (ifx:0, 74:da:88:b7:da:3e), tid:0, ssn:0, winSize:64
I (7426) Sntp: Time:1673374166
I (7616) MB_TCP_MASTER_PORT: TCP master stack initialized.
I (7616) MB_TCP_MASTER_PORT: Host[IP]: "192.168.68.120"[192.168.68.120]
I (7616) MB_TCP_MASTER_PORT: Add slave IP: 192.168.68.120
I (7626) MB_TCP_MASTER_PORT: Connecting to slaves...
-I (7936) MB_TCP_MASTER_PORT: Connected 1 slaves, start polling...
E (9946) MB_TCP_MASTER_PORT: Socket(#54)(192.168.68.120) connection closed.
E (9946) MB_TCP_MASTER_PORT: Slave #0, Socket(#54)(192.168.68.120), critical error=-11.
I (9956) MB_TCP_MASTER_PORT: Connecting to slaves...
-I (9966) MB_TCP_MASTER_PORT: Connected 1 slaves, start polling...
E (10936) MB_CONTROLLER_MASTER: mbc_master_get_parameter(73): Master get parameter failure, error=(0x108) (ESP_ERR_INVALID_RESPONSE).
E (10936) ModbusTCP: Characteristic #0 (Act Charge) read fail, err = 0x108 (ESP_ERR_INVALID_RESPONSE).
E (10956) MB_TCP_MASTER_PORT: Socket(#54)(192.168.68.120) connection closed.
E (10956) MB_TCP_MASTER_PORT: Slave #0, Socket(#54)(192.168.68.120), critical error=-11.
I (10966) MB_TCP_MASTER_PORT: Connecting to slaves...
-.I (10986) MB_TCP_MASTER_PORT: Connected 1 slaves, start polling...
E (11956) MB_CONTROLLER_MASTER: mbc_master_get_parameter(73): Master get parameter failure, error=(0x108) (ESP_ERR_INVALID_RESPONSE).
E (11956) ModbusTCP: Characteristic #1 (Set Charge) read fail, err = 0x108 (ESP_ERR_INVALID_RESPONSE).

Any pointers to help me understand how to make the ModbusTCP Master controller work is really appreciated - but also pointers to where in the documentation I should be able to find the necessary information to acheive a stable connection.

Thanks in advance!

alisitsyn commented 1 year ago

Hi @fink-at-trmc-dk , this error happens because there is specific of using your modbus slave software simulator.

The esp-modbus master supports multiple slave connection and it establishes connection to all slaves first then starts communication. In your case the error happens because your slave simulator closes connection after timeout when master opens it. Please try to play with the options -o # Master activity time-out in seconds (1.0 - 100, 3 s is default) and -c # Connection time-out in seconds (1.0 - 3600, 60 s is default) of your diagslave simulator.

fink-at-trmc-dk commented 1 year ago

Thanks a lot for the pointer which led me to analyzing with wireshark. It turned out that the slave ID sent is zero even though the slave ID was set to 0x47.

I fixed it by adding pucMBTCPFrame[MB_TCP_UID] = (UCHAR)(pxInfo->ucSlaveAddr); in xMBMasterTCPPortSendResponse line 990 and the slave ID is now correctly set.

I do not know if this is the right place to put the fix, but you should be able to reproduce it and come up with a proper fix.

Thanks for the help :-)

alisitsyn commented 1 year ago

@fink-at-trmc-dk ,

Thank you for update. The UID was added long time ago then gone on some merge stage. It will be updated soon as well as other pending MRs.

alisitsyn commented 1 year ago

@fink-at-trmc-dk ,

The issue will be closed automatically once the fix is merged. The fix has been implemented in v1.0.9, commit 8e3771847f826aad37491b96b2b4a2de8d2cbf76. The issue is closed.