Go Down

Topic: Serial to Client data go lost (Read 787 times) previous topic - next topic

Elma96

Oct 09, 2019, 12:56 pm Last Edit: Oct 09, 2019, 02:00 pm by Elma96
I am sending data from serial to client, and it's partially working because I only get short messages delivered, while long messages (like 4000bit) get the most of them lost. when I use the softwareSerial example in the IDE to send from serial to serial it works with no data lost. I am trying to do like the example as possible with the serial to client code using client.write(mySerial.read()) but not working as expected! what am I missing?




Code: [Select]

#include <SoftwareSerial.h>
#include <Bridge.h>
#include <BridgeClient.h>

#define PORT 9000
// Make the client connect to the desired server and port
IPAddress addr(192, 168, 0, 100);

//not all pins on the yun are assignable as rx/tx
SoftwareSerial mySerial(10, 11); // RX, TX

// Define our client object
BridgeClient client;

int led = 4;
bool Connected;
void setup() {
 pinMode(led, OUTPUT);

 // set the data rate for the SoftwareSerial port
 mySerial.begin(9600);
 mySerial.println("Hello, world?");
 mySerial.setTimeout(20000);

 // Start Bridge
 Bridge.begin();
 //delay(1000);

 // Start Console communications and wait for port to open:
 //Console.begin();
 //delay(1000);

 //Console.println("Client connecting on port 9000");
 Connected = false;

 //delay(1000);
 //connectToClient();
 connectToClient();
}
 
void loop() // run over and over
{
 while (mySerial.available()) {

 client.write(mySerial.read());

 //mySerial.read();
 }

}

void connectToClient() {

 // is a connection currently active?
 if (!Connected)
 {
 // not currently connected, try to establish a connection
 client.connect(addr, PORT);
 delay(1000);

 if (client.connected())
 {
 // send something to the client
 client.println("hello server!");
 digitalWrite(led, HIGH);
 }
 else
 {
 connectToClient();
 digitalWrite(led, LOW);

 }
 }
}


pylon

It looks like this code should run on an Yun. We usually expect an Arduino UNO if the post doesn't contain an explicit Arduino model as for many problems the model is essential.

Quote
I am trying to do like the example as possible with the serial to client code using client.write(mySerial.read()) but not working as expected! what am I missing?
What exact output do you get if you send what exact content? What is the sending device? An Arduino too? If yes, please post the code you use there.

Which version of the IDE are you using? (The SoftwareSerial library recently got a major update) Which AVR core version?

Elma96

I am working with Arduino Yun.

I am sending the data (as a file content on one time, not in sequence) from pc using terminal Programm sscom32e. I am receiving the data as client using netcat on the same pc (Yun and PC connected with RS232-USB and are on the same network).

IDE version 1.8.9 (I mainly use Visual Basic for coding and bootloading though)

-AVR core version? I don't know where to find this

Data sent(on sscom32e):
Code: [Select]

1
2
3
4
5
6
7
8
9
11
22
33
44
55
66
77
88
99
111
222
333
444
555
666
777
888
999
1111
2222
3333
4444
5555
6666
7777
8888
9999



data received(on netcat):
Code: [Select]

1
2
3
4
5
6
7
8
9
11
22
33
44
55
66
77
88
99
1



pylon

Quote
IDE version 1.8.9
That's current enough.

Quote
data received(on netcat):
So it doesn't loose bytes but suddenly stops and seems to freeze.

BTW, the recursion you have in conectToClient() should have a limitation or be converted into a loop instead of the recursion.

The reason for the stop isn't obvious so you should add more code that prints to the console what happens. You don't have code that checks if the connection to the server still exists and reconnects if it failed.

Elma96

It is not a connection problem, cause I still can send and receive data over and over  :smiley-confuse:

pylon

In that case you have to describe in detail what you do and what output you get. In the above output you see all data at the beginning and a sudden stop. All data to that point was correctly transmitted and after that point no data is received anymore. If that's not the case, post the details.

Elma96

I believe now that serial.read and client.write cann't work together at the same time efficiently. when client.write starts, serial.read stops and therefore data get lost. Now I am saving the serial.read in 3 arrays of each 255Byte, when they are full or I receive an end-marker I call client.write to send them and Serial stops anyway. This works but for max. 765 Byte data. I can't do more arrays to save the serial data due to the limited memory of the module, which means it's not the best solution right now. I will post the code for this later when I optimate it. the other Idea coming to my mind is to send orders to the serial to wait until client.write finishes and then continue receiving and so on. Is this possible? Is Serial that flexible? How could I communicate with Serial to wait and to continue?

pylon

Quote
I believe now that serial.read and client.write cann't work together at the same time efficiently. when client.write starts, serial.read stops and therefore data get lost.
No, the serial.read() calls just read from a buffer, so the bytes were already received at that time. SoftwareSerial of more or less current IDEs use interrupts to get the bits and the BridgeClient doesn't stop interrupts.
But it's a bad idea to write single bytes using the BridgeClient as using that single byte write for every byte written 8 bytes are sent to the linux part and at least 6 bytes are received.
Although the baudrate of the bridge is 250k you might get into troubles as you need about 140k of it just for the serial transfers and there will be some wait times. So it might be that your serial buffer fills up over time if the bytes are arriving at full speed and the read bytes aren't sent fast enough to the linux part. Once the buffer is full you'll loose some bytes.
The easiest circumvention is to read as many bytes as possible into a buffer on the Arduino side and send that complete buffer using the multibyte write version (client.write(buffer, length)). That's because the overhead is constant, so if you write a buffer of 20 bytes, 27 bytes are sent and 6 bytes are received.

Elma96

I did a buffer of 4x255Byte arrays and the result is pretty good for the first 1kB received. While the bytes afterwards still have the same problem of losing alot of them. I can't do more buffer arrays due to the limited memory of the module. You think this is the best I can get of it? Only the first 1kB? Can't I save the buffer somewhere else than the 2.5kB small memory?

Elma96

Here is a snippet from my last updated code. pls. tell me I am doing something wrong and I can do better.

Code: [Select]

const byte numChars = 255;//Max size of each array

char receivedChars[4][numChars]; // 4x255Byte array of arrays to store incoming serial data

boolean arrayIsFull[] = { false, false, false, false };//Is array full loaded?

boolean newData = false; // Are data ready to be printed?

size_t i = 0;// For-loops check-variable


void loop() { // run over and over
processSerialData();
sendToPrinter();
}

//To process the serial data received from RS232
void processSerialData() {
static byte ndx = 0;//Index for data arrays
char endMarker = '\f';     //Form Feed as terminator
char rc;//Current read char

while (mySerial.available() > 0 && newData == false) {

rc = mySerial.read();

if (rc != endMarker) {
for (i = 0; i < 4; i++)
{
if (!arrayIsFull[i]) {
receivedChars[i][ndx] = rc;
ndx++;
if (ndx >= numChars - 1) {//last byte in array
receivedChars[i][numChars - 1] = '\0';//terminate string at this array and mark it as full
ndx = 0;
arrayIsFull[i] = true;
}
if (arrayIsFull[3]) {//Means all arrays are full loaded now
ndx = 0;
newData = true;
}
break;
}
}
}
else {
for (i = 0; i < 4; i++)
{
if (!arrayIsFull[i]) {//Terminate the string at the last-written-to array and mark it as full
receivedChars[i][ndx] = endMarker;

if (ndx < numChars - 1)
{
receivedChars[i][ndx + 1] = '\0'; // For the rare case that the endmarker is at position 254!
}
arrayIsFull[i] = true;
break; // break the for loop
}
}
ndx = 0;
newData = true;
}
}
}

//To send data to printer after all arrays has been full loaded or an End-Marker received
void sendToPrinter() {
if (newData == true) {
for (i = 0; i < 4; i++)
{
if (arrayIsFull[i]) {//Print all full arrays
client.print(receivedChars[i]);
arrayIsFull[i] = false;
}
}
newData = false;//To start from the beginning --> new data can be received & processed
}
}

pylon

Quote
I did a buffer of 4x255Byte arrays and the result is pretty good for the first 1kB received. While the bytes afterwards still have the same problem of losing alot of them. I can't do more buffer arrays due to the limited memory of the module. You think this is the best I can get of it?
That's a rather complex buffering. Why do you have 4 buffers of 255 byte? Why not one of 1024 byte?

Do you know in what timing you receive the incoming data? What size are the blocks? If you get a constant stream on the SoftwareSerial (no pauses) you should think about changing the hardware because a software emulation of a serial interface is not suited for such a task as it wastes to much of the available computing power for such a task hardware is doing much better.

Elma96

#11
Oct 21, 2019, 07:50 pm Last Edit: Oct 21, 2019, 09:49 pm by Elma96 Reason: improvment
I used 4 arrays becausr Byte type is max. 255Byte. As I remember, I tried other types but there was a Problem with them.

Yes I know the timing when the data come (actually I hit a button to send data to arduino)  the block size is not really the same every time but it's more or less700Bytes.

What hardware do you mean should I get? You mean a board with more memory? What do you suggest?

Elma96

#12
Oct 21, 2019, 09:50 pm Last Edit: Oct 21, 2019, 09:51 pm by Elma96
Quote
If you get a constant stream on the SoftwareSerial (no pauses)
yes true. the data are already there and as I hit the button, the just go to the Arduino without pauses!

pylon

Quote
I used 4 arrays becausr Byte type is max. 255Byte. As I remember, I tried other types but there was a Problem with them.
But you can use integers for the indexing of arrays of type byte. Maybe I misunderstand something...

Quote
yes true. the data are already there and as I hit the button, the just go to the Arduino without pauses!
It should work if it's always about 700 bytes and then you have a pause again. Use a buffer of about 800 bytes, fill it up until you have a pause of let's say 3ms (use millis() for that) and as soon as you ran into that timeout, write the whole buffer to the bridge.

Quote
What hardware do you mean should I get? You mean a board with more memory? What do you suggest?
One of the modern MKR boards might be a better fit but given the above information I think the Yun might do the job.

Elma96

I didn't mean "time blocks", but actually blocks with a remarkable end-marker which in this case the form feed '\f'.
So there is no pauses at all till the stream end.

After weeks, I just used software flow control XOFF/XON and I can't believe it's finally working! only one block with form feed at the end is buffered(XOFF) and the serial waits till it is sent to the client and then serial continues!(XON).

I can't believe that I spent so much time on such a trivial thing!

Thanks pylon! You helped me alot.

Now I am moving to implement a parallel port (yes parallel!) to the board to receive the same data and I will be then having parallel as well as serial inputs.


yooooooooooooooooooooooohoooooooooooooooooooooooooooo

Go Up