1

我正在研究串行端口。我面临一个新问题,即一旦收到数据,我的数据就会不完整。如何检查我的数据是否完整然后处理它们,如果不完整,不处理它们?

这是我的数据接收和发送功能:

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

我知道我的数据是在几个包中收到的,我需要等到响应完成,但根据上面的代码我不知道。我应该如何检查数据是否完整,以确定是否等待?(PS:收到的响应大小不同。)

4

3 回答 3

2

没有完整性或数据包大小的内置概念。

您必须附加到缓冲区,直到看到您(或其他人)定义为协议规范的一部分的可识别的数据包结束模式。- 如果你还没有看到你要找的东西,那么可能会在一段时间后超时。

于 2013-02-01T01:14:45.950 回答
0

老项目的例子,注意firstindex,lastindex,你输入一个字符来知道长度,开始/结束字符是预定义的,可以是你选择的任何字符,注意不要带任何常见字符

这适用于 tcp/ip,但同样的原理可用于串口

    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());
        }
    }
于 2013-02-01T01:32:26.683 回答
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()。

于 2013-02-01T03:53:30.533 回答