B4J Question MODBUS RTU

knutf

Member
Licensed User
Longtime User
In MODBUS RTU, framing is constructed by measuring gaps of silence on the communication line. The gap must be 3,5 char long. But I can't figure out how to detect a silence in the inputstream

I have tried jSerial with AsyncStreams, but the received messages is split up in seveveral parts.

Knut
 

knutf

Member
Licensed User
Longtime User
So:
if (current event time) is bigger than 1000ms / baud * 11bit/char * (Buffer.Length + 1.5) + (last event time) then
The characters in this buffer belongs to the next frame
process the current frame....
clear current frame
put the buffer in the current frame
else
Append buffer to the current frame
end if

But if I don't want to wait until the next frame has started to process the current frame, is this possible?
 
Upvote 0

knutf

Member
Licensed User
Longtime User
...and can I be sure the last buffer contain only characters from the next fram, not also characters from the current frame?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
and can I be sure the last buffer contain only characters from the next fram, not also characters from the current frame?
AsyncStreams in non-prefix mode doesn't buffer anything. You shouldn't assume that messages will not be split or merged.
AsyncStreams just raises the event whenever the data is available.
 
Upvote 0

knutf

Member
Licensed User
Longtime User
Ok, from that I can conclude that the buffering happens in a level below the AsyncStreams. The AsyncStreams NewData event is raised whenever the main thread is ready and there is received one or more bytes.

The number of bytes in the Buffer array is only dependent on how many bytes is received and when it was possible to raise the NewData event on the main thread, right?

Maybe it is possible to tell if there is a periode of silence among the received bytes by calculations on the event times and number of bytes in the Buffer array, but it is not possible to tell where the silence was, right?

It is not possible to use AsyncStreams to split the bytes into frames separated by a silence, right?
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The AsyncStreams NewData event is raised whenever the main thread is ready and there is received one or more bytes.
No. There is a dedicated thread that reads from the stream.

The number of bytes in the Buffer array is only dependent on how many bytes is received and when it was possible to raise the NewData event on the main thread, right?
No. There is no relation to the main thread.

Maybe it is possible to tell if there is a periode of silence among the received bytes by calculations on the event times and number of bytes in the Buffer array, but it is not possible to tell where the silence was, right?

It is not possible to use AsyncStreams to split the bytes into frames separated by a silence, right?
It depends on the silent period length. Assuming that it is large enough then it should be quite simple to find it. For example:
B4X:
Sub AStreams_NewData(data() As Byte)
 DataIndex = DataIndex + 1 'this is a global variable
 Dim MyIndex As Int = DataIndex
 Sleep(50)
 If MyIndex = DataIndex Then
   'no data arrived in ~50 ms
 End If
End Sub
 
Upvote 0

knutf

Member
Licensed User
Longtime User
I see you have corrected my statements, thats good.

Erel, your NewData example is smart, I think I can use it as long as I am making an MODBUS master.

The RTU MODBUS spesifications says that the frames are separated by at least 3,5character long silent periode. For baud rates above 19200baud it is a fixed value, 1.75 ms. This is quite short compared to the 50ms you use in your routin. If it was a MODBUS slave I was making, I think I could come in to problems if the master sends a new message before the 50ms has elapsed.

No. There is no relation to the main thread.

Is this true? I supose the NewData event is raised in the main thread in a B4J console application. If the main thread is busy while a lot of bytes are received in the AsyncStreams dedicated thread, more bytes are in the buffer when the newData event finaly is raised. Is this right?

Also: When the main thread meets the Sleep(50) in the NewData event, the thread is not sleeping, it just leaves the NewData event, ready to do other tasks, for example handle more NewData events from AsyncStreams. When 50 ms has elapsed, the main thread continues in the first NewData event call. But it can happen that the returning to the routine happens later if the main thread is busy in a long running task. Is this right?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I supose the NewData event is raised in the main thread in a B4J console application. If the main thread is busy while a lot of bytes are received in the AsyncStreams dedicated thread, more bytes are in the buffer when the newData event finaly is raised. Is this right?
No. The network thread receives the available data. It then raises an event that is sent to the message queue. It is true that if the main thread is busy then it will take longer for the event sub to actually be executed.

For baud rates above 19200baud it is a fixed value, 1.75 ms
You need to test it. If it is a non-ui project that the message queue might be fast enough.

When 50 ms has elapsed, the main thread continues in the first NewData event call. But it can happen that the returning to the routine happens later if the main thread is busy in a long running task. Is this right?
Yes. Everything happens through the message queue.
 
Upvote 0
Top