// 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);}
typedefstructRXSTATE_STRUCT{ unsignedint headerFound: 1; // 1: have get headerunsignedint enderFound : 1; // 1: have get enderunsignedint isFull : 1; // 1: the buffer is fullunsignedint uniqueFound: 1; // 1: this is unique flag. } RxState;
/*
*******************************************************************************************
*
*
* 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#endiftypedefuint8_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 flagtypedefstructRXFLAG_STRUCT{ uint8_tconst * 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
*********************************************************************************************
*/typedefstructRXSTATE_STRUCT{ unsignedint headerFound: 1; // 1: have get headerunsignedint enderFound : 1; // 1: have get enderunsignedint isFull : 1; // 1: the buffer is fullunsignedint uniqueFound: 1; // 1: this is unique flag. } RxState; typedefstructRXMAC_STRUCT * RxMac; typedefvoid (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender); typedefvoid (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedefvoid (* 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 RxMacvoidRxMac_Destroy(RxMac mac); // 向接收机内喂字节voidRxMac_FeedDatas(RxMac mac, uint8_tconst * buf, uint16_t len); voidRxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度//uint8_t RxMac_ResetRxSize(RxMac mac);// 设置最大接收到多少个字节uint8_tRxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态uint8_tRxMac_ResetState(RxMac mac); // 强制接收机flushuint8_tRxMac_Flush(RxMac mac); // 设置onFeededuint8_tRxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeaderuint8_tRxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlusheduint8_tRxMac_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
*******************************************************************************************
*/typedefstructRXFLAGMGR_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); staticvoid _RxFlagMgr_Destroy(RxMac mac); staticvoid _RxFlagMgr_Reset(RxMac mac); /*
*******************************************************************************************
* STRUCT DIFINITION
*******************************************************************************************
*/typedefstructRXMAC_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 bufferuint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byteuint16_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))#elsestatic RXMAC_STRUCT _mac; // 单例模式中,这个指针用于标识是否单例已初始化过static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag)#define _Flags (_mac.FlagMgr.Flags)#define _FlagsCnt (_mac.FlagMgr.FlagsCnt)#define _state (_mac.FlagMgr.state)#define _pHorU (_mac.pHorU)#define _pRxBuf (_mac.pRxBuf)#define _RxBufSize (_mac.RxBufSize)#define _RxCnt (_mac.RxCnt)#define _fonFeeded (_mac.onFeeded)#define _fonGetHeader (_mac.onGetHeader)#define _fonFlushed (_mac.onFlushed)#define _RxMac_Destroy() (_pMac = NULL)#endif#define _stateByte (*(uint8_t *)(&_state))#define _isRxBufFull() (_RxCnt >= _RxBufSize)#ifndef RXMAC_ONFEEDED_DISABLE#define _onFeeded(pChar,cnt) 文章来源于:21IC 原文链接