I'm reading a packet from a serial port. The packet has a one byte 0x7E flag sequence at the beginning and end of the packet. I'm using this code to read the packet from the serial port:
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort.BytesToRead > 0)
{
byte[] buffer = new byte[serialPort.BytesToRead];
int count = serialPort.Read(buffer, 0, serialPort.BytesToRead);
dataIN = ByteArrayToString(buffer);
this.Invoke(new EventHandler(DisplayData));
}
}
I usually get the whole packet all at once. The problem is sometimes the packet is broken up. This messes up my whole code and breaks it. I was wondering is there a easy fix for this?
Since I dont know the rest of your code I guessed something together, modify as needed. If you already employ flags, why not use them?
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte lastByte = 0
ASCIIEncoding ascii = new ASCIIEncoding();
while (lastByte != 0x7E || serialPort.BytesToRead > 0)
{
int lastByte = serialPort.ReadByte()
if (lastByte != 0x7E)
dataIN += ascii.GetString(lastByte)
}
this.Invoke(new EventHandler(DisplayData));
}
Related
I am receiving data (in byte) from serial port, and now I want to write a if else in the data receive handler.
If(condition)
{}
else
{}
condition for if is: number of bytes received / 8 = interger.
For example, I received 16 bytes of data, so 16/2=8, is an integer. I received 20 bytes of data, 20/8=2.5, it s not an integer.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
byte[] b = new byte[800];
int Received;
SerialPort sp = (SerialPort)sender;
if (condition)
{
MessageBox.Show(" Transmission error!");
}
else
{
Received = sp.Read(b,0,8);
if (Received < 8)
return;
float f11 = BitConverter.ToSingle(b, 0);
float f22 = BitConverter.ToSingle(b, 4);
Invoke(new Action(() =>
{
textBox3.Text += f11.ToString() + " "+f22.ToString()+"\r\n";
//MessageBox.Show(" New Message Received!");
}));
Received = 0;
}
}
You can use % operator:
if (number_of_bytes_received % 8 == 0)
I am writing a C# application to read from several serial COM ports at the same time to analyze the data communication of an IPOD. The data being sent needs to be interpreted as HEX bytes. For example,
0xFF 0x55 0x01 0x00 0x04 0xC3 0xFF 0x55 ...
I want to be able to read this and display it in a rich textbox, for example
0xFF 0x55 0x01 0x00 0x04 0xC3
0xFF 0x55 ...
The start of a command includes a header (0xFF 0x55) and the rest is is the command + parameters + checksum.
What is the best way to go about this?
I currently have:
private delegate void SetTextDeleg(string text);
void sp_DataReceivedRx(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
try
{
string data = IPODRxPort.ReadExisting(); // Is this appropriate??
// Invokes the delegate on the UI thread, and sends the data that was received to the invoked method.
// ---- The "si_DataReceived" method will be executed on the UI thread which allows populating of the textbox.
this.BeginInvoke(new SetTextDeleg(si_DataReceivedRx), new object[] { data });
}
catch
{ }
}
private void si_DataReceivedRx(string data)
{
int dataLength = data.Length*2;
double numLines = dataLength / 16.0;
for (int i = 0; i < numLines; ++i)
IPODTx_rtxtBox.Text += "\n";
IPODRx_rtxtBox.Text += SpliceText(convertAsciiTextToHex(data), 32) + "\n";
}
I can read data, but it is not in the appropriate format.
Im just not sure what the best way to get the hex data from the com port and display it line by line by command based on the command header (0xFF 0x55).
Any Suggestions?
Alex Farber's method works. Below is my code example:
SerialPort sp = (SerialPort) sender;
// string s = sp.ReadExisting();
// labelSerialMessage.Invoke(this.showSerialPortDelegate, new object[] { s });
int length = sp.BytesToRead;
byte[] buf = new byte[length];
sp.Read(buf, 0, length);
System.Diagnostics.Debug.WriteLine("Received Data:" + buf);
labelSerialMessage.Invoke(this.showSerialPortDelegate, new object[] {
System.Text.Encoding.Default.GetString(buf, 0, buf.Length) });
I'm working on Serialport. I'm facing a new problem that once I receive data my data are incomplete. How can I check if my data are complete then process them, and if not, don't process them?
Here are my data receive and my send function:
private void Send(byte[] cmd)
{
bResponse = new byte[0];
Write(cmd);
}
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int iCount = comPort.BytesToRead;
byte[] bBuffer = new byte[iCount];
comPort.Read(bBuffer, 0, iCount)
if (bBuffer.Length == 1 && bBuffer[0] == ACK)
Write(new byte[] { ENQ });
else if (bBuffer.Length == 1 && bBuffer[0] == NAK)
{
Debug.WriteLine("Incomplete Message detected!");
}
else
{
bResponse = bResponse.Concat(bBuffer).ToArray();
rResponse = Decode(bResponse);
Write(new byte[] { ACK });
}
}
I know my data are received in a few packages and I need to wait until the response is complete, but I don't know based on the code above. How should I check whether the data are complete to determine whether to wait? (P.S: The size of the received response varies.)
There is no built-in concept of completeness or packet size.
You'll have to append to a buffer until you see some recognizable end-of-packet pattern that you (or someone else) defined as part of the protocol specification. - And then probably time out after a while if you haven't seen what you are looking for.
Example of old project, notice the firstindex, lastindex, you put in a character to know the length, the start/end character is predefined and can be any character you choose, just be sure not to take any common characters
This is for tcp/ip, but same principle can be used for serialport
public void ReceiveMessage(IAsyncResult ar)
{
int bytesRead;
try
{
lock (client1.GetStream())
{
bytesRead = client1.GetStream().EndRead(ar);
}
string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
received = messageReceived;
int firstindex = received.IndexOf((char)2);
int lastindex = received.IndexOf((char)3);
if (firstindex > 0 && lastindex > 0)
{
string first = received.Substring(firstindex, 1);
string last = received.Substring(lastindex, 1);
}
lock (client1.GetStream())
{
client1.GetStream().BeginRead(data, 0, System.Convert.ToInt32(client1.ReceiveBufferSize), ReceiveMessage, null);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I have some code for you.
First, you implement the DataReceived Event (as you have done already). This event is only called when there is data to process. While I would not call it interrupt-based (as in "realtime capable") is is definitely not polling. Which is good.
Second: When the event is called you may have only one byte, but there may be more bytes. To capture each packet you need to implement an custom buffer.
Third: After you append one byte to your buffer, you check whether the buffer contains a valid packet. If so, process it. If not: Append another one. If no bytes are left, wait for the event to be called again.
In code it looks like this:
const BUFFERLENGTH = 17; // Bytes
byte[] buffer = new byte[BUFFERLENGTH];
private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
while (port.BytesToRead > 0)
{
var data = (byte)port.ReadByte();
Read(data);
}
}
private void Read(byte value)
{
// Append Byte to buffer
System.Buffer.BlockCopy(buffer, 1, buffer, 0, BUFFERLENGTH- 1);
buffer[BUFFERLENGTH - 1] = value;
// Check for valid Packet
if (IsValidPacket(buffer))
{
// Yeah! Gotcha :-)
// Now copy your Packet from the Buffer to your struct/whatever
}
}
private bool IsValidPacket(byte[] buffer)
{
// Todo: Check whether buffer contains a valid Packet.
// Some think like:
// return buffer != null && buffer[0] == 0xF4 && buffer[2] == buffer.length
throw new NotImplementedException();
}
Note that I did not "append the byte to the buffer". I discarded the first byte, shifted every byte by one position and inserted the new byte at the end. If a valid Packet was found I could just copy it in one block into a struct. So the buffer size is always constant and exactly as long as one packet.
This may not be the fastest code out there (because it's reading each byte separately) but it works well for me :-)
Oh, and remember to use Begininvoke() if you want to display that stuff in your GUI.
I have a form in which I am able to receive data and show it in a richtextbox, but what I need is to read the data that is coming continuously from serial port and decode accordingly.
For ex: I am receiving data in bytes in the format as 36 0 0 0 1 0 0...., 36 is used to indicate start of frame n rest are the data through which an event will be fired.
My code:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
Bytenumber = serialPort1.BytesToRead;
// read one byte from buffer
ByteToRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DoUpdate));
}
Above code is used to receive data and fire an event. The code for the event is as follows:
int w=0;
public void DoUpdate(object sender, System.EventArgs e)
{
byte[] t = new byte[Bytenumber];
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead);
}
w++;
// richTextBox1.Text += ByteToRead;
if (ByteToRead == 36)
{
for (int r = 0; r <= 73; r++)
{
if (ByteToRead == 0x01)
{
timer1.Start();
w++;
}
}
}
}
In the data received event handler I am looking for 36 (i.e., start of frame) once I get that I am looking for 1s from the buffer. The problem is when I get 36 (i.e., start of frame) the same data is retained in the if loop and tries to compare with 1 which will not be true # any case. All I need is to read the next bytes of data coming from the buffer once I get 36.
I can spot a few problems. A little code-review:
Bytenumber = serialPort1.BytesToRead;
ByteNumber is the Bytes-to-Read at this moment. It is not thread-safe to keep this in a member field.
ByteToRead = serialPort1.ReadByte();
This only reads 1 Byte. And then, on another thread:
byte[] t = new byte[Bytenumber]; // ByteNumber may have changed already
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead); // store the _same_ byte in all elements
}
What you should do (not complete code):
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
int n = serialPort1.BytesToRead;
byte[] buffer = new byte[n];
// read one byte from buffer
int bytesToProcess = serialPort1.Read(buffer, 0, n);
this.Invoke(UpdateMethod, buffer, bytesToProcess);
}
But do search the internet for working code. I just made this up.
I want to communicate between my PC and some controller boards.
The expectation is that the PC will send an identifier of the board on RS-485 and then it should receive the answer from the board.
When I try to receive the response, I receive the wrong data.
Here is my code:
public void set()
{
SerialPort sp = new SerialPort("COM1");
sp.Open();
if (sp.IsOpen)
{
byte[] id = new byte[]{0,0,0,0,0,0,0,0,0,0};
byte[] rec = new byte[540];
while (!end)
{
sp.Write(id,0,id.Length);
sp.Read(rec,0,rec.Length);
//do some with rec
//WORKING
//do soem with rec
}
}
sp.Close();
}
It works if I am using RS-232, but not when I am using RS-485.
UPDATE :
It is RS-485 2 wire.(http://en.wikipedia.org/wiki/RS-485)
I found the problem.
sp.Read(rec,0,rec.Length);
Read is a non-blocking method so it reads the buffer but does not wait for all of the bytes. So you need to use the return value of this function which returns an integer with a number of bytes that it could read.
I am using this:
int read = 0;
int shouldRead = readData1.Length;
int len;
while (read < shouldRead )
{
len = serialport.Read(buffer, 0, readData1.Length);
if (len == 0)
continue;
Array.Copy(buffer, 0, readData1, read, len);
read += len;
Thread.Sleep(20);
}