Modbus: Support for user defined function codes


Henrik Lindblom
 

Hi!

I was wondering if there's any work being done to allow users to
extend Modbus by defining their own function codes (and handlers to
those)? I looked at the implementation in 2.6.0 and there is
MODBUS_RAW which sort of allows the user to define a callback to
handle arbitrary ADUs, but this is only for TCP (not really sure as to
why the limitation, though). I was tinkering around the codebase and
figured it would be easy enough to augment struct modbus_context to
include a list of user provided extensions that are tried if the PDU
has an unknown function code.

There are a few of reasons why having this feature would be nice:

- As of now, it seems that the full Modbus spec isn't implemented and
this would allow end users to work around that, if necessary.
- Modbus has specific function ranges for user defined features.
- Since Modbus is easy to extend, it's not uncommon to do so.

I implemented a quick hack which I'm still testing, but one thing that
I find a bit redundant in my approach is that MODBUS_RAW already
implements *almost* this functionality. The drawback IMO is that it
only allows a single callback to be defined, which ~works, but doesn't
allow users to benefit from the existing handler code, and makes the
API / Kconfig more confusing. I at least had no clue what MODBUS_RAW
was until I looked at the code. The optimal solution would be to
combine these two and remove the TCP only -restriction from
MODBUS_RAW.

I'm willing to put in a PR for review if anybody else is interested in
this.

Cheers,
Henrik


Johann Fischer
 

Hi,

Am 16.10.2021 20:43 schrieb Henrik Lindblom:
Hi!
I was wondering if there's any work being done to allow users to
extend Modbus by defining their own function codes (and handlers to
those)?
not yet.

I looked at the implementation in 2.6.0 and there is
MODBUS_RAW which sort of allows the user to define a callback to
handle arbitrary ADUs, but this is only for TCP (not really sure as to
why the limitation, though).
It is not limited to TCP and allows to use any transport backend than UART.
It is actually other end of the system.

I was tinkering around the codebase and
figured it would be easy enough to augment struct modbus_context to
include a list of user provided extensions that are tried if the PDU
has an unknown function code.
It could work, struct modbus_server_param should also be changed accordingly.
And we would need test for this functionality.

There are a few of reasons why having this feature would be nice:
- As of now, it seems that the full Modbus spec isn't implemented and
this would allow end users to work around that, if necessary.
- Modbus has specific function ranges for user defined features.
- Since Modbus is easy to extend, it's not uncommon to do so.
There is a mandatory function from the spec that is not implemented? Which one?

I implemented a quick hack which I'm still testing, but one thing that
I find a bit redundant in my approach is that MODBUS_RAW already
implements *almost* this functionality. The drawback IMO is that it
only allows a single callback to be defined, which ~works, but doesn't
allow users to benefit from the existing handler code, and makes the
API / Kconfig more confusing. I at least had no clue what MODBUS_RAW
was until I looked at the code. The optimal solution would be to
combine these two and remove the TCP only -restriction from
MODBUS_RAW.
As said MODBUS_RAW is another side of the system and has nothing to do with "FC handling" directly.

Johann


Henrik Lindblom
 

Hi Johann, thanks for the reply!

>> There are a few of reasons why having this feature would be nice:
>> - As of now, it seems that the full Modbus spec isn't implemented and
>> this would allow end users to work around that, if necessary.
>> - Modbus has specific function ranges for user defined features.
>> - Since Modbus is easy to extend, it's not uncommon to do so.

> There is a mandatory function from the spec that is not implemented? Which one?

Well, depends on how you look at it whether you'd consider it
mandatory. The spec
https://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
section 5 p. 10 says that there are specific ranges of user-defined
function codes whose implementation is left to the vendor, referring
to device manufacturers. The existence of said ranges probably doesn't
count as a mandatory requirement for the software stack provider (in
this case Zephyr), but device vendors might consider it a requirement
when selecting a stack. Anyway, it's a nice feature to have.


> It could work, struct modbus_server_param should also be changed accordingly.
> And we would need test for this functionality.

I was originally thinking of adding a new API function in the lines of modbus_register_function(),
but adding a pointer to modbus_server_param is arguably simpler.

I haven't had the time to dig into the testing side of Zephyr. I guess the tests are written against QEMU?
If so, I might try to add a few tests next.

Btw, what's your preferred workflow with GitHub PRs? Mainly, should I open an issue before creating
a PR and who to add as reviewers? I scanned the maintainers file but couldn't find a suitable
section for Modbus.