我正在使用Serialport。我正面临一个新问题,一旦我收到数据,我的数据就不完整了。如何检查我的数据是否完整然后处理它们,如果没有,不处理它们?
以下是我的数据接收和发送功能:
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 });
}
}
我知道我的数据是在几个包中收到的,我需要等到响应完成,但我不知道基于上面的代码。我该如何检查数据是否完整以确定是否等待? (P.S:收到的答复的大小各不相同。)
答案 0 :(得分:2)
没有完整性或数据包大小的内置概念。
您必须附加到缓冲区,直到您看到一些可识别的数据包结束模式(您或其他人)将其定义为协议规范的一部分。 - 如果你还没有看到你想要的东西,那么一段时间后可能会超时。
答案 1 :(得分:0)
旧项目的示例,注意firstindex,lastindex,你输入一个字符来知道长度,开始/结束字符是预定义的,可以是你选择的任何字符,只是一定不要采取任何常见字符
这适用于tcp / ip,但同样的原则可用于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());
}
}
答案 2 :(得分:0)
我有一些代码给你。 首先,您实现DataReceived事件(就像您已经完成的那样)。仅在有数据要处理时才会调用此事件。虽然我不会称它为基于中断(如“实时能力”),但绝对不是轮询。哪个好。
第二:调用事件时,您可能只有一个字节,但可能有更多字节。要捕获每个数据包,您需要实现自定义缓冲区。
第三步:在缓冲区附加一个字节后,检查缓冲区是否包含有效数据包。如果是,请处理它。如果不是:追加另一个。如果没有剩余字节,则等待再次调用该事件。
在代码中它看起来像这样:
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();
}
请注意,我没有“将字节附加到缓冲区”。我丢弃了第一个字节,将每个字节移位一个位置并在最后插入新字节。如果找到有效的数据包,我可以将它在一个块中复制到结构中。因此缓冲区大小始终是恒定的,并且与一个数据包完全一样长。
这可能不是那里最快的代码(因为它分别读取每个字节),但它适用于我: - )
哦,如果你想在GUI中显示那些内容,请记得使用Begininvoke()。