nxmodbus NuttX Modbus
NxModbus is a lightweight Modbus protocol stack implementation for NuttX RTOS. It provides client and server functionality for RTU, ASCII, and TCP transports with a clean, callback-based API.
NxModbus follows the Modbus Organization’s modern terminology (adopted September 2020):
Client: Device that initiates requests (formerly “Master”)
Server: Device that processes requests and returns responses (formerly “Slave”)
Device: Remote Modbus device (in exception codes)
This aligns with current industry standards and matches other modern protocols (HTTP, MQTT, OPC-UA).
NxModbus uses 0-based addressing. Addresses passed to application callbacks match the Modbus wire protocol directly: address 0 on the wire is address 0 in the callback. This is consistent with libmodbus, pymodbus, and the Modbus Application Protocol specification.
This differs from FreeModBus, which adds 1 to wire addresses before passing
them to callbacks (PLC register numbering convention). If migrating from
FreeModBus, remove any addr - 1 adjustments in your callback functions.
Features
Multiple Transports: RTU (serial), ASCII (serial), TCP, and raw ADU
Client/Server Modes: Full support for both roles
Callback Architecture: No internal data storage, application controls all data
Conditional Termios: Supports systems with and without termios
Thread-Safe: Mutex-protected context operations
Multi-Instance: Supports concurrent instances with independent configuration
Extensible: Custom function code registration via
nxmb_register_custom_fc()
Supported Function Codes
NxModbus implements the following Modbus function codes:
Bit Access:
FC01 (0x01): Read Coils
FC02 (0x02): Read Discrete Inputs
FC05 (0x05): Write Single Coil
FC15 (0x0F): Write Multiple Coils
Register Access:
FC03 (0x03): Read Holding Registers
FC04 (0x04): Read Input Registers
FC06 (0x06): Write Single Holding Register
FC16 (0x10): Write Multiple Holding Registers
FC23 (0x17): Read/Write Multiple Holding Registers
Diagnostics and Identification:
FC08 (0x08): Diagnostics (sub-function 0x0000 Return Query Data)
FC17 (0x11): Report Server ID
Each server-side function code handler can be individually enabled or disabled
via Kconfig (all enabled by default). Disabled handlers respond with
Illegal Function exception. Client-side request functions are always available
when CONFIG_NXMODBUS_CLIENT is enabled. Custom function codes can be
registered via nxmb_register_custom_fc() when CONFIG_NXMODBUS_CUSTOM_FC
is enabled.
Transport Modes
RTU (
CONFIG_NXMODBUS_RTU): Binary encoding over serial with CRC16 error checking. Uses T1.5 and T3.5 character timing for frame delimiting. Supports configurable baud rate and parity.ASCII (
CONFIG_NXMODBUS_ASCII): Hex-encoded text over serial with LRC error checking. Frames are delimited by ‘:’ start and CR/LF end markers. Character timeout is configurable viaCONFIG_NXMODBUS_ASCII_TIMEOUT_SEC.TCP (
CONFIG_NXMODBUS_TCP): Modbus frames encapsulated in TCP/IP using the MBAP (Modbus Application Protocol) header. Default port 502. Supports both server (listening) and client (connecting) modes. Server mode supports multiple simultaneous client connections (configurable viaCONFIG_NXMODBUS_TCP_MAX_CLIENTS, default 1, up to 8). RequiresCONFIG_NET_TCP.Raw ADU (
CONFIG_NXMODBUS_RAW_ADU): Application-provided callbacks for transmitting and receiving raw Modbus frames. Enables custom transport backends such as TLS, CAN, BLE, or MQTT.
Architecture
NxModbus uses a three-layer architecture:
Core Layer (
core/): Protocol logic, function handlers, exception handlingTransport Layer (
transport/): RTU, ASCII, TCP, and raw ADU implementationsPublic API (
include/nxmodbus/): Application interface
The transport layer uses a function pointer-based abstraction (nxmb_transport_ops_s)
allowing runtime selection of transport mode.
Configuration Options
NxModbus configuration is integrated into the NuttX Kconfig system:
Role Selection:
CONFIG_NXMODBUS_SERVER– Enable Modbus server supportCONFIG_NXMODBUS_CLIENT– Enable Modbus master (client) support
Transport Selection:
CONFIG_NXMODBUS_RTU– Enable Modbus RTU (serial) transportCONFIG_NXMODBUS_ASCII– Enable Modbus ASCII (serial) transportCONFIG_NXMODBUS_TCP– Enable Modbus TCP transport (requiresCONFIG_NET_TCP)CONFIG_NXMODBUS_RAW_ADU– Enable raw ADU transport (custom backends)
Function Code Selection (server-side, all enabled by default):
CONFIG_NXMODBUS_FUNC_READ_COILS– FC01 Read CoilsCONFIG_NXMODBUS_FUNC_READ_DISCRETE– FC02 Read Discrete InputsCONFIG_NXMODBUS_FUNC_READ_HOLDING– FC03 Read Holding RegistersCONFIG_NXMODBUS_FUNC_READ_INPUT– FC04 Read Input RegistersCONFIG_NXMODBUS_FUNC_WRITE_COIL– FC05 Write Single CoilCONFIG_NXMODBUS_FUNC_WRITE_HOLDING– FC06 Write Single Holding RegisterCONFIG_NXMODBUS_FUNC_DIAGNOSTICS– FC08 DiagnosticsCONFIG_NXMODBUS_FUNC_WRITE_COILS– FC15 Write Multiple CoilsCONFIG_NXMODBUS_FUNC_WRITE_HOLDINGS– FC16 Write Multiple Holding RegistersCONFIG_NXMODBUS_FUNC_REPORT_SERVER_ID– FC17 Report Server IDCONFIG_NXMODBUS_FUNC_READWRITE_HOLDINGS– FC23 Read/Write Multiple Holding Registers
Instance and Buffer Configuration:
CONFIG_NXMODBUS_MAX_INSTANCES– Maximum concurrent Modbus instances (1-16, default: 1)CONFIG_NXMODBUS_BUFFER_SIZE– ADU buffer size in bytes (64-256, default: 256)
FC17 Report Server ID:
CONFIG_NXMODBUS_REP_SERVER_ID_BUF– Buffer size for Report Server ID response data (4-253, default: 32). Holds server ID, run indicator, and optional additional data configured vianxmb_set_server_id().
Timeouts:
CONFIG_NXMODBUS_CLIENT_TIMEOUT_MS– Default client response timeout in milliseconds (100-60000, default: 1000). Can be overridden at runtime vianxmb_set_timeout().CONFIG_NXMODBUS_TCP_MAX_CLIENTS– Maximum simultaneous TCP client connections per server instance (1-8, default: 1).CONFIG_NXMODBUS_TCP_TIMEOUT_SEC– TCP idle connection timeout in seconds (1-3600, default: 60). Connections with no activity beyond this period are closed.CONFIG_NXMODBUS_RTU_IDLE_TIMEOUT_MS– RTU inter-frame idle timeout in milliseconds (1-1000, default: 50). Fallbackselect()timeout when waiting for a new frame. T3.5 character timing is still used for frame delimiting during active reception.CONFIG_NXMODBUS_ASCII_TIMEOUT_SEC– Character timeout for ASCII mode in seconds (1-60, default: 1)
Serial Configuration (RTU/ASCII):
CONFIG_SERIAL_TERMIOS– Enable termios-based serial configurationIf disabled, serial ports are used in raw mode without baud rate or parity configuration. This is useful for systems without termios support or when using pre-configured serial devices.
Extensibility:
CONFIG_NXMODBUS_CUSTOM_FC– Enable custom function code handler registration
Termios Support
NxModbus conditionally uses termios for serial port configuration based on
CONFIG_SERIAL_TERMIOS:
With termios (CONFIG_SERIAL_TERMIOS=y):
Full baud rate configuration (9600, 19200, 38400, 57600, 115200)
Parity configuration (none, even, odd)
Automatic raw mode setup (no echo, no canonical mode)
Original settings saved and restored on cleanup
Without termios (CONFIG_SERIAL_TERMIOS=n):
Serial device opened in raw mode
No baud rate or parity configuration
Device must be pre-configured or support raw I/O
Useful for:
Systems without termios support
Pre-configured serial backends
Custom serial drivers
Non-standard serial devices
API Reference
Instance Management:
nxmb_create()– Create and initialize an NxModbus instancenxmb_destroy()– Destroy an instance and release resourcesnxmb_enable()– Enable transport and start processingnxmb_disable()– Stop processing and release transport
Server Configuration:
nxmb_set_callbacks()– Register application callbacks for data model accessnxmb_set_server_id()– Configure FC17 Report Server ID response datanxmb_poll()– Execute one server-side polling iteration
Client Functions (require CONFIG_NXMODBUS_CLIENT):
nxmb_read_coils()– Read coils (FC01)nxmb_read_discrete()– Read discrete inputs (FC02)nxmb_read_holding()– Read holding registers (FC03)nxmb_read_input()– Read input registers (FC04)nxmb_write_coil()– Write single coil (FC05)nxmb_write_holding()– Write single holding register (FC06)nxmb_write_coils()– Write multiple coils (FC15)nxmb_write_holdings()– Write multiple holding registers (FC16)nxmb_readwrite_holdings()– Read/write multiple holding registers (FC23)nxmb_set_timeout()– Set client-side response timeout
Extensibility (require CONFIG_NXMODBUS_CUSTOM_FC):
nxmb_register_custom_fc()– Register a custom function code handler
Exception Codes
NxModbus implements standard Modbus exception codes:
NXMB_EX_NONE(0x00): No exceptionNXMB_EX_ILLEGAL_FUNCTION(0x01): Function code not supportedNXMB_EX_ILLEGAL_DATA_ADDRESS(0x02): Register address out of rangeNXMB_EX_ILLEGAL_DATA_VALUE(0x03): Invalid data valueNXMB_EX_DEVICE_FAILURE(0x04): Device failureNXMB_EX_ACKNOWLEDGE(0x05): Request acknowledged (long operation)NXMB_EX_DEVICE_BUSY(0x06): Device busyNXMB_EX_MEMORY_PARITY_ERROR(0x08): Memory parity errorNXMB_EX_GATEWAY_PATH_FAILED(0x0A): Gateway path unavailableNXMB_EX_GATEWAY_TGT_FAILED(0x0B): Gateway target failed to respond
Comparison with FreeModBus
NxModbus is an alternative to FreeModBus with several improvements:
Modern client/server terminology
Cleaner API with opaque handles
Multi-instance support
Conditional termios support
Thread-safe by design
No global state
Raw ADU transport for custom backends (TLS, CAN, BLE, MQTT)
Extensible function code table via
nxmb_register_custom_fc()