我通过COM端口收到数据包。每个数据包以{0xFF,0xFF}开头,以{0xFE,OxFE}结束。所有收到的字节都在Queue<byte>
中排队,并在每个void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
之后我正在处理该队列。
如果数据包中出现任何0xFF或0xFE,则设备在其后添加0x00。
我的第一个问题是:
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);
}
}
}
我正在尝试删除在Queue<byte>
内可以找到的任何0xFE和0xFF之后的所有0x00,到目前为止我想出了:
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);
}
有没有人可能有任何其他解决方案/建议呢?
答案 0 :(得分:0)
尝试以下方法:
在DataReceived事件处理程序中继续读取传入数据并将其附加到缓冲区(byte [])。
首先,您需要在接收数据的缓冲区中找到开始标记({0xFF,0xFF})。您需要确定缓冲区中此标记的索引。
获得起始索引后,需要继续将输入数据附加到缓冲区,并检查结束标记(0xFE,0xFE)是否已到达。捕获缓冲区内结束标记的索引。
获得开始和结束索引后,您可以在它们之间提取数据包。没关系在它之后添加的额外0x00字节。您知道开始和结束标记的索引及其长度(2)。只需提取它们之间的字节数组。
您需要创建一个适合此目的的搜索算法。 needle和haystack都是一个字节数组(byte [])。您可以使用Boyer-Moore string search algorithm来实现此目的。
这是Boyer-Moore算法的简单C#实现,它只实现the bad character rule。如果您还想实现good suffix rule,请阅读维基百科。
该算法通常用于字符串,但我修改它以使用字节数组。使用IP摄像头在本地进行测试,以提取收到的JPEG图像。
查看维基百科文章,了解有关它的更多信息。它包含一个完整的Java实现,您可以轻松地将其转换为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;
}
}
使用示例:
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,在这个例子中,包字节数组包含9个字节,只包含开始和结束标记之间的字节。您现在可以触发事件并将数据包作为事件arg传递。例如。
备注:从COM端口接收数据是一个连续事件。你需要继续监控它。继续附加收到的数据,并继续检查起始和索引标记,提取包...等。注意你的缓冲区不会溢出。你需要在那里实施一些内务管理。
希望它有所帮助。请查看AForge MJPEGStream的实施情况,以获取持续读取传入数据的示例。
概括说明:
您需要实施一些内务处理以确保缓冲区不会溢出(> 4096字节)。例如,一旦找到数据包,就可以将缓冲区清理到最后收到的结束标记。