After tinkering with the source code, I finally found a
"solution" (for those who experience similar problems.
The root problem here is that for some reason the FTDI chip is sending
a stream of 0s (perhaps some status code?) periodically. See the
following log (after my fix that prevented a complete crash):
INFO Modbus.IO.ModbusRtuTransport ReadRequest - RX: 10, 3, 0, 1, 0,
10, 149, 118
DEBUG Modbus.Device.ModbusSerialSlave Listen - NModbus Slave 1
ignoring request intended for NModbus Slave 10
INFO Modbus.IO.ModbusRtuTransport ReadRequest - RX: 10, 3, 20, 32, 0,
0, 65, 0
DEBUG Modbus.Device.ModbusSerialSlave Listen - NModbus Slave 1
ignoring request intended for NModbus Slave 10
ERROR Modbus.IO.ModbusRtuTransport RequestBytesToRead - Function code
0 not supported.
INFO Modbus.IO.ModbusRtuTransport ReadRequest - RX: 0, 0, 0, 0, 0, 0,
0
ERROR Modbus.Device.ModbusSerialSlave Listen - Argument Exception
encountered while listening for requests - Unsupported function code 0
Parameter name: frame
ERROR Modbus.IO.ModbusRtuTransport RequestBytesToRead - Function code
55 not supported.
INFO Modbus.IO.ModbusRtuTransport ReadRequest - RX: 2, 55, 81, 151,
1, 4, 0
My fix was simple. Basically, I modify the main listen() loop to catch
and ignore the exception generated when an improper function code is
provided. This at least prevents crashing. In the catch() statement, I
flush the input buffer.
The problem then is that the buffer seems to flush in the middle of a
frame (using 9600 baud, with multiple polls per second, so data is
always coming in), making all consecutive frames start at the improper
place. Since ours is a slave with only one function that will ever be
called, I plan to make a simple state machine in the function that
builds the frame, which simply looks for the ID and function code in
the correct order before it allows the frame to be sent.
Figured I'd post this in case other people have problems. Also, if you
have suggestions on how to recover in order to build a complete frame,
that would be nice. It seems using Serial RTU that they missed an
important step of providing a delimiter between frames in order to
determine where it should start. Once it gets off, it stays off unless
you use some magic to bring it back.