Storing Serialread Bytes in an array - c#

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);
}
}

Related

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.

reading and storing serial port data

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),

Read bytes from serial port

I have written code to read data as a byte array from a serial port and show it in a textbox. The code compiles fine, but doesn't work properly:
private void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen == false)
serialPort1.Open();
serialPort1.WriteLine(textBox1.Text);
int bytes = serialPort1.BytesToRead;
byte[] byte_buffer = new byte[bytes];
serialPort1.Read(byte_buffer, 0, bytes);
//textBox2.Text = " ";
for (int t = 0; t < bytes; t++)
{
textBox2.Text += (byte_buffer[t]).ToString();
}
}
serialPort1.WriteLine(textBox1.Text);
int bytes = serialPort1.BytesToRead;
The bytes value will always be zero. Unless you debug this code and single-step it to slow it down. It takes time for the bytes you've written with WriteLine() to be transmitted. And it takes time for the device to process them. And it takes time for the response to be received. This adds up to many milliseconds.
You'll need to fix this by looping, repeated calling the Read() method until you get the full response. If you set the SerialPort.NewLine property correctly then you'll have some odds that simply calling ReadLine() is enough to solve your problem.
You are going about this the wrong way.
Clicking a button will open serialPort1; sure. It will then try to read the buffer. But you only opened the port in the same method!
Take a look at this tutorial: http://www.dreamincode.net/forums/topic/35775-serial-port-communication-in-c%23/
It takes you through the entirety of serial communications in C#. You certainly don't want to be opening and reading the port only on a button press event handler.
Use button2 event to send the data to the port. Put the needed code (for sending the data) into a SynchronizationContext (use SynchronizationContext.Post method).
Next, register on the DataReceived event of the SerialPort class and do the reading there (again enclosed into the same SynchronicationContext object, otherwise you'll get a timeout on serial port reading/writing)
Cheers,

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.

What is the purpose of the SerialPort write buffer?

From outside SerialPort object, it seems to make no difference what the size of the write buffer is, and whether or not it is full.
Using synchronous writing, the write method blocks until all the data has been sent and the buffer is empty.
Using async writing, the data is queued and the program continues on going. The callback method is not called until the write operation is completed and the data is out of the buffer.
The behavior of the serialport object seems to be the same regardless of how much data is in the buffer and whether or not the buffer is full. No errors seem to happen when the write buffer is full.
So, why be able to check BytesToWrite and WriteBufferSize at all? Is there any way that SerialPort behaves differently when the write buffer is full?
Buffers are a mechanism designed to allow whoever processes the buffer to do it in their own way, at their own time.
When i send data, i want it to be pushed at the maximal rate of the port, but i don't want to busywait on the port and wait for each byte to be sent before i push the next one. So you have a processing buffer that feeds the hardware, and can be passed in chunks.
As for the why you'd want to check the BytesToWrite - you are often interested to know if all your data was sent before moving on to the next thing you want to do, you might expect a response after a given period of time, you might want to know what the actual transfer rate is etc'.
The C# SerialPort.BytesToWrite property corresponds to the unmanaged Win32 COMSTAT.cbOutQue field which is described as:
The number of bytes of user data remaining to be transmitted for all write operations. This value will be zero for a nonoverlapped write.
This seems to suggest you could observe the write buffer being consumed as it is sent with async writing before the write complete callback is called.
I wanted to create a test utility that constantly sends out 0xAA out the serial port, with no gaps, forever. I don't care about RX.
I used a timer to keep the buffer full, and monitored BytesToWrite to wait below it was below threshold, before I wrote more data into the buffer.
I could have alternatively not used a timer, but refreshed the serial port in the AsyncCallback, but I wanted to do it this way for fun. You can view the label11 to see the buffer fill and empty.
Note you can get away with BeginWrite without EndWrite for a short time, but eventually you will run out resources. I am basically just putting in a dummy EndWrite.
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
timerFill.Enabled = checkBox2.Checked;
}
private void timerFill_Tick(object sender, EventArgs e)
{
GenerateSquareWave();
}
int const bufferSize = 256;
void GenerateSquareWave()
{
int k = serialPort1.BytesToWrite;
label11.Text = k.ToString();
if (k < bufferSize)
{
byte[] data = new byte[bufferSize];
for (int i = 0; i < bufferSize; i++)
{
data[i] = 0xAA;
}
serialPort1.BaseStream.BeginWrite(data, 0, data.Length, new AsyncCallback((IAsyncResult ar) => serialPort1.BaseStream.EndWrite(ar)), null);
}
}

Categories