嵌入式通用接收模块(基于状态机)

嵌入式大杂烩 2023-03-10 21:30

原文:https://blog.csdn.net/lin_strong/article


前言

在软件开发的过程中,只要涉及到通信,就会涉及到数据接收机的编写,通信协议虽然多种多样,但是数据包的形式确是很相似的(暂时没看到特别复杂,此模块解决不了的),为此可以把其中通用的部分抽象出来,然后就成了这个模块。

模块相关概念和逻辑

接收机状态

接收机有两个基本状态:

  • • 状态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[] = "\r\n";
*                   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)    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 CODEWARRIOR
static 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 < flagsCnt; i++){
    if(flags[i].len > 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 < len; i++)
    RxMac_FeedData(mac,buf[i]);
}

void RxMac_FeedData(RxMac mac,uint8_t c){
  RxFlag curFlag;
  _checkMacNotNull_void();
  _onFeeded(&c,_RxCnt + 1);
  _pRxBuf[_RxCnt++] = c;
  curFlag = _RxFlagMgr_GetNextMatchedAtThisState(mac,c);
  if(curFlag == NULL){        // if no flag match
    _RxMac_FlushIfFull(mac);
    return;
  }
  _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(mac,curFlag);
  if(_RxFlag_isHeader(curFlag)){
    _RxMac_GetHeaderProcess(mac,curFlag);
  }else if(_RxFlag_isUnique(curFlag)){
    _RxMac_GetUniqueProcess(mac,curFlag);
  }else{   // if(_RxFlag_isEnder(curFlag))
    _RxMac_GetEnderProcess(mac,curFlag);
  }
}
/*
*******************************************************************************************
*                                        RxMac_SetRxSize()
*
* Description : set the size of RxBuf.   设置接收缓冲区的大小
*
* Arguments   : mac     the target receive machine.     目标接收机
*               size    the size to set;
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*               RXMAC_ERR_ARGUMENT        if size is wrong.
* Note(s)     : the size should bigger than the current number of chars in the RxBuf.
*               
*******************************************************************************************
*/

uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size){
  _checkMacNotNull();
#ifndef RXMAC_ARGUMENT_CHECK_DISABLE
  if(size <= _RxCnt)
    return RXMAC_ERR_ARGUMENT;
#endif
  _RxBufSize = size;
  return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
*                                        RxMac_ResetState()
*
* Description : reset the state of receive machine.   重置接收机的状态
*
* Arguments   : mac    the target receive machine.    目标接收机
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*******************************************************************************************
*/

uint8_t RxMac_ResetState(RxMac mac){
  _checkMacNotNull();
  // 复位接收机
  Buffer_Cleanup((Buffer)_BufForFlag);
  _RxCnt = 0;
  _stateByte = 0;
  _pHorU = NULL;
  return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : mac     the target receive machine.     目标接收机
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*******************************************************************************************
*/


uint8_t RxMac_Flush(RxMac mac){
  _checkMacNotNull();
  _flush(_pMac,NULL);
  return RXMAC_ERR_NONE;
}

/*
******************************************************************************************
*                                        RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments   : mac       the target receive machine.     目标接收机
*               onFeeded  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/

uint8_t RxMac_SetOnFeeded(RxMac mac,RXMAC_FILTER onFeeded){
  _checkMacNotNull();
  _fonFeeded = onFeeded;
  return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
*                                        RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments   : mac          the target receive machine.     目标接收机
*               onGetHeader  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/

uint8_t RxMac_SetOnGetHeader(RxMac mac,RXMAC_FLAG_EVENT onGetHeader){
  _checkMacNotNull();
  _fonGetHeader = onGetHeader;
  return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
*                                        RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments   : mac          the target receive machine.     目标接收机
*               onFlushed    the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/

uint8_t RxMac_SetOnFlushed(RxMac mac,RXMAC_FLUSH_EVENT onFlushed){
  _checkMacNotNull();
  _fonFlushed = onFlushed;
  return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
*                                        _RxMac_printBuffer()
*
* Description : print the internal buffer, just for developer.
*               给开发者用于查看内部缓存的
*
* Arguments   : mac          the target receive machine.     目标接收机
*               onFlushed    the callback function to set;   要设置的回调函数
*
* Return      : the len of buffer printed.
*
* Note(s)     :
*
******************************************************************************************
*/


uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf){
  memcpy(buf,_pRxBuf,_RxCnt);
  return _RxCnt;
}

/*
******************************************************************************************
*                                   LOCAL  FUNCITON 
******************************************************************************************
*/

static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n){
  RxMacPtr p = dest;
  while(n-- > 0)
    *p++ = *src++;
  return dest;
}

static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len){
  memcpy(_pRxBuf+_RxCnt,buf,len);
  _RxCnt += len;
}

static void _flush(RxMac mac,RxFlag ender){
  // 触发回调
  if((_RxCnt > 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 < flagJustGot->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 < _FlagsCnt; i++){
    if((_Flags[i].option & mask) && 
      BufferUINT8Indexed_BackMatch(_BufForFlag,_Flags[i].pBuf,_Flags[i].len)){
        Buffer_Cleanup((Buffer)_BufForFlag);
        return &_Flags[i];
    }
  }
  return NULL;
}

static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen){
  if(_BufForFlag = (BufferIndexed)BufferUINT8MallocArray_Create(maxLen)){
    _Flags = flags;
    _FlagsCnt = flagsCnt;
    _stateByte = 0;
  }
  return _BufForFlag != NULL;
}

static void _RxFlagMgr_Destroy(RxMac mac){
  Buffer_Destroy(_BufForFlag);
}

static void _RxFlagMgr_Reset(RxMac mac){
  Buffer_Cleanup((Buffer)_BufForFlag);
}

测试/示例代码

已略去非必要代码

#include 
#include "RxMac.h"

/*
*********************************************************************************************************
*                                      LOCAL  FUNCTION  DECLARE
*********************************************************************************************************
*/


static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender);
static void onGetHeader(RxMac sender,RxFlag flag);
static void onGetHeader2(RxMac sender,RxFlag flag);

/*
*********************************************************************************************************
*                                           LOVAL VARIABLE
*********************************************************************************************************
*/

static RxMac  mac = NULL;
static RXFLAG_STRUCT flags[4];
#define BUF_SIZE  20
static uint8_t buffer[BUF_SIZE];

// 协议示例1:
// 帧头    :HEADER 或者 START
// 强帧尾  :END
// 强特殊串:12345  
// 
static void protocol1_init(void){
  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);
  mac = RxMac_Create(flags,4,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
}
// 协议示例2:
// 帧头    : START
// 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾
// 帧尾    : END
// 特殊串:  NOW
// 
static void protocol2_init(void){
  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);
  mac = RxMac_Create(flags,3,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
}
/*
*********************************************************************************************************
*                                           CALLBACK FUNCITON
*********************************************************************************************************
*/


static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt){
  // 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytesCnt来判断当前位置
  RxMac_SetOnFeeded(sender,NULL);
  if(*pCurChar > '0' && *pCurChar <= '9' ){
    // bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的
    RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  }
}
static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender){
  buf[len] = '\0';
  printf("\nFlushed:");
  if(state.headerFound)
    printf("headerFound,");
  if(state.enderFound)
    printf("enderFound,");
  if(state.isFull)
    printf("full,");
  if(state.uniqueFound)
    printf("unique,");
  printf("\nDatas:%s\n",buf);
  RxMac_SetRxSize(sender,BUF_SIZE);
}
static void onGetHeader(RxMac sender,RxFlag flag){
  printf("\nFoundHeader:%s\n",flag->pBuf);
}
static void onGetHeader2(RxMac sender,RxFlag flag){
  printf("\nFoundHeader:%s\n",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[] = "\r\n";
*                   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_MODE

typedef 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        0xC0

typedef 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 RxMac
INT8U 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);
// 强制接收机flush
INT8U RxMac_Flush(pRX_MAC pRxMac);
// 设置onFeeded
INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded);
// 设置onGetHeader
INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader);
// 设置onFlushed
INT8U 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)


// 因为不能保证用户把数据放在非分页区,只好自己实现一个,实际使用中如果确定在非分页区可以把下面的宏替换为库函数memcpy
static 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:
*                 <----------------------  BufLen  ---------------------->
*                |                 RxBuffer             |                 |   
*                 <------------- RxBufSize ------------> <-maxLenOfFlags->

*               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 < FlagsCnt; i++){
    //  if(Flags[i].len > 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 < _FlagsCnt; i++){
    if((_Flags[i].option & mask) && 
      (RingQueueMatch(&_FlagQueue,(pRQTYPE)_Flags[i].pBuf,_Flags[i].len) >= 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 < size || size <= _pCur - _pRxBuf)
    return RXMAC_ERR_ARGUMENT;
#endif
  _RxBufSize = size;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_ResetState()
*
* Description : reset the state of receive machine.   重置接收机的状态
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*********************************************************************************************************
*/

INT8U RxMac_ResetState(pRX_MAC pRxMac){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  // 复位接收机
  RingQueueClear(&_FlagQueue);
  _pCur = _pRxBuf;
  _stateByte = 0;
  _pHorU = NULL;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*********************************************************************************************************
*/

INT8U RxMac_Flush(pRX_MAC pRxMac){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _flush(_pRxMac,NULL);
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*               onFeeded  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/

INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onFeeded = onFeeded;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收机结构体的指针
*               onGetHeader  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/

INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onGetHeader = onGetHeader;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收机结构体的指针
*               onFlushed    the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/

INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onFlushed = onFlushed;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                   LOCAL  FUNCITON 
*********************************************************************************************************
*/

static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n){
  pRB_BYTE p = dest;
  while(n-- > 0)
    *p++ = *src++;
  return dest;
}

static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len){
  _memcpy(_pCur,pBuf,len);
  _pCur += len;
}

static void _flush(pRX_MAC pRxMac,pRX_FLAG ender){
  // 触发回调
  if(_pCur-_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 <= '9' ){
    // bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的
    RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  }
}
void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){
  SCI_PutCharsB(SCI0,"\nFlushed:",9,0);
  if(state.headerFound)
    SCI_PutCharsB(SCI0,"headerFound,",12,0);
  if(state.enderFound)
    SCI_PutCharsB(SCI0,"enderFound,",11,0);
  if(state.isFull)
    SCI_PutCharsB(SCI0,"full,",5,0);
  if(state.uniqueFound)
    SCI_PutCharsB(SCI0,"unique,",7,0);
  SCI_PutCharsB(SCI0,"\nDatas:",7,0);
  SCI_PutCharsB(SCI0,pBuf,len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
  RxMac_ResetRxSize(sender);
}
void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){
  SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
}
void onGetHeader2(pRX_MAC sender,pRX_FLAG pFlag){
  SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
  RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
*                                           FLAGS
*********************************************************************************************************
*/

RX_MAC  _rxmac;
#define BUF_SIZE  20
INT8U  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);
  }
}


本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

注意

由于微信公众号近期改变了推送规则,为了防止找不到,可以星标置顶,这样每次推送的文章才会出现在您的订阅列表里。

猜你喜欢:

易懂 | 手把手教你编写你的第一个上位机

适用于嵌入式的差分升级通用库!

分享一种灵活性很高的协议格式(附代码例子)

分享几个实用的代码片段(第二弹)

分享一种你可能不知道的bug定位方法

分享一种修改配置文件的方法

《嵌入式大杂烩周记第 13 期:lz4》

《嵌入式并行多线程处理器,了解一下!》


在公众号聊天界面回复1024,可获取嵌入式资源;回复 ,可查看文章汇总

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论
  • 在不断发展的电子元件领域,继电器——作为切换电路的关键设备,正在经历前所未有的技术变革。固态继电器(SSR)和机械继电器之间的争论由来已久。然而,从未来发展的角度来看,固态继电器正逐渐占据上风。本文将从耐用性、速度和能效三个方面,全面剖析固态继电器为何更具优势,并探讨其在行业中的应用与发展趋势。1. 耐用性:经久耐用的设计机械继电器:机械继电器依靠物理触点完成电路切换。然而,随着时间的推移,这些触点因电弧、氧化和材料老化而逐渐磨损,导致其使用寿命有限。因此,它们更适合低频或对切换耐久性要求不高的
    腾恩科技-彭工 2025-01-10 16:15 100浏览
  • 随着通信技术的迅速发展,现代通信设备需要更高效、可靠且紧凑的解决方案来应对日益复杂的系统。中国自主研发和制造的国产接口芯片,正逐渐成为通信设备(从5G基站到工业通信模块)中的重要基石。这些芯片凭借卓越性能、成本效益及灵活性,满足了现代通信基础设施的多样化需求。 1. 接口芯片在通信设备中的关键作用接口芯片作为数据交互的桥梁,是通信设备中不可或缺的核心组件。它们在设备内的各种子系统之间实现无缝数据传输,支持高速数据交换、协议转换和信号调节等功能。无论是5G基站中的数据处理,还是物联网网关
    克里雅半导体科技 2025-01-10 16:20 444浏览
  • 数字隔离芯片是现代电气工程师在进行电路设计时所必须考虑的一种电子元件,主要用于保护低压控制电路中敏感电子设备的稳定运行与操作人员的人身安全。其不仅能隔离两个或多个高低压回路之间的电气联系,还能防止漏电流、共模噪声与浪涌等干扰信号的传播,有效增强电路间信号传输的抗干扰能力,同时提升电子系统的电磁兼容性与通信稳定性。容耦隔离芯片的典型应用原理图值得一提的是,在电子电路中引入隔离措施会带来传输延迟、功耗增加、成本增加与尺寸增加等问题,而数字隔离芯片的目标就是尽可能消除这些不利影响,同时满足安全法规的要
    华普微HOPERF 2025-01-15 09:48 78浏览
  • 流量传感器是实现对燃气、废气、生活用水、污水、冷却液、石油等各种流体流量精准计量的关键手段。但随着工业自动化、数字化、智能化与低碳化进程的不断加速,采用传统机械式检测方式的流量传感器已不能满足当代流体计量行业对于测量精度、测量范围、使用寿命与维护成本等方面的精细需求。流量传感器的应用场景(部分)超声波流量传感器,是一种利用超声波技术测量流体流量的新型传感器,其主要通过发射超声波信号并接收反射回来的信号,根据超声波在流体中传播的时间、幅度或相位变化等参数,间接计算流体的流量,具有非侵入式测量、高精
    华普微HOPERF 2025-01-13 14:18 482浏览
  • 随着全球向绿色能源转型的加速,对高效、可靠和环保元件的需求从未如此强烈。在这种背景下,国产固态继电器(SSR)在实现太阳能逆变器、风力涡轮机和储能系统等关键技术方面发挥着关键作用。本文探讨了绿色能源系统背景下中国固态继电器行业的前景,并强调了2025年的前景。 1.对绿色能源解决方案日益增长的需求绿色能源系统依靠先进的电源管理技术来最大限度地提高效率并最大限度地减少损失。固态继电器以其耐用性、快速开关速度和抗机械磨损而闻名,正日益成为传统机电继电器的首选。可再生能源(尤其是太阳能和风能
    克里雅半导体科技 2025-01-10 16:18 325浏览
  • 食物浪费已成为全球亟待解决的严峻挑战,并对环境和经济造成了重大影响。最新统计数据显示,全球高达三分之一的粮食在生产过程中损失或被无谓浪费,这不仅导致了资源消耗,还加剧了温室气体排放,并带来了巨大经济损失。全球领先的光学解决方案供应商艾迈斯欧司朗(SIX:AMS)近日宣布,艾迈斯欧司朗基于AS7341多光谱传感器开发的创新应用来解决食物浪费这一全球性难题。其多光谱传感解决方案为农业与食品行业带来深远变革,该技术通过精确判定最佳收获时机,提升质量控制水平,并在整个供应链中有效减少浪费。 在2024
    艾迈斯欧司朗 2025-01-14 18:45 61浏览
  • 电动汽车(EV)正在改变交通运输,为传统内燃机提供更清洁、更高效的替代方案。这种转变的核心是电力电子和能源管理方面的创新,而光耦合器在其中发挥着关键作用。这些不起眼的组件可实现可靠的通信、增强安全性并优化电动汽车系统的性能,使其成为正在进行的革命中不可或缺的一部分。光耦合器,也称为光隔离器,是一种使用光传输电信号的设备。通过隔离高压和低压电路,光耦合器可确保安全性、减少干扰并保持信号完整性。这些特性对于电动汽车至关重要,因为精确控制和安全性至关重要。 光耦合器在电动汽车中的作用1.电池
    腾恩科技-彭工 2025-01-10 16:14 78浏览
  • 新年伊始,又到了对去年做总结,对今年做展望的时刻 不知道你在2024年初立的Flag都实现了吗? 2025年对自己又有什么新的期待呢? 2024年注定是不平凡的一年, 一年里我测评了50余块开发板, 写出了很多科普文章, 从一个小小的工作室成长为科工公司。 展望2025年, 中国香河英茂科工, 会继续深耕于,具身机器人、飞行器、物联网等方面的研发, 我觉得,要向未来学习未来, 未来是什么? 是掌握在孩子们生活中的发现,和精历, 把最好的技术带给孩子,
    丙丁先生 2025-01-11 11:35 457浏览
  •   在信号处理过程中,由于信号的时域截断会导致频谱扩展泄露现象。那么导致频谱泄露发生的根本原因是什么?又该采取什么样的改善方法。本文以ADC性能指标的测试场景为例,探讨了对ADC的输出结果进行非周期截断所带来的影响及问题总结。 两个点   为了更好的分析或处理信号,实际应用时需要从频域而非时域的角度观察原信号。但物理意义上只能直接获取信号的时域信息,为了得到信号的频域信息需要利用傅里叶变换这个工具计算出原信号的频谱函数。但对于计算机来说实现这种计算需要面对两个问题: 1.
    TIAN301 2025-01-14 14:15 108浏览
  • 随着数字化的不断推进,LED显示屏行业对4K、8K等超高清画质的需求日益提升。与此同时,Mini及Micro LED技术的日益成熟,推动了间距小于1.2 Pitch的Mini、Micro LED显示屏的快速发展。这类显示屏不仅画质卓越,而且尺寸适中,通常在110至1000英寸之间,非常适合应用于电影院、监控中心、大型会议、以及电影拍摄等多种室内场景。鉴于室内LED显示屏与用户距离较近,因此对于噪音控制、体积小型化、冗余备份能力及电气安全性的要求尤为严格。为满足这一市场需求,开关电源技术推出了专为
    晶台光耦 2025-01-13 10:42 498浏览
  • 01. 什么是过程能力分析?过程能力研究利用生产过程中初始一批产品的数据,预测制造过程是否能够稳定地生产符合规格的产品。可以把它想象成一种预测。通过历史数据的分析,推断未来是否可以依赖该工艺持续生产高质量产品。客户可能会要求将过程能力研究作为生产件批准程序 (PPAP) 的一部分。这是为了确保制造过程能够持续稳定地生产合格的产品。02. 基本概念在定义制造过程时,目标是确保生产的零件符合上下规格限 (USL 和 LSL)。过程能力衡量制造过程能多大程度上稳定地生产符合规格的产品。核心概念很简单:
    优思学院 2025-01-12 15:43 522浏览
  • Snyk 是一家为开发人员提供安全平台的公司,致力于协助他们构建安全的应用程序,并为安全团队提供应对数字世界挑战的工具。以下为 Snyk 如何通过 CircleCI 实现其“交付”使命的案例分析。一、Snyk 的挑战随着客户对安全工具需求的不断增长,Snyk 的开发团队面临多重挑战:加速交付的需求:Snyk 的核心目标是为开发者提供更快、更可靠的安全解决方案,但他们的现有 CI/CD 工具(TravisCI)运行缓慢,无法满足快速开发和部署的要求。扩展能力不足:随着团队规模和代码库的不断扩大,S
    艾体宝IT 2025-01-10 15:52 164浏览
  • ARMv8-A是ARM公司为满足新需求而重新设计的一个架构,是近20年来ARM架构变动最大的一次。以下是对ARMv8-A的详细介绍: 1. 背景介绍    ARM公司最初并未涉足PC市场,其产品主要针对功耗敏感的移动设备。     随着技术的发展和市场需求的变化,ARM开始扩展到企业设备、服务器等领域,这要求其架构能够支持更大的内存和更复杂的计算任务。 2. 架构特点    ARMv8-A引入了Execution State(执行状
    丙丁先生 2025-01-12 10:30 466浏览
  • PNT、GNSS、GPS均是卫星定位和导航相关领域中的常见缩写词,他们经常会被用到,且在很多情况下会被等同使用或替换使用。我们会把定位导航功能测试叫做PNT性能测试,也会叫做GNSS性能测试。我们会把定位导航终端叫做GNSS模块,也会叫做GPS模块。但是实际上他们之间是有一些重要的区别。伴随着技术发展与越发深入,我们有必要对这三个词汇做以清晰的区分。一、什么是GPS?GPS是Global Positioning System(全球定位系统)的缩写,它是美国建立的全球卫星定位导航系统,是GNSS概
    德思特测试测量 2025-01-13 15:42 491浏览
  • 根据Global Info Research(环洋市场咨询)项目团队最新调研,预计2030年全球无人机电池和电源产值达到2834百万美元,2024-2030年期间年复合增长率CAGR为10.1%。 无人机电池是为无人机提供动力并使其飞行的关键。无人机使用的电池类型因无人机的大小和型号而异。一些常见的无人机电池类型包括锂聚合物(LiPo)电池、锂离子电池和镍氢(NiMH)电池。锂聚合物电池是最常用的无人机电池类型,因为其能量密度高、设计轻巧。这些电池以输出功率大、飞行时间长而著称。不过,它们需要
    GIRtina 2025-01-13 10:49 182浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦