reading and storing serial port data - c#

at micro-controller end:
I am sending 18 bytes from a micro controller via uart to a winform application every 100 ms.
UART_SendData((void*)&uart, 18, dataBuffer);
at winform app end:
I am trying to read these 18 byte. I want to read them in one go, store them and process them as after 100ms new data is arriving (18 is variable and can be 20, 30 and so on till 128 Bytes). Following is the code I am trying.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] data = new byte[sp.BytesToRead];
sp.Read(data, 0, data.Length);
}
But I am receiving bytes not at a time at winform app end. I receive 1 and then 17. or 2 and then 16 and similar pattern. I want the all data at a time so that I can process it.
What should be my strategy here. Is my current code wrong or should I use any other approach like circular buffer etc to store data? or ..?
ps: First 2 bytes of the sent bytes (18Bytes in the above example) from microcontroller are always same(kind of an id),

Related

WinForms Serial port eats data

I have a serial port that recieves some color data from arduino board at 115200 baud rate. At small scale (1-byte request from arduino for pc to send next command, implemented for synchronization) it works fine, but when i request a lot of data (393 bytes) and it sends them, it looks as if serial port just eats data, and BytesToRead usually equals to 5 or 6
Code:
void GetCurrentState()
{
int i = 0;
Color WrittenColor; //Color to write to an array
byte red;
byte green;
byte blue;
AddToQueue(new byte[] { 6 }); //adds command that requests data to a sender queue
while (i <= StripLength) //read data until array is read completly
{
Console.WriteLine($"Bytes to read: {SerialPort1.BytesToRead}");//Debug
if (SerialPort1.BytesToRead >= 3) //if we have a color ready to read and construct, do it, else wait for more data
{
red = (byte)SerialPort1.ReadByte(); //Read red part
green = (byte)SerialPort1.ReadByte(); //Read green part
blue = (byte)SerialPort1.ReadByte(); //Read blue part
WrittenColor = Color.FromArgb(red, green, blue); //Make a color
SavedState[i] = WrittenColor; //Write it
i++; //increment counter
}
}
}
You might try buffering the serial port data to another stream in memory, and then read data from that stream. This is because if you are actually transferring enough data to need that high of a baud rate, then it's possible that you are not reading the data fast enough. (I know that's not a massive data rate, but most hobby applications can get away with less)
Have you tried a lower baud rate? Or are you stuck with this one?
You might find this post helpful:
Reading serial port faster
I would probably have one thread reading the serial port in a loop, and then queuing the data into a thread-safe ConcurrentQueue. I would have another thread read from that queue and do useful things with the data. And, as you are already doing, use a queue to send commands, but I would use another thread for sending them (you might already be doing this).

Storing Serialread Bytes in an array

I am working on Visual Studio & I am designing a GUI for my sensor. My sensor is transmitting 8 bytes on press of button and I am having trouble while reading those 8 bytes available serially and store them in array, so I can further use those bytes here is my code below for serially reading available bytes.
For storing serial available bytes in an array I have created and assigned new array as follows:
byte incoming = new byte[9];
Serially writing to sensor is achieved successfully now I am facing trouble in reading the bytes available on serial port transmitted by my sensor. Kindly assist me in achieving best possible solution.
private void timer1_Tick(object sender, EventArgs e)
{
if (!serialPort1.IsOpen)
{
MessageBox.Show("Command cannot be sent, Serial Port Not opened");
}
else
{
serialPort1.Write(TandH, 0, TandH.Length);
serialPort1.Read(incoming[], 0, 8);
}
}

Xamarin Bluetooth Chat with Arduino - Giving strange two line results

I am working with Xamarin on Visual Studio and the most updated C# Bluetooth Chat I could find online. I have some trouble getting the proper output. I have the Arduino send data to the bluetooth ~every 2 seconds as follows
Serial.Println("In Standby Mode");
The bluetooth chat app receives this using a thread separate from the UI
public override void Run ()
{
Log.Info (TAG, "BEGIN mConnectedThread");
//data from socket
byte[] buffer = new byte[1024];
//number of bytes read
int bytes;
string bufferString;
// Keep listening to the InputStream while connected
while (true) {
try {
lock(buffer)
{
bytes = mmInStream.Read (buffer, 0, buffer.Length);
bufferString = System.Text.Encoding.ASCII.GetString(buffer);
var bufferStringJava = new Java.Lang.String(buffer, 0, buffer.Length);
System.Console.WriteLine("Incoming Data from Bluetooth Is:" + bufferStringJava);
_service._handler.ObtainMessage (BluetoothChat.MESSAGE_READ, bytes, -1, bufferString) //Edited to send a string instead of an array
.SendToTarget ();
}
} catch (Java.IO.IOException e) {
Log.Error (TAG, "disconnected", e);
_service.ConnectionLost ();
break;
}
}
You can see I have the output printed here. Also, I have the output printed on the Android Activity
readString2 = String.Copy((string)msg.Obj);
var readMessage = new Java.Lang.String(Encoding.ASCII.GetBytes(readString2), 0, msg.Arg1);
bluetoothChat.conversationArrayAdapter.Add(bluetoothChat.connectedDeviceName + ": " + readMessage);
The console output is very strange, giving things as follows. Various letters are typically missing from the output.
05-24 22:25:29.286 I/mono-stdout( 4690): Incoming Data from Bluetooth Is:I Standby Mode
Incoming Data from Bluetooth Is:I Standby Mode
05-24 22:25:29.306 I/mono-stdout( 4690): Incoming Data from Bluetooth Is:n Standby Mode
Incoming Data from Bluetooth Is:n Standby Mode
05-24 22:25:30.316 I/mono-stdout( 4690): Incoming Data from Bluetooth Is:I Standby Mode
Incoming Data from Bluetooth Is:I Standby Mode
The Activity display can be seen in the picture attached. Essentially, it displays everything properly, but typically splits the "In Standby Mode" text in half.
Bluetooth Chat Output
I am very confused why there are missing letters in my console output, but not in the app display. Also, why the app is displaying as two lines. Also, I am not sure why my console seems to output the same thing twice.
Thanks for the help!
I figured out what was happening. Essentially, the thread reading the bluetooth socket data repeats over and over without any delay. The look will read data from the stream (mmInStream.Read()), then send that data using a handler. But it simply reads whatever is available at that moment. So if only the letter "I" has sent, it won't pick up the other letters until the next time around the look. This explains why the message was split. I fixed this using the following code.
if (mmInStream.IsDataAvailable())
{
await System.Threading.Tasks.Task.Delay(20);
bytes = mmInStream.Read(buffer, 0, buffer.Length);
Next, each time around the look, the byte[] buffer data is NOT reset. Since I was taking all the buffer each time, some characters from previous reads remained, giving me strange outputs.
To fix this, I copied the buffer into a string of length each to the bytes read, giving by the integer variable named bytes.
for (int i = 0; i < bytes; i++)
{
temp[i] = buffer[i];
}
bufferString = System.Text.Encoding.ASCII.GetString(temp);
I still haven't figured out how to get rid of double output from mono.

Serial Port Trigger DataReceived when certain amounts of bytes received

I am trying to write a program that updates a windows form every time new data comes in on a serial port, but am struggling with understanding how the serial port works, and how I can use it in a way I want it.
I have an external device sending 8 bytes at 1Hz to my serial port, and wish to use the DataReceived event from the SerialPort Class. When I debug my code, the event is more or less triggered randomly based on what the program is doing at a certain time. The code as is is below:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//byte[] rxbyte = new byte[1];
byte[] rxbyte = new byte[8];
byte currentbyte;
port.Read(rxbyte, 0, port.BytesToRead);
currentbyte = rxbyte[0];
int channel = (currentbyte >> 6) & 3; //3 = binary 11, ANDS the last 2 bits
int msb_2bit = (currentbyte >> 0) & 255; //AND compare all bits in a byte
currentbyte = rxbyte[1];
int val = ((msb_2bit << 8) | (currentbyte << 0));
//Extra stuff
SetText_tmp1(val.ToString());
}
I want to be able to have exactly 8 bytes in the receive buffer before I call the Read function, but I am not sure how to do this (never used SerialPort class before), and want to do all manipulation of data only when I have the entire 8 bytes. Is there a built in way to toggle the event only when a certain amount of bytes are in the buffer? Or is there another way to obtain only 8 bytes, but not more, and leave the remaining bytes to the next instance?
Yeah, you are not coding this correctly. You cannot predict how many bytes you are going to receive. So just don't process the received bytes until you've got them all. Like this:
private byte[] rxbyte = new byte[8];
private int rxcount = 0;
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
rxcount += port.Read(rxbyte, rxcount, 8 - rxcount);
if (rxcount < 8) return;
rxcount = 0;
// Process rxbyte content
//...
}
Set the ReceivedBytesThreshold property to 8. As in port.ReceivedBytesThreshold = 8;
An effective way to handle this is to add a timer to the class that ticks along at maybe 9 times a second. Eliminate the serial port event handler completely.
At each timer tick have the code check the serial port for bytes received from the serial port. If there are some there then grab them out of the serial port and append them to the end of buffer maintained in the class as a data member.
When the buffer has eight or more characters in it then timer tick logic would take the first 8 bytes out of the buffer and use them to update the user interface window. Any remaining bytes in the buffer can be moved up to the head of the buffer.
The timer tick routine can also maintain a counter value that increments each time the tick comes in and there is no data ready at the serial port at this tick. When this counter reaches a value of say 3 or 4 the code would reset the data buffer to empty and reset the counter back to zero. When data is actually seen from the serial port this counter is reset to zero. The purpose of this counter mechanism is to synchronize the data receive buffer with the 1Hz data stream coming in so the receive process does not get out of sync with what data represents the start of the 8-byte message.
Note that this method is superior to the serial port received data event because it allows your program to stay in control of things. I've already described the ability to synchronize with the data stream bursts - which is not possible to do with trying to set the serial port received data threshold to a count like 8. Another advantage is that the timer tick code can include additional handling functions such as signalling a timeout if no data arrives from the serial port in say 2 or 3 seconds.

C# .Net Serial DataReceived Event response too slow for high-rate data

I have set up a SerialDataReceivedEventHandler, with a forms based program in VS2008 express. My serial port is set up as follows:
115200, 8N1
Dtr and Rts enabled
ReceivedBytesThreshold = 1
I have a device I am interfacing with over a BlueTooth, USB to Serial. Hyper terminal receives the data just fine at any data rate. The data is sent regularly in 22 byte long packets. This device has an adjustable rate at which data is sent. At low data rates, 10-20Hz, the code below works great, no problems. However, when I increase the data rate past 25Hz, there starts to recieve mulitple packets on one call. What I mean by this is that there should be a event trigger for every incoming packet. With higher output rates, I have tested the buffer size (BytesToRead command) immediatly when the event is called and there are multiple packets in the buffer then. I think that the event fires slowly and by the time it reaches the code, more packes have hit the buffer. One test I do is see how many time the event is trigger per second. At 10Hz, I get 10 event triggers, awesome. At 100Hz, I get something like 40 event triggers, not good. My goal for data rate is 100HZ is acceptable, 200Hz preferred, and 300Hz optimum. This should work because even at 300Hz, that is only 52800bps, less than half of the set 115200 baud rate. Anything I am over looking?
public Form1()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(Display_Results));
}
private void Display_Results(object s, EventArgs e)
{
serialPort1.Read(IMU, 0, serial_Port1.BytesToRead);
}
Did you try to ajust time latency on the USB serial converter? I had the same problem with a FTDI USB to serial converter. I use an oscilloscope to see my IN and OUT data coming from the device and I could see that the computer was always slow to respond. By default, time latency on the device is set to 16 ms. I changed it to 2 ms and it makes a big difference. Go to your USB Serial Converter in the Device Manager and in the advanced settings, change Latency time to 2 ms. It should works. Try it.
Why do you Invoke() the call to DisplayResults?
This will push it to the MessageLoop, an unnecessary delay.
It would be better if DataReceived() pushed data onto a (thread-safe) queue for decoupled processing.
I also think you could run into problems with split packages.
You could try setting ReceivedBytesThreshold = 22, which will result in the event being fired when there are at least 22 bytes to read. Note that it will be at least 22. There may be more.
I don't think I would personally do this though, because what happens if your packet size changes in the future, for example to 12 bytes? You would end up with 12 bytes in the buffer but not firing the event at all.
Far better to leave it set to 1, which will fire the event when at least 1 byte is available. Then push all received bytes into a list or a queue as Henk has already posted.
Note that the DataReceivedEvent has no knowledge of what you consider a packet of data to be of course. It just fires when there are bytes available. It is up to the developer to assemble these bytes into a meaningful message or packet.
The problem lies in the received data handler.
I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.
using System.Threading;
Thread readThread = new Thread(Read);
readThread.Start();
Hope someone else doesn't need to spend 3 hours fixing this.

Categories