Page 1 of 1

mbc_slave_get_param_info does not catch different addresses

Posted: Wed Jul 31, 2024 3:37 pm
by AndreaS73
ESP32-S3, here my code derived from the slave example:

Code: Select all

#include "modbus.h"
#include <mbcontroller.h>

#include "../resources/modbus_params.h"
#include "../utils/settings.h"

#include <esp_err.h>
#include <esp_log.h>
#include <esp_system.h>
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <esp_netif.h>
#include <esp_mac.h>
#include <sys/time.h>

#include "../tasks/task_wifi.h"
#include "pump.h"
#include "valves.h"

#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) >> 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) >> 1))

#define MB_REG_DISCRETE_INPUT_START         (0x0000)
#define MB_REG_COILS_START                  (0x0000)
#define MB_REG_INPUT_START                  (INPUT_OFFSET(battery_voltage)) 
#define MB_REG_HOLDING_START                (HOLD_OFFSET(w_datetime))

#define MB_READ_MASK                        (MB_EVENT_INPUT_REG_RD \
                                                | MB_EVENT_HOLDING_REG_RD \
                                                | MB_EVENT_DISCRETE_RD \
                                                | MB_EVENT_COILS_RD)
#define MB_WRITE_MASK                       (MB_EVENT_HOLDING_REG_WR \
                                                | MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK                  (MB_READ_MASK | MB_WRITE_MASK)

static const char *TAG = "MODBUS";

extern Settings_t settings;

static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;

static void init_reg_data(void)
{
    discrete_reg_params.gasket_lock = 0;

    holding_reg_params.w_datetime = 0;
    strcpy(holding_reg_params.serial_number, "12345678");
    strcpy(holding_reg_params.id_position, "abcdefgh");
    // other initializations
}

static void slave_operation_func(void *arg)
{
    esp_err_t err;
    mb_param_info_t reg_info; 

    while (1)
    {
        mb_event_group_t event = mbc_slave_check_event(MB_WRITE_MASK);
        if (event & MB_EVENT_HOLDING_REG_WR)
        {
            err = mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT);
            ESP_LOGI(TAG, "%d\tHOLDING WRITE, ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
                            err,
                            (unsigned)reg_info.mb_offset,
                            (unsigned)reg_info.type,
                            (uint32_t)reg_info.address,
                            (unsigned)reg_info.size);
        }

        printf(".\n");
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

esp_err_t init_reg_area(mb_param_type_t type, uint16_t start_offset, void *address, size_t size)
{
    mb_register_area_descriptor_t reg_area; 
    reg_area.type = type;
    reg_area.start_offset = start_offset; 
    reg_area.address = address; 
    reg_area.size = size;
    esp_err_t err = mbc_slave_set_descriptor(reg_area);
    MB_RETURN_ON_FALSE(err == ESP_OK, ESP_ERR_INVALID_STATE, TAG, "mbc_slave_set_descriptor fail, returns(0x%x).", (int) err);
    return err;
}

static esp_err_t slave_init(mb_communication_info_t *comm_info)
{
    void *slave_handler = NULL;

    esp_err_t err = mbc_slave_init_tcp(&slave_handler);
    MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE, TAG, "mb controller initialization fail.");

    comm_info->ip_addr = NULL;
    comm_info->ip_netif_ptr = (void*) Wifi_GetNetif();
    comm_info->slave_uid = MB_SLAVE_ADDR;
    err = mbc_slave_setup((void*)comm_info);
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mbc_slave_setup fail, returns(0x%x).", (int)err);

    init_reg_area(MB_PARAM_HOLDING, MB_REG_HOLDING_START, (void*)&holding_reg_params, sizeof(holding_reg_params));
    init_reg_area(MB_PARAM_INPUT, MB_REG_INPUT_START, (void*)&input_reg_params, sizeof(input_reg_params));
    init_reg_area(MB_PARAM_COIL, MB_REG_COILS_START, (void*)&coil_reg_params, sizeof(coil_reg_params));
    init_reg_area(MB_PARAM_DISCRETE, MB_REG_DISCRETE_INPUT_START, (void*)&discrete_reg_params, sizeof(discrete_reg_params));
    init_reg_data();

    err = mbc_slave_start();
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mbc_slave_start fail, returns(0x%x).", (int)err);
    vTaskDelay(5);
    return err;
}

static esp_err_t slave_destroy(void)
{
    esp_err_t err = mbc_slave_destroy();
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mbc_slave_destroy fail, returns(0x%x).", (int) err);
    return err;
}

void Modbus_Init(void)
{
    mb_communication_info_t comm_info = { 0 };

    comm_info.ip_addr_type = MB_IPV4;
    comm_info.ip_mode = MB_MODE_TCP;
    comm_info.ip_port = MB_TCP_PORT_NUMBER;
    ESP_ERROR_CHECK(slave_init(&comm_info));
    slave_operation_func(NULL);
}

void Modbus_Deinit(void)
{
    slave_destroy();
}
The problem is, no matter which holding register I write, it returns the following info:
I (31790) MODBUS: 0 HOLDING WRITE, ADDR:0, TYPE:2, INST_ADDR:0x3fca1ff0, SIZE:40
I don't understand why it does not catch the other addresses. Also the size is wron: it returns the whole size of the holding registers, not of the one being written.

Here my data definition:

Code: Select all

#pragma pack(push, 1)
typedef struct
{
    uint64_t w_datetime; // 400001
    char serial_number[10]; // 400005
    char id_position[10]; // 400010

    float target_pressure; // 400015
    float critical_pressure; // 400017
    float min_pressure; // 400019
    int16_t timeout; // 40021

    int16_t target_pressure_max; // 40022
    int16_t target_pressure_min; // 40023
    int16_t target_inflate_timeout; // 40024
    int16_t target_hold_timeout; // 40025
    int16_t target_hold_duration; // 40026
    int16_t test_pressure_drop; // 40027
    int16_t test_duration;  // 40028

    float t_offset; // 40029
    float t_gain; // 40031
    float e_offset; // 40033
    float e_gain; // 40035
    uint64_t calibration_datetime; // 400037
} holding_reg_params_t;
#pragma pack(pop)

Re: mbc_slave_get_param_info does not catch different addresses

Posted: Wed Jul 31, 2024 4:04 pm
by AndreaS73
After digging it out, it seems the problem is:

Code: Select all

mb_event_group_t event = mbc_slave_check_event(MB_WRITE_MASK);
that does not filter out the readings. For example, my client reads every 1000 ms and sometimes writes a holding register.
But `event` has the following value 0x83, hence both reading and writing. But I asked for writings only!

Now when I try to get the details of the writings with:

Code: Select all

mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT);
it happens that it return the details of the readings instead!
I tried to add:

Code: Select all

if (reg_info.type != MB_EVENT_HOLDING_REG_WR) continue;
and to change:

Code: Select all

mbc_slave_check_event(MB_READ_WRITE_MASK);
but still no luck. With these two changes sometimes I also get the right details from `mbc_slave_get_param_info`.

What should I do?