// 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
* 通用接收狀態(tài)機(jī)
*
* 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#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 標(biāo)志字符串結(jié)構(gòu)體的數(shù)組// flagsCnt 標(biāo)志字符串結(jié)構(gòu)體的個(gè)數(shù)// buf 用戶提供給接收機(jī)用的緩沖區(qū) // bufLen 緩沖區(qū)的大小(起碼應(yīng)該要能放的下最長的標(biāo)志字符串)// onFeeded 在每次被Feed時(shí)觸發(fā)// onGetHeader 獲得頭標(biāo)志位時(shí)觸發(fā)。// onFlushed 收到一幀數(shù)據(jù)時(shí)的回調(diào)函數(shù) 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); // 向接收機(jī)內(nèi)喂字節(jié)voidRxMac_FeedDatas(RxMac mac, uint8_tconst * buf, uint16_t len); voidRxMac_FeedData(RxMac mac, uint8_t c); // 重置接收區(qū)長度為最長那個(gè)長度//uint8_t RxMac_ResetRxSize(RxMac mac);// 設(shè)置最大接收到多少個(gè)字節(jié)uint8_tRxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收機(jī)的狀態(tài)uint8_tRxMac_ResetState(RxMac mac); // 強(qiáng)制接收機(jī)flushuint8_tRxMac_Flush(RxMac mac); // 設(shè)置onFeededuint8_tRxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 設(shè)置onGetHeaderuint8_tRxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 設(shè)置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
*******************************************************************************************
*/// 打印內(nèi)部緩沖區(qū),返回緩沖區(qū)的長度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
* 通用接收狀態(tài)機(jī)
*
* 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; // 單例模式中,這個(gè)指針用于標(biāo)識是否單例已初始化過static RxMac _pMac = NULL; #define _BufForFlag (_mac.FlagMgr.BufForFlag)#define _Flags (_mac.FlagMgr.Flags)#define _FlagsCnt (_mac.FlagMgr.FlagsCnt)#define _state (_mac.FlagMgr.state)#define _pHorU (_mac.pHorU)#define _pRxBuf (_mac.pRxBuf)#define _RxBufSize (_mac.RxBufSize)#define _RxCnt (_mac.RxCnt)#define _fonFeeded (_mac.onFeeded)#define _fonGetHeader (_mac.onGetHeader)#define _fonFlushed (_mac.onFlushed)#define _RxMac_Destroy() (_pMac = NULL)#endif#define _stateByte (*(uint8_t *)(&_state))#define _isRxBufFull() (_RxCnt >= _RxBufSize)#ifndef RXMAC_ONFEEDED_DISABLE#define _onFeeded(pChar,cnt) if(_fonFeeded != NULL) _fonFeeded(_pMac,pChar,cnt);#else#define _onFeeded(pChar,cnt)#endif#define _onGetHeader(headerFlag) if(_fonGetHeader != NULL) _fonGetHeader(_pMac,headerFlag);#undef _DONT_CHECK_MAC#ifdef RXMAC_ARGUMENT_CHECK_DISABLE#define _DONT_CHECK_MAC#endif#ifdef RXMAC_SINGLETON_EN#define _DONT_CHECK_MAC#endif#ifdef _DONT_CHECK_MAC#define _checkMacNotNull()#define _checkMacNotNull_void()#else#define _checkMacNotNull() if(_pMac == NULL) return RXMAC_ERR_POINTERNULL;#define _checkMacNotNull_void() if(_pMac == NULL) return;#endif#ifdef RXMAC_BUF_RPAGE#ifdef CODEWARRIORstatic RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n); #define memcpy(dest,src,n) _memcpy_internal(dest,src,n)#endif#endif// 沖刷緩沖區(qū)staticvoid _flush(RxMac mac,RxFlag ender); // 往接收機(jī)緩沖區(qū)內(nèi)放數(shù)據(jù)staticvoid _BufIn(RxMac mac,RxMacPtr buf,uint16_t len); staticvoid _RxMac_FlushIfFull(RxMac mac); staticvoid _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot); staticvoid _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot); staticvoid _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot); staticvoid _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot); /*
*******************************************************************************************
* RxMac_Create()
*
* Description : To create a receive machine instance. 創(chuàng)建一個(gè)接收機(jī)實(shí)例
*
* Arguments : flags pointer to the flags(an array); 指向標(biāo)志串(數(shù)組)的指針
* flagsCnt the count of the flags; 有多少個(gè)標(biāo)志串;
* buf pointer to the buffer provided to the RxMac;提供給接收機(jī)使用的緩存
* 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時(shí)會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標(biāo)志位的判斷
* onGetHeader the callback func that will be called when find a header.
* 當(dāng)發(fā)現(xiàn)幀頭時(shí)會調(diào)用的回調(diào)函數(shù)
* onFlushed the callback func that will be called when flushed.
* 當(dāng)Flush時(shí)會調(diào)用的回調(diào)函數(shù)
*
* 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_DISABLEif((flags == NULL && flagsCnt > 0 ) || buf == NULL) returnNULL; #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_DISABLEif(bufLen < maxLen){ returnNULL;
} #endif#ifdef RXMAC_SINGLETON_ENif(_pMac != NULL) // if have created one instance, free the previous FlagBuf _RxFlagMgr_Destroy(&_mac); else _pMac = &_mac; #elseif((mac = (RxMac)malloc(sizeof(RXMAC_STRUCT))) == NULL){ returnNULL;
} #endifif(!_RxFlagMgr_Init(_pMac,flags,flagsCnt,maxLen)){
_RxMac_Destroy(); returnNULL;
}
_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. 目標(biāo)接收機(jī)
*
* Return :
*
* Note(s) :
*
*******************************************************************************************
*/voidRxMac_Destroy(RxMac mac){ if(_pMac == NULL) return;
_RxFlagMgr_Destroy(mac);
_RxMac_Destroy();
} /*
*******************************************************************************************
* RxMac_FeedData(s)
*
* Description : To feed RxMac the next char(s). 用于給接收機(jī)下一個(gè)字符
*
* Arguments : mac the target receive machine. 目標(biāo)接收機(jī)
* c the char to feed; 下一個(gè)字符
*
* Return :
*
* Note(s) :
*******************************************************************************************
*/voidRxMac_FeedDatas(RxMac mac, uint8_tconst * buf, uint16_t len){ uint16_t i; for(i = 0; i < len; i++) RxMac_FeedData(mac,buf[i]); } voidRxMac_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);
}elseif(_RxFlag_isUnique(curFlag)){
_RxMac_GetUniqueProcess(mac,curFlag);
}else{ // if(_RxFlag_isEnder(curFlag)) _RxMac_GetEnderProcess(mac,curFlag);
}
} /*
*******************************************************************************************
* RxMac_SetRxSize()
*
* Description : set the size of RxBuf. 設(shè)置接收緩沖區(qū)的大小
*
* Arguments : mac the target receive machine. 目標(biāo)接收機(jī)
* 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_tRxMac_SetRxSize(RxMac mac, uint16_t size){
_checkMacNotNull(); #ifndef RXMAC_ARGUMENT_CHECK_DISABLEif(size <= _RxCnt) return RXMAC_ERR_ARGUMENT; #endif _RxBufSize = size; return RXMAC_ERR_NONE;
} /*
*******************************************************************************************
* RxMac_ResetState()
*
* Description : reset the state of receive machine. 重置接收機(jī)的狀態(tài)
*
* Arguments : mac the target receive machine. 目標(biāo)接收機(jī)
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
* Note(s) : it will not trigger call-back of onFlush.
*******************************************************************************************
*/uint8_tRxMac_ResetState(RxMac mac){
_checkMacNotNull(); // 復(fù)位接收機(jī) 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. 目標(biāo)接收機(jī)
*
* 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_tRxMac_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. 目標(biāo)接收機(jī)
* onFeeded the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
*
* Note(s) :
*
******************************************************************************************
*/uint8_tRxMac_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. 目標(biāo)接收機(jī)
* onGetHeader the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
*
* Note(s) :
*
******************************************************************************************
*/uint8_tRxMac_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. 目標(biāo)接收機(jī)
* onFlushed the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) :
*
******************************************************************************************
*/uint8_tRxMac_SetOnFlushed(RxMac mac,RXMAC_FLUSH_EVENT onFlushed){
_checkMacNotNull();
_fonFlushed = onFlushed; return RXMAC_ERR_NONE;
} /*
******************************************************************************************
* _RxMac_printBuffer()
*
* Description : print the internal buffer, just for developer.
* 給開發(fā)者用于查看內(nèi)部緩存的
*
* Arguments : mac the target receive machine. 目標(biāo)接收機(jī)
* onFlushed the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* 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;
} staticvoid _BufIn(RxMac mac,RxMacPtr buf,uint16_t len){ memcpy(_pRxBuf+_RxCnt,buf,len);
_RxCnt += len;
} staticvoid _flush(RxMac mac,RxFlag ender){ // 觸發(fā)回調(diào)if((_RxCnt > 0 || ender != NULL) && _fonFlushed != NULL)
_fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender); // 復(fù)位接收機(jī) _RxCnt = 0;
_stateByte = 0;
_pHorU = NULL;
}
BOOL BufferUINT8Indexed_BackMatch(BufferUINT8Indexed buf,uint8_tconst *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;
} staticvoid _RxMac_FlushIfFull(RxMac mac){ if(_isRxBufFull()){
_state.isFull = 1;
_flush(_pMac,NULL);
}
} staticvoid _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;
}
} staticvoid _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot){ #ifndef RXMAC_NOTFILL_DISABLEif(!_RxFlag_dontFillHeader(flagJustGot)) #endif _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_state.headerFound = 1;
_onGetHeader(flagJustGot);
_RxMac_FlushIfFull(mac);
} staticvoid _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot){
_state.uniqueFound = 1;
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_flush(_pMac,NULL);
} staticvoid _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_DISABLEif(_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];
}
} returnNULL;
} 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;
} staticvoid _RxFlagMgr_Destroy(RxMac mac){
Buffer_Destroy(_BufForFlag);
} staticvoid _RxFlagMgr_Reset(RxMac mac){
Buffer_Cleanup((Buffer)_BufForFlag);
}
/*
*********************************************************************************************************
*
*
* Universal Receive State Machine
* 通用接收狀態(tài)機(jī)
*
* 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_MODEtypedef INT8U RB_BYTE; typedef RB_BYTE * RXMAC_BUF_ADDRESSING_MODE pRB_BYTE; /*
*********************************************************************************************************
* CONFIGURATION 配置
*********************************************************************************************************
*/#define RXMAC_ARGUMENT_CHECK_EN TRUE#define RXMAC_NOTFILL_EN TRUE#define RXMAC_ONFEEDED_EN TRUE // TRUE: enable the onFeeded function.#define RXMAC_SINGLETON_EN FALSE // TRUE: enable singleton pattern,so argument pRxMac of interfaces// is useless, and user don't need to allocate space for RX_MAC,// but you still need to allocate buffer and call init();/*
*********************************************************************************************************
* CONST
*********************************************************************************************************
*/#define RXMAC_ERR_NONE 0#define RXMAC_ERR_ARGUMENT 1#define RXMAC_ERR_POINTERNULL 2#define RXMAC_ERR_UNKNOWN 3#define RXMAC_ERR_INIT 4/*
*********************************************************************************************************
* TYPE DEFINITION
*********************************************************************************************************
*/// struct of RX_FLAG.option /*typedef struct FLAG_OPTION{
unsigned int isHeader : 1; // 1: the flag is the head of the frame
unsigned int strong_H : 1; // 1: strong-header, RxMac will
unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header
unsigned int isEnder : 1; // 1: the flag is the end of the frame
unsigned int strong_E : 1; //
unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender
unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame.
unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not
}; //*/// 接收標(biāo)志位typedefstructrx_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 0xC0typedefstructrx_state{ 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. } RX_STATE; typedefstructrx_macRX_MAC, *pRX_MAC; typedefvoid (* RXMAC_FLUSH_EVENT)(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder); typedefvoid (* RXMAC_FLAG_EVENT)(pRX_MAC sender,pRX_FLAG pFlag); typedefvoid (* RXMAC_FILTER)(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt); structrx_mac{
RING_QUEUE FlagQueue; // 用于判斷標(biāo)志串的環(huán)形緩沖區(qū)對象 pRX_FLAG Flags; // 標(biāo)志數(shù)組 INT8U FlagsCnt; // 標(biāo)志數(shù)組的個(gè)數(shù) RX_STATE state; // 接收的狀態(tài)(內(nèi)部使用) pRX_FLAG pHorU; // 內(nèi)部使用 pRB_BYTE pRxBuf; // 存放數(shù)據(jù)的緩沖區(qū) INT16U RxBufSize; // 緩沖區(qū)的長度 pRB_BYTE pCur; // 指向緩沖區(qū)內(nèi)下一個(gè)填充字符的位置 RXMAC_FILTER onFeeded; // 當(dāng)被喂字符時(shí)觸發(fā),返回指向緩沖區(qū)中剛剛喂進(jìn)來的字符的指針以及是緩沖區(qū)內(nèi)的第幾個(gè)字符 RXMAC_FLAG_EVENT onGetHeader; // 獲得頭標(biāo)志位時(shí)觸發(fā)。 RXMAC_FLUSH_EVENT onFlushed; // 回調(diào)函數(shù) }; /*
*********************************************************************************************************
* 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, // 需要用戶自己申請個(gè)UNI_RX_MACHINE對象的空間 RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags, // 提供標(biāo)志字符串的數(shù)組 pRB_BYTE pBuf,INT16U BufLen, // 用戶需要提供緩沖區(qū) (緩存區(qū)大小起碼應(yīng)該要能// 放的下最長的Flag+最長的幀,最后部分會分配給RQ) RXMAC_FILTER onFeeded, // 在每次被Feed時(shí)觸發(fā) RXMAC_FLAG_EVENT onGetHeader, // 獲得頭標(biāo)志位時(shí)觸發(fā)。 RXMAC_FLUSH_EVENT onFlushed // 收到一幀數(shù)據(jù)時(shí)的回調(diào)函數(shù) ); // 向接收機(jī)內(nèi)喂字節(jié)voidRxMac_FeedData(pRX_MAC pRxMac,INT8U c); // 重置接收區(qū)長度為最長那個(gè)長度 INT8U RxMac_ResetRxSize(pRX_MAC pRxMac); // 設(shè)置最大接收到多少個(gè)字節(jié) INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size); // 重置接收機(jī)的狀態(tài) INT8U RxMac_ResetState(pRX_MAC pRxMac); // 強(qiáng)制接收機(jī)flush INT8U RxMac_Flush(pRX_MAC pRxMac); // 設(shè)置onFeeded INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded); // 設(shè)置onGetHeader INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader); // 設(shè)置onFlushed INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed); #endif// of RX_MAC_H
源文件:
/*
*********************************************************************************************************
*
*
* Universal Receive State Machine
* 通用接收狀態(tài)機(jī)
*
* 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#elsestatic 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)// 因?yàn)椴荒鼙WC用戶把數(shù)據(jù)放在非分頁區(qū),只好自己實(shí)現(xiàn)一個(gè),實(shí)際使用中如果確定在非分頁區(qū)可以把下面的宏替換為庫函數(shù)memcpystatic pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n); #define _memcpy(dest,src,n) _memcpy_internal(dest,src,n)// 沖刷緩沖區(qū)staticvoid _flush(pRX_MAC pRxMac,pRX_FLAG ender); // 往接收機(jī)緩沖區(qū)內(nèi)放數(shù)據(jù)staticvoid _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len); /*
*********************************************************************************************************
* RxMac_Init()
*
* Description : To initialize a RxMac. 初始化接收機(jī)
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收機(jī)結(jié)構(gòu)體的指針
* Flags pointer to the flags(an array); 指向標(biāo)志串(數(shù)組)的指針
* FlagsCnt the count of the flags; 有多少個(gè)標(biāo)志串;
* maxLenOfFlags the max length of flags; 標(biāo)志字符串最長的長度
* pBuf pointer to the buffer provided to the RxMac;提供給接收機(jī)使用的緩存
* BufLen the size of the buffer. 緩存的大小
* onFeeded the callback func that will be called when feeded.
* 每次被feed時(shí)會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標(biāo)志位的判斷
* onGetHeader the callback func that will be called when find a header.
* 當(dāng)發(fā)現(xiàn)幀頭時(shí)會調(diào)用的回調(diào)函數(shù)
* onFlushed the callback func that will be called when flushed.
* 當(dāng)Flush時(shí)會調(diào)用的回調(diào)函數(shù)
*
* Return : RXMAC_ERR_NONE if success
* RXMAC_ERR_ARGUMENT if the length of longest Flags bigger than Buflen,or one of them is 0
* RXMAC_ERR_POINTERNULL if empty pointer
*
* Note(s) : size of buffer should bigger than the longest flag plus the longest frame
* that may be received(so at least 2 * maxLenOfFlags).
* the buffer is allocate as follow:
** | RxBuffer | |
**
* void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag):
* sender the pointer to the RxMac which call this function
* pFlag the header matched
*
* void onFeeded(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt):
* sender the pointer to the RxMac which call this function
* pCurChar point to the char in the buffer just received.
* bytesCnt the number of bytes in the buffer including the char just feeded.
*
* void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,
* pRX_FLAG pEnder);
* sender the pointer to the RxMac which call this function
* pBuf the pointer to the frame.
* len the length of frame.
* state the state of frame.
* pHorU point to the header flag if state.headerFound == 1, or unique flag if
* state.uniqueFound == 1.
* pEnder point to the ender flag if state.enderFound == 1.
*********************************************************************************************************
*/ INT8U RxMac_Init (pRX_MAC pRxMac,RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags,pRB_BYTE pBuf,INT16U BufLen,
RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){ //INT8U maxLen = 0; INT8U i; #if(RXMAC_ARGUMENT_CHECK_EN)if( #if(!RXMAC_SINGLETON_EN) _pRxMac == NULL || #endif Flags == NULL || pBuf == NULL) return RXMAC_ERR_POINTERNULL; #endif// find out the max length of flags.//for(i = 0; i < 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的最后一段分配給環(huán)形緩沖區(qū) 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. 用于給接收機(jī)下一個(gè)字符
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收機(jī)結(jié)構(gòu)體的指針
* c the char to feed; 下一個(gè)字符
*
* Return :
*
* Note(s) :
*********************************************************************************************************
*/voidRxMac_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; // 填入緩沖區(qū)#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; // 尋找匹配的標(biāo)志串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;
}
} // 如果沒有發(fā)現(xiàn)標(biāo)志串,檢查下有沒滿了,滿了就Flushif(pFlag == NULL){ if(_isRxBufFull()){
_state.isFull = 1;
_flush(_pRxMac,NULL);
} return;
} // 這4種標(biāo)志串要_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. 重置接收緩沖區(qū)
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收機(jī)結(jié)構(gòu)體的指針
*
* 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. 重置接收緩沖區(qū)
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收機(jī)結(jié)構(gòu)體的指針
* 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; #endifif(_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. 重置接收機(jī)的狀態(tài)
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收機(jī)結(jié)構(gòu)體的指針
*
* 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// 復(fù)位接收機(jī) 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; 指向接收機(jī)結(jié)構(gòu)體的指針
*
* 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; 指向接收機(jī)結(jié)構(gòu)體的指針
* onFeeded the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* 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; 指向接收機(jī)結(jié)構(gòu)體的指針
* onGetHeader the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* 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; 指向接收機(jī)結(jié)構(gòu)體的指針
* onFlushed the callback function to set; 要設(shè)置的回調(diào)函數(shù)
*
* 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;
} staticvoid _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len){
_memcpy(_pCur,pBuf,len);
_pCur += len;
} staticvoid _flush(pRX_MAC pRxMac,pRX_FLAG ender){ // 觸發(fā)回調(diào)if(_pCur-_pRxBuf > 0 && _onFlushed != NULL)
_onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender); // 復(fù)位接收機(jī) _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
*********************************************************************************************************
*/staticvoidAppTaskStart(void *p_arg); /*
*********************************************************************************************************
* CALLBACK FUNCITON
*********************************************************************************************************
*/voidonGetData(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt){ // 因?yàn)榘l(fā)現(xiàn)幀頭后才掛載事件,所以下一次回掉正好是說明字符數(shù)的那個(gè)字符,否則還得根據(jù)bytesCnt來判斷當(dāng)前位置 RxMac_SetOnFeeded(sender,NULL); if(*pCurChar > '0' && *pCurChar <= '9' ){ // bytesCnt是當(dāng)前收到了多少個(gè)字符,所以接收區(qū)大小為當(dāng)前字符數(shù)加上還要接收的 RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
}
} voidonFlushed(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);
} voidonGetHeader(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);
} voidonGetHeader2(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]; // 協(xié)議示例1:// 幀頭 :HEADER 或者 START// 強(qiáng)幀尾 :END// 強(qiáng)特殊串:12345 // staticvoidprotocol1_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);
} // 協(xié)議示例2:// 幀頭 : START// 幀頭后的第1個(gè)字符表示后面還要接收多少個(gè)字符 1-9,'4'表示4個(gè),如果不是數(shù)字或?yàn)?0',則等待幀尾// 幀尾 : END// 特殊串: NOW// staticvoidprotocol2_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
*********************************************************************************************************
*/voidmain(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();
} staticvoidAppTaskStart (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(); // 選擇想要實(shí)驗(yàn)的協(xié)議來初始化 protocol1_init(); //protocol2_init();while (DEF_TRUE)
{ // 獲取下一個(gè)字符 c = SCI_GetCharB(SCI0,0,&err); // 回顯 SCI_PutCharB(SCI0,c,0); // 喂給接收機(jī) RxMac_FeedData(&_rxmac,c);
}
}