How to search for bytes in Queue<byte> and extract packet? - c#

I'm receiving packets over COM port. Each packet begins with {0xFF, 0xFF} and ends with {0xFE, OxFE}. All received bytes are queued in Queue<byte> and after each void port_DataReceived(object sender, SerialDataReceivedEventArgs e) I'm processing that queue.
If any 0xFF or 0xFE shows up in packet, device add 0x00 after it.
How to extract each packet?
How to delete unnecessary 0x00 inside each packet that have header byte inside?
For the first issue I have:
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[port.BytesToRead];
try
{
port.Read(data, 0, data.Length);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
data.ToList().ForEach(newByte => receivedData.Enqueue(newByte));
processData();
}
private void processData()
{
// Determine if we have a "packet" in the queue
if (Enumerable.SequenceEqual(receivedData.Take(2), new List<byte> { 0xFF, 0xFF }))
{
// Beginning of new packet in the front of queue is ready!
if (Enumerable.SequenceEqual(receivedData.Skip(Math.Max(0, receivedData.Count() - 2)).Take(2), new List<byte> { 0xFE, 0xFE }))
{
List<byte> tempPacket = new List<byte>();
// Whole packet in the queue
while(receivedData.Count > 0)
tempPacket.Add(receivedData.Dequeue());
tempPacket.TrimExcess();
Packet pack = new Packet(tempPacket, PacketOrigin.Serial);
}
}
}
I'm trying to remove all 0x00 that are after any 0xFE and 0xFF that can be found inside Queue<byte> so far I came up with:
List<byte> unconvertedPacket = new List<byte> { 0xFF, OxFF, 0x00, 0x00,0x4D, 0xFA 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE}
int index = 0;
while (index != null)
{
unconvertedPacket.RemoveAt(index + 1);
index = unconvertedPacket.IndexOf(0xFE);
}
while (index != null)
{
unconvertedPacket.RemoveAt(index + 1);
index = unconvertedPacket.IndexOf(0xFF);
}
Does anyone have maybe any other solution/advice for doing it?

Try the following approach:
In the DataReceived event handler keep reading the incoming data and append it to a buffer (byte[]).
First you need to find the start marker ({0xFF, 0xFF}) in the buffer of received data. You need to determine the index of this marker within the buffer.
Once you have the start index, you need to keep appending incoming data to the buffer and check if the end marker (0xFE, 0xFE) has arrived. Capture the index of the end marker within the buffer.
Once you have the start and end index you can extract the packet between them. Nevermind about the extra 0x00 byte that gets added after it. You know the index of the start and end marker and their length (2). Just extract the array of bytes between them.
You need to create a search algorithm to suit this purpose. Both the needle and the haystack are an array of bytes (byte[]). You can use the Boyer-Moore string search algorithm for this purpose.
Here's a simple C# implementation of the Boyer-Moore algorithm which only implements the bad character rule. Read up on Wikipedia if you also want to implement the good suffix rule.
The algorithm is normally intended for strings, but I modified it to work with byte arrays. Tested this locally with an IP camera to extract the received JPEG images.
Check out the Wikipedia article for more information about it. It contains a full Java implementation which you can easily translate to C#.
public class BoyerMoore
{
public static int IndexOf(byte[] needle, byte[] haystack)
{
if (needle == null || needle.Length == 0)
return -1;
int[] charTable = CreateCharTable(needle);
for (int i = needle.Length - 1, j; i < haystack.Length;)
{
for (j = needle.Length - 1; needle[j] == haystack[i]; i--, j--)
{
if (j == 0)
return i;
}
i += charTable[haystack[i]];
}
return -1;
}
private static int[] CreateCharTable(byte[] needle)
{
const int ALPHABET_SIZE = 256;
var table = new int[ALPHABET_SIZE];
for (int i = 0; i < table.Length; i++)
{
table[i] = needle.Length;
}
for (int i = 0; i < needle.Length - 1; i++)
{
table[needle[i]] = needle.Length - 1 - i;
}
return table;
}
}
Example usage:
var haystack = new byte[]
{0xFF, 0xFF, 0x00, 0x00, 0x4D, 0xFA, 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE};
var startIndexOf = BoyerMoore.IndexOf(new byte[] {0xFF, 0xFF}, haystack);
var endIndexOf = BoyerMoore.IndexOf(new byte[] {0xFE, 0xFE}, haystack);
var packet = new byte[endIndexOf - 2 - startIndexOf];
for (int i = startIndexOf + 2, j = 0; i < endIndexOf - startIndexOf; i++, j++)
{
packet[j] = haystack[i];
}
Voila, the packet byte array contains 9 bytes in this example and only contains the bytes between the start and end marker. You can now trigger an event and pass the packet as an event arg for example.
Remark: Receiving the data from the COM port is a continuous event. You need to keep monitoring it. Keep appending the received data and keep checking for the start -and index markers, extract the packages...etc. Watch out that your buffer does not overflow. You need to implement some housekeeping there.
Hope it helps. Check out AForge implementation of an MJPEGStream for an example of continuously reading incoming data.
To recapitulate:
Declare an instance variable to store the received data (e.g. _buffer = new byte[4096]).
Append the incoming data to the buffer in the DataReceived event handler.
Search for the start marker. If found remember the start index in an instance variable.
If you already know the position of the start marker, then search for the index of the end marker.
When you find the end marker, extract the packet and fire an event. Use the packet as part of the event's EventArgs.
Wash, rinse, repeat.
You need to implement some housekeeping to make sure the buffer won't overflow (> 4096 bytes). For instance once you find a packet you can clean up the buffer up until the last received end marker.

Related

C# - Reading Sequence of Hex Bytes in Binary

So I've been googling & googling for this, but I can't find a solution for my case. I could find things about byte arrays. but I hope there's also a simpler solution for my case.
Maybe it's just me using the wrong search terms, don't know.
Anyways, I already have a kinda working code which is:
static void Main(string[] args)
{
// Open the file to search in
BinaryReader br = new BinaryReader(File.OpenRead("D:/Users/Joey/Desktop/prod"));
for (int i = 0; i <= br.BaseStream.Length; i++)
{
// Search the file for the given byte
if (br.BaseStream.ReadByte() == (byte)0xC0)
{
Console.WriteLine("Found the byte at offset " + i); //write to the console on which offset it has been found
}
}
}
This example works.
However, I need it to be able to search for more than just one byte.
For example: C0035FD6
I feel like I'm missing something so simple, but I just can't seem to figure it out.
If anyone has gotten a solution for me, that would be great :D
You can use this extension to search for AOB:
public static class StreamExtensions
{
public static IEnumerable<long> ScanAOB(this Stream stream, params byte[] aob)
{
long position;
byte[] buffer = new byte[aob.Length - 1];
while ((position = stream.Position) < stream.Length)
{
if (stream.ReadByte() != aob[0]) continue;
if (stream.Read(buffer, 0, aob.Length - 1) == 0) continue;
if (buffer.SequenceEqual(aob.Skip(1)))
{
yield return position;
}
}
}
public static IEnumerable<long> ScanAOB(this Stream stream, params byte?[] aob)
{
long position;
byte[] buffer = new byte[aob.Length - 1];
while ((position = stream.Position) < stream.Length)
{
if (stream.ReadByte() != aob[0]) continue;
if (stream.Read(buffer, 0, aob.Length - 1) == 0) continue;
if (buffer.Cast<byte?>().SequenceEqual(aob.Skip(1), new AobComparer()))
{
yield return position;
}
}
}
private class AobComparer : IEqualityComparer<byte?>
{
public bool Equals(byte? x, byte? y) => x == null || y == null || x == y;
public int GetHashCode(byte? obj) => obj?.GetHashCode() ?? 0;
}
}
Example:
void Main()
{
using (var stream = new MemoryStream(FakeData().ToArray()))
{
stream.ScanAOB(0x1, 0x2).Dump("Addresses of: 01 02");
stream.Position = 0;
stream.ScanAOB(0x03, 0x12).Dump("Addresses of: 03 12");
stream.Position = 0;
stream.ScanAOB(0x04, null, 0x06).Dump("Addresses of: 04 ?? 06");
}
}
// Define other methods and classes here
IEnumerable<byte> FakeData()
{
return Enumerable.Range(0, 2)
.SelectMany(_ => Enumerable.Range(0, 255))
.Select(x => (byte)x);
}
Give this a shot. You will need to verify the arrays are correct. In a binary stream, a byte array is just a collection of bytes starting at offset with count bytes as its size.
//here is where you initialize your array. you may need to tweak the values to match your byte range (array)
byte[] dataArray = new byte[9] { 0x93, 0x0E, 0x40, 0xF9, 0x53, 0x00, 0x00, 0xB5, 0xDE };
//here is where you initialize the NEW array you want to write where your matching array lives
byte[] newArray = new byte[9] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Open the file to search in
BinaryReader br = new BinaryReader(File.OpenRead("D:/Users/Joey/Desktop/prod"));
for (int i = 0; i <= br.BaseStream.Length; i++)
{
// Search the file for the STARTING byte of my match
if (br.BaseStream.ReadByte() == (byte)0x93)
{
Console.WriteLine("Found the starting byte at offset " + i); //write to the console on which offset it has been found
byte[] tempArray = new byte[9];
tempArray = br.ReadBytes(9);
//now compare the arrays to see if you have a full match:
int matched = 0;
for (int j=0; j<tempArray.Length; j++)
{
if(tempArray[j] == dataArray[j])
{
matched++;
}
}
//if the arrays match, write your new values:
if(matched == tempArray.Length-1)
{
br.BaseStream.Write(newArray, i, 9);
break; //exit the loop when finished
}
}
}

C# how to send & receive from a hardware protocol?

I'm a C# programmer and I know nothing about hardware protocol things.
today I received a document that is some protocols of a Lock hardware, like this:
lock command
start 0x80
board address 0x01-0xf
lock address 0x00-18
command 0x33
verify code XX
sample:
machine send 0x80 0x01 0x01 0x33 0xB2
if recieve 0x80 0x01 0x01 0x01 0x91 (means unlock)
if receive 0x80 0x01 0x01 0x00 0x80 (means locked)
All I want to know is, if C# can handle these commands? if can, where I can have a quick start, or what should I search on google?
Thanks.
Yes. C# can handle this. This is call polling. Basically, the idea is
send command, receive reply, substring information that you need (in your case, most probably the last 2 bytes) and perform some function on it. I'm not sure if you understand but I'll give you an example on something I've done previously but this is event where data is send to machine whenever event is triggered.
public enum Transaction
{
LOCK = 0x01,
UNLOCK
};
private static string getTransactionDescription(Transaction transaction, string data = "")
{
string result = "";
switch (transaction)
{
case Transaction.UNLOCK:
case Transaction.LOCK:
var slot = ByteOperation.reverse4ByteBitPattern(data.Substring(32, 64));
for (int i = 8 - 1; i >= 0; i--)
{
for (int j = 0; j < 8; j++)
{
if ((Convert.ToInt32(ByteOperation.ToggleEndian_4Bytes(slot.Substring(i * 8, 8)), 16) & (1 << j)) > 0)
{
if (!string.IsNullOrWhiteSpace(result))
{
result += ", ";
}
result += "Slot " + (((7 - i) * 8) + j + 1).ToString("D3");
}
}
}
break;
}
return result;

Random arithmetic overflows when reading from serial port

What I'm doing is taking a user entered string, creating a packet with the data, then sending the string out to a serial port. I am then reading the data I send via a loopback connector. My send is working flawlessly, however my receive is randomly throwing an arithmetic overflow exception.
I say randomly because it is not happening consistently. For example, I send the message "hello" twice. The first time works fine, the second time outputs nothing and throws an exception. I restart my program, run the code again, and send hello only to receive "hell" and then an exception. On rare occasion, I'll receive the packet 3 or 4 times in a row without error before the exception.
Here is my relevant code:
public void receivePacket(object sender, SerialDataReceivedEventArgs e)
{
byte[] tempByte = new byte[2];
int byteCount = 0;
while (serialPort1.BytesToRead > 0)
{
if (byteCount <= 1)
{
tempByte[byteCount] = (byte)serialPort1.ReadByte();
}
if (byteCount == 1)
{
receivedString = new byte[tempByte[byteCount]];
receivedString[0] = tempByte[0];
receivedString[1] = tempByte[1];
}
else if (byteCount > 1)
{
byte b = (byte)serialPort1.ReadByte();
receivedString[byteCount] = b;
}
byteCount++;
}
int strLen = (byteCount - 3);
tempByte = new byte[strLen];
int newBit = 0;
for (int i = 2; i <= strLen+1; i++)
{
tempByte[newBit] = receivedString[i];
newBit++;
}
string receivedText = encoder.GetString(tempByte);
SetText(receivedText.ToString());
}
I'm well aware that my implementation using byteCount (which I use to traverse the byte array) is rather sloppy. When I step through the code, I find that when I get the error byteCount == 1, which is making strLen a negative number (since strLen is byteCount - 3, which is done because the packet contains a header, length, and CRC i.e. byteCount - 3 == # of actual data bytes received). This leads to by tempByte having a size of -2, which throws my exceptions. I, however, am having a very hard time figuring out why byteCount is being set to 1.
The code after this basically just traverses the data section of the array, copies it into the tempByte, then is sent off to a function to append the text in another thread.
I am guessing that byteCount is 1 because you only received one byte - or rather, you processed the first byte before the second one arrived in the buffer.
The ReadByte function will wait for a certain amount of time for a byte to arrive if there isn't one waiting.
Maybe if instead of checking BytesToRead, you did something more like this:
byte headerByte = serialPort1.ReadByte();
byte length = serialPort1.ReadByte();
receivedString = new byte[length];
receivedString[0] = headerByte;
receivedString[1] = length;
for (int i = 2; i < length; i++) {
receivedString[i] = serialPort1.ReadByte();
}

C# Serial Port reading HEX data

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

SerialPort in c# , Data Receive Incomplete Message

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.

Categories

Resources