缓冲区管理和从串行数据中提取帧
Buffer management and extracting frames from serial data
我正在编写代码,使用 windows api 通过 C 解析串行数据。我能够读取数据,并且还编写了代码来解析帧。我面临的困难是从传入的串行数据中提取有效帧。
我的解析函数接受一个有效的框架,没有。该帧中的字节数。
void parse_serial(unsigned char* receivedData, int noOfBytes)
这个帧结构如下:header(0x10), subsystemID, status, datalength, data, checksum(header till 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);
}
}
只需使用 memmove 将不完整的帧(消息)移动到缓冲区的开头,并且在完成应用程序的功能之前不要关心优化(只需在代码中添加 TODO 注释以了解可能的改进)。
稍后当您无事可做时,您可以结合 ReadFileScatter 实现循环缓冲区,这允许您将传入数据写入多个块,这些块可以位于不同的缓冲区中(即在缓冲区的开头)和缓冲区的结尾,一半的帧占据了缓冲区的中间)
更新:
我检查了 ReadFileScatter 的文档,我怀疑它不适合您的目的,因为它需要缓冲区对齐,并且会使循环缓冲区的实现更加复杂,并且在小型静态缓冲区的情况下可能是不可能的。
您仍然可以将 FileRead 与循环缓冲区一起使用,但复制少量数据的开销很小,因此我建议您将实现限制为使用 memmove 以保持解决方案简单(除非您开始使用大框架喜欢> 64kb)。
你可以 return 回到 ReadFileScatter 解决方案只有当你使用大缓冲区并且 memmove 会开始减慢你的应用程序时(但是使用 "slow" 串行通信速度你很可能不会遇到任何瓶颈)。
我相信您一定能够自己找到循环缓冲区的现有解决方案。
我明白了。
我正在读取 SerialBuffer
中有关 compot 的所有可用数据,并将其复制到 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;
我正在编写代码,使用 windows api 通过 C 解析串行数据。我能够读取数据,并且还编写了代码来解析帧。我面临的困难是从传入的串行数据中提取有效帧。
我的解析函数接受一个有效的框架,没有。该帧中的字节数。
void parse_serial(unsigned char* receivedData, int noOfBytes)
这个帧结构如下:header(0x10), subsystemID, status, datalength, data, checksum(header till 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);
}
}
只需使用 memmove 将不完整的帧(消息)移动到缓冲区的开头,并且在完成应用程序的功能之前不要关心优化(只需在代码中添加 TODO 注释以了解可能的改进)。
稍后当您无事可做时,您可以结合 ReadFileScatter 实现循环缓冲区,这允许您将传入数据写入多个块,这些块可以位于不同的缓冲区中(即在缓冲区的开头)和缓冲区的结尾,一半的帧占据了缓冲区的中间)
更新: 我检查了 ReadFileScatter 的文档,我怀疑它不适合您的目的,因为它需要缓冲区对齐,并且会使循环缓冲区的实现更加复杂,并且在小型静态缓冲区的情况下可能是不可能的。
您仍然可以将 FileRead 与循环缓冲区一起使用,但复制少量数据的开销很小,因此我建议您将实现限制为使用 memmove 以保持解决方案简单(除非您开始使用大框架喜欢> 64kb)。
你可以 return 回到 ReadFileScatter 解决方案只有当你使用大缓冲区并且 memmove 会开始减慢你的应用程序时(但是使用 "slow" 串行通信速度你很可能不会遇到任何瓶颈)。
我相信您一定能够自己找到循环缓冲区的现有解决方案。
我明白了。
我正在读取 SerialBuffer
中有关 compot 的所有可用数据,并将其复制到 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;