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

Restrict write operation on holding register (IDFGH-9625) #23

Closed JimitD closed 1 year ago

JimitD commented 1 year ago

Hello team,

I am developing Modbus Slave Application with read and write access to multiple registers. The application requirement is, Master should be able to read all the registers in one go. (Say 100 registers at a time). So I have defined "reg_area.type" as "MB_PARAM_HOLDING". In this case, access is given to all the registers to be Read & Write. I need to have some registers to be Read-only access. Here I can use "reg_area.type" as "MB_PARAM_INPUT " but, I can not read all the registers in the one Go. I have to read Holding Registers and again I have to read Input Registers.

So, how can I restrict write operations to specific Holding Registers?

I am using example code given in ESP-Modbus as linked below,

https://github.com/espressif/esp-idf/blob/v4.1/examples/protocols/modbus/serial/mb_slave/main/slave.c

alisitsyn commented 1 year ago

Hello @JimitD,

Could you let me know what physical interface you use for your slave device (TCP or Serial)?

Here I can use "reg_area.type" as "MB_PARAM_INPUT " but, I can not read all the registers in the one Go. I have to read Holding Registers and again I have to read Input Registers.

If I understand your project correctly you need a way to define the custom holding register area with the write restriction on slave side to read it.

40001, 99 - Holding reg area 1 (read and write allowed) 40100, 49 - Holding register area 2 (write protected, on write returns an exception MB_EIO to Modbus master) 40150, N- Holding register read/write area

Read of whole area 40001 - 40160 is allowed, write is restricted for area 40100 40150.

This is custom option and not supported for now. The Modbus defines RW and RO register areas and if you need read only access you define your registers as INPUT and HOLDING otherwise. If the above is what is desired for your project I can explain on how to add access restriction option for register area and your custom read/write handler in the stack to realize this behavior. This option will require modification of stack code.

JimitD commented 1 year ago

Hi @alisitsyn,

Thanks for your time.

I am using the Serial interface for communication.

Yes, your example is correct. I need to have specific register area where it is write protected. (with Holding register only)

This need arise because Master wanted to read all the parameter in one go & if I define different "register_area" then Master need to poll them sequentially.

Please explain how to write custom read/write handler to achieve this functionality.

Also, how to validate data before it is written to any register? can we restrict this too?

In present stack, event is given to know if it is READ or WRITE operation but I would like to know the data before it is written to register.

Kind regards, Jimit Damania

alisitsyn commented 1 year ago

Hi @Jimit Damania, The steps are below:

  1. Move the esp-modbus component folder to the components folder of your root project and remove the idf_component.yml from your project main folder if it is.

  2. The below modifications of the component can be done in components/esp-modbus folder.

  3. Implement the holding register handler similar to default

  4. Implement the customized write handler in the [mbc_serial_slave.c] (https://github.com/espressif/esp-modbus/blob/master/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c#L233) and then assign the mbs_interface_ptr->slave_reg_cb_holding = your_new_holding_rw_handler;.

  5. Implement the new field bool access_ro here. This can be assigned to true when you create the restricted holding register area in your user application.

  6. In your write handler, your_new_holding_rw_handler() function implement the custom functionality to check the it->bool access_ro field and return MB_EIO exception from function which will trigger an exception for master if it tries to write to this area. You can also get the source data and the memory address it will be written to.

Please note that the handler should be relatively simple[short] and shall handle all possible exceptions carefully.

JimitD commented 1 year ago

Hi @alisitsyn,

Thank you for explanation. I will check and let you know

JimitD commented 1 year ago

Hi @alisitsyn,

Would you please provide one sample your_new_holding_rw_handler() function? Also, will it be able to get source data and address info before it is written to registers?

Thanks,

alisitsyn commented 1 year ago

The example of overridden function is implemented here. Some earlier example is here

Also, will it be able to get source data and address info before it is written to registers?

Yes, you will have access to all required data from the custom handler. See the reg_buffer, and holding_buffer pointers description, address, n_regs.

JimitD commented 1 year ago

Thank you @alisitsyn.

This helps a lot.