嵌入式开发模块指南:通用接收状态机模块

前言
在软件开发的过程中,只要涉及到通信,就会涉及到数据接收机的编写,通信协议虽然多种多样,但是数据包的形式确是很相似的(暂时没看到特别复杂,此模块解决不了的),为此可以把其中通用的部分抽象出来,然后就成了这个模块。
模块相关概念和逻辑
接收机状态
接收机有两个基本状态:
状态a:prerx 等待帧头中,这个时候接收机会不断判断是否收到了特殊序列、帧头和强帧尾。如果收到了帧头,则(默认)会把帧头填入缓冲区的最前面,然后进入状态b。
状态b:rxing 等待帧尾中,收到的数据会按序填入接收缓冲区,同时不断查找帧尾、强帧头以及强特殊序列,不管找到了哪一个都会触发flush。如果,找到的是强帧头,则仍然在状态b,否则恢复状态a。
不管在哪一个状态下,如果接受缓冲区满了,都会触发flush并回到状态a。
标志字符序列
接收机定义了以下标志序列类型:
类型 模块中标记 描述
帧头 header 只在状态a起作用;找到时会导致之前接收区内的数据被flush,然后默认会填入接收区的最前面,可以通过选项来改变这个行为,然后接收机进入状态b。
强帧头 strong-header 在状态b也会起作用,其他行为与普通帧头一样
帧尾 ender 只在状态b起作用;找到时会导致当前接收区内的数据被flush,默认会处于回调时给用户的buffer的最后面,可以通过选项来改变这个行为,然后接收机回到状态a。
强帧头 strong-header 在状态a也会起作用,其他行为与普通帧尾一样
特殊序列 unique 只在状态a起作用;找到时会导致之前接收区内的数据被flush,然后自己被填入接收区内后再次触发flush,然后接收机回到状态a。
强特殊序列 strong-unique 在状态b也会起作用,其他行为与特殊序列一样
对应模块中的结构体为:
// receive flagtypedef struct rxflag_struct{   uint8_t const * pbuf;   uint8_t len;   uint8_t option;} rxflag_struct;typedef rxflag_struct const * rxflag;1234567  
一般的流程中,初始化接收机前,用户需要准备好接收机使用的所有标志序列,标志好每个序列的类型。模块提供宏函数以抽象这个过程:
// 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事件
当找到任意帧头时会触发。
接收机运行逻辑
接收机的运作逻辑如下:
img
边际条件
标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。
同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。
对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况:
如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。
如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pender参数来得知真正的帧尾。
帧尾不会发生这种边际条件。
相关代码
此模块使用了我自己写的buffer模块作为内部缓冲区来判断标志字符串。
[嵌入式开发模块]环形缓冲区/循环队列 c语言实现
接收机代码
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#endiftypedef 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 flagtypedef 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 rxmacvoid 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);// 强制接收机flushuint8_t rxmac_flush(rxmac mac);// 设置onfeededuint8_t rxmac_setonfeeded(rxmac mac, rxmac_filter onfeeded);// 设置ongetheaderuint8_t rxmac_setongetheader(rxmac mac, rxmac_flag_event ongetheader);// 设置onflusheduint8_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)    if(_fonfeeded != null)  _fonfeeded(_pmac,pchar,cnt);#else  #define _onfeeded(pchar,cnt)#endif#define  _ongetheader(headerflag)       if(_fongetheader != null) _fongetheader(_pmac,headerflag);#undef _dont_check_mac#ifdef rxmac_argument_check_disable#define _dont_check_mac#endif#ifdef rxmac_singleton_en#define _dont_check_mac#endif#ifdef _dont_check_mac  #define _checkmacnotnull()  #define _checkmacnotnull_void()#else  #define _checkmacnotnull()       if(_pmac == null)  return rxmac_err_pointernull;  #define _checkmacnotnull_void()  if(_pmac == null)  return;#endif#ifdef rxmac_buf_rpage#ifdef codewarriorstatic rxmacptr _memcpy_internal(rxmacptr dest, rxmacptr src, size_t n);#define memcpy(dest,src,n)   _memcpy_internal(dest,src,n)#endif#endif// 冲刷缓冲区static void _flush(rxmac mac,rxflag ender);// 往接收机缓冲区内放数据static void _bufin(rxmac mac,rxmacptr buf,uint16_t len);static void _rxmac_flushiffull(rxmac mac);static void _rxmac_recordandflushprebytesifgotheaderorunique(rxmac mac,rxflag flagjustgot);static void _rxmac_getheaderprocess(rxmac mac,rxflag flagjustgot);static void _rxmac_getuniqueprocess(rxmac mac,rxflag flagjustgot);static void _rxmac_getenderprocess(rxmac mac,rxflag flagjustgot);/*********************************************************************************************                                      rxmac_create()** description : to create a receive machine instance.    创建一个接收机实例** arguments   : flags      pointer to the flags(an array); 指向标志串(数组)的指针*               flagscnt   the count of the flags;         有多少个标志串;*               buf        pointer to the buffer provided to the rxmac;提供给接收机使用的缓存*               buflen     the size of the buffer.         缓存的大小*               onfeeded   the callback func that will be called everytime feeded, you*                          can modify the feeded byte in this callback.*                          每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断*               ongetheader the callback func that will be called when find a header.*                          当发现帧头时会调用的回调函数*               onflushed  the callback func that will be called when flushed.*                          当flush时会调用的回调函数** return      : pointer to the created instance.*               null      if any error.** note(s)     : 1. size of buffer should bigger than the longest flag, or the flag will be *               useless.*               2. if flagscnt > 0, flags can't point to null.*               3. you must provide a buffer.*               4. if you enable the rxmac_singleton_en, multi-create will pointer to the*                  same instance initialized as the last create.**               void ongetheader(rxmac sender,rxflag flag):*                sender   the pointer to the rxmac which call this function*                flag     the header matched**               void onfeeded(rxmac sender,uint8_t * pcurchar,uint16_t bytescnt):*                sender    the pointer to the rxmac which call this function*                pcurchar  point to the byte just received, you can change it before any other process.*                bytescnt  the number of bytes in the buffer including the char just feeded.**               void onflushed(rxmac sender,rxmacptr pbuf,uint16_t len,rxstate state,rxflag horu,*                  rxflag ender);*                sender    the pointer to the rxmac which call this function*                buf       the pointer to the frame.*                len       the length of frame.*                state     the state of frame.*                horu      point to the header flag if state.headerfound == 1, or unique flag if *                          state.uniquefound == 1.*                ender     point to the ender flag if state.enderfound == 1.********************************************************************************************/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){  uint8_t i, maxlen = 0;#ifndef rxmac_singleton_en  rxmac mac;#endif#ifndef rxmac_argument_check_disable  if((flags == null && flagscnt > 0 ) || buf == null)    return null;#endif  // find out the max length of flags.  for(i = 0; i  maxlen)      maxlen = flags[i].len;  }#ifndef rxmac_argument_check_disable  if(buflen < maxlen){    return null;  }#endif#ifdef rxmac_singleton_en  if(_pmac != null)            // if have created one instance, free the previous flagbuf    _rxflagmgr_destroy(&_mac);  else    _pmac = &_mac;#else  if((mac = (rxmac)malloc(sizeof(rxmac_struct))) == null){    return null;  }#endif  if(!_rxflagmgr_init(_pmac,flags,flagscnt,maxlen)){    _rxmac_destroy();    return null;  }  _phoru = null;  _prxbuf = buf;  _rxcnt = 0;  _rxbufsize = buflen;  _fonfeeded = onfeeded;  _fongetheader = ongetheader;  _fonflushed = onflushed;  return _pmac;}/*********************************************************************************************                                        rxmac_destroy()** description : destroy a receive machine instance.** arguments   : mac     the target receive machine.     目标接收机** return      : ** note(s)     : *********************************************************************************************/void rxmac_destroy(rxmac mac){  if(_pmac == null)    return;  _rxflagmgr_destroy(mac);  _rxmac_destroy();}/*********************************************************************************************                                        rxmac_feeddata(s)** description : to feed rxmac the next char(s).    用于给接收机下一个字符** arguments   : mac    the target receive machine.     目标接收机*               c      the char to feed;               下一个字符** return      : ** note(s)     : ********************************************************************************************/void rxmac_feeddatas(rxmac mac, uint8_t const * buf, uint16_t len){  uint16_t i;  for(i = 0; i  0 || ender != null) && _fonflushed != null)    _fonflushed(_pmac,_prxbuf,_rxcnt,_state,_phoru,ender);  // 复位接收机  _rxcnt = 0;  _statebyte = 0;  _phoru = null;}bool bufferuint8indexed_backmatch(bufferuint8indexed buf,uint8_t const *tomatch,uint16_t len){  uint16_t cnt = _buffer_getcount(buf);  if(len > cnt)     return false;  while(len > 0){    if(_bufferuint8indexed_get(buf,--cnt) != tomatch[--len])      return false;  }  return true;}static void _rxmac_flushiffull(rxmac mac){  if(_isrxbuffull()){    _state.isfull = 1;    _flush(_pmac,null);  }}static void _rxmac_recordandflushprebytesifgotheaderorunique(rxmac mac,rxflag flagjustgot){  if(flagjustgot->option & rxflagmask_usuhsh){    if(_rxcnt > flagjustgot->len){      _rxcnt -= flagjustgot->len;      _flush(_pmac,null);    }else{      _rxcnt = 0;    }    _phoru = flagjustgot;  }}static void _rxmac_getheaderprocess(rxmac mac,rxflag flagjustgot){#ifndef rxmac_notfill_disable  if(!_rxflag_dontfillheader(flagjustgot))#endif    _bufin(_pmac,(rxmacptr)flagjustgot->pbuf,flagjustgot->len);  _state.headerfound = 1;  _ongetheader(flagjustgot);  _rxmac_flushiffull(mac);}static void _rxmac_getuniqueprocess(rxmac mac,rxflag flagjustgot){  _state.uniquefound = 1;  _bufin(_pmac,(rxmacptr)flagjustgot->pbuf,flagjustgot->len);  _flush(_pmac,null);}static void _rxmac_getenderprocess(rxmac mac,rxflag flagjustgot){  _state.enderfound = 1;  if(_rxcnt len){          // if part of the flag has been manually flushed.    _rxcnt = 0;                           // restore the buffer.    _bufin(_pmac,(rxmacptr)flagjustgot->pbuf,flagjustgot->len);   }#ifndef rxmac_notfill_disable  if(_rxflag_dontfillender(flagjustgot))    if(_rxcnt > flagjustgot->len)      _rxcnt -= flagjustgot->len;    else      _rxcnt = 0;#endif  _flush(_pmac,flagjustgot);}static rxflag _rxflagmgr_getnextmatchedatthisstate(rxmac mac,uint8_t nextbyte){  uint8_t i,mask;  if(_buffer_isfull(_bufforflag))    bufferuint8_frontout((bufferuint8)_bufforflag);  bufferuint8_backin((bufferuint8)_bufforflag,nextbyte);  // mask to identify possible flag  mask = (_state.headerfound)?statemask_stepb:statemask_stepa;  for(i = 0; i  '0' && *pcurchar pbuf);}static void ongetheader2(rxmac sender,rxflag flag){  printf(foundheader:%s,flag->pbuf);  rxmac_setonfeeded(sender,ongetdata);}/***********************************************************************************************************                                           main function**********************************************************************************************************/void main(void) {  // 选择想要实验的协议来初始化  protocol1_init();  // protocol2_init();  while (1) {    c = getchar();    // 回显    putchar(c);    rxmac_feeddata(mac,c);  }}  
示例协议1测试结果
示例协议2测试结果可以看到,第二个协议中我们通过改变缓冲区大小成功控制了数据包的长度。
虽然这里的示例都是基于ascii的,但这只是为了观察起来方便,普通的基于二进制的协议也是可以使用这个模块的。
v1.0代码
旧版代码中引用了我自己写的(现已弃用)环形缓冲区模块:
https://blog.csdn.net/lin_strong/article/details/73604561
接收机代码
头文件
/*************************************************************************************************************                                  universal receive state machine*                                          通用接收状态机** file : rxmac.h** by   : lin shijun(https://blog.csdn.net/lin_strong)* date: 2018/05/29* version: 1.0* history: 2018/05/29     the prototype* 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()*           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 phoru*               state.enderfound  == 1:   find any ender,  the ender  is passed by pender*               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 datas in the buffer will be the flag.*           4. to use this module, for each receive machine:*              a. allocate the space for buffer, rxmac & flags*                   rx_mac _mac;*                   rx_flag flags[2];*                   int8u buf[300];*              b. set the flags according to the protocol, define the callback funcitons*                  according to your need.*                   static void ongetheader(prx_mac sender,prx_flag pflag){ ...... };*                   static void onflushed(prx_mac sender,prb_byte pbuf,int16u len,*                      rx_state state,prx_flag phoru,prx_flag pender){ ...... };*                   const int8u headerflag[] = header;*                   const int8u enderflag[] = ;*                   rx_flag_init(flags,headerflag,strsize(headerflag),flag_option_header);*                   rx_flag_init(&flags[1],enderflag,strsize(enderflag),flag_option_ender |*                                 flag_option_notfill_ender);*              c. init the receive machine:*                   rxmac_init(&_mac,flags,2,6,buf,300,null, ongetheader, onflushed );*              d. feed the receive machine:*                   while(1){*                     c = getnextchar();*                     rxmac_feeddata(&_mac,c);*                   }**********************************************************************************************************/#ifndef rx_mac_h#define rx_mac_h/***********************************************************************************************************                                       includes**********************************************************************************************************/#include ringqueue.h#include //typedef unsigned char int8u;//typedef unsigned short int16u;/***********************************************************************************************************                                       addressing mode 寻址模式**********************************************************************************************************/// the addressing mode for buffer#define rxmac_buf_addressing_mode   rq_addressing_modetypedef int8u     rb_byte;typedef rb_byte * rxmac_buf_addressing_mode prb_byte;/***********************************************************************************************************                                       configuration  配置**********************************************************************************************************/#define rxmac_argument_check_en   true#define rxmac_notfill_en          true#define rxmac_onfeeded_en         true    // true: enable the onfeeded function.#define rxmac_singleton_en        false   // true: enable 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();/***********************************************************************************************************                                       const**********************************************************************************************************/#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/***********************************************************************************************************                                 type definition**********************************************************************************************************/// struct of rx_flag.option /*typedef struct flag_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 }; //*/// 接收标志位typedef struct rx_flag{   int8u const *pbuf;   int8u len;   int8u option;} rx_flag,* prx_flag;// normal header, rxmac will only check it in step a#define flag_option_header               0x01// strong header, rxmac will always check it.#define flag_option_strong_header        0x03// the header will not be filled into buffer when found.(only valid when is header)#define flag_option_notfill_header       0x04// normal ender, rxmac will only check it in step b#define flag_option_ender                0x08// strong header, rxmac will always check it.#define flag_option_strong_ender         0x18// the ender will not be filled into buffer when found.(only valid when is ender)#define flag_option_notfill_ender        0x20// normal unique, rxmac will only check it in step a#define flag_option_unique               0x40// strong unique, rxmac will always check it.#define flag_option_strong_unique        0xc0typedef struct rx_state{  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.} rx_state;typedef struct rx_mac rx_mac, *prx_mac;typedef void (* rxmac_flush_event)(prx_mac sender,prb_byte pbuf,int16u len,rx_state state,prx_flag phoru,prx_flag pender);typedef void (* rxmac_flag_event)(prx_mac sender,prx_flag pflag);typedef void (* rxmac_filter)(prx_mac sender,prb_byte pcurchar,int16u bytescnt);struct rx_mac{   ring_queue flagqueue;   // 用于判断标志串的环形缓冲区对象      prx_flag flags;         // 标志数组   int8u flagscnt;         // 标志数组的个数   rx_state state;         // 接收的状态(内部使用)   prx_flag phoru;         // 内部使用   prb_byte prxbuf;        // 存放数据的缓冲区   int16u rxbufsize;       // 缓冲区的长度      prb_byte pcur;          // 指向缓冲区内下一个填充字符的位置      rxmac_filter onfeeded;  // 当被喂字符时触发,返回指向缓冲区中刚刚喂进来的字符的指针以及是缓冲区内的第几个字符      rxmac_flag_event ongetheader;  // 获得头标志位时触发。   rxmac_flush_event onflushed;    // 回调函数};/***********************************************************************************************************                                  function declaration**********************************************************************************************************/// to set the flag's option//    pbuf     pointer to the flag buffer//    bufsize  size of flag //    opt      see  flag_option_xxxxx#define rx_flag_init(pflag,pbuf,bufsize,opt)              (pflag)->pbuf =(pbuf);(pflag)->len =(bufsize);(pflag)->option = (opt);// to init the rxmacint8u rxmac_init(prx_mac prxmac,            // 需要用户自己申请个uni_rx_machine对象的空间                    rx_flag flags[],int8u flagscnt,int8u maxlenofflags,  // 提供标志字符串的数组                    prb_byte pbuf,int16u buflen, // 用户需要提供缓冲区 (缓存区大小起码应该要能                                                 // 放的下最长的flag+最长的帧,最后部分会分配给rq)                    rxmac_filter onfeeded,           // 在每次被feed时触发                    rxmac_flag_event ongetheader,    // 获得头标志位时触发。                    rxmac_flush_event onflushed      // 收到一帧数据时的回调函数                    );// 向接收机内喂字节void rxmac_feeddata(prx_mac prxmac,int8u c);// 重置接收区长度为最长那个长度int8u rxmac_resetrxsize(prx_mac prxmac);// 设置最大接收到多少个字节int8u rxmac_setrxsize(prx_mac prxmac, int16u size);// 重置接收机的状态int8u rxmac_resetstate(prx_mac prxmac);// 强制接收机flushint8u rxmac_flush(prx_mac prxmac);// 设置onfeededint8u rxmac_setonfeeded(prx_mac prxmac,rxmac_filter onfeeded);// 设置ongetheaderint8u rxmac_setongetheader(prx_mac prxmac,rxmac_flag_event ongetheader);// 设置onflushedint8u rxmac_setonflushed(prx_mac prxmac,rxmac_flush_event onflushed);#endif // of rx_mac_h  
源文件:
/*************************************************************************************************************                                  universal receive state machine*                                          通用接收状态机** file : rxmac.c** by   : lin shijun(https://blog.csdn.net/lin_strong)* date: 2018/05/29* version: 1.0* history: * note(s): ***********************************************************************************************************//***********************************************************************************************************                                       includes**********************************************************************************************************/#include rxmac.h#include #include /***********************************************************************************************************                                       constant**********************************************************************************************************/// normal header, rxmac will only check it in step a#define flag_optbit_header               0x01// strong header, rxmac will always check it.#define flag_optbit_strong_header        0x02// the header will not be filled into buffer when found.(only valid when is header)#define flag_optbit_notfill_header       0x04// normal ender, rxmac will only check it in step b#define flag_optbit_ender                0x08// strong header, rxmac will always check it.#define flag_optbit_strong_ender         0x10// the ender will not be filled into buffer when found.(only valid when is ender)#define flag_optbit_notfill_ender        0x20// normal unique, rxmac will only check it in step a#define flag_optbit_unique               0x40// strong unique, rxmac will always check it.#define flag_optbit_strong_unique        0x80#define statemask_stepa   (flag_optbit_header | flag_optbit_unique | flag_optbit_strong_ender)#define statemask_stepb   (flag_optbit_strong_unique | flag_optbit_ender | flag_optbit_strong_header)#define flagmask_usuhsh   (flag_optbit_header | flag_optbit_strong_header | flag_option_unique | flag_optbit_strong_unique)/***********************************************************************************************************                                   local  funciton  declaration**********************************************************************************************************/#if(rxmac_singleton_en == false)  #define _prxmac       prxmac#else  static rx_mac _rxmac;  #define _prxmac       (&_rxmac)#endif#define _flagqueue   (_prxmac->flagqueue)#define _flags       (_prxmac->flags)#define _flagscnt    (_prxmac->flagscnt)#define _state       (_prxmac->state)#define _statebyte   (*(int8u *)(&_state))#define _phoru       (_prxmac->phoru)#define _prxbuf      (_prxmac->prxbuf)#define _rxbufsize   (_prxmac->rxbufsize)#define _pcur        (_prxmac->pcur)#define _onfeeded    (_prxmac->onfeeded)#define _ongetheader (_prxmac->ongetheader)#define _onflushed   (_prxmac->onflushed)#define _isrxbuffull()  ((_pcur - _prxbuf) >= _rxbufsize)// 因为不能保证用户把数据放在非分页区,只好自己实现一个,实际使用中如果确定在非分页区可以把下面的宏替换为库函数memcpystatic prb_byte _memcpy_internal(prb_byte dest, prb_byte src, size_t n);#define _memcpy(dest,src,n)   _memcpy_internal(dest,src,n)// 冲刷缓冲区static void _flush(prx_mac prxmac,prx_flag ender);// 往接收机缓冲区内放数据static void _bufin(prx_mac prxmac,prb_byte pbuf,int16u len);/***********************************************************************************************************                                        rxmac_init()** description : to initialize a rxmac.    初始化接收机** arguments   : prxmac    pointer to the rxmac struct;    指向接收机结构体的指针*               flags     pointer to the flags(an array); 指向标志串(数组)的指针*               flagscnt  the count of the flags;         有多少个标志串;*               maxlenofflags  the max length of flags;   标志字符串最长的长度 *               pbuf      pointer to the buffer provided to the rxmac;提供给接收机使用的缓存*               buflen    the size of the buffer.         缓存的大小*               onfeeded   the callback func that will be called when feeded.*                          每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断*               ongetheader the callback func that will be called when find a header.*                          当发现帧头时会调用的回调函数*               onflushed  the callback func that will be called when flushed.*                          当flush时会调用的回调函数** return      : rxmac_err_none        if success*               rxmac_err_argument    if the length of longest flags bigger than buflen,or one of them is 0*               rxmac_err_pointernull if empty pointer ** note(s)     : size of buffer should bigger than  the longest flag plus the longest frame *               that may be received(so at least 2 * maxlenofflags).*               the buffer is allocate as follow:*                 *                |                 rxbuffer             |                 |   *                  * *               void ongetheader(prx_mac sender,prx_flag pflag):*                sender   the pointer to the rxmac which call this function*                pflag    the header matched**               void onfeeded(prx_mac sender,prb_byte pcurchar,int16u bytescnt):*                sender    the pointer to the rxmac which call this function*                pcurchar  point to the char in the buffer just received.*                bytescnt  the number of bytes in the buffer including the char just feeded.**               void onflushed(prx_mac sender,prb_byte pbuf,int16u len,rx_state state,prx_flag phoru,*                  prx_flag pender);*                sender    the pointer to the rxmac which call this function*                pbuf      the pointer to the frame.*                len       the length of frame.*                state     the state of frame.*                phoru     point to the header flag if state.headerfound == 1, or unique flag if *                          state.uniquefound == 1.*                pender    point to the ender flag if state.enderfound == 1.**********************************************************************************************************/int8u rxmac_init  (prx_mac prxmac,rx_flag flags[],int8u flagscnt,int8u maxlenofflags,prb_byte pbuf,int16u buflen,    rxmac_filter onfeeded,rxmac_flag_event ongetheader,rxmac_flush_event onflushed){    //int8u maxlen = 0;    int8u i;#if(rxmac_argument_check_en)    if( #if(!rxmac_singleton_en)      _prxmac == null || #endif      flags == null || pbuf == null)      return rxmac_err_pointernull;#endif    // find out the max length of flags.    //for(i = 0; i  maxlen)    //    maxlen = flags[i].len;    //}#if(rxmac_argument_check_en)    if(maxlenofflags == 0 || (maxlenofflags * 2) > buflen || buflen == 0 || flagscnt == 0 ||      maxlenofflags == 0)      return rxmac_err_argument;#endif    buflen -= maxlenofflags;    // 把buffer的最后一段分配给环形缓冲区    ringqueueinit(&_flagqueue,pbuf + buflen,maxlenofflags,&i);    _flags = flags;    _flagscnt = flagscnt;    _statebyte = 0;    _phoru = null;    _prxbuf = pbuf;    _rxbufsize = buflen;    _pcur = pbuf;    _onfeeded = onfeeded;    _ongetheader = ongetheader;    _onflushed = onflushed;    return rxmac_err_none;}/***********************************************************************************************************                                        rxmac_feeddata()** description : to feed rxmac the next char.    用于给接收机下一个字符** arguments   : prxmac    pointer to the rxmac struct;    指向接收机结构体的指针*               c         the char to feed;               下一个字符** return      : ** note(s)     : **********************************************************************************************************/void rxmac_feeddata(prx_mac prxmac,int8u c){  int8u i,mask;  prx_flag pflag = null;#if(rxmac_onfeeded_en)  prb_byte pcurchar = _pcur;#endif#if(rxmac_argument_check_en && !rxmac_singleton_en)  if(_prxmac == null)    return;#endif  *_pcur++ = c;    // 填入缓冲区#if(rxmac_onfeeded_en)  if(_onfeeded != null)    _onfeeded(_prxmac,pcurchar,_pcur - _prxbuf);  ringqueuein(&_flagqueue,*pcurchar,rq_option_when_full_discard_first,&i);#else  ringqueuein(&_flagqueue,c,rq_option_when_full_discard_first,&i);#endif  // _state.headerfound == 1  说明在等待帧尾,否则在等待帧头  mask = (_state.headerfound)?statemask_stepb:statemask_stepa;  // 寻找匹配的标志串  for(i = 0; i = 0)){        ringqueueclear(&_flagqueue);        pflag = &_flags[i];        break;    }  }  // 如果没有发现标志串,检查下有没满了,满了就flush  if(pflag == null){    if(_isrxbuffull()){      _state.isfull = 1;      _flush(_prxmac,null);    }    return;  }  // 这4种标志串要_flush掉前面的东西  if(pflag->option & flagmask_usuhsh){    _pcur -= pflag->len;    _flush(_prxmac,null);    _phoru = pflag;  }  // 如果是帧头的处理  if(pflag->option & (flag_option_strong_header | flag_option_header)){#if(rxmac_notfill_en == true)    if(!(pflag->option & flag_option_notfill_header))#endif      _bufin(_prxmac,(prqtype)pflag->pbuf,pflag->len);    _state.headerfound = 1;    if(_ongetheader != null)      _ongetheader(_prxmac,pflag);    return;  }  // 如果是unique的处理  if(pflag->option & (flag_option_strong_unique | flag_option_unique)){    _state.uniquefound = 1;    _bufin(_prxmac,(prqtype)pflag->pbuf,pflag->len);    _flush(_prxmac,null);  }else{   // 能到这里说明是帧尾    _state.enderfound = 1;#if(rxmac_notfill_en == true)    if(pflag->option & flag_option_notfill_ender)      _pcur -= pflag->len;#endif    _flush(_prxmac,pflag);  }  return;}/***********************************************************************************************************                                        rxmac_resetrxsize()** description : reset the size of rxbuf to the max size.   重置接收缓冲区** arguments   : prxmac    pointer to the rxmac struct;    指向接收机结构体的指针** return      : rxmac_err_none            if success;*               rxmac_err_pointernull     if prxmac == null*               rxmac_err_init            if rxmac hasn't inited or any error in initialization* note(s)     : **********************************************************************************************************/int8u rxmac_resetrxsize(prx_mac prxmac){  int size;#if(rxmac_argument_check_en && !rxmac_singleton_en)  if(_prxmac == null)    return rxmac_err_pointernull;#endif  size = _flagqueue.ringbuf - _prxbuf;#if(rxmac_argument_check_en)  if(size < 0)    return rxmac_err_init;#endif  _rxbufsize = (int16u)size;  return rxmac_err_none;}/***********************************************************************************************************                                        rxmac_setrxsize()** description : set the size of rxbuf to the max size.   重置接收缓冲区** arguments   : prxmac    pointer to the rxmac struct;    指向接收机结构体的指针*               size      the size to set;                ** return      : rxmac_err_none            if success;*               rxmac_err_pointernull     if prxmac == null*               rxmac_err_argument        if size is wrong.* note(s)     : the size shouldn't be bigger than the initial value, and should bigger than*               the current number of chars in the rxbuf.*               **********************************************************************************************************/int8u rxmac_setrxsize(prx_mac prxmac, int16u size){#if(rxmac_argument_check_en) #if (!rxmac_singleton_en)  if(_prxmac == null)    return rxmac_err_pointernull; #endif  if(_flagqueue.ringbuf - _prxbuf  0 && _onflushed != null)    _onflushed(_prxmac,_prxbuf,_pcur-_prxbuf,_state,_phoru,ender);  // 复位接收机  _pcur = _prxbuf;  _statebyte = 0;  _phoru = null;}  
测试/示例代码
/***********************************************************************************************************                                                uc/os-ii*                                          the real-time kernel*                                               framework** by  : lin shijun* note: this is a framework for ucos-ii project with only s12cpu, none float, banked memory model.*       you can use this framework with same modification as the start point of your project.*       i've removed the os_probe module,since i thought it useless in most case.*       this framework is adapted from the official release.**********************************************************************************************************/#include includes.h#include sci_def.h#include rxmac.h/***********************************************************************************************************                                      stack space declaration**********************************************************************************************************/static  os_stk  apptaskstartstk[app_task_start_stk_size];/***********************************************************************************************************                                      task function declaration**********************************************************************************************************/static  void    apptaskstart(void *p_arg);/***********************************************************************************************************                                           callback funciton**********************************************************************************************************/void ongetdata(prx_mac sender,prb_byte pcurchar,int16u bytescnt){  // 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytescnt来判断当前位置  rxmac_setonfeeded(sender,null);  if(*pcurchar > '0' && *pcurchar pbuf,pflag->len,0);  sci_putcharsb(sci0,,1,0);}void ongetheader2(prx_mac sender,prx_flag pflag){  sci_putcharsb(sci0,foundheader:,13,0);  sci_putcharsb(sci0,pflag->pbuf,pflag->len,0);  sci_putcharsb(sci0,,1,0);  rxmac_setonfeeded(sender,ongetdata);}/***********************************************************************************************************                                           flags**********************************************************************************************************/rx_mac  _rxmac;#define buf_size  20int8u  buffer[buf_size];rx_flag flags[4];// 协议示例1:// 帧头    :header 或者 start// 强帧尾  :end// 强特殊串:12345  // static void protocol1_init(){  rx_flag_init(&flags[0],header,6,flag_option_header);  rx_flag_init(&flags[1],start,5,flag_option_header);  rx_flag_init(&flags[2],end,3,flag_option_strong_ender);  rx_flag_init(&flags[3],12345,5,flag_option_strong_unique);  rxmac_init(&_rxmac,flags,4,6,buffer,buf_size,null,ongetheader,onflushed);}// 协议示例2:// 帧头    : start// 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾// 帧尾    : end// 特殊串:  now// static void protocol2_init(){  rx_flag_init(&flags[0],start,5,flag_option_header);  rx_flag_init(&flags[1],end,3,flag_option_ender);  rx_flag_init(&flags[2],now,3,flag_option_unique);  rxmac_init(&_rxmac,flags,3,5,buffer,buf_size,null,ongetheader2,onflushed);}/***********************************************************************************************************                                           main function**********************************************************************************************************/void main(void) {    int8u  err;        bsp_intdisall();                                                    /* disable all interrupts to the interrupt controller       */    osinit();                                                           /* initialize uc/os-ii                                      */    err = ostaskcreate(apptaskstart,                          null,                          (os_stk *)&apptaskstartstk[app_task_start_stk_size - 1],                          app_task_start_prio);                         osstart();}static  void  apptaskstart (void *p_arg){  int8u c,err;  (void)p_arg;                      /* prevent compiler warning  */  bsp_init();   sci_init(sci0);  sci_enabletrans(sci0);  sci_enablerecv(sci0);  sci_enablerxint(sci0);  sci_bufferinit();  // 选择想要实验的协议来初始化  protocol1_init();  //protocol2_init();  while (def_true)   {    // 获取下一个字符    c = sci_getcharb(sci0,0,&err);    // 回显    sci_putcharb(sci0,c,0);    // 喂给接收机    rxmac_feeddata(&_rxmac,c);  }}  


商用机器人开启高端智慧生活
中银航空租赁有限公司截至到2019年9月30日的营运交易情况分析
深度详解MOS管的半导体结构与驱动应用
为啥手机厂商都要争OLED屏?连iPhone8也要抢!
LG将发布一款新的旗舰机型V60 ThinQ主打双屏体验
嵌入式开发模块指南:通用接收状态机模块
2019年新款iPad Pro真机图曝光,将强化与AR技术功能
这才是真正的iphone8,与网传的谍照还是有区别!
面向面粉机制造商的数据采集远程监控系统解决方案
vivo NEX3 5G版究竟凭什么冲出包围?下面四点才是关键
2022电视盒子哪款好?好口碑网络电视盒子排行榜
变频器过电流跳闸的特性
准谐振和零电流开关DC-DC转换器的工作原理与结构特点及优势分析
沁恒股份16段数码管驱动及键盘控制芯片CH454概述
星环科技入选“上海2019年度大数据服务供应商推荐目录”
Silicon Labs发布满足高速收发器需求的新一代高性能振荡器Si54x
复盘腾讯与阿里的成长路径
中国限制AI技术出口:TikTok需经国家批准才可出售
智慧医疗变革得益于什么
三星Micro LED能否迎来国内首次亮相引悬念