Skip to content

Modbus server: Support more than one unit #97868

@sjlongland

Description

@sjlongland

Summary

In the Modbus server implementation, the interface doesn't allow for more than one Modbus unit to be defined.

In my use case, I had a number of I²C devices (TI INA219s) that I wanted to expose via Modbus/RTU so I could poll them over a serial link from collectd. However, when I went to implement the callback functions for the Modbus server, I observed that they only provide a register number and a pointer for the result. There was no way for me to know which unit ID was being accessed.

It would appear that struct modbus_iface_param only makes provision for a single server.

This is quite limiting. I've had to kludge it by jamming everything into a single logical Modbus "unit" and using register offsets to identify which device the data is coming from.

Describe the solution you'd like

It'd be much more flexible if the struct modbus_iface_param could take an array of struct modbus_server_params, each optionally passing a void * context pointer; passing the pointer to the struct modbus_server_param to callback functions as the first argument.

i.e.

struct modbus_user_callbacks {
        int (*coil_rd)(const struct modbus_server_param *server, uint16_t addr, bool *state);
        int (*coil_wr)(const struct modbus_server_param *server, uint16_t addr, bool state);
        int (*discrete_input_rd)(const struct modbus_server_param *server, uint16_t addr, bool *state);
        int (*input_reg_rd)(const struct modbus_server_param *server, uint16_t addr, uint16_t *reg);
        int (*input_reg_rd_fp)(const struct modbus_server_param *server, uint16_t addr, float *reg);
        int (*holding_reg_rd)(const struct modbus_server_param *server, uint16_t addr, uint16_t *reg);
        int (*holding_reg_wr)(const struct modbus_server_param *server, uint16_t addr, uint16_t reg);
        int (*holding_reg_rd_fp)(const struct modbus_server_param *server, uint16_t addr, float *reg);
        int (*holding_reg_wr_fp)(const struct modbus_server_param *server, uint16_t addr, float reg);
};

struct modbus_server_param {
        modbus_user_callbacks *user_cb;
        void *user_ctx;
        uint8_t unit_id;
};

struct modbus_iface_param {
        enum modbus_mode mode;
        union {
                struct modbus_server_param *server;
                uint32_t rx_timeout;
        };
        union {
                struct modbus_serial_param serial;
                struct modbus_raw_cb rawcb;
        };
};

The array could be terminated by a struct modbus_server_param with a unit_id of 0; since that is a "reserved" address used for broadcasts to "all slave devices". Alternatively, a NULL user_cb pointer could indicate "the end".

This would make it possible to define homogenous or even heterogenous arrays of arbitrary Modbus units that would then be exposed on the Modbus/RTU or Modbus/TCP interface.

Alternatives

No response

Additional Context

No response

Metadata

Metadata

Assignees

Labels

EnhancementChanges/Updates/Additions to existing featuresarea: modbus

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions