【问题标题】:Buffer management and extracting frames from serial data缓冲区管理和从串行数据中提取帧
【发布时间】:2019-11-22 04:23:53
【问题描述】:

我正在编写代码以使用 windows api 通过 C 解析串行数据。我能够读取数据,并且还编写了解析帧的代码。我面临的困难是从传入的串行数据中提取有效帧。

我的解析函数需要一个有效的帧并且没有。该帧中的字节数。

void parse_serial(unsigned char* receivedData, int noOfBytes)

这个帧的结构如下:header(0x10),subsystemID,status,datalength,data,checksum(sum of header until data)。

我想从传入的数据中提取此帧并将其发送到我的解析函数。此外,如果未提取一半帧,则剩余数据应与下一个传入数据一起使用。到目前为止,这是我的代码:

hSerial = CreateFileA(pcCommPort,
    GENERIC_READ | GENERIC_WRITE,
    0,
    0,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0);

void read_serial()
{
    int BUFFERLENGTH =256;
    BOOL  Read_Status;
    unsigned char  SerialBuffer[BUFFERLENGTH+1];
    DWORD NoBytesRead;

    Read_Status = SetCommMask(hSerial, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception

        if (Read_Status == FALSE)
            printf("Error! in Setting CommMask");
        else
            printf("Setting CommMask successful");

        Read_Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received

         /*-------------------------- Program will Wait here till a Character is received ------------------------*/

        if (Read_Status == FALSE)
        {
            printf("\n    Error! in Setting WaitCommEvent()");
        }
        else If  WaitCommEvent()==True Read the RXed data using ReadFile();
        {
            printf("\n\n    Characters Received \t");

            do
            {
                Read_Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
                if (!ReadFile(hComm, SerialBuffer, BUFFERLENGTH, &NoBytesRead, NULL))
                {
                    printf("wrong character");
                }
                SerialBuffer[i] = TempChar;
                printf("%c", SerialBuffer[i]);
                i++;
            } while (NoBytesRead > 0);
        }
  }

【问题讨论】:

  • 您实际上并没有告诉我们问题所在。您得到的最接近的是“我面临的困难是在提取有效帧时”。但你永远不会说那个“困难”到底是什么。
  • @kaylum 我不知道如何处理缓冲区的移动。我正在寻找一个流程,在读取串行端口并在 SerialBuffer 中获取数据后如何进行。我应该再制作一个数组来存储它并使用它来附加传入的串行数据吗?

标签: c parsing serial-port serial-communication


【解决方案1】:

只需使用 memmove 将不完整的帧(消息)移动到缓冲区的开头,并且在您完成应用程序的功能之前不关心优化(只需在代码中添加 TODO 注释以了解可能的改进)。

稍后当您无事可做时,您可以结合ReadFileScatter 实现循环缓冲区,它允许您将传入数据写入可以位于不同缓冲区中的多个块(即在缓冲区的开头和结尾处)缓冲区的一半占据缓冲区的中间)

更新: 我检查了ReadFileScatter 的文档,我怀疑它不适合您的目的,因为它需要缓冲区对齐,并且会使循环缓冲区实现更加复杂,并且在静态缓冲区较小的情况下可能是不可能的。

您仍然可以将 FileRead 与循环缓冲区一起使用,但复制少量数据的开销很小,因此我建议您将实现限制为使用 memmove 以保持您的解决方案简单(除非您开始使用像 > 64kb)。

只有当您使用大缓冲区并且 memmove 会开始减慢您的应用程序时,您才能返回到 ReadFileScatter 解决方案(但“慢”串行通信速度您很可能不会遇到任何瓶颈)。

我相信您将能够自己找到现有的循环缓冲区解决方案。

【讨论】:

  • 谢谢。我想如果我不想丢失我的数据,我必须这样做。你能提供任何演示代码吗?
【解决方案2】:

我想通了。 我正在读取SerialBuffer com pot 上的所有可用数据,并在上一个周期的任何剩余数据之后将其复制到localBuff

if(ReadFile(hSerial, SerialBuffer, BUFFERLENGTH, &NoBytesRead, NULL))
       {
            if(NoBytesRead<=0)
           {
               qDebug()<<"No data on serial port";
           }
           else
           {
               tempDataAvail = NoBytesRead;
               memcpy(&localBuff[lastCycleBytes], &SerialBuffer,(sizeof(localBuff) - lastCycleBytes));
           }
       }

我将localBuff 发送到extractValidFrame 没有。上一个周期的字节数附加了新数据。

lastCycleBytes += tempDataAvail;
       if(lastCycleBytes >= sizeof(localBuff))
       {
           qDebug()<<"buffer filled with garbage - flushed!";
           lastCycleBytes = 0;
       }
extractValidFrame(localBuff,lastCycleBytes);

提取一帧后,我将其发送以解析并将剩余的数据按帧大小移动。

memcpy(&validFrame[0], &receivedData[startLoc],endLoc-startLoc+1);
parse_serial(validFrame);
memset(&validFrame, 0,endLoc-startLoc+1);
memcpy(&receivedData[0], &receivedData[endLoc+1],noOfBytes-endLoc-1);
lastCycleBytes = noOfBytes-endLoc-1;

【讨论】:

    猜你喜欢
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    • 2021-11-29
    • 2013-03-26
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多