Modbus TCP Implementation

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: Modbus TCP Implementation

Postby ESP_alisitsyn » Tue Nov 17, 2020 9:01 pm

It is pretty simple to implement in current update but let me know if you need help. Please make sure your callback function can safely return after maximum timeout even when r/w operation is not completed.

jas39_
Posts: 21
Joined: Mon Aug 29, 2016 8:26 pm

Re: Modbus TCP Implementation

Postby jas39_ » Sun Dec 06, 2020 12:35 pm

@ESP_alisitsyn,

I think I've found an issue with the the code. I have a multi-region setup where I also have a mix of 16 and 32 bit registers. This means that one memory region can be followed by another without an "empty" address in between but with different read/write sizes.

The current check to see if an address is withinin a defined area looks liker this, (copied from (esp_modbus_slave.c):

Code: Select all

   
   // search for the register in each area
    for (it = LIST_FIRST(&mbs_opts->mbs_area_descriptors[type]); it != NULL; it = LIST_NEXT(it, entries)) {
        reg_size = REG_SIZE(type, it->size);
        if ((addr >= it->start_offset)
            && (it->address)
            && (regs >= 1)
            && ((addr + regs) <= (it->start_offset + reg_size +1 ))   // This seems to be the issue
            && (reg_size >= 1)) {
            return it;
        }
    }
  
i.e less or equal to the area +1, which works if there is a gap in address but not in the described case. Easily fixed :D
Last edited by jas39_ on Thu Mar 04, 2021 6:41 pm, edited 1 time in total.

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: Modbus TCP Implementation

Postby ESP_alisitsyn » Tue Dec 22, 2020 2:47 pm

@ jas39_,

This has been already fixed in my MR. Thanks for finding.

jas39_
Posts: 21
Joined: Mon Aug 29, 2016 8:26 pm

Re: Modbus TCP Implementation

Postby jas39_ » Thu Mar 04, 2021 9:40 pm

@Esp_alisitsyn,
Do you have a plan to push your MR to github? This bug remains in v4.3-beta

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: Modbus TCP Implementation

Postby ESP_alisitsyn » Fri Mar 05, 2021 11:08 am

@jas39_

The MR has been merged. The fix commit is 60dfb09122f079af4e513a87e3778a5de252e6ca and will be replicated to github repo automatically. I will try to find the reasons for delays.

SergeyV
Posts: 1
Joined: Wed Aug 18, 2021 7:53 pm

Re: Modbus TCP Implementation

Postby SergeyV » Wed Aug 18, 2021 8:03 pm

Hello
where are the register addresses defined? Can I change them from 4000 to 0?
In which function is the address checked for a range (ILLEGAL DATA ADRESS )?
thanks

ESP_alisitsyn
Posts: 211
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: Modbus TCP Implementation

Postby ESP_alisitsyn » Thu Aug 19, 2021 4:15 pm

Hello @SergeyV,

In the master/slave stack examples the register addresses are zero based. in the example if you need to address the 4x register area (Holding register) = 40002 the stack will have the offset = 0x0002
Modbus Master:
The address of the register is defined in the object dictionary

Code: Select all

// Example Data (Object) Dictionary for Modbus parameters:
// The CID field in the table must be unique.
// Modbus Slave Addr field defines slave address of the device with correspond parameter.
// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such).
// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly.
// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value.
// Data Type, Data Size specify type of the characteristic and its data size.
// Parameter Options field specifies the options that can be used to process parameter value (limits or masks).
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
const mb_parameter_descriptor_t device_parameters[] = {
    // { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
    { CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2 /*(for address 40002)*/, 2,
            HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 65535, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    ....
    }
   

Code: Select all

 mb_reg_start = 2 (Relative register address of the characteristic in the register area.)

Modbus Slave:

Register definition example:

Code: Select all

#define MB_REG_INPUT_START_AREA0    (0)
#define MB_REG_HOLDING_START_AREA0  (0) // <<<<<<<<<<< register offset for the area
#define MB_REG_HOLD_CNT             (100)
#define MB_REG_INPUT_CNT            (100)

mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
unit16_t holding_reg_area[MB_REG_HOLD_CNT] = {0}; // storage area for holding registers
unit16_t input_reg_area[MB_REG_INPUT_CNT] = {0}; // storage area for input registers

reg_area.type = MB_PARAM_HOLDING;                                  // Set type of register area
reg_area.start_offset = MB_REG_HOLDING_START_AREA0;   // Offset of register area in Modbus protocol (<<<< register offset)
reg_area.address = (void*)&holding_reg_area[0];                 // Set pointer to storage instance
reg_area.size = sizeof(holding_reg_area) << 1;                    // Set the size of register storage area in bytes
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

reg_area.type = MB_PARAM_INPUT;
reg_area.start_offset = MB_REG_INPUT_START_AREA0;
reg_area.address = (void*)&input_reg_area[0];
reg_area.size = sizeof(input_reg_area) << 1;
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
The function mbc_modbus_slave.c::mbc_slave_find_reg_descriptor(mb_param_type_t type, uint16_t addr, size_t regs)
https://github.com/espressif/esp-idf/bl ... lave.c#L62
is called from each function handler to check if the register being read by master corresponds to defined register area.
The slave code supports definition of several register areas of each type.

In your question it is not clear if you going to define register with offset 4000 in master or slave and the address looks very similar to Modicon notation of registers and my answer follows this notation. Register types and reference ranges recognized with Modicon notation are as follows:

0x = Coil = 00001-09999
1x = Discrete Input = 10001-19999
3x = Input Register = 30001-39999
4x = Holding Register = 40001-49999

Please let me know if you need more information. Thanks.

Who is online

Users browsing this forum: Corand and 117 guests