Data Frame Parsing of the serial port network port (supporting packet connection, data disconnection, and error data filtering) and serial port Parsing
In the embedded system, I think a lot about data acceptance. Next I will summarize my personal experience.
For serial transmission, I personally think it is reasonable to use modbus protocol to accept data. The timeout mechanism of 3.5char characters is adopted. If the timeout mechanism is determined during acceptance, the data is processed as one frame, in this case, the frame format is not explained in this case, and the sending and timeout mechanisms can be completed.
The second type of network port is usually used, and the serial port is also used. Under what circumstances, when the sent data does not have a fixed format or length, in addition, the sending time is not very special. The common format is:
Frame header + Length + Data + verification + frame end, this format can be regarded as a universal data processing format, almost all can be applied.
The pasted code mainly has the following functions:
First, it is useless data format processing. If the frame header is 0xa5 and the sending is not the character 0xa5, it is all filtered. If it is not filtered, the buffer of the loop queue will be wasted.
The second is to handle the intermittent transmission. If a frame of data is first reached during transmission, and a part is then reached, the Mechanism I adopt is that the frame of data is not accepted, then it will not be processed.
Third, when multiple frames are accepted together, there will be a sticky package. In this case, we need to extract all the received data according to the frame format analysis, the processed data is valid single-frame data. I use the callback mechanism here. You just need to register your frame format processing function. After the data processing is complete, it will automatically call your registration function.
4. ram can only process a single packet of no more than 6 K data. If the length mark exceeds 6 K, the data will be filtered. Of course, this is not fixed and you can modify it, the program does not use macro definition.
It is written in C ++. Of course, you only need to modify it slightly to support the C language. You only need a header file.
Create a Queue. h file
# Ifndef QUEUE_H # define bytes // use 10 k ram as the buffer # define START_CHAR0xa5 # define extends unsigned char limit; typedef unsigned long uint32_t; typedef enum {RES_ OK = 0, RES_ERROR} STATUS; typedef enum {RECEIVED_START, NO_RECEIVED_START} RECV_FSM; typedef void (* AnalysisFun) (uint8_t *, int len); // callback function type class Queue {private: uint32_t front; uint32_t rear; uint8_t data [MAXSIZE]; Analys IsFun anaFun; public: Queue (AnalysisFun cb) {front = 0; rear = 0; anaFun = cb ;}~ Queue () {} STATUS EnQueue (uint8_t e) {if (rear + 1) % MAXSIZE = front) {return RES_ERROR;} data [rear] = e; rear = (rear + 1) % MAXSIZE; return RES_ OK;} int QueueLength () {return (rear-front + MAXSIZE) % MAXSIZE;} uint8_t GetQueue (int index) {return data [(front + index) % MAXSIZE];} void HandleData () {uint32_t frame_len, frame_startpos = 0; uint8_t frame_check, c; RECV_FSM frame_state = NO_RECEIVED_START; uint 32_t len = (rear-front + MAXSIZE) % MAXSIZE; // The Data Length in the cyclic queue for (uint32_t I = 0; I <len; I ++) {if (frame_state = NO_RECEIVED_START) {if (GetQueue (I) = START_CHAR) // 0xa5 {frame_check = 0; frame_state = RECEIVED_START; // switch, processing frame data analysis} else {frame_startpos = I + 1; // tag the location where the Buffer Queue needs to be released} else if (frame_state = RECEIVED_START) {if (I + 4 <= len) // four bytes in length {frame_len = (uint32_t) GetQueue (I ++); frame_len | = (uint32 _ T) GetQueue (I ++) <8; frame_len | = (uint32_t) GetQueue (I ++) <16; frame_len | = (uint32_t) getQueue (I ++) <24; if (frame_len> 6137) // the data in a single package exceeds 6 K {frame_state = NO_RECEIVED_START; frame_startpos = I; // flag the position where to release continue;} if (I + frame_len + 2 <= len) // Data Length + verification + end of frame {uint8_t * p = new uint8_t [frame_len + 2]; // allocate space and transfer the cyclic queue data to the new space if (! P) {return ;}for (uint32_t k = 0; k <frame_len; k ++) {c = GetQueue (I ++ ); // retrieve a data in the cyclic queue p [k] = c; // transfer frame_check + = c; // check sum} c = GetQueue (I ++ ); // compare the obtained verification code and sum content. if (c = frame_check & GetQueue (I) = END_CHAR) // how to compare the content consistent and the end of the frame is also correct {anaFun (p, frame_len); // callback processing} frame_state = NO_RECEIVED_START; // switch to the re-Wait 0xa5 status frame_startpos = I + 1; // re-mark the location of the Buffer Queue to be released delete [] p; // release space} else {break ;}} else {break ;}}front = (front + frame_startpos) % MAXSIZE; // release the buffer}; # endif
Create main. cpp. I created this project in VS2010:
// Thread. cpp: defines the entry point of the console application. # Include "stdafx. h "# include <iostream> # include" Queue. h "using namespace std; void Print (uint8_t * str, int len) // The content processed by the callback function, which is printed here {for (int I = 0; I <len; I ++) {printf ("% d = % 02x \ r \ n", I, str [I]) ;}} int _ tmain (int argc, _ TCHAR * argv []) {Queue queue (Print); uint8_t t [] = {0xa5, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x5a, // filtered out. The data exceeds 6K0xa5, 0x02, 0x00, 0x00, 0x00, 0x02, 0x03, 0x05, 0x5a, // print 0xa5, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x5a, // check error. Filter 0xaa, 0xa1, 0x33, //. The data does not contain 0xa50xa5, 0x03, 0x00, // 0xa5 is available for resumable data transfer, and cannot be filtered}; for (int I = 0; I <sizeof (t); I ++) {if (queue. enQueue (t [I]) {cout <"error" <endl ;}} queue. handleData (); printf ("len = % d \ r \ n", queue. queueLength (); getchar (); return 0 ;}
Debugging content, of course, I hope a lot of friends can test it. Here I use sum verification.