// 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);}
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;
/* ******************************************************************************************* * * * 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 <stdint.h>
/* ******************************************************************************************* * 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 寻址模式 ******************************************************************************************* */
/* ********************************************************************************************* * 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
// 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;
/* ******************************************************************************************* * 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
/* ******************************************************************************************* * * * 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): * ******************************************************************************************* */
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;
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;
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_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, * ******************************************************************************************* */
/* ********************************************************************************************************* * LOCAL FUNCTION DECLARE ********************************************************************************************************* */
/* ********************************************************************************************************* * * * 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 <os_cpu.h>
//typedef unsigned char INT8U; //typedef unsigned short INT16U;
/* ********************************************************************************************************* * ADDRESSING MODE 寻址模式 ********************************************************************************************************* */ // the addressing mode for buffer #define RXMAC_BUF_ADDRESSING_MODE RQ_ADDRESSING_MODE
#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();
// 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 }; //*/
// 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;
/* ********************************************************************************************************* * 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);
/* ********************************************************************************************************* * INCLUDES ********************************************************************************************************* */ #include "RxMac.h"
#include <string.h> #include <stddef.h> /* ********************************************************************************************************* * 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
/* ********************************************************************************************************* * 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. ********************************************************************************************************* */
/* ********************************************************************************************************* * MAIN FUNCTION ********************************************************************************************************* */
void main(void) { INT8U err; BSP_IntDisAll(); /* Disable ALL interrupts to the interrupt controller */ OSInit(); /* Initialize uC/OS-II */