Reputation: 302
I am writing a code to parse serial data via C using windows api. I am able to read data and I have also written a code to parse frames. The difficulty I am facing is while extracting a valid frame from incoming serial data.
My parsing function takes a valid frame and no. of bytes in that frame.
void parse_serial(unsigned char* receivedData, int noOfBytes)
This frame has structure as follows: header(0x10), subsystemID, status, datalength, data, checksum(sum of header till data).
I want to extract this frame from incoming data and send it to my parsing function. Also, remaining data should be used with the next incoming data if half of the frame is not extracted. Here is my code so far:
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);
}
}
Upvotes: 0
Views: 880
Reputation: 302
I figured it out.
I am reading all available data on com pot in SerialBuffer
and copy it to localBuff
after any leftover data from the previous cycle.
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));
}
}
I am sending localBuff
to extractValidFrame
with no. of bytes from the previous cycle appended with new data.
lastCycleBytes += tempDataAvail;
if(lastCycleBytes >= sizeof(localBuff))
{
qDebug()<<"buffer filled with garbage - flushed!";
lastCycleBytes = 0;
}
extractValidFrame(localBuff,lastCycleBytes);
After extracting a frame I am sending it to parse and shifting the remaining data left by frame size.
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;
Upvotes: 0
Reputation: 2218
Just use memmove to move incomplete frame(message) to the start of the buffer and do not care about optimizations until you are done with functionality of the app (just add TODO comment into the code about possible improvement).
Later on when you have nothing to do you could implement circular buffer in combination with ReadFileScatter, which allows you write incoming data into several chunks which can be located in different buffers (i.e. at the start of buffer and end of you buffer with half of frame occupying the middle of the buffer)
UPDATE: I checked documentation for ReadFileScatter and I suspect that it is not suitable for your purpose because it requires buffer alignment and would make circular buffer implementation even more complicated and probably impossible in case of small static buffers.
You still can use FileRead with circular buffer but overhead of copying of small amount of data is small so I would suggest you to limit you implementation to the use of memmove to keep your solution simple (unless you start using big frames like > 64kb).
You could return back to ReadFileScatter solution only when you use big buffers and memmove would start slowing your app down (but with "slow" serial communication speeds you will most likely not encounter any bottlenecks).
I'm sure you will be able to find existing solution for circular buffer yourself.
Upvotes: 1