Modbus TCP Implementation
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: Modbus TCP Implementation
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.
Re: Modbus TCP Implementation
@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):
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
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;
}
}
Last edited by jas39_ on Thu Mar 04, 2021 6:41 pm, edited 1 time in total.
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: Modbus TCP Implementation
@ jas39_,
This has been already fixed in my MR. Thanks for finding.
This has been already fixed in my MR. Thanks for finding.
Re: Modbus TCP Implementation
@Esp_alisitsyn,
Do you have a plan to push your MR to github? This bug remains in v4.3-beta
Do you have a plan to push your MR to github? This bug remains in v4.3-beta
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: Modbus TCP Implementation
@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.
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.
Re: Modbus TCP Implementation
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
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
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: Modbus TCP Implementation
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
Modbus Slave:
Register definition example:
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.
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));
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: No registered users and 100 guests