Reworked the RTU process
Miq1 opened this issue · comments
@BrotherCreamy @I-Connect @OekoSolveMG @zivillian @SuGlider @TLS1000
Guys, I mentioned you because you all were affected by some bugs and shortcomings in the RTU handling of eModbus (issues #252, #239 and #198, to name the most relevant).
In the meantime I reworked the RTU receive process in a couple of steps and I believe it will do better now. I would ask you to give it a try and report back about the results.
The new code is in a separate branch for now, called Stream-RTU
.
Major changes:
- the RTU code now accepts a
Stream
object instead of aHardwareSerial
. For the latter there will be few differences, but it opens up to useSoftwareSerial
or whatever elseStream
-derived channel is used. - as a consequence the
begin()
functions ofModbusClientRTU
andModbusServerRTU
have been changed. They will need a baud rate as first parameter now and optionally can give a core to be run on as the second:
void ModbusClientRTU::begin(uint32_t baudrate = 9600, int coreID = -1);
void ModbusServerRTU::begin(uint32_t baudRate = 9600, int coreID = -1);
- The baud rate is necessary to calculate the message interval from it, a
Stream
does not have a notion of it. As you can see the default is set to 9600 baud, but that will definitely fail for baud rates used in the communication that are below that value. It was the best assumption I could make today. - Note that the older start/stop in
ModbusServerRTU
now has been replaced by begin/end!
The extraction of the HardwareSerial
manipulations from the code requires the user (you! 😉 ) to do preparations before starting a ModbusServerRTU
/ModbusClientRTU
, though. Here as an example are shown the settings necessary for Serial1
:
// Set up Serial1
Serial1.setRxBufferSize(520); // Needed with higher baud rates. ASCII=520, RTU=260
Serial1.begin(BaudRate, SERIAL_8N1, GPIO_NUM_32, GPIO_NUM_33);
Serial1.setRxFIFOFull(1); // Most important!
You will need to set the buffer size only for higher baud rates and if you are expecting messages exceeding the UART FIFO size of 128 bytes. The values given are somewhat arbitrary - they should fit a complete message basically.
Note that the buffer size has to be set before the begin()
call for the Serial!
After having started the Serial
as usual, the third line is the most relevant one. This will have the UART copy every single byte into the UART buffer as soon as it shows up in the FIFO. Only that enables the RTU logic to take care of the timing.
Note that the FIFO threshold has to be set after the Serial has been started!
I got it working flawlessly up to the maximum possible baud rate of 5,000,000.
I've compiled my gateway using the Stream RTU branch and it looks promising:
The current error rate is zero, previously it was around 1.5%:
I'll check again tomorrow and report back. Thank you very much!
after ~24h, nearly 400K messages and an error rate below 0.1% I can say that it's fixed for me:
RTU Messages: 393799
RTU Errors: 275
Thanks again - hopefully it's merged soon
Sounds good - thanks for the report.
thx for putting in the effort, I am a bit pressed for time at the moment, I will have to look into this later on and get back to you
thx for putting in the effort, I am a bit pressed for time at the moment, I will have to look into this later on and get back to you
Take your time - I have no deadline to meet 😄
Changes have been incorporated into master
and the last release.
Have a look at the release notes and/or docs: the API has been slightly adapted again!