AI问小芯
领先的电子元器件AI模型
扫码立即咨询
联系站长: 邮箱:contact@huluic.com
在软件开发的过程中,只要涉及到通信,就会涉及到数据接收机的编写,通信协议虽然多种多样,但是数据包的形式确是很相似的(暂时没看到特别复杂,此模块解决不了的),为此可以把其中通用的部分抽象出来,然后就成了这个模块。
接收机有两个基本状态:
• 状态A:preRx 等待帧头中,这个时候接收机会不断判断是否收到了特殊序列、帧头和强帧尾。如果收到了帧头,则(默认)会把帧头填入缓冲区的最前面,然后进入状态B。
• 状态B:Rxing 等待帧尾中,收到的数据会按序填入接收缓冲区,同时不断查找帧尾、强帧头以及强特殊序列,不管找到了哪一个都会触发flush。如果,找到的是强帧头,则仍然在状态B,否则恢复状态A。
不管在哪一个状态下,如果接受缓冲区满了,都会触发flush并回到状态A。
接收机定义了以下标志序列类型:
对应模块中的结构体为:
// receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag;
一般的流程中,初始化接收机前,用户需要准备好接收机使用的所有标志序列,标志好每个序列的类型。模块提供宏函数以抽象这个过程: // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} flush 每当接收机根据标志字符序列找到一个完整或不完整的数据包时,接收机会进行回调以通知用户处理这个数据包,这个行为被称为flush,这个回调函数叫做onFlushed。 此函数的原型如下: typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); 整个数据包为buf指向的长度为len的区域。 数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下: typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; 通过判断每个标志位是否置1,可以得知当前数据包的状态。 如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头 如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾 如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。 如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列 接收机类 V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。 typedef struct RXMAC_STRUCT * RxMac; 模块提供Create函数来创建接收机实例并返回指向实例的指针。 // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); 调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
一般的流程中,初始化接收机前,用户需要准备好接收机使用的所有标志序列,标志好每个序列的类型。模块提供宏函数以抽象这个过程:
// void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);}
flush 每当接收机根据标志字符序列找到一个完整或不完整的数据包时,接收机会进行回调以通知用户处理这个数据包,这个行为被称为flush,这个回调函数叫做onFlushed。 此函数的原型如下: typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); 整个数据包为buf指向的长度为len的区域。 数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下: typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; 通过判断每个标志位是否置1,可以得知当前数据包的状态。 如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头 如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾 如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。 如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列 接收机类 V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。 typedef struct RXMAC_STRUCT * RxMac; 模块提供Create函数来创建接收机实例并返回指向实例的指针。 // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); 调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
每当接收机根据标志字符序列找到一个完整或不完整的数据包时,接收机会进行回调以通知用户处理这个数据包,这个行为被称为flush,这个回调函数叫做onFlushed。
此函数的原型如下:
typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender);
整个数据包为buf指向的长度为len的区域。 数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下: typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; 通过判断每个标志位是否置1,可以得知当前数据包的状态。 如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头 如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾 如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。 如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列 接收机类 V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。 typedef struct RXMAC_STRUCT * RxMac; 模块提供Create函数来创建接收机实例并返回指向实例的指针。 // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); 调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
整个数据包为buf指向的长度为len的区域。
数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下:
typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState;
通过判断每个标志位是否置1,可以得知当前数据包的状态。 如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头 如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾 如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。 如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列 接收机类 V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。 typedef struct RXMAC_STRUCT * RxMac; 模块提供Create函数来创建接收机实例并返回指向实例的指针。 // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); 调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
通过判断每个标志位是否置1,可以得知当前数据包的状态。
如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头
如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾
如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。
如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列
V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。
typedef struct RXMAC_STRUCT * RxMac;
模块提供Create函数来创建接收机实例并返回指向实例的指针。 // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); 调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
模块提供Create函数来创建接收机实例并返回指向实例的指针。
// to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed);
调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。 过滤器 接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下: typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); • pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。
接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下:
typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
• pCurChar :指向接收区中刚收到的字符 • bytesCnt :这个字符是接收区中的第几个字符 此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。 onGetHeader事件 当找到任意帧头时会触发。 接收机运行逻辑 接收机的运作逻辑如下: 边际条件 标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。 同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。 对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况: 如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。 如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。 相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。 https://blog.csdn.net/lin_strong/article/details/88236566 接收机代码 RxMac.h /* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
• pCurChar :指向接收区中刚收到的字符
• bytesCnt :这个字符是接收区中的第几个字符
此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。
当找到任意帧头时会触发。
接收机的运作逻辑如下:
标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。
同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。
对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况:
如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。
如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。
相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。
https://blog.csdn.net/lin_strong/article/details/88236566
/* ******************************************************************************************* * * * Universal Receive State Machine * 通用接收状态机 * * File : RxMac.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 modify the type names to more readable ones, though preserve * the old-style for forward compatibility; * change init method to create method which use malloc to alloc * instance, and the corresponding destroy method. * change the internal buffer module from RINGQUEUE to BufferArray, * so user no longer need to know the internal flags management and * allocate the space for it. * add RxMac_FeedDatas method for convenient. * 2019/03/07 2.1 some modification to the malloc configuration * * NOTE(s): 1. the receive process has two basic state * A. preRx: when haven't found any header, the RxMac will search for the unique * flag, header and strong-ender. Only when a header is found will come * to next step. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search * for the strong-unique, strong-header, ender. * 2. the module is drived by the RxMac_FeedData(), user should get the the char * from data stream and pass the data one by one to the RxMac through RxMac_FeedData() * or RxMac_FeedDatas(). * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed * to notify the results; user can judge the frame through the state parameter; * state.headerFound == 1: find any header, the header is passed by HorU * state.enderFound == 1: find any ender, the ender is passed by Ender * state.isFull == 1: the buffer is full, maybe you should check headerFound * to see whether a header has been found. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will * always be 0 ,the data in the buffer will be the flag, * and the unique flag is passed by HorU. * 4. To use this module, for each receive machine: * A. define malloc to configure the module, see CONFIGURATION * B. allocate the space for buffer and FLAGS. * RXFLAG_STRUCT flags[2]; * uint8_t buf[300]; * C. set the flags according to the protocol, define the callback functions * according to your need. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... }; * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len, * RxState state,RxFlag HorU,RxFlag Ender){ ...... }; * const uint8_t HeaderFlag[] = "Header"; * const uint8_t EnderFlag[] = " "; * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER); * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER | * RXFLAG_OPTION_NOTFILL_ENDER); * D. create the receive machine: * RxMac mac; * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, * onGetHeader, onFlushed ); * E. feed the receive machine: * while(1){ * c = GetNextChar(); * RxMac_FeedData(mac,c); * } * F. destroy the receive machine if need. * RxMac_Destroy(mac); ******************************************************************************************* */ #ifndef RX_MAC_H #define RX_MAC_H /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include /* ******************************************************************************************* * CONFIGURATION 配置 ******************************************************************************************* */ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /* ******************************************************************************************* * ADDRESSING MODE 寻址模式 ******************************************************************************************* */ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /* ********************************************************************************************* * ERROR CODE ********************************************************************************************* */ #define RXMAC_ERR_NONE 0 #define RXMAC_ERR_ARGUMENT 1 #define RXMAC_ERR_POINTERNULL 2 #define RXMAC_ERR_UNKNOWN 3 #define RXMAC_ERR_INIT 4 /* ********************************************************************************************* * RECEIVE FLAG STRUCT ********************************************************************************************* */ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER 0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER 0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option; } RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to initialize a receive flag // flag point to the target RXFLAG_STRUCT. // buf pointer to the flag buffer // size size of flag // opt see RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt) {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /* ********************************************************************************************* * TYPE DEFINITION ********************************************************************************************* */ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state, RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // to create an instance of RxMac // flags 标志字符串结构体的数组 // flagsCnt 标志字符串结构体的个数 // buf 用户提供给接收机用的缓冲区 // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串) // onFeeded 在每次被Feed时触发 // onGetHeader 获得头标志位时触发。 // onFlushed 收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H
RxMacPrivate.h /* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
/* ******************************************************************************************* * * * Private Declarations for Universal Receive State Machine * * File : RxMacPrivate.h * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: * NOTE(s): ******************************************************************************************* */ /* ******************************************************************************************* * FUNCTION DECLARATION ******************************************************************************************* */ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /* ******************************************************************************************* * RECEIVE FLAG STRUCT ******************************************************************************************* */ // struct of RXFLAG_STRUCT.option /*typedef struct RXFLAG_OPTION{ unsigned int isHeader : 1; // 1: the flag is the head of the frame unsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header unsigned int isEnder : 1; // 1: the flag is the end of the frame unsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not }; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER 0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER 0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE 0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80 #define STATEMASK_STEPA (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag) ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /* ******************************************************************************************* * FORWARD COMPATIBILITY ******************************************************************************************* */ // 以下仅为前向兼容 typedef RxMacPtr pRB_BYTE; typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG; typedef RxMac pRX_MAC; typedef RxState RX_STATE; #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT RxFlag_Init
RxMac.c /* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
/* ******************************************************************************************* * * * Implementation of the Universal Receive State Machine * 通用接收状态机 * * File : RxMac.c * By : Lin Shijun(https://blog.csdn.net/lin_strong) * Date: 2019/03/07 * version: 2.1 * History: 2018/05/29 1.0 the prototype * 2019/01/23 2.0 In addition to the content in RxMac.h: * abstract the flag management part as RxFlagMgr and the * corresponding methods. * refactor the code. * 2019/03/07 2.1 some modification to the malloc configuration * NOTE(s): * ******************************************************************************************* */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include #include #include #include "RxMac.h" #include "BufferMallocArray.h" /* ******************************************************************************************* * RECEIVE FLAGS MANAGER ******************************************************************************************* */ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior. // controlled by the child class. RxState state; }RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /* ******************************************************************************************* * STRUCT DIFINITION ******************************************************************************************* */ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt; RXMAC_FILTER onFeeded; RXMAC_FLAG_EVENT onGetHeader; RXMAC_FLUSH_EVENT onFlushed; } RXMAC_STRUCT; /* ******************************************************************************************* * LOCAL FUNCITON DECLARATION ******************************************************************************************* */ #ifndef RXMAC_SINGLETON_EN #define _pMac mac #define _BufForFlag (_pMac->FlagMgr.BufForFlag) #define _Flags (_pMac->FlagMgr.Flags) #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt) #define _state (_pMac->FlagMgr.state) #define _pHorU (_pMac->pHorU) #define _pRxBuf (_pMac->pRxBuf) #define _RxBufSize (_pMac->RxBufSize) #define _RxCnt (_pMac->RxCnt) #define _fonFeeded (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed (_pMac->onFlushed) #define _RxMac_Destroy() (free(mac)) #else static RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过 static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag) #define _Flags (_mac.FlagMgr.Flags) #define _FlagsCnt (_mac.FlagMgr.FlagsCnt) #define _state (_mac.FlagMgr.state) #define _pHorU (_mac.pHorU) #define _pRxBuf (_mac.pRxBuf) #define _RxBufSize (_mac.RxBufSize) #define _RxCnt (_mac.RxCnt) #define _fonFeeded (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed (_mac.onFlushed) #define _RxMac_Destroy() (_pMac = NULL) #endif #define _stateByte (*(uint8_t *)(&_state)) #define _isRxBufFull() (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接
我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>
利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>
充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>
我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>
我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>
凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>
我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>