[嵌入式开发模块]通用接收状态机模块
文章目录
- 前言
- 模块相关概念和逻辑
- 接收机状态
- 标志字符序列
- flush
- 接收机类
- 过滤器
- onGetHeader事件
- 接收机运行逻辑
- 边际条件
- 相关代码
- 接收机代码
- RxMac.h
- RxMacPrivate.h
- RxMac.c
- 测试/示例代码
- v1.0代码
- 接收机代码
- 测试/示例代码
- 后记
- 更新历史
前言
在软件开发的过程中,只要涉及到通信,就会涉及到数据接收机的编写,通信协议虽然多种多样,但是数据包的形式确是很相似的(暂时没看到特别复杂,此模块解决不了的),为此可以把其中通用的部分抽象出来,然后就成了这个模块。
模块相关概念和逻辑
接收机状态
接收机有两个基本状态:
- 状态A:preRx 等待帧头中,这个时候接收机会不断判断是否收到了特殊序列、帧头和强帧尾。如果收到了帧头,则(默认)会把帧头填入缓冲区的最前面,然后进入状态B。
- 状态B:Rxing 等待帧尾中,收到的数据会按序填入接收缓冲区,同时不断查找帧尾、强帧头以及强特殊序列,不管找到了哪一个都会触发flush。如果,找到的是强帧头,则仍然在状态B,否则恢复状态A。
不管在哪一个状态下,如果接受缓冲区满了,都会触发flush并回到状态A。
标志字符序列
接收机定义了以下标志序列类型:
类型 | 模块中标记 | 描述 |
---|---|---|
帧头 | header | 只在状态A起作用;找到时会导致之前接收区内的数据被flush,然后默认会填入接收区的最前面,可以通过选项来改变这个行为,然后接收机进入状态B。 |
强帧头 | strong-header | 在状态B也会起作用,其他行为与普通帧头一样 |
帧尾 | ender | 只在状态B起作用;找到时会导致当前接收区内的数据被flush,默认会处于回调时给用户的buffer的最后面,可以通过选项来改变这个行为,然后接收机回到状态A。 |
强帧头 | strong-header | 在状态A也会起作用,其他行为与普通帧尾一样 |
特殊序列 | unique | 只在状态A起作用;找到时会导致之前接收区内的数据被flush,然后自己被填入接收区内后再次触发flush,然后接收机回到状态A。 |
强特殊序列 | strong-unique | 在状态B也会起作用,其他行为与特殊序列一样 |
对应模块中的结构体为:
// receive flag
typedef struct RXFLAG_STRUCT{uint8_t const * pBuf;uint8_t len;uint8_t option;
} RXFLAG_STRUCT;
typedef RXFLAG_STRUCT const * RxFlag;
一般的流程中,初始化接收机前,用户需要准备好接收机使用的所有标志序列,标志好每个序列的类型。模块提供宏函数以抽象这个过程:
// void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt);
// to initialize a receive flag
// flag point to the target RXFLAG_STRUCT.
// buf pointer to the flag buffer
// size size of flag
// opt see RXFLAG_OPTION_XXXXX, bit mode
#define RxFlag_Init(flag,buf,size,opt) \{(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);}
flush
每当接收机根据标志字符序列找到一个完整或不完整的数据包时,接收机会进行回调以通知用户处理这个数据包,这个行为被称为flush,这个回调函数叫做onFlushed。
此函数的原型如下
typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender);
整个数据包为buf指向的长度为len的区域。
数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下
typedef struct RXSTATE_STRUCT{unsigned int headerFound: 1; // 1: have get headerunsigned int enderFound : 1; // 1: have get enderunsigned int isFull : 1; // 1: the buffer is fullunsigned int uniqueFound: 1; // 1: this is unique flag.
} RxState;
通过判断每个标志位是否置1,可以得知当前数据包的状态。
如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头
如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾
如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。
如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列
接收机类
V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。
typedef struct RXMAC_STRUCT * RxMac;
模块提供Create函数来创建接收机实例并返回指向实例的指针。
// to create an instance of RxMac
// flags 标志字符串结构体的数组
// flagsCnt 标志字符串结构体的个数
// buf 用户提供给接收机用的缓冲区
// bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串)
// onFeeded 在每次被Feed时触发
// onGetHeader 获得头标志位时触发。
// onFlushed 收到一帧数据时的回调函数
RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed);
调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。
过滤器
接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下:
typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
pCurChar :指向接收区中刚收到的字符
bytesCnt :这个字符是接收区中的第几个字符
此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。
onGetHeader事件
当找到任意帧头时会触发。
接收机运行逻辑
接收机的运作逻辑如下:
边际条件
标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。
同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。
对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况:
如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。
如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。
帧尾不会发生这种边际条件。
相关代码
此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。
https://blog.csdn.net/lin_strong/article/details/88236566
接收机代码
RxMac.h
/*
*******************************************************************************************
*
*
* Universal Receive State Machine
* 通用接收状态机
*
* File : RxMac.h
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 2018/05/29 1.0 the prototype
* 2019/01/23 2.0 modify the type names to more readable ones, though preserve
* the old-style for forward compatibility;
* change init method to create method which use malloc to alloc
* instance, and the corresponding destroy method.
* change the internal buffer module from RINGQUEUE to BufferArray,
* so user no longer need to know the internal flags management and
* allocate the space for it.
* add RxMac_FeedDatas method for convenient.
* 2019/03/07 2.1 some modification to the malloc configuration
*
* NOTE(s): 1. the receive process has two basic state
* A. preRx: when haven't found any header, the RxMac will search for the unique
* flag, header and strong-ender. Only when a header is found will come
* to next step.
* B. Rxing: the RxMac will put the successive bytes into the buffer, and search
* for the strong-unique, strong-header, ender.
* 2. the module is drived by the RxMac_FeedData(), user should get the the char
* from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
* or RxMac_FeedDatas().
* 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
* to notify the results; user can judge the frame through the state parameter;
* state.headerFound == 1: find any header, the header is passed by HorU
* state.enderFound == 1: find any ender, the ender is passed by Ender
* state.isFull == 1: the buffer is full, maybe you should check headerFound
* to see whether a header has been found.
* state.uniqueFound == 1: find any unique flag. In this case, other parameters will
* always be 0 ,the data in the buffer will be the flag,
* and the unique flag is passed by HorU.
* 4. To use this module, for each receive machine:
* A. define malloc to configure the module, see CONFIGURATION
* B. allocate the space for buffer and FLAGS.
* RXFLAG_STRUCT flags[2];
* uint8_t buf[300];
* C. set the flags according to the protocol, define the callback functions
* according to your need.
* static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... };
* static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,
* RxState state,RxFlag HorU,RxFlag Ender){ ...... };
* const uint8_t HeaderFlag[] = "Header";
* const uint8_t EnderFlag[] = "\r\n";
* RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER);
* RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER |
* RXFLAG_OPTION_NOTFILL_ENDER);
* D. create the receive machine:
* RxMac mac;
* mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL,
* onGetHeader, onFlushed );
* E. feed the receive machine:
* while(1){
* c = GetNextChar();
* RxMac_FeedData(mac,c);
* }
* F. destroy the receive machine if need.
* RxMac_Destroy(mac);
*******************************************************************************************
*/#ifndef RX_MAC_H
#define RX_MAC_H/*
*******************************************************************************************
* INCLUDES
*******************************************************************************************
*/#include <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 寻址模式
*******************************************************************************************
*/#ifdef RXMAC_BUF_RPAGE
#ifdef CODEWARRIOR
#define RXMAC_BUF_ADDRESSING_MODE __rptr
#endif
#endif#ifndef RXMAC_BUF_ADDRESSING_MODE
#define RXMAC_BUF_ADDRESSING_MODE
#endif
typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr;/*
*********************************************************************************************
* ERROR CODE
*********************************************************************************************
*/#define RXMAC_ERR_NONE 0
#define RXMAC_ERR_ARGUMENT 1
#define RXMAC_ERR_POINTERNULL 2
#define RXMAC_ERR_UNKNOWN 3
#define RXMAC_ERR_INIT 4/*
*********************************************************************************************
* RECEIVE FLAG STRUCT
*********************************************************************************************
*/// normal header, RxMac will only check it in Step A
#define RXFLAG_OPTION_HEADER 0x01
// strong header, RxMac will always check it.
#define RXFLAG_OPTION_STRONG_HEADER 0x03
// the header will not be filled into buffer when found.(only valid when is header)
#define RXFLAG_OPTION_NOTFILL_HEADER 0x04
// normal ender, RxMac will only check it in Step B
#define RXFLAG_OPTION_ENDER 0x08
// strong header, RxMac will always check it.
#define RXFLAG_OPTION_STRONG_ENDER 0x18
// the ender will not be filled into buffer when found.(only valid when is ender)
#define RXFLAG_OPTION_NOTFILL_ENDER 0x20
// normal unique, RxMac will only check it in Step A
#define RXFLAG_OPTION_UNIQUE 0x40
// strong unique, RxMac will always check it.
#define RXFLAG_OPTION_STRONG_UNIQUE 0xC0// receive flag
typedef struct RXFLAG_STRUCT{uint8_t const * pBuf;uint8_t len;uint8_t option;
} RXFLAG_STRUCT;
typedef RXFLAG_STRUCT const * RxFlag;// void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt);
// to initialize a receive flag
// flag point to the target RXFLAG_STRUCT.
// buf pointer to the flag buffer
// size size of flag
// opt see RXFLAG_OPTION_XXXXX, bit mode
#define RxFlag_Init(flag,buf,size,opt) \
{(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);}/*
*********************************************************************************************
* TYPE DEFINITION
*********************************************************************************************
*/typedef struct RXSTATE_STRUCT{unsigned int headerFound: 1; // 1: have get headerunsigned int enderFound : 1; // 1: have get enderunsigned int isFull : 1; // 1: the buffer is fullunsigned int uniqueFound: 1; // 1: this is unique flag.
} RxState;typedef struct RXMAC_STRUCT * RxMac;typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender);
typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag);
typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);/*
*******************************************************************************************
* FUNCTION DECLARATION
*******************************************************************************************
*/// to create an instance of RxMac
// flags 标志字符串结构体的数组
// flagsCnt 标志字符串结构体的个数
// buf 用户提供给接收机用的缓冲区
// bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串)
// onFeeded 在每次被Feed时触发
// onGetHeader 获得头标志位时触发。
// onFlushed 收到一帧数据时的回调函数
RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed);
// to destroy the RxMac
void RxMac_Destroy(RxMac mac);
// 向接收机内喂字节
void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len);
void RxMac_FeedData(RxMac mac, uint8_t c);
// 重置接收区长度为最长那个长度
//uint8_t RxMac_ResetRxSize(RxMac mac);
// 设置最大接收到多少个字节
uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size);
// 重置接收机的状态
uint8_t RxMac_ResetState(RxMac mac);
// 强制接收机flush
uint8_t RxMac_Flush(RxMac mac);
// 设置onFeeded
uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded);
// 设置onGetHeader
uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader);
// 设置onFlushed
uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed);#include "RxMacPrivate.h"#endif // of RX_MAC_H
RxMacPrivate.h
/*
*******************************************************************************************
*
*
* Private Declarations for Universal Receive State Machine
*
* File : RxMacPrivate.h
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History:
* NOTE(s):
*******************************************************************************************
*//*
*******************************************************************************************
* FUNCTION DECLARATION
*******************************************************************************************
*/
// 打印内部缓冲区,返回缓冲区的长度
uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf);/*
*******************************************************************************************
* RECEIVE FLAG STRUCT
*******************************************************************************************
*/// struct of RXFLAG_STRUCT.option
/*typedef struct RXFLAG_OPTION{unsigned int isHeader : 1; // 1: the flag is the head of the frameunsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as headerunsigned int isEnder : 1; // 1: the flag is the end of the frameunsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as enderunsigned 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 <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "RxMac.h"
#include "BufferMallocArray.h"/*
*******************************************************************************************
* RECEIVE FLAGS MANAGER
*******************************************************************************************
*/typedef struct RXFLAGMGR_STRUCT {// buffer to hold the pre-data which hasn't matched any flag.BufferUINT8Indexed BufForFlag;// the flag array to be matched.RxFlag Flags;// count of flags.uint8_t FlagsCnt;// current state, in which headerFound will influence the match behavior. // controlled by the child class.RxState state;
}RXFLAGMGR_STRUCT;static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte);
static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen);
static void _RxFlagMgr_Destroy(RxMac mac);
static void _RxFlagMgr_Reset(RxMac mac);/*
*******************************************************************************************
* STRUCT DIFINITION
*******************************************************************************************
*/typedef struct RXMAC_STRUCT{// manage the flag matches.RXFLAGMGR_STRUCT FlagMgr;// record the Header or Unique flag.RxFlag pHorU;// internal buffer to hold data.RxMacPtr pRxBuf;// length of the internal 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) if(_fonFeeded != NULL) _fonFeeded(_pMac,pChar,cnt);
#else#define _onFeeded(pChar,cnt)
#endif
#define _onGetHeader(headerFlag) if(_fonGetHeader != NULL) _fonGetHeader(_pMac,headerFlag);#undef _DONT_CHECK_MAC
#ifdef RXMAC_ARGUMENT_CHECK_DISABLE
#define _DONT_CHECK_MAC
#endif
#ifdef RXMAC_SINGLETON_EN
#define _DONT_CHECK_MAC
#endif#ifdef _DONT_CHECK_MAC#define _checkMacNotNull()#define _checkMacNotNull_void()
#else#define _checkMacNotNull() if(_pMac == NULL) return RXMAC_ERR_POINTERNULL;#define _checkMacNotNull_void() if(_pMac == NULL) return;
#endif#ifdef RXMAC_BUF_RPAGE
#ifdef CODEWARRIOR
static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n);
#define memcpy(dest,src,n) _memcpy_internal(dest,src,n)
#endif
#endif
// 冲刷缓冲区
static void _flush(RxMac mac,RxFlag ender);
// 往接收机缓冲区内放数据
static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len);static void _RxMac_FlushIfFull(RxMac mac);
static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot);
static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot);
static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot);
static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot);
/*
*******************************************************************************************
* RxMac_Create()
*
* Description : To create a receive machine instance. 创建一个接收机实例
*
* Arguments : flags pointer to the flags(an array); 指向标志串(数组)的指针
* flagsCnt the count of the flags; 有多少个标志串;
* buf pointer to the buffer provided to the RxMac;提供给接收机使用的缓存
* bufLen the size of the buffer. 缓存的大小
* onFeeded the callback func that will be called everytime feeded, you
* can modify the feeded byte in this callback.
* 每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
* onGetHeader the callback func that will be called when find a header.
* 当发现帧头时会调用的回调函数
* onFlushed the callback func that will be called when flushed.
* 当Flush时会调用的回调函数
*
* Return : Pointer to the created instance.
* NULL if any error.
*
* Note(s) : 1. size of buffer should bigger than the longest flag, or the flag will be
* useless.
* 2. if flagsCnt > 0, flags can't point to NULL.
* 3. you must provide a buffer.
* 4. if you enable the RXMAC_SINGLETON_EN, multi-create will pointer to the
* same instance initialized as the last create.
*
* void onGetHeader(RxMac sender,RxFlag flag):
* sender the pointer to the RxMac which call this function
* flag the header matched
*
* void onFeeded(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt):
* sender the pointer to the RxMac which call this function
* pCurChar point to the byte just received, you can change it before any other process.
* bytesCnt the number of bytes in the buffer including the char just feeded.
*
* void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,RxState state,RxFlag HorU,
* RxFlag Ender);
* sender the pointer to the RxMac which call this function
* buf the pointer to the frame.
* len the length of frame.
* state the state of frame.
* HorU point to the header flag if state.headerFound == 1, or unique flag if
* state.uniqueFound == 1.
* Ender point to the ender flag if state.enderFound == 1.
*******************************************************************************************
*/
RxMac RxMac_Create(RXFLAG_STRUCT const flags[],uint8_t flagsCnt,RxMacPtr buf,uint16_t bufLen,RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){uint8_t i, maxLen = 0;
#ifndef RXMAC_SINGLETON_ENRxMac mac;
#endif
#ifndef RXMAC_ARGUMENT_CHECK_DISABLEif((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_DISABLEif(bufLen < maxLen){return NULL;}
#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){return NULL;}
#endifif(!_RxFlagMgr_Init(_pMac,flags,flagsCnt,maxLen)){_RxMac_Destroy();return NULL;}_pHorU = NULL;_pRxBuf = buf;_RxCnt = 0;_RxBufSize = bufLen;_fonFeeded = onFeeded;_fonGetHeader = onGetHeader;_fonFlushed = onFlushed;return _pMac;
}
/*
*******************************************************************************************
* RxMac_Destroy()
*
* Description : Destroy a receive machine instance.
*
* Arguments : mac the target receive machine. 目标接收机
*
* Return :
*
* Note(s) :
*
*******************************************************************************************
*/
void RxMac_Destroy(RxMac mac){if(_pMac == NULL)return;_RxFlagMgr_Destroy(mac);_RxMac_Destroy();
}
/*
*******************************************************************************************
* RxMac_FeedData(s)
*
* Description : To feed RxMac the next char(s). 用于给接收机下一个字符
*
* Arguments : mac the target receive machine. 目标接收机
* c the char to feed; 下一个字符
*
* Return :
*
* Note(s) :
*******************************************************************************************
*/void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len){uint16_t i;for(i = 0; i < len; i++)RxMac_FeedData(mac,buf[i]);
}void RxMac_FeedData(RxMac mac,uint8_t c){RxFlag curFlag;_checkMacNotNull_void();_onFeeded(&c,_RxCnt + 1);_pRxBuf[_RxCnt++] = c;curFlag = _RxFlagMgr_GetNextMatchedAtThisState(mac,c);if(curFlag == NULL){ // if no flag match_RxMac_FlushIfFull(mac);return;}_RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(mac,curFlag);if(_RxFlag_isHeader(curFlag)){_RxMac_GetHeaderProcess(mac,curFlag);}else if(_RxFlag_isUnique(curFlag)){_RxMac_GetUniqueProcess(mac,curFlag);}else{ // if(_RxFlag_isEnder(curFlag))_RxMac_GetEnderProcess(mac,curFlag);}
}
/*
*******************************************************************************************
* RxMac_SetRxSize()
*
* Description : set the size of RxBuf. 设置接收缓冲区的大小
*
* Arguments : mac the target receive machine. 目标接收机
* size the size to set;
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
* RXMAC_ERR_ARGUMENT if size is wrong.
* Note(s) : the size should bigger than the current number of chars in the RxBuf.
*
*******************************************************************************************
*/
uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size){_checkMacNotNull();
#ifndef RXMAC_ARGUMENT_CHECK_DISABLEif(size <= _RxCnt)return RXMAC_ERR_ARGUMENT;
#endif_RxBufSize = size;return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
* RxMac_ResetState()
*
* Description : reset the state of receive machine. 重置接收机的状态
*
* Arguments : mac the target receive machine. 目标接收机
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
* Note(s) : it will not trigger call-back of onFlush.
*******************************************************************************************
*/
uint8_t RxMac_ResetState(RxMac mac){_checkMacNotNull();// 复位接收机Buffer_Cleanup((Buffer)_BufForFlag);_RxCnt = 0;_stateByte = 0;_pHorU = NULL;return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
* RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments : mac the target receive machine. 目标接收机
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
*
* Note(s) : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*******************************************************************************************
*/uint8_t RxMac_Flush(RxMac mac){_checkMacNotNull();_flush(_pMac,NULL);return RXMAC_ERR_NONE;
}/*
******************************************************************************************
* RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments : mac the target receive machine. 目标接收机
* onFeeded the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
*
* Note(s) :
*
******************************************************************************************
*/
uint8_t RxMac_SetOnFeeded(RxMac mac,RXMAC_FILTER onFeeded){_checkMacNotNull();_fonFeeded = onFeeded;return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
* RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments : mac the target receive machine. 目标接收机
* onGetHeader the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if mac == NULL
*
* Note(s) :
*
******************************************************************************************
*/
uint8_t RxMac_SetOnGetHeader(RxMac mac,RXMAC_FLAG_EVENT onGetHeader){_checkMacNotNull();_fonGetHeader = onGetHeader;return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
* RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments : mac the target receive machine. 目标接收机
* onFlushed the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) :
*
******************************************************************************************
*/
uint8_t RxMac_SetOnFlushed(RxMac mac,RXMAC_FLUSH_EVENT onFlushed){_checkMacNotNull();_fonFlushed = onFlushed;return RXMAC_ERR_NONE;
}
/*
******************************************************************************************
* _RxMac_printBuffer()
*
* Description : print the internal buffer, just for developer.
* 给开发者用于查看内部缓存的
*
* Arguments : mac the target receive machine. 目标接收机
* onFlushed the callback function to set; 要设置的回调函数
*
* Return : the len of buffer printed.
*
* Note(s) :
*
******************************************************************************************
*/uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf){memcpy(buf,_pRxBuf,_RxCnt);return _RxCnt;
}/*
******************************************************************************************
* LOCAL FUNCITON
******************************************************************************************
*/
static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n){RxMacPtr p = dest;while(n-- > 0)*p++ = *src++;return dest;
}static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len){memcpy(_pRxBuf+_RxCnt,buf,len);_RxCnt += len;
}static void _flush(RxMac mac,RxFlag ender){// 触发回调if((_RxCnt > 0 || ender != NULL) && _fonFlushed != NULL)_fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender);// 复位接收机_RxCnt = 0;_stateByte = 0;_pHorU = NULL;
}BOOL BufferUINT8Indexed_BackMatch(BufferUINT8Indexed buf,uint8_t const *toMatch,uint16_t len){uint16_t cnt = _Buffer_getCount(buf);if(len > cnt) return FALSE;while(len > 0){if(_BufferUINT8Indexed_get(buf,--cnt) != toMatch[--len])return FALSE;}return TRUE;
}static void _RxMac_FlushIfFull(RxMac mac){if(_isRxBufFull()){_state.isFull = 1;_flush(_pMac,NULL);}
}static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot){if(flagJustGot->option & RXFLAGMASK_USUHSH){if(_RxCnt > flagJustGot->len){_RxCnt -= flagJustGot->len;_flush(_pMac,NULL);}else{_RxCnt = 0;}_pHorU = flagJustGot;}
}static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot){#ifndef RXMAC_NOTFILL_DISABLEif(!_RxFlag_dontFillHeader(flagJustGot))
#endif_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);_state.headerFound = 1;_onGetHeader(flagJustGot);_RxMac_FlushIfFull(mac);
}static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot){_state.uniqueFound = 1;_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);_flush(_pMac,NULL);
}static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot){_state.enderFound = 1;if(_RxCnt < flagJustGot->len){ // if part of the flag has been manually flushed._RxCnt = 0; // restore the buffer._BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len); }
#ifndef RXMAC_NOTFILL_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 flagmask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;for(i = 0; i < _FlagsCnt; i++){if((_Flags[i].option & mask) && BufferUINT8Indexed_BackMatch(_BufForFlag,_Flags[i].pBuf,_Flags[i].len)){Buffer_Cleanup((Buffer)_BufForFlag);return &_Flags[i];}}return NULL;
}static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen){if(_BufForFlag = (BufferIndexed)BufferUINT8MallocArray_Create(maxLen)){_Flags = flags;_FlagsCnt = flagsCnt;_stateByte = 0;}return _BufForFlag != NULL;
}static void _RxFlagMgr_Destroy(RxMac mac){Buffer_Destroy(_BufForFlag);
}static void _RxFlagMgr_Reset(RxMac mac){Buffer_Cleanup((Buffer)_BufForFlag);
}
测试/示例代码
已略去非必要代码
#include <stdio.h>
#include "RxMac.h"/*
*********************************************************************************************************
* LOCAL FUNCTION DECLARE
*********************************************************************************************************
*/static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender);
static void onGetHeader(RxMac sender,RxFlag flag);
static void onGetHeader2(RxMac sender,RxFlag flag);/*
*********************************************************************************************************
* LOVAL VARIABLE
*********************************************************************************************************
*/
static RxMac mac = NULL;
static RXFLAG_STRUCT flags[4];
#define BUF_SIZE 20
static uint8_t buffer[BUF_SIZE];// 协议示例1:
// 帧头 :HEADER 或者 START
// 强帧尾 :END
// 强特殊串:12345
//
static void protocol1_init(void){RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);mac = RxMac_Create(flags,4,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
}
// 协议示例2:
// 帧头 : START
// 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾
// 帧尾 : END
// 特殊串: NOW
//
static void protocol2_init(void){RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);mac = RxMac_Create(flags,3,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
}
/*
*********************************************************************************************************
* CALLBACK FUNCITON
*********************************************************************************************************
*/static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt){// 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytesCnt来判断当前位置RxMac_SetOnFeeded(sender,NULL);if(*pCurChar > '0' && *pCurChar <= '9' ){// bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);}
}
static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender){buf[len] = '\0';printf("\nFlushed:");if(state.headerFound)printf("headerFound,");if(state.enderFound)printf("enderFound,");if(state.isFull)printf("full,");if(state.uniqueFound)printf("unique,");printf("\nDatas:%s\n",buf);RxMac_SetRxSize(sender,BUF_SIZE);
}
static void onGetHeader(RxMac sender,RxFlag flag){printf("\nFoundHeader:%s\n",flag->pBuf);
}
static void onGetHeader2(RxMac sender,RxFlag flag){printf("\nFoundHeader:%s\n",flag->pBuf);RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
* MAIN FUNCTION
*********************************************************************************************************
*/void main(void) {// 选择想要实验的协议来初始化protocol1_init();// protocol2_init();while (1) {c = getchar();// 回显putchar(c);RxMac_FeedData(mac,c);}
}
示例协议1测试结果
示例协议2测试结果
可以看到,第二个协议中我们通过改变缓冲区大小成功控制了数据包的长度。
虽然这里的示例都是基于ASCII的,但这只是为了观察起来方便,普通的基于二进制的协议也是可以使用这个模块的。
v1.0代码
旧版代码中引用了我自己写的(现已弃用)环形缓冲区模块:
https://blog.csdn.net/lin_strong/article/details/73604561
接收机代码
头文件
/*
*********************************************************************************************************
*
*
* Universal Receive State Machine
* 通用接收状态机
*
* File : RxMac.h
*
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2018/05/29
* version: 1.0
* History: 2018/05/29 the prototype
* NOTE(s): 1. the receive process has two basic state
* A. preRx: when haven't found any header, the RxMac will search for the unique
* flag, header and strong-ender. Only when a header is found will come
* to next step.
* B. Rxing: the RxMac will put the successive bytes into the buffer, and search
* for the strong-unique, strong-header, ender.
* 2. the module is drived by the RxMac_FeedData(), user should get the the char
* from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
* 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
* to notify the results; user can judge the frame through the state parameter;
* state.headerFound == 1: find any header, the header is passed by pHorU
* state.enderFound == 1: find any ender, the ender is passed by pEnder
* state.isFull == 1: the buffer is full, maybe you should check headerFound
* to see whether a header has been found.
* state.uniqueFound == 1: find any unique flag. In this case, other parameters will
* always be 0 & the datas in the buffer will be the flag.
* 4. To use this module, for each receive machine:
* A. allocate the space for buffer, RxMac & FLAGS
* RX_MAC _Mac;
* RX_FLAG flags[2];
* INT8U buf[300];
* B. set the flags according to the protocol, define the callback funcitons
* according to your need.
* static void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){ ...... };
* static void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,
* RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){ ...... };
* const INT8U HeaderFlag[] = "Header";
* const INT8U EnderFlag[] = "\r\n";
* RX_FLAG_INIT(flags,HeaderFlag,StrSize(HeaderFlag),FLAG_OPTION_HEADER);
* RX_FLAG_INIT(&flags[1],EnderFlag,StrSize(EnderFlag),FLAG_OPTION_ENDER |
* FLAG_OPTION_NOTFILL_ENDER);
* C. init the receive machine:
* RxMac_Init(&_Mac,flags,2,6,buf,300,NULL, onGetHeader, onFlushed );
* D. feed the receive machine:
* while(1){
* c = GetNextChar();
* RxMac_FeedData(&_Mac,c);
* }
*********************************************************************************************************
*/#ifndef RX_MAC_H
#define RX_MAC_H/*
*********************************************************************************************************
* INCLUDES
*********************************************************************************************************
*/
#include "RingQueue.h"
#include <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_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 frameunsigned int strong_H : 1; // 1: strong-header, RxMac will unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as headerunsigned int isEnder : 1; // 1: the flag is the end of the frameunsigned int strong_E : 1; // unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as enderunsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame.unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not
}; //*/// 接收标志位
typedef struct rx_flag{INT8U const *pBuf;INT8U len;INT8U option;
} RX_FLAG,* pRX_FLAG;// normal header, RxMac will only check it in Step A
#define FLAG_OPTION_HEADER 0x01
// strong header, RxMac will always check it.
#define FLAG_OPTION_STRONG_HEADER 0x03
// the header will not be filled into buffer when found.(only valid when is header)
#define FLAG_OPTION_NOTFILL_HEADER 0x04
// normal ender, RxMac will only check it in Step B
#define FLAG_OPTION_ENDER 0x08
// strong header, RxMac will always check it.
#define FLAG_OPTION_STRONG_ENDER 0x18
// the ender will not be filled into buffer when found.(only valid when is ender)
#define FLAG_OPTION_NOTFILL_ENDER 0x20
// normal unique, RxMac will only check it in Step A
#define FLAG_OPTION_UNIQUE 0x40
// strong unique, RxMac will always check it.
#define FLAG_OPTION_STRONG_UNIQUE 0xC0typedef struct rx_state{unsigned int headerFound: 1; // 1: have get headerunsigned int enderFound : 1; // 1: have get enderunsigned int isFull : 1; // 1: the buffer is fullunsigned int uniqueFound: 1; // 1: this is unique flag.
} RX_STATE;typedef struct rx_mac RX_MAC, *pRX_MAC;
typedef void (* RXMAC_FLUSH_EVENT)(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder);
typedef void (* RXMAC_FLAG_EVENT)(pRX_MAC sender,pRX_FLAG pFlag);
typedef void (* RXMAC_FILTER)(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt);struct rx_mac{RING_QUEUE FlagQueue; // 用于判断标志串的环形缓冲区对象pRX_FLAG Flags; // 标志数组INT8U FlagsCnt; // 标志数组的个数RX_STATE state; // 接收的状态(内部使用)pRX_FLAG pHorU; // 内部使用pRB_BYTE pRxBuf; // 存放数据的缓冲区INT16U RxBufSize; // 缓冲区的长度pRB_BYTE pCur; // 指向缓冲区内下一个填充字符的位置RXMAC_FILTER onFeeded; // 当被喂字符时触发,返回指向缓冲区中刚刚喂进来的字符的指针以及是缓冲区内的第几个字符RXMAC_FLAG_EVENT onGetHeader; // 获得头标志位时触发。RXMAC_FLUSH_EVENT onFlushed; // 回调函数
};/*
*********************************************************************************************************
* FUNCTION DECLARATION
*********************************************************************************************************
*/
// to set the flag's option
// pbuf pointer to the flag buffer
// bufSize size of flag
// opt see FLAG_OPTION_XXXXX
#define RX_FLAG_INIT(pFlag,pbuf,bufSize,opt) \(pFlag)->pBuf =(pbuf);(pFlag)->len =(bufSize);(pFlag)->option = (opt);// to init the RxMac
INT8U RxMac_Init(pRX_MAC pRxMac, // 需要用户自己申请个UNI_RX_MACHINE对象的空间RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags, // 提供标志字符串的数组pRB_BYTE pBuf,INT16U BufLen, // 用户需要提供缓冲区 (缓存区大小起码应该要能// 放的下最长的Flag+最长的帧,最后部分会分配给RQ)RXMAC_FILTER onFeeded, // 在每次被Feed时触发RXMAC_FLAG_EVENT onGetHeader, // 获得头标志位时触发。RXMAC_FLUSH_EVENT onFlushed // 收到一帧数据时的回调函数);
// 向接收机内喂字节
void RxMac_FeedData(pRX_MAC pRxMac,INT8U c);
// 重置接收区长度为最长那个长度
INT8U RxMac_ResetRxSize(pRX_MAC pRxMac);
// 设置最大接收到多少个字节
INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size);
// 重置接收机的状态
INT8U RxMac_ResetState(pRX_MAC pRxMac);
// 强制接收机flush
INT8U RxMac_Flush(pRX_MAC pRxMac);
// 设置onFeeded
INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded);
// 设置onGetHeader
INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader);
// 设置onFlushed
INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed);#endif // of RX_MAC_H
源文件:
/*
*********************************************************************************************************
*
*
* Universal Receive State Machine
* 通用接收状态机
*
* File : RxMac.c
*
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2018/05/29
* version: 1.0
* History:
* NOTE(s):
*
*********************************************************************************************************
*//*
*********************************************************************************************************
* INCLUDES
*********************************************************************************************************
*/
#include "RxMac.h"#include <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#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)// 因为不能保证用户把数据放在非分页区,只好自己实现一个,实际使用中如果确定在非分页区可以把下面的宏替换为库函数memcpy
static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n);
#define _memcpy(dest,src,n) _memcpy_internal(dest,src,n)
// 冲刷缓冲区
static void _flush(pRX_MAC pRxMac,pRX_FLAG ender);
// 往接收机缓冲区内放数据
static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len);/*
*********************************************************************************************************
* RxMac_Init()
*
* Description : To initialize a RxMac. 初始化接收机
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* Flags pointer to the flags(an array); 指向标志串(数组)的指针
* FlagsCnt the count of the flags; 有多少个标志串;
* maxLenOfFlags the max length of flags; 标志字符串最长的长度
* pBuf pointer to the buffer provided to the RxMac;提供给接收机使用的缓存
* BufLen the size of the buffer. 缓存的大小
* onFeeded the callback func that will be called when feeded.
* 每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
* onGetHeader the callback func that will be called when find a header.
* 当发现帧头时会调用的回调函数
* onFlushed the callback func that will be called when flushed.
* 当Flush时会调用的回调函数
*
* Return : RXMAC_ERR_NONE if success
* RXMAC_ERR_ARGUMENT if the length of longest Flags bigger than Buflen,or one of them is 0
* RXMAC_ERR_POINTERNULL if empty pointer
*
* Note(s) : size of buffer should bigger than the longest flag plus the longest frame
* that may be received(so at least 2 * maxLenOfFlags).
* the buffer is allocate as follow:
* <---------------------- BufLen ---------------------->
* | RxBuffer | |
* <------------- RxBufSize ------------> <-maxLenOfFlags->
*
* void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag):
* sender the pointer to the RxMac which call this function
* pFlag the header matched
*
* void onFeeded(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt):
* sender the pointer to the RxMac which call this function
* pCurChar point to the char in the buffer just received.
* bytesCnt the number of bytes in the buffer including the char just feeded.
*
* void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,
* pRX_FLAG pEnder);
* sender the pointer to the RxMac which call this function
* pBuf the pointer to the frame.
* len the length of frame.
* state the state of frame.
* pHorU point to the header flag if state.headerFound == 1, or unique flag if
* state.uniqueFound == 1.
* pEnder point to the ender flag if state.enderFound == 1.
*********************************************************************************************************
*/
INT8U RxMac_Init(pRX_MAC pRxMac,RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags,pRB_BYTE pBuf,INT16U BufLen,RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){//INT8U maxLen = 0;INT8U i;
#if(RXMAC_ARGUMENT_CHECK_EN)if(
#if(!RXMAC_SINGLETON_EN)_pRxMac == NULL ||
#endifFlags == 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;
#endifBufLen -= maxLenOfFlags;// 把buffer的最后一段分配给环形缓冲区RingQueueInit(&_FlagQueue,pBuf + BufLen,maxLenOfFlags,&i);_Flags = Flags;_FlagsCnt = FlagsCnt;_stateByte = 0;_pHorU = NULL;_pRxBuf = pBuf;_RxBufSize = BufLen;_pCur = pBuf;_onFeeded = onFeeded;_onGetHeader = onGetHeader;_onFlushed = onFlushed;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_FeedData()
*
* Description : To feed RxMac the next char. 用于给接收机下一个字符
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* c the char to feed; 下一个字符
*
* Return :
*
* Note(s) :
*********************************************************************************************************
*/
void RxMac_FeedData(pRX_MAC pRxMac,INT8U c){INT8U i,mask;pRX_FLAG pFlag = NULL;
#if(RXMAC_ONFEEDED_EN)pRB_BYTE pCurChar = _pCur;
#endif
#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return;
#endif*_pCur++ = c; // 填入缓冲区
#if(RXMAC_ONFEEDED_EN)if(_onFeeded != NULL)_onFeeded(_pRxMac,pCurChar,_pCur - _pRxBuf);RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#elseRingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#endif// _state.headerFound == 1 说明在等待帧尾,否则在等待帧头mask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;// 寻找匹配的标志串for(i = 0; i < _FlagsCnt; i++){if((_Flags[i].option & mask) && (RingQueueMatch(&_FlagQueue,(pRQTYPE)_Flags[i].pBuf,_Flags[i].len) >= 0)){RingQueueClear(&_FlagQueue);pFlag = &_Flags[i];break;}}// 如果没有发现标志串,检查下有没满了,满了就Flushif(pFlag == NULL){if(_isRxBufFull()){_state.isFull = 1;_flush(_pRxMac,NULL);}return;}// 这4种标志串要_flush掉前面的东西if(pFlag->option & FLAGMASK_USUHSH){_pCur -= pFlag->len;_flush(_pRxMac,NULL);_pHorU = pFlag;}// 如果是帧头的处理if(pFlag->option & (FLAG_OPTION_STRONG_HEADER | FLAG_OPTION_HEADER)){#if(RXMAC_NOTFILL_EN == TRUE)if(!(pFlag->option & FLAG_OPTION_NOTFILL_HEADER))
#endif_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);_state.headerFound = 1;if(_onGetHeader != NULL)_onGetHeader(_pRxMac,pFlag);return;}// 如果是Unique的处理if(pFlag->option & (FLAG_OPTION_STRONG_UNIQUE | FLAG_OPTION_UNIQUE)){_state.uniqueFound = 1;_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);_flush(_pRxMac,NULL);}else{ // 能到这里说明是帧尾_state.enderFound = 1;
#if(RXMAC_NOTFILL_EN == TRUE)if(pFlag->option & FLAG_OPTION_NOTFILL_ENDER)_pCur -= pFlag->len;
#endif_flush(_pRxMac,pFlag);}return;
}
/*
*********************************************************************************************************
* RxMac_ResetRxSize()
*
* Description : reset the size of RxBuf to the max size. 重置接收缓冲区
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
* RXMAC_ERR_INIT if RxMac hasn't inited or any error in initialization
* Note(s) :
*********************************************************************************************************
*/
INT8U RxMac_ResetRxSize(pRX_MAC pRxMac){int size;
#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endifsize = _FlagQueue.RingBuf - _pRxBuf;
#if(RXMAC_ARGUMENT_CHECK_EN)if(size < 0)return RXMAC_ERR_INIT;
#endif_RxBufSize = (INT16U)size;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_SetRxSize()
*
* Description : set the size of RxBuf to the max size. 重置接收缓冲区
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* size the size to set;
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
* RXMAC_ERR_ARGUMENT if size is wrong.
* Note(s) : the size shouldn't be bigger than the initial value, and should bigger than
* the current number of chars in the RxBuf.
*
*********************************************************************************************************
*/
INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size){#if(RXMAC_ARGUMENT_CHECK_EN)#if (!RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;#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. 重置接收机的状态
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
* Note(s) : it will not trigger call-back of onFlush.
*********************************************************************************************************
*/
INT8U RxMac_ResetState(pRX_MAC pRxMac){#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endif// 复位接收机RingQueueClear(&_FlagQueue);_pCur = _pRxBuf;_stateByte = 0;_pHorU = NULL;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*********************************************************************************************************
*/
INT8U RxMac_Flush(pRX_MAC pRxMac){#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endif_flush(_pRxMac,NULL);return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* onFeeded the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded){#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endif_onFeeded = onFeeded;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* onGetHeader the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader){#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endif_onGetHeader = onGetHeader;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
* onFlushed the callback function to set; 要设置的回调函数
*
* Return : RXMAC_ERR_NONE if Success;
* RXMAC_ERR_POINTERNULL if pRxMac == NULL
*
* Note(s) :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed){#if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)if(_pRxMac == NULL)return RXMAC_ERR_POINTERNULL;
#endif_onFlushed = onFlushed;return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
* LOCAL FUNCITON
*********************************************************************************************************
*/
static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n){pRB_BYTE p = dest;while(n-- > 0)*p++ = *src++;return dest;
}static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len){_memcpy(_pCur,pBuf,len);_pCur += len;
}static void _flush(pRX_MAC pRxMac,pRX_FLAG ender){// 触发回调if(_pCur-_pRxBuf > 0 && _onFlushed != NULL)_onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender);// 复位接收机_pCur = _pRxBuf;_stateByte = 0;_pHorU = NULL;
}
测试/示例代码
/*
*********************************************************************************************************
* uC/OS-II
* The Real-Time Kernel
* Framework
*
* By : Lin Shijun
* Note: This is a framework for uCos-ii project with only S12CPU, none float, banked memory model.
* You can use this framework with same modification as the start point of your project.
* I've removed the os_probe module,since I thought it useless in most case.
* This framework is adapted from the official release.
*********************************************************************************************************
*/#include "includes.h"
#include "SCI_def.h"
#include "RxMac.h"
/*
*********************************************************************************************************
* STACK SPACE DECLARATION
*********************************************************************************************************
*/
static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];/*
*********************************************************************************************************
* TASK FUNCTION DECLARATION
*********************************************************************************************************
*/static void AppTaskStart(void *p_arg);/*
*********************************************************************************************************
* CALLBACK FUNCITON
*********************************************************************************************************
*/
void onGetData(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt){// 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytesCnt来判断当前位置RxMac_SetOnFeeded(sender,NULL);if(*pCurChar > '0' && *pCurChar <= '9' ){// bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);}
}
void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){SCI_PutCharsB(SCI0,"\nFlushed:",9,0);if(state.headerFound)SCI_PutCharsB(SCI0,"headerFound,",12,0);if(state.enderFound)SCI_PutCharsB(SCI0,"enderFound,",11,0);if(state.isFull)SCI_PutCharsB(SCI0,"full,",5,0);if(state.uniqueFound)SCI_PutCharsB(SCI0,"unique,",7,0);SCI_PutCharsB(SCI0,"\nDatas:",7,0);SCI_PutCharsB(SCI0,pBuf,len,0);SCI_PutCharsB(SCI0,"\n",1,0);RxMac_ResetRxSize(sender);
}
void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);SCI_PutCharsB(SCI0,"\n",1,0);
}
void onGetHeader2(pRX_MAC sender,pRX_FLAG pFlag){SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);SCI_PutCharsB(SCI0,"\n",1,0);RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
* FLAGS
*********************************************************************************************************
*/
RX_MAC _rxmac;
#define BUF_SIZE 20
INT8U buffer[BUF_SIZE];
RX_FLAG flags[4];// 协议示例1:
// 帧头 :HEADER 或者 START
// 强帧尾 :END
// 强特殊串:12345
//
static void protocol1_init(){RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);RxMac_Init(&_rxmac,flags,4,6,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
}
// 协议示例2:
// 帧头 : START
// 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾
// 帧尾 : END
// 特殊串: NOW
//
static void protocol2_init(){RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);RxMac_Init(&_rxmac,flags,3,5,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
}/*
*********************************************************************************************************
* MAIN FUNCTION
*********************************************************************************************************
*/void main(void) {INT8U err; BSP_IntDisAll(); /* Disable ALL interrupts to the interrupt controller */OSInit(); /* Initialize uC/OS-II */err = OSTaskCreate(AppTaskStart,NULL,(OS_STK *)&AppTaskStartStk[APP_TASK_START_STK_SIZE - 1],APP_TASK_START_PRIO); OSStart();
}static void AppTaskStart (void *p_arg)
{INT8U c,err;(void)p_arg; /* Prevent compiler warning */BSP_Init(); SCI_Init(SCI0);SCI_EnableTrans(SCI0);SCI_EnableRecv(SCI0);SCI_EnableRxInt(SCI0);SCI_BufferInit();// 选择想要实验的协议来初始化protocol1_init();//protocol2_init();while (DEF_TRUE) {// 获取下一个字符c = SCI_GetCharB(SCI0,0,&err);// 回显SCI_PutCharB(SCI0,c,0);// 喂给接收机RxMac_FeedData(&_rxmac,c);}
}
后记
此模块已经通过单元测试,但难保不会有一些未发现的bug,如果使用中发现任何问题或者有任何建议意见请立刻联系我,谢谢。
更新历史
2018/05/29 V1.0
2019/03/07 V2.1
[嵌入式开发模块]通用接收状态机模块相关推荐
- 计算机抄作通用模块,通用命令行模块的设计及实现
摘要: 自从上个世纪八十年代以来,图形用户界面得到快速发展,计算机逐渐进入各类企业,家庭,其应用得到广泛的推广.对比起命令行界面来说,图形界面在交互性上有着不可比拟的优势.但在一些需要执行大量重复性工 ...
- 细数嵌入式开发与通用系统开发的不同
嵌入式开发指在嵌入式操作系统下进行开发,包括在系统化设计指导下的硬件和软件以及综合研发.而通用系统开发则是指在具有有多道批处理.分时.实时处理功能中的两种及以上功能的操作系统中进行开发. 与通用系统相 ...
- 第一次发文-汽车数字液晶仪表盘制作-嵌入式开发板-qt-linux-can总线-mcp2515模块-汽车obd
各位客官老爷们大家好,这是我第一次申请公众号,也是第一次发文章,本着分享与求知的心态,记录一下自己开发汽车obd数字仪表盘的过程,能对别人有一丝的帮助,那是最好不过的,如果没有,也求拍砖与批评指导,对 ...
- [嵌入式开发模块]JY61姿态角度传感器 驱动模块
文章目录 前言 JY61简介 概述 通信协议 驱动文件 JY61Driver.h JY61Recver.c JY61Cmder.c 依赖 使用示例 更新历史 前言 干活中用到了JY61姿态角度传感器, ...
- [嵌入式开发模块]SHT30/20 温湿度传感器 驱动模块
文章目录 前言 SHT30简介 概述 通信协议 驱动文件 SHT30Driver.h SHT30Recver.c SHT30Cmder.c 依赖 使用示例 更新历史 前言 干活中用到了SHT30,其实 ...
- excel进销存管理系统_通用Excel助力企业定制开发信息化系统常用功能模块
信息化成为现代企业管理的趋势,而企业管理系统则是推动这一趋势发展的重要载体.那么什么是企业管理系统呢?企业管理系统都有那些呢? 通用Excel助力企业定制开发信息化系统常用功能模块 企业管理系统,是指 ...
- Winform开发框架之通用高级查询模块--SNF快速开发平台3.3-Spring.Net.Framework
最近项目确实忙,但也是一直忙于有关项目和框架技术的事情,也一直致力于改善我的WInform开发框架.使得自己及客户使用起来更加方便,更加友好,更加高效. 在很多程序模块中都很常见,也是给客户扩展查询的 ...
- 2021物联网国赛Lora模块通用库开发——A卷
2021物联网国赛Lora模块通用库开发--A卷 1:声明全局变量和导入本次所使用到的包 #include "hal_oled.h" int Stat_key=0; //记录按键次 ...
- c语言数组实现环形缓冲区,[嵌入式开发模块]环形缓冲区/循环队列 C语言实现
忙着毕设,很久没有写文章了,终于答辩完了,得了个校优秀毕业设计.毕设做的是个智能接口模块,用一周时间入门了,MC9S12XEP100的开发,又用一周时间入门了uC/OS-II嵌入式操作系统,在做毕设的 ...
最新文章
- java接口多实现super_Java 8:自动合成多个接口的默认方法
- 关于JS数组API的总结
- Html标签带来的安全隐患
- android 去空字符串,android – TextUtils.isEmpty()方法为空字符串返回false
- js基础总结性能优化
- 特殊类型结构--枚举
- 深度学习——loss函数的学习笔记(legacy)
- 破解版超级数据恢复软件-内含已破解注册码
- php md5校验工具下载,md5校验工具下载_md5校验工具下载「最新|免费」-太平洋下载中心...
- 如何才能更好发挥WinRunner,实现真正的自动化测试
- 解决visual studio安装Dev后不显示控件或控件灰色不可用
- BlueCoat被私募股权公司收购
- mysql 1556_mysqldump: Got error: 1556: You can't use locks with log tables.解决办法
- LeetCode 848. Shifting Letters
- 广告术语(持续更新...)
- ZYNQ产品生产拷机问题思考
- 手把手教你快速入门 APP 的开发
- latex 参考文献显示问号_如何自学latex软件
- G1D33-BTG复现重跑实验
- 特征值是否重根与特征向量及基础解系的关系
热门文章
- 浅谈游戏中的2D/3D换装
- 新零售mysql设计(购物券表 客户关联购物券表)二次修改
- 6-1 简单实现x的n次方 (7 分)
- Mcgs跟转接小板(用电脑模拟)收发数据(通过Modbus Tcp协议)
- Go-AES算法详解与代码
- C语言设圆半径r=1.5,圆柱高h=3,求圆周长、圆面积、圆球表面积、圆球体积、圆柱体积。用scanf输人数据,输出计算结果,输出时要求有文字说明,取小数点后2位数字。
- STC8单片机驱动DDS信号发生器AD9850扫频
- 计算机社团动员大会发言稿,学生社团总结会讲话稿
- 免费快递查询接口不限量对接
- 小米手机已经没落,炒作把市场注入了期货有害思想