Skip to content

drivers/modbus: add initial support (v4) - #22455

Open
basilfx wants to merge 8 commits into
RIOT-OS:masterfrom
basilfx:feature/modbus_rtu_v4
Open

drivers/modbus: add initial support (v4)#22455
basilfx wants to merge 8 commits into
RIOT-OS:masterfrom
basilfx:feature/modbus_rtu_v4

Conversation

@basilfx

@basilfx basilfx commented Jul 9, 2026

Copy link
Copy Markdown
Member

Contribution description

Fourth Third time is the charm, I hope, again.

This is not a complete rewrite, as was the case with #22032. But it does decouple the framing (ADU) from the transports (PDU) as suggested by @kfessel, making it significant enough for a new PR. And while at it, I also added support for ASCII and TCP transports.

Features that are included:

  • ASCII/RTU/TCP support
  • Client/server implementation, with the possibility to run/emulate multiple servers
  • Broadcast support
  • Message validation
  • Separation of PDU and ADU layers
  • Supported function codes:
    • Read Coils (1)
    • Read Discrete Inputs (2)
    • Read Holding Registers (3)
    • Read Input Registers (4)
    • Write Single Coil (5)
    • Write Single Register (6)
    • Write Multiple Coils (15)
    • Write Multiple Registers (16)

Changes

Compared to the previous PRs, the main changes are:

V4:

  • Separated the PDU and ADU layers
  • Added support for ASCII and TCP transports
  • Extended the unit tests a lot.
  • Transport test compatible with all transports
  • Renamed 'Modbus driver' to 'Modbus transport'

V3:

  • Changed from "master/slave" to "server/client" terminology
  • Changed return codes to errno.h ones
  • Separated PDU and ADU layers:
    • drivers/modbus: core protocol data unit (PDU) handling
    • drivers/modbus_rtu: application data unit (ADU) for RTU-specific framing, timing, and error checking
    • Should provide a basis for future Modbus variants (e.g., TCP)
  • Simplified server handling:
    • sending a reply (or not) is now the responsibility of the callback
    • the server can now do whatever it wants with the message
  • Added unit tests for PDU layer
  • Simplified the SAUL example

Testing procedure

I have added three applications to test this driver. My suggestion is to focus on tests/drivers/modbus and tests/drivers/modbus_transport.

tests/drivers/modbus

These are the unit tests for the Modbus PDU layer.

tests/drivers/modbus_transport

This test application provides a shell, with commands to either start a server, a client or both (loopback). This will test the Modbus ASCII, RTU or TCP transport, and proper parsing of the Modbus protocol data units (PDUs).

To run this test in loopback mode, you need a board with at least three UARTs (stdio + server + client). For separated server and client mode, two boards are sufficient. TCP does not support loopback mode

It also includes a 'misbehave' option for servers, to check how a client reacts to misbehaving servers.

See the README.md for more details.

tests/advanced/modbus_saul

This is an example application that demonstrates how to build a Modbus server that wraps around SAUL. Buttons are exposed as 'coils' to read, while LEDs are exposed as 'coils' to write.

To run this application, you need one board for the server, and a USB <-> RS-485 to connect it to a computer. I used qmodbus to interact with the server from the computer.

It also supports Modbus ASCII and TCP. The latter makes it possible to run this natively.

See the README.md for more details.

Bonus: Eastron SDM120

OK, this isn't really part of this branch, but demonstrates how the driver can be used as a client.

The source code can be found in this Gist.

Issues/PRs references

Successor of #22032, #20386, #19819 and #13913

Declaration of AI-Tools / LLMs usage:

AI-Tools / LLMs that were used are:

  • Claude Code with Opus 4.8 was used to get from drivers/modbus: add initial support (v3) #22032 to this PR. That PR was already heavily supported by Opus 4.7.
  • Claude Code with Opus 4.8 was used to generate ASCII and TCP support.
  • Claude Code with Fable 5 was used for reviewing. Comments were resolved manually.

basilfx added 8 commits July 10, 2026 00:13
This adds initial support for the protocol data unit (PDU) part of
the Modbus specification. It provides support for both server and
client mode (formerly master and slave), while also supporting
multiple servers simultaneously.

The following function codes are supported:

* MODBUS_FC_READ_COILS
* MODBUS_FC_READ_DISCRETE_INPUTS
* MODBUS_FC_READ_HOLDING_REGISTERS
* MODBUS_FC_READ_INPUT_REGISTERS
* MODBUS_FC_WRITE_SINGLE_COIL
* MODBUS_FC_WRITE_SINGLE_HOLDING_REGISTER
* MODBUS_FC_WRITE_MULTIPLE_COILS
* MODBUS_FC_WRITE_MULTIPLE_HOLDING_REGISTERS
This commit provides the application data unit (ADU) part of the
Modbus RTU specification. The implementation provides a 'recv' and
'send' implementation that takes care of the framing, timing and error
checking. Any received frame (of interest) is then offloaded to the
generic part that parses the protocol data unit (PDU).
This commit adds the unit tests for the Modbus module.
This application will test the Modbus transport implementations.
This example will demonstrate how to implement a Modbus server, that
wraps around SAUL switches and buttons.
@basilfx
basilfx requested a review from leandrolanzieri as a code owner July 9, 2026 22:22
@basilfx basilfx added the Type: new feature The issue requests / The PR implemements a new feature for RIOT label Jul 9, 2026
@basilfx basilfx added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR AI: Co-Authored PR/Issue relies on AI. Documentation / Code was partly generated by AI. labels Jul 9, 2026
@riot-ci

riot-ci commented Jul 9, 2026

Copy link
Copy Markdown

Murdock results

FAILED

8971358 examples: add examples/modbus_saul to README.md

Success Failures Total Runtime
973 0 10230 01m:55s

Artifacts

@github-actions github-actions Bot added Area: doc Area: Documentation Area: tests Area: tests and testing framework Area: drivers Area: Device drivers Area: examples Area: Example Applications labels Jul 9, 2026
@basilfx

basilfx commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

This is how I manually started the 8 node test:

Scherm­afbeelding 2026-07-09 om 22 48 21

And this is when I made it fail (bottom right):

Scherm­afbeelding 2026-07-09 om 22 45 57

This was my ASCII/RTU set-up (@AnnsAnns wants to see real hardware setups):

IMG_7892

Schematically, it is like this:

553239166-7fd28fb4-6775-41de-8457-95718446962b

This was the set-up of interacting with a real energy meter (a real Modbus device). Unfortunately it isn't that big, but it is the second thing from the left mounted on the rail:

IMG_7894

This is Modbus TCP running on real hardware, even though you don't see the ethernet cable:

IMG_7883

Here are video's of the tests a few of the many tests I ran:

@AnnsAnns

AnnsAnns commented Jul 9, 2026

Copy link
Copy Markdown
Member

This was my ASCII/RTU set-up (@AnnsAnns wants to see real hardware setups):

Don't worry I trust you and your code but cool to see regardless 😆, I can also assume that you have a working dev environment? /s

@basilfx

basilfx commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

And the test results. I ran the tests for Modbus ASCII, Modbus RTU, Modbus TCP and the unit tests. I ran it on several boards, to check for differences in timing and stability (basically the 8 node setup above). All test have ran for a short but long enough time (1-2 minutes). TCP was limited to native only, and the example on the Seeeduino Arch Pro (the only board I have with TCP).

(the tables scroll horizontally)

ASCII

Board CPU Architecture test/drivers/modbus_transport (As server) test/drivers/modbus_transport (As client) examples/advanced/modbus_saul (4800 baud) examples/advanced/modbus_saul (9600 baud) examples/advanced/modbus_saul (115200 baud)
stk3600 EFM32 Cortex M3 OK OK OK OK Not supported (1)
slstk3401a EFM32 Cortex M4 OK OK OK OK Not supported (1)
slstk3402a EFM32 Cortex M4 OK OK OK OK Not supported (1)
pro-mico-nrf52840 nRF52840 Cortex M4 OK OK OK OK OK
rpi-pico RP2040 Cortex M0 OK OK OK OK OK
seeeduino_arch-pro LPC1768 Cortex M3 OK OK OK OK OK
weact-f401ce STM32 Cortex M4 OK OK OK OK OK

RTU

Board CPU Architecture test/drivers/modbus_transport (As server) test/drivers/modbus_transport (As client) examples/advanced/modbus_saul (4800 baud) examples/advanced/modbus_saul (9600 baud) examples/advanced/modbus_saul (115200 baud) sdm120 (extra)
stk3600 EFM32 Cortex M3 OK OK OK OK Not supported (1) OK
slstk3401a EFM32 Cortex M4 OK OK OK OK Not supported (1) OK
slstk3402a EFM32 Cortex M4 OK OK OK OK Not supported (1) OK
pro-mico-nrf52840 nRF52840 Cortex M4 OK OK OK OK OK OK
rpi-pico RP2040 Cortex M0 OK OK OK OK OK OK
seeeduino_arch-pro LPC1768 Cortex M3 OK OK OK OK OK OK
weact-f401ce STM32 Cortex M4 OK OK OK OK OK OK

TCP

Board CPU Architecture test/drivers/modbus_transport (As server) test/drivers/modbus_transport (As client) examples/advanced/modbus_saul
native native64 X64 OK OK OK
seeeduino_arch-pro LPC1768 Cortex M3 Not tested (2) Not tested (2) OK

Unit tests

Board CPU Architecture tests/drivers/modbus
stk3600 EFM32 Cortex M3 OK
slstk3401a EFM32 Cortex M4 OK
slstk3402a EFM32 Cortex M4 OK
pro-mico-nrf52840 nRF52840 Cortex M4 OK
rpi-pico RP2040 Cortex M0 OK
seeeduino_arch-pro LPC1768 Cortex M3 OK
weact-f401ce STM32 Cortex M4 OK
native Native x64 OK
rpi-pico-2-riscv RP2350 RISC-V OK

Footnotes

(1): Secondary UART is limited to 9600 baud.
(2): I only own a single board.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is noted that this is a rather complex test now, especially with ASCII, RTU and TCP support. I did try to split this file into multiple pieces, but the net result was more lines of code.

That said, this test has been really valuable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much more is "more"?

IMO three smaller tests would be more desirable if someone wants to write a Modbus application and take the test as a foundation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to split it in a test part, thread part and 'the rest'. But that adds several headers, and a lot of external declarations because of shared state. Let's say 100+ lines.

A better example for an application is examples/advanced/modbus_saul to be honest.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file itself grew from 1007 lines in V3 to 1246 in V4 btw.

@basilfx
basilfx requested a review from kfessel July 9, 2026 22:52
@basilfx basilfx changed the title Feature/modbus rtu v4 drivers/modbus: add initial support (v4) Jul 9, 2026
@basilfx basilfx added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Co-Authored PR/Issue relies on AI. Documentation / Code was partly generated by AI. Area: doc Area: Documentation Area: drivers Area: Device drivers Area: examples Area: Example Applications Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants