Modbus class design in Python
From Digi Developer
Designing a class system for Modbus
The Modbus protocol is actually 3 forms of encoding of the same core command - referred to by [modbus-ida.org] as a Protocol Data Unit or PDU. Once encoded, the messages become (per Modbus-IDA) an Application Data Unit or ADU. Unfortunately this usage of terms is confusing in an ISO/OSI world since the ADU is the smallest core user data, and not one padded with protocol-specific overhead. But then Modbus is older than ISO/OSI.
Here are example bytes for the function 3 call to node 1 to read 10 words starting at 4x00123 (the 123rd word, which is 122 on the wire)
- Modbus PDU as hex, 0x01 03 00 7A 00 0A
- Modbus/RTU as hex, 0x01 03 00 7A 00 0A (CRCx2)
- Modbus/ASCII as hex, 0x3A,30 31,30 33,30 30,37 41,30 30,30 41 (BCC) 0D 0A (is ASCII string ":0103007A000A??\r\n"
- Modbus/TCP as hex, 0x12 23 00 00 00 06 01 03 00 7A 00 0A
So the natural class design for any Modbus server or client consists of a base class called modbus_pdu, plus three children classes called modbus_tcp, modbus_rtu, and modbus_ascii.
Modbus Server Routines
The actual TCP or UDP handling routines are fairly standard; loop, accept connection and requests, then return response. So the first Modbus-specfic routine for our modbus_tcp and modbus_serial classes to provide is a test_if_complete_message( bytes_seen).
- For class modbus_tcp we first confirm we have a full 6 byte header, then we can parse the length field and confirm we have the correct number of bytes of attached modbus_pdu. Be careful though - over wide-area-network TCP segments might become fragmented, so you cannot assume an entire request arrives at one time. Also, some applications concatenate (pipeline) multiple requests into one segment, so a TCP packet with 36 bytes of data might contain three complete 12-byte requests.
- For class modbus_rtu the task is more difficult. The formal definition for Modbus/RTU ending with a pause of 3.5 'character times' is meaningless over wide-area-network. The best solution - since this is YOUR server - is just to make a function-aware tool. You know which functions you support, so confirm each supported function is the correct length
- For class modbus_ascii the task is simpler again; anything starting with a ":" character and ending in the two characters "\r\n" is considered complete.
