0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式开发模块指南:通用接收状态机模块

技术让梦想更伟大 来源:CSDN-夏日白云 2023-03-28 09:28 次阅读

前言

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

模块相关概念和逻辑

接收机状态

接收机有两个基本状态:

状态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也会起作用,其他行为与特殊序列一样

对应模块中的结构体为:

//receiveflag
typedefstructRXFLAG_STRUCT{
uint8_tconst*pBuf;
uint8_tlen;
uint8_toption;
}RXFLAG_STRUCT;
typedefRXFLAG_STRUCTconst*RxFlag;
1234567

一般的流程中,初始化接收机前,用户需要准备好接收机使用的所有标志序列,标志好每个序列的类型。模块提供宏函数以抽象这个过程:

//voidRxFlag_Init(RXFLAG_STRUCT*flag,uint8_tconst*buf,uint8_tlen,uint8_topt);
//toinitializeareceiveflag
//flagpointtothetargetRXFLAG_STRUCT.
//bufpointertotheflagbuffer
//sizesizeofflag
//optseeRXFLAG_OPTION_XXXXX,bitmode
#defineRxFlag_Init(flag,buf,size,opt)
{(flag)->pBuf=(buf);(flag)->len=(size);(flag)->option=(opt);}

flush

每当接收机根据标志字符序列找到一个完整或不完整的数据包时,接收机会进行回调以通知用户处理这个数据包,这个行为被称为flush,这个回调函数叫做onFlushed。

此函数的原型如下

typedefvoid(*RXMAC_FLUSH_EVENT)(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,
RxFlagHorU,RxFlagEnder);

整个数据包为buf指向的长度为len的区域。

数据包的状态可以通过state参数得知,RX_STATE 的类型定义如下

typedefstructRXSTATE_STRUCT{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RxState;

通过判断每个标志位是否置1,可以得知当前数据包的状态。
如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头
如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾
如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。
如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列

接收机类

V1.0版本中要求用户自己分配结构体的空间,为了更加面向对象,现已改为动态分配,而把具体结构体和对应方法封装在模块内部。

typedefstructRXMAC_STRUCT*RxMac;

模块提供Create函数来创建接收机实例并返回指向实例的指针。

//tocreateaninstanceofRxMac
//flags标志字符串结构体的数组
//flagsCnt标志字符串结构体的个数
//buf用户提供给接收机用的缓冲区
//bufLen缓冲区的大小(起码应该要能放的下最长的标志字符串)
//onFeeded在每次被Feed时触发
//onGetHeader获得头标志位时触发。
//onFlushed收到一帧数据时的回调函数
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,
RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed);

调用实例的方法时把这个指针作为第一个参数以模拟面向对象操作。

过滤器

接收机每次被feed时,都会触发onFeeded事件(可以在配置中取消这个事件以节省点代码)。原型如下:

typedefvoid(*RXMAC_FILTER)(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);

pCurChar :指向接收区中刚收到的字符
bytesCnt :这个字符是接收区中的第几个字符

此时,接收机已经将其放入接收区但是还没进一步进行判断,用户可以修改字符/配置接收机以改变接收机的行为,比如将收到的字母全变为小写。或者根据收到的数据来决定还要收多少数据。

onGetHeader事件

当找到任意帧头时会触发。

接收机运行逻辑

接收机的运作逻辑如下:

6fb489b2-ccde-11ed-bfe3-dac502259ad0.pngimg

边际条件

标志序列尽量不要有重合,如果同时可能匹配两个标志序列,最终行为是未定义的,不保证正确执行,最终结果可能与标志序列的位置以及类型有关系。

同一个标志串可以同时是多种类型,比如同时是帧头与帧尾,但要小心类型间不要有冲突,否则不保证正确执行。

对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况:
如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。
如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。
帧尾不会发生这种边际条件。

相关代码

此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。
[嵌入式开发模块]环形缓冲区/循环队列 C语言实现

接收机代码

RxMac.h

/*
*******************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收状态机
*
*File:RxMac.h
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:2018/05/291.0theprototype
*2019/01/232.0modifythetypenamestomorereadableones,thoughpreserve
*theold-styleforforwardcompatibility;
*changeinitmethodtocreatemethodwhichusemalloctoalloc
*instance,andthecorrespondingdestroymethod.
*changetheinternalbuffermodulefromRINGQUEUEtoBufferArray,
*sousernolongerneedtoknowtheinternalflagsmanagementand
*allocatethespaceforit.
*addRxMac_FeedDatasmethodforconvenient.
*2019/03/072.1somemodificationtothemallocconfiguration
*
*NOTE(s):1.thereceiveprocesshastwobasicstate
*A.preRx:whenhaven'tfoundanyheader,theRxMacwillsearchfortheunique
*flag,headerandstrong-ender.Onlywhenaheaderisfoundwillcome
*tonextstep.
*B.Rxing:theRxMacwillputthesuccessivebytesintothebuffer,andsearch
*forthestrong-unique,strong-header,ender.
*2.themoduleisdrivedbytheRxMac_FeedData(),usershouldgetthethechar
*fromdatastreamandpassthedataonebyonetotheRxMacthroughRxMac_FeedData()
*orRxMac_FeedDatas().
*3.eachtimeRxMacfindaframe(completeorincomplete),itwillcalltheonFlushed
*tonotifytheresults;usercanjudgetheframethroughthestateparameter;
*state.headerFound==1:findanyheader,theheaderispassedbyHorU
*state.enderFound==1:findanyender,theenderispassedbyEnder
*state.isFull==1:thebufferisfull,maybeyoushouldcheckheaderFound
*toseewhetheraheaderhasbeenfound.
*state.uniqueFound==1:findanyuniqueflag.Inthiscase,otherparameterswill
*alwaysbe0,thedatainthebufferwillbetheflag,
*andtheuniqueflagispassedbyHorU.
*4.Tousethismodule,foreachreceivemachine:
*A.definemalloctoconfigurethemodule,seeCONFIGURATION
*B.allocatethespaceforbufferandFLAGS.
*RXFLAG_STRUCTflags[2];
*uint8_tbuf[300];
*C.settheflagsaccordingtotheprotocol,definethecallbackfunctions
*accordingtoyourneed.
*staticvoidonGetHeader(RxMacsender,RxFlagpFlag){......};
*staticvoidonFlushed(RxMacsender,RxMacPtrpBuf,uint16_tlen,
*RxStatestate,RxFlagHorU,RxFlagEnder){......};
*constuint8_tHeaderFlag[]="Header";
*constuint8_tEnderFlag[]="
";
*RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER);
*RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER|
*RXFLAG_OPTION_NOTFILL_ENDER);
*D.createthereceivemachine:
*RxMacmac;
*mac=RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL,
*onGetHeader,onFlushed);
*E.feedthereceivemachine:
*while(1){
*c=GetNextChar();
*RxMac_FeedData(mac,c);
*}
*F.destroythereceivemachineifneed.
*RxMac_Destroy(mac);
*******************************************************************************************
*/

#ifndefRX_MAC_H
#defineRX_MAC_H

/*
*******************************************************************************************
*INCLUDES
*******************************************************************************************
*/

#include

/*
*******************************************************************************************
*CONFIGURATION配置
*******************************************************************************************
*/
//#defineRXMAC_ARGUMENT_CHECK_DISABLEtodisabletheargumentcheckfunctionsofthismodule
//#defineRXMAC_ARGUMENT_CHECK_DISABLE

//#defineRXMAC_NOTFILL_DISABLEtodisablethenotFilloption
//#defineRXMAC_NOTFILL_DISABLE

//#defineRXMAC_ONFEEDED_DISABLEtodisabletheonFeededevent.
//#defineRXMAC_ONFEEDED_DISABLE

//#defineRXMAC_SINGLETON_ENtousesingletonpattern,soargumentpRxMacofinterfacesis
//useless,anduserdon'tneedtoallocatespaceforRX_MAC,butyoustillneedtoallocate
//bufferandcallinit();
//#defineRXMAC_SINGLETON_EN

//#defineRXMAC_BUF_RPAGEifyouwantreceivemachineusethepagedarrayasbuffer.
//anddon'tforgettodefineCODEWARRIORmalloc
//#defineRXMAC_BUF_RPAGE
/*
*******************************************************************************************
*ADDRESSINGMODE寻址模式
*******************************************************************************************
*/

#ifdefRXMAC_BUF_RPAGE
#ifdefCODEWARRIOR
#defineRXMAC_BUF_ADDRESSING_MODE__rptr
#endif
#endif

#ifndefRXMAC_BUF_ADDRESSING_MODE
#defineRXMAC_BUF_ADDRESSING_MODE
#endif
typedefuint8_t*RXMAC_BUF_ADDRESSING_MODERxMacPtr;

/*
*********************************************************************************************
*ERRORCODE
*********************************************************************************************
*/

#defineRXMAC_ERR_NONE0
#defineRXMAC_ERR_ARGUMENT1
#defineRXMAC_ERR_POINTERNULL2
#defineRXMAC_ERR_UNKNOWN3
#defineRXMAC_ERR_INIT4

/*
*********************************************************************************************
*RECEIVEFLAGSTRUCT
*********************************************************************************************
*/

//normalheader,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTION_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_HEADER0x03
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineRXFLAG_OPTION_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineRXFLAG_OPTION_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_ENDER0x18
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineRXFLAG_OPTION_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTION_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_UNIQUE0xC0

//receiveflag
typedefstructRXFLAG_STRUCT{
uint8_tconst*pBuf;
uint8_tlen;
uint8_toption;
}RXFLAG_STRUCT;
typedefRXFLAG_STRUCTconst*RxFlag;

//voidRxFlag_Init(RXFLAG_STRUCT*flag,uint8_tconst*buf,uint8_tlen,uint8_topt);
//toinitializeareceiveflag
//flagpointtothetargetRXFLAG_STRUCT.
//bufpointertotheflagbuffer
//sizesizeofflag
//optseeRXFLAG_OPTION_XXXXX,bitmode
#defineRxFlag_Init(flag,buf,size,opt)
{(flag)->pBuf=(buf);(flag)->len=(size);(flag)->option=(opt);}


/*
*********************************************************************************************
*TYPEDEFINITION
*********************************************************************************************
*/

typedefstructRXSTATE_STRUCT{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RxState;

typedefstructRXMAC_STRUCT*RxMac;

typedefvoid(*RXMAC_FLUSH_EVENT)(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,
RxFlagHorU,RxFlagEnder);
typedefvoid(*RXMAC_FLAG_EVENT)(RxMacsender,RxFlagflag);
typedefvoid(*RXMAC_FILTER)(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);

/*
*******************************************************************************************
*FUNCTIONDECLARATION
*******************************************************************************************
*/

//tocreateaninstanceofRxMac
//flags标志字符串结构体的数组
//flagsCnt标志字符串结构体的个数
//buf用户提供给接收机用的缓冲区
//bufLen缓冲区的大小(起码应该要能放的下最长的标志字符串)
//onFeeded在每次被Feed时触发
//onGetHeader获得头标志位时触发。
//onFlushed收到一帧数据时的回调函数
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed);
//todestroytheRxMac
voidRxMac_Destroy(RxMacmac);
//向接收机内喂字节
voidRxMac_FeedDatas(RxMacmac,uint8_tconst*buf,uint16_tlen);
voidRxMac_FeedData(RxMacmac,uint8_tc);
//重置接收区长度为最长那个长度
//uint8_tRxMac_ResetRxSize(RxMacmac);
//设置最大接收到多少个字节
uint8_tRxMac_SetRxSize(RxMacmac,uint16_tsize);
//重置接收机的状态
uint8_tRxMac_ResetState(RxMacmac);
//强制接收机flush
uint8_tRxMac_Flush(RxMacmac);
//设置onFeeded
uint8_tRxMac_SetOnFeeded(RxMacmac,RXMAC_FILTERonFeeded);
//设置onGetHeader
uint8_tRxMac_SetOnGetHeader(RxMacmac,RXMAC_FLAG_EVENTonGetHeader);
//设置onFlushed
uint8_tRxMac_SetOnFlushed(RxMacmac,RXMAC_FLUSH_EVENTonFlushed);

#include"RxMacPrivate.h"

#endif//ofRX_MAC_H

RxMacPrivate.h

/*
*******************************************************************************************
*
*
*PrivateDeclarationsforUniversalReceiveStateMachine
*
*File:RxMacPrivate.h
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:
*NOTE(s):
*******************************************************************************************
*/


/*
*******************************************************************************************
*FUNCTIONDECLARATION
*******************************************************************************************
*/
//打印内部缓冲区,返回缓冲区的长度
uint16_t_RxMac_printBuffer(RxMacmac,uint8_t*buf);

/*
*******************************************************************************************
*RECEIVEFLAGSTRUCT
*******************************************************************************************
*/

//structofRXFLAG_STRUCT.option
/*typedefstructRXFLAG_OPTION{
unsignedintisHeader:1;//1:theflagistheheadoftheframe
unsignedintstrong_H:1;//1:strong-header,RxMacwill
unsignedintnotfill_H:1;//0:filltheflagintothebufferwhenfoundasheader
unsignedintisEnder:1;//1:theflagistheendoftheframe
unsignedintstrong_E:1;//
unsignedintnotfill_E:1;//0:filltheflagintothebufferwhenfoundasender
unsignedintisUnique:1;//1:theflagisauniqueflagwhichistreatedassingleframe.
unsignedintstrong_U:1;//0:whenreceivingaframe,RxMacwillnot
};//*/
//normalheader,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTBIT_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_HEADER0x02
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineRXFLAG_OPTBIT_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineRXFLAG_OPTBIT_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_ENDER0x10
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineRXFLAG_OPTBIT_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTBIT_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_UNIQUE0x80

#defineSTATEMASK_STEPA
(RXFLAG_OPTBIT_HEADER|RXFLAG_OPTBIT_UNIQUE|RXFLAG_OPTBIT_STRONG_ENDER)
#defineSTATEMASK_STEPB
(RXFLAG_OPTBIT_STRONG_UNIQUE|RXFLAG_OPTBIT_ENDER|RXFLAG_OPTBIT_STRONG_HEADER)
#defineRXFLAGMASK_USUHSH
(RXFLAG_OPTBIT_HEADER|RXFLAG_OPTBIT_STRONG_HEADER|
RXFLAG_OPTBIT_UNIQUE|RXFLAG_OPTBIT_STRONG_UNIQUE)

//BOOL_RxFlag_isHeader(RxFlagflag);
#define_RxFlag_isHeader(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_HEADER|RXFLAG_OPTION_HEADER))
//BOOL_RxFlag_isEnder(RxFlagflag);
#define_RxFlag_isEnder(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_ENDER|RXFLAG_OPTION_ENDER))
//BOOL_RxFlag_isUnique(RxFlagflag);
#define_RxFlag_isUnique(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_UNIQUE|RXFLAG_OPTION_UNIQUE))
//BOOL_RxFlag_dontFillHeader(RxFlagflag);
#define_RxFlag_dontFillHeader(flag)
((flag)->option&RXFLAG_OPTBIT_NOTFILL_HEADER)
//BOOL_RxFlag_dontFillEnder(RxFlagflag);
#define_RxFlag_dontFillEnder(flag)
((flag)->option&RXFLAG_OPTBIT_NOTFILL_ENDER)

/*
*******************************************************************************************
*FORWARDCOMPATIBILITY
*******************************************************************************************
*/
//以下仅为前向兼容
typedefRxMacPtrpRB_BYTE;
typedefRXFLAG_STRUCTRX_FLAG,*pRX_FLAG;
typedefRxMacpRX_MAC;
typedefRxStateRX_STATE;
#defineFLAG_OPTION_HEADERRXFLAG_OPTION_HEADER
#defineFLAG_OPTION_STRONG_HEADERRXFLAG_OPTION_STRONG_HEADER
#defineFLAG_OPTION_NOTFILL_HEADERRXFLAG_OPTION_NOTFILL_HEADER
#defineFLAG_OPTION_ENDERRXFLAG_OPTION_ENDER
#defineFLAG_OPTION_STRONG_ENDERRXFLAG_OPTION_STRONG_ENDER
#defineFLAG_OPTION_NOTFILL_ENDERRXFLAG_OPTION_NOTFILL_ENDER
#defineFLAG_OPTION_UNIQUERXFLAG_OPTION_UNIQUE
#defineFLAG_OPTION_STRONG_UNIQUERXFLAG_OPTION_STRONG_UNIQUE
#defineRX_FLAG_INITRxFlag_Init

RxMac.c

/*
*******************************************************************************************
*
*
*ImplementationoftheUniversalReceiveStateMachine
*通用接收状态机
*
*File:RxMac.c
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:2018/05/291.0theprototype
*2019/01/232.0InadditiontothecontentinRxMac.h:
*abstracttheflagmanagementpartasRxFlagMgrandthe
*correspondingmethods.
*refactorthecode.
*2019/03/072.1somemodificationtothemallocconfiguration
*NOTE(s):
*
*******************************************************************************************
*/

/*
*******************************************************************************************
*INCLUDES
*******************************************************************************************
*/
#include
#include
#include
#include"RxMac.h"
#include"BufferMallocArray.h"

/*
*******************************************************************************************
*RECEIVEFLAGSMANAGER
*******************************************************************************************
*/

typedefstructRXFLAGMGR_STRUCT{
//buffertoholdthepre-datawhichhasn'tmatchedanyflag.
BufferUINT8IndexedBufForFlag;
//theflagarraytobematched.
RxFlagFlags;
//countofflags.
uint8_tFlagsCnt;
//currentstate,inwhichheaderFoundwillinfluencethematchbehavior.
//controlledbythechildclass.
RxStatestate;
}RXFLAGMGR_STRUCT;

staticRxFlag_RxFlagMgr_GetNextMatchedAtThisState(RxMacmac,uint8_tnextByte);
staticBOOL_RxFlagMgr_Init(RxMacmac,RxFlagflags,uint8_tflagsCnt,uint8_tmaxLen);
staticvoid_RxFlagMgr_Destroy(RxMacmac);
staticvoid_RxFlagMgr_Reset(RxMacmac);

/*
*******************************************************************************************
*STRUCTDIFINITION
*******************************************************************************************
*/

typedefstructRXMAC_STRUCT{
//managetheflagmatches.
RXFLAGMGR_STRUCTFlagMgr;
//recordtheHeaderorUniqueflag.
RxFlagpHorU;
//internalbuffertoholddata.
RxMacPtrpRxBuf;
//lengthoftheinternalbuffer
uint16_tRxBufSize;
//Countofthebytesintheinternalbuffer/theindexfornextfeededbyte
uint16_tRxCnt;
RXMAC_FILTERonFeeded;
RXMAC_FLAG_EVENTonGetHeader;
RXMAC_FLUSH_EVENTonFlushed;
}RXMAC_STRUCT;

/*
*******************************************************************************************
*LOCALFUNCITONDECLARATION
*******************************************************************************************
*/
#ifndefRXMAC_SINGLETON_EN
#define_pMacmac
#define_BufForFlag(_pMac->FlagMgr.BufForFlag)
#define_Flags(_pMac->FlagMgr.Flags)
#define_FlagsCnt(_pMac->FlagMgr.FlagsCnt)
#define_state(_pMac->FlagMgr.state)
#define_pHorU(_pMac->pHorU)
#define_pRxBuf(_pMac->pRxBuf)
#define_RxBufSize(_pMac->RxBufSize)
#define_RxCnt(_pMac->RxCnt)
#define_fonFeeded(_pMac->onFeeded)
#define_fonGetHeader(_pMac->onGetHeader)
#define_fonFlushed(_pMac->onFlushed)
#define_RxMac_Destroy()(free(mac))
#else
staticRXMAC_STRUCT_mac;
//单例模式中,这个指针用于标识是否单例已初始化过
staticRxMac_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)

#ifndefRXMAC_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
#ifdefRXMAC_ARGUMENT_CHECK_DISABLE
#define_DONT_CHECK_MAC
#endif
#ifdefRXMAC_SINGLETON_EN
#define_DONT_CHECK_MAC
#endif

#ifdef_DONT_CHECK_MAC
#define_checkMacNotNull()
#define_checkMacNotNull_void()
#else
#define_checkMacNotNull()if(_pMac==NULL)returnRXMAC_ERR_POINTERNULL;
#define_checkMacNotNull_void()if(_pMac==NULL)return;
#endif


#ifdefRXMAC_BUF_RPAGE
#ifdefCODEWARRIOR
staticRxMacPtr_memcpy_internal(RxMacPtrdest,RxMacPtrsrc,size_tn);
#definememcpy(dest,src,n)_memcpy_internal(dest,src,n)
#endif
#endif
//冲刷缓冲区
staticvoid_flush(RxMacmac,RxFlagender);
//往接收机缓冲区内放数据
staticvoid_BufIn(RxMacmac,RxMacPtrbuf,uint16_tlen);

staticvoid_RxMac_FlushIfFull(RxMacmac);
staticvoid_RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetHeaderProcess(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetUniqueProcess(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetEnderProcess(RxMacmac,RxFlagflagJustGot);
/*
*******************************************************************************************
*RxMac_Create()
*
*Description:Tocreateareceivemachineinstance.创建一个接收机实例
*
*Arguments:flagspointertotheflags(anarray);指向标志串(数组)的指针
*flagsCntthecountoftheflags;有多少个标志串;
*bufpointertothebufferprovidedtotheRxMac;提供给接收机使用的缓存
*bufLenthesizeofthebuffer.缓存的大小
*onFeededthecallbackfuncthatwillbecalledeverytimefeeded,you
*canmodifythefeededbyteinthiscallback.
*每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
*onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader.
*当发现帧头时会调用的回调函数
*onFlushedthecallbackfuncthatwillbecalledwhenflushed.
*当Flush时会调用的回调函数
*
*Return:Pointertothecreatedinstance.
*NULLifanyerror.
*
*Note(s):1.sizeofbuffershouldbiggerthanthelongestflag,ortheflagwillbe
*useless.
*2.ifflagsCnt>0,flagscan'tpointtoNULL.
*3.youmustprovideabuffer.
*4.ifyouenabletheRXMAC_SINGLETON_EN,multi-createwillpointertothe
*sameinstanceinitializedasthelastcreate.
*
*voidonGetHeader(RxMacsender,RxFlagflag):
*senderthepointertotheRxMacwhichcallthisfunction
*flagtheheadermatched
*
*voidonFeeded(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt):
*senderthepointertotheRxMacwhichcallthisfunction
*pCurCharpointtothebytejustreceived,youcanchangeitbeforeanyotherprocess.
*bytesCntthenumberofbytesinthebufferincludingthecharjustfeeded.
*
*voidonFlushed(RxMacsender,RxMacPtrpBuf,uint16_tlen,RxStatestate,RxFlagHorU,
*RxFlagEnder);
*senderthepointertotheRxMacwhichcallthisfunction
*bufthepointertotheframe.
*lenthelengthofframe.
*statethestateofframe.
*HorUpointtotheheaderflagifstate.headerFound==1,oruniqueflagif
*state.uniqueFound==1.
*Enderpointtotheenderflagifstate.enderFound==1.
*******************************************************************************************
*/
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed){
uint8_ti,maxLen=0;
#ifndefRXMAC_SINGLETON_EN
RxMacmac;
#endif
#ifndefRXMAC_ARGUMENT_CHECK_DISABLE
if((flags==NULL&&flagsCnt>0)||buf==NULL)
returnNULL;
#endif
//findoutthemaxlengthofflags.
for(i=0;i< flagsCnt; i++){
    if(flags[i].len >maxLen)
maxLen=flags[i].len;
}
#ifndefRXMAC_ARGUMENT_CHECK_DISABLE
if(bufLen< maxLen){
    return NULL;
  }
#endif
#ifdef RXMAC_SINGLETON_EN
  if(_pMac != NULL)            // if have created one instance, free the previous FlagBuf
    _RxFlagMgr_Destroy(&_mac);
  else
    _pMac = &_mac;
#else
  if((mac = (RxMac)malloc(sizeof(RXMAC_STRUCT))) == NULL){
    return NULL;
  }
#endif
  if(!_RxFlagMgr_Init(_pMac,flags,flagsCnt,maxLen)){
    _RxMac_Destroy();
    return NULL;
  }
  _pHorU = NULL;
  _pRxBuf = buf;
  _RxCnt = 0;
  _RxBufSize = bufLen;
  _fonFeeded = onFeeded;
  _fonGetHeader = onGetHeader;
  _fonFlushed = onFlushed;
  return _pMac;
}
/*
*******************************************************************************************
*                                        RxMac_Destroy()
*
* Description : Destroy a receive machine instance.
*
* Arguments   : mac     the target receive machine.     目标接收机
*
* Return      : 
*
* Note(s)     : 
*
*******************************************************************************************
*/
void RxMac_Destroy(RxMac mac){
  if(_pMac == NULL)
    return;
  _RxFlagMgr_Destroy(mac);
  _RxMac_Destroy();
}
/*
*******************************************************************************************
*                                        RxMac_FeedData(s)
*
* Description : To feed RxMac the next char(s).    用于给接收机下一个字符
*
* Arguments   : mac    the target receive machine.     目标接收机
*               c      the char to feed;               下一个字符
*
* Return      : 
*
* Note(s)     : 
*******************************************************************************************
*/

void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len){
  uint16_t i;
  for(i = 0; i < len; i++)
    RxMac_FeedData(mac,buf[i]);
}

void RxMac_FeedData(RxMac mac,uint8_t c){
  RxFlag curFlag;
  _checkMacNotNull_void();
  _onFeeded(&c,_RxCnt + 1);
  _pRxBuf[_RxCnt++] = c;
  curFlag = _RxFlagMgr_GetNextMatchedAtThisState(mac,c);
  if(curFlag == NULL){        // if no flag match
    _RxMac_FlushIfFull(mac);
    return;
  }
  _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(mac,curFlag);
  if(_RxFlag_isHeader(curFlag)){
    _RxMac_GetHeaderProcess(mac,curFlag);
  }else if(_RxFlag_isUnique(curFlag)){
    _RxMac_GetUniqueProcess(mac,curFlag);
  }else{   // if(_RxFlag_isEnder(curFlag))
    _RxMac_GetEnderProcess(mac,curFlag);
  }
}
/*
*******************************************************************************************
*                                        RxMac_SetRxSize()
*
* Description : set the size of RxBuf.   设置接收缓冲区的大小
*
* Arguments   : mac     the target receive machine.     目标接收机
*               size    the size to set;
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*               RXMAC_ERR_ARGUMENT        if size is wrong.
* Note(s)     : the size should bigger than the current number of chars in the RxBuf.
*               
*******************************************************************************************
*/
uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size){
  _checkMacNotNull();
#ifndef RXMAC_ARGUMENT_CHECK_DISABLE
  if(size <= _RxCnt)
    return RXMAC_ERR_ARGUMENT;
#endif
  _RxBufSize = size;
  return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
*                                        RxMac_ResetState()
*
* Description : reset the state of receive machine.   重置接收机的状态
*
* Arguments   : mac    the target receive machine.    目标接收机
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*******************************************************************************************
*/
uint8_t RxMac_ResetState(RxMac mac){
  _checkMacNotNull();
  // 复位接收机
  Buffer_Cleanup((Buffer)_BufForFlag);
  _RxCnt = 0;
  _stateByte = 0;
  _pHorU = NULL;
  return RXMAC_ERR_NONE;
}
/*
*******************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : mac     the target receive machine.     目标接收机
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*******************************************************************************************
*/

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

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

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

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

staticvoid_BufIn(RxMacmac,RxMacPtrbuf,uint16_tlen){
memcpy(_pRxBuf+_RxCnt,buf,len);
_RxCnt+=len;
}

staticvoid_flush(RxMacmac,RxFlagender){
//触发回调
if((_RxCnt>0||ender!=NULL)&&_fonFlushed!=NULL)
_fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender);
//复位接收机
_RxCnt=0;
_stateByte=0;
_pHorU=NULL;
}

BOOLBufferUINT8Indexed_BackMatch(BufferUINT8Indexedbuf,uint8_tconst*toMatch,uint16_tlen){
uint16_tcnt=_Buffer_getCount(buf);
if(len>cnt)
returnFALSE;
while(len>0){
if(_BufferUINT8Indexed_get(buf,--cnt)!=toMatch[--len])
returnFALSE;
}
returnTRUE;
}


staticvoid_RxMac_FlushIfFull(RxMacmac){
if(_isRxBufFull()){
_state.isFull=1;
_flush(_pMac,NULL);
}
}

staticvoid_RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMacmac,RxFlagflagJustGot){
if(flagJustGot->option&RXFLAGMASK_USUHSH){
if(_RxCnt>flagJustGot->len){
_RxCnt-=flagJustGot->len;
_flush(_pMac,NULL);
}else{
_RxCnt=0;
}
_pHorU=flagJustGot;
}
}

staticvoid_RxMac_GetHeaderProcess(RxMacmac,RxFlagflagJustGot){
#ifndefRXMAC_NOTFILL_DISABLE
if(!_RxFlag_dontFillHeader(flagJustGot))
#endif
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_state.headerFound=1;
_onGetHeader(flagJustGot);
_RxMac_FlushIfFull(mac);
}

staticvoid_RxMac_GetUniqueProcess(RxMacmac,RxFlagflagJustGot){
_state.uniqueFound=1;
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_flush(_pMac,NULL);
}

staticvoid_RxMac_GetEnderProcess(RxMacmac,RxFlagflagJustGot){
_state.enderFound=1;
if(_RxCnt< flagJustGot->len){//ifpartoftheflaghasbeenmanuallyflushed.
_RxCnt=0;//restorethebuffer.
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
}
#ifndefRXMAC_NOTFILL_DISABLE
if(_RxFlag_dontFillEnder(flagJustGot))
if(_RxCnt>flagJustGot->len)
_RxCnt-=flagJustGot->len;
else
_RxCnt=0;
#endif
_flush(_pMac,flagJustGot);
}

staticRxFlag_RxFlagMgr_GetNextMatchedAtThisState(RxMacmac,uint8_tnextByte){
uint8_ti,mask;
if(_Buffer_isFull(_BufForFlag))
BufferUINT8_FrontOut((BufferUINT8)_BufForFlag);
BufferUINT8_BackIn((BufferUINT8)_BufForFlag,nextByte);
//masktoidentifypossibleflag
mask=(_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
for(i=0;i< _FlagsCnt; i++){
    if((_Flags[i].option & mask) && 
      BufferUINT8Indexed_BackMatch(_BufForFlag,_Flags[i].pBuf,_Flags[i].len)){
        Buffer_Cleanup((Buffer)_BufForFlag);
        return &_Flags[i];
    }
  }
  return NULL;
}

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

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

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

测试/示例代码

已略去非必要代码

#include
#include"RxMac.h"

/*
*********************************************************************************************************
*LOCALFUNCTIONDECLARE
*********************************************************************************************************
*/

staticvoidonGetData(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);
staticvoidonFlushed(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,RxFlagHorU,RxFlagEnder);
staticvoidonGetHeader(RxMacsender,RxFlagflag);
staticvoidonGetHeader2(RxMacsender,RxFlagflag);

/*
*********************************************************************************************************
*LOVALVARIABLE
*********************************************************************************************************
*/
staticRxMacmac=NULL;
staticRXFLAG_STRUCTflags[4];
#defineBUF_SIZE20
staticuint8_tbuffer[BUF_SIZE];

//协议示例1:
//帧头:HEADER或者START
//强帧尾:END
//强特殊串:12345
//
staticvoidprotocol1_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
//
staticvoidprotocol2_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);
}
/*
*********************************************************************************************************
*CALLBACKFUNCITON
*********************************************************************************************************
*/

staticvoidonGetData(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt){
//因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据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] = '�';
  printf("
Flushed:");
  if(state.headerFound)
    printf("headerFound,");
  if(state.enderFound)
    printf("enderFound,");
  if(state.isFull)
    printf("full,");
  if(state.uniqueFound)
    printf("unique,");
  printf("
Datas:%s
",buf);
  RxMac_SetRxSize(sender,BUF_SIZE);
}
static void onGetHeader(RxMac sender,RxFlag flag){
  printf("
FoundHeader:%s
",flag->pBuf);
}
staticvoidonGetHeader2(RxMacsender,RxFlagflag){
printf("
FoundHeader:%s
",flag->pBuf);
RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
*MAINFUNCTION
*********************************************************************************************************
*/

voidmain(void){
//选择想要实验的协议来初始化
protocol1_init();
//protocol2_init();
while(1){
c=getchar();
//回显
putchar(c);
RxMac_FeedData(mac,c);
}
}

示例协议1测试结果6ff5a622-ccde-11ed-bfe3-dac502259ad0.png

示例协议2测试结果701c574a-ccde-11ed-bfe3-dac502259ad0.png可以看到,第二个协议中我们通过改变缓冲区大小成功控制了数据包的长度。

虽然这里的示例都是基于ASCII的,但这只是为了观察起来方便,普通的基于二进制的协议也是可以使用这个模块的。

v1.0代码

旧版代码中引用了我自己写的(现已弃用)环形缓冲区模块:
https://blog.csdn.net/lin_strong/article/details/73604561

接收机代码

头文件

/*
*********************************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收状态机
*
*File:RxMac.h
*
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2018/05/29
*version:1.0
*History:2018/05/29theprototype
*NOTE(s):1.thereceiveprocesshastwobasicstate
*A.preRx:whenhaven'tfoundanyheader,theRxMacwillsearchfortheunique
*flag,headerandstrong-ender.Onlywhenaheaderisfoundwillcome
*tonextstep.
*B.Rxing:theRxMacwillputthesuccessivebytesintothebuffer,andsearch
*forthestrong-unique,strong-header,ender.
*2.themoduleisdrivedbytheRxMac_FeedData(),usershouldgetthethechar
*fromdatastreamandpassthedataonebyonetotheRxMacthroughRxMac_FeedData()
*3.eachtimeRxMacfindaframe(completeorincomplete),itwillcalltheonFlushed
*tonotifytheresults;usercanjudgetheframethroughthestateparameter;
*state.headerFound==1:findanyheader,theheaderispassedbypHorU
*state.enderFound==1:findanyender,theenderispassedbypEnder
*state.isFull==1:thebufferisfull,maybeyoushouldcheckheaderFound
*toseewhetheraheaderhasbeenfound.
*state.uniqueFound==1:findanyuniqueflag.Inthiscase,otherparameterswill
*alwaysbe0&thedatasinthebufferwillbetheflag.
*4.Tousethismodule,foreachreceivemachine:
*A.allocatethespaceforbuffer,RxMac&FLAGS
*RX_MAC_Mac;
*RX_FLAGflags[2];
*INT8Ubuf[300];
*B.settheflagsaccordingtotheprotocol,definethecallbackfuncitons
*accordingtoyourneed.
*staticvoidonGetHeader(pRX_MACsender,pRX_FLAGpFlag){......};
*staticvoidonFlushed(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,
*RX_STATEstate,pRX_FLAGpHorU,pRX_FLAGpEnder){......};
*constINT8UHeaderFlag[]="Header";
*constINT8UEnderFlag[]="
";
*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.initthereceivemachine:
*RxMac_Init(&_Mac,flags,2,6,buf,300,NULL,onGetHeader,onFlushed);
*D.feedthereceivemachine:
*while(1){
*c=GetNextChar();
*RxMac_FeedData(&_Mac,c);
*}
*********************************************************************************************************
*/

#ifndefRX_MAC_H
#defineRX_MAC_H


/*
*********************************************************************************************************
*INCLUDES
*********************************************************************************************************
*/
#include"RingQueue.h"
#include

//typedefunsignedcharINT8U;
//typedefunsignedshortINT16U;

/*
*********************************************************************************************************
*ADDRESSINGMODE寻址模式
*********************************************************************************************************
*/
//theaddressingmodeforbuffer
#defineRXMAC_BUF_ADDRESSING_MODERQ_ADDRESSING_MODE

typedefINT8URB_BYTE;
typedefRB_BYTE*RXMAC_BUF_ADDRESSING_MODEpRB_BYTE;
/*
*********************************************************************************************************
*CONFIGURATION配置
*********************************************************************************************************
*/

#defineRXMAC_ARGUMENT_CHECK_ENTRUE
#defineRXMAC_NOTFILL_ENTRUE

#defineRXMAC_ONFEEDED_ENTRUE//TRUE:enabletheonFeededfunction.

#defineRXMAC_SINGLETON_ENFALSE//TRUE:enablesingletonpattern,soargumentpRxMacofinterfaces
//isuseless,anduserdon'tneedtoallocatespaceforRX_MAC,
//butyoustillneedtoallocatebufferandcallinit();

/*
*********************************************************************************************************
*CONST
*********************************************************************************************************
*/

#defineRXMAC_ERR_NONE0
#defineRXMAC_ERR_ARGUMENT1
#defineRXMAC_ERR_POINTERNULL2
#defineRXMAC_ERR_UNKNOWN3
#defineRXMAC_ERR_INIT4
/*
*********************************************************************************************************
*TYPEDEFINITION
*********************************************************************************************************
*/

//structofRX_FLAG.option
/*typedefstructFLAG_OPTION{
unsignedintisHeader:1;//1:theflagistheheadoftheframe
unsignedintstrong_H:1;//1:strong-header,RxMacwill
unsignedintnotfill_H:1;//0:filltheflagintothebufferwhenfoundasheader
unsignedintisEnder:1;//1:theflagistheendoftheframe
unsignedintstrong_E:1;//
unsignedintnotfill_E:1;//0:filltheflagintothebufferwhenfoundasender
unsignedintisUnique:1;//1:theflagisauniqueflagwhichistreatedassingleframe.
unsignedintstrong_U:1;//0:whenreceivingaframe,RxMacwillnot
};//*/

//接收标志位
typedefstructrx_flag{
INT8Uconst*pBuf;
INT8Ulen;
INT8Uoption;
}RX_FLAG,*pRX_FLAG;

//normalheader,RxMacwillonlycheckitinStepA
#defineFLAG_OPTION_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_HEADER0x03
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineFLAG_OPTION_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineFLAG_OPTION_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_ENDER0x18
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineFLAG_OPTION_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineFLAG_OPTION_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_UNIQUE0xC0

typedefstructrx_state{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RX_STATE;

typedefstructrx_macRX_MAC,*pRX_MAC;
typedefvoid(*RXMAC_FLUSH_EVENT)(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,RX_STATEstate,pRX_FLAGpHorU,pRX_FLAGpEnder);
typedefvoid(*RXMAC_FLAG_EVENT)(pRX_MACsender,pRX_FLAGpFlag);
typedefvoid(*RXMAC_FILTER)(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt);

structrx_mac{
RING_QUEUEFlagQueue;//用于判断标志串的环形缓冲区对象

pRX_FLAGFlags;//标志数组
INT8UFlagsCnt;//标志数组的个数
RX_STATEstate;//接收的状态(内部使用)
pRX_FLAGpHorU;//内部使用

pRB_BYTEpRxBuf;//存放数据的缓冲区
INT16URxBufSize;//缓冲区的长度

pRB_BYTEpCur;//指向缓冲区内下一个填充字符的位置

RXMAC_FILTERonFeeded;//当被喂字符时触发,返回指向缓冲区中刚刚喂进来的字符的指针以及是缓冲区内的第几个字符

RXMAC_FLAG_EVENTonGetHeader;//获得头标志位时触发。
RXMAC_FLUSH_EVENTonFlushed;//回调函数
};


/*
*********************************************************************************************************
*FUNCTIONDECLARATION
*********************************************************************************************************
*/
//tosettheflag'soption
//pbufpointertotheflagbuffer
//bufSizesizeofflag
//optseeFLAG_OPTION_XXXXX
#defineRX_FLAG_INIT(pFlag,pbuf,bufSize,opt)
(pFlag)->pBuf=(pbuf);(pFlag)->len=(bufSize);(pFlag)->option=(opt);

//toinittheRxMac
INT8URxMac_Init(pRX_MACpRxMac,//需要用户自己申请个UNI_RX_MACHINE对象的空间
RX_FLAGFlags[],INT8UFlagsCnt,INT8UmaxLenOfFlags,//提供标志字符串的数组
pRB_BYTEpBuf,INT16UBufLen,//用户需要提供缓冲区(缓存区大小起码应该要能
//放的下最长的Flag+最长的帧,最后部分会分配给RQ)
RXMAC_FILTERonFeeded,//在每次被Feed时触发
RXMAC_FLAG_EVENTonGetHeader,//获得头标志位时触发。
RXMAC_FLUSH_EVENTonFlushed//收到一帧数据时的回调函数
);
//向接收机内喂字节
voidRxMac_FeedData(pRX_MACpRxMac,INT8Uc);
//重置接收区长度为最长那个长度
INT8URxMac_ResetRxSize(pRX_MACpRxMac);
//设置最大接收到多少个字节
INT8URxMac_SetRxSize(pRX_MACpRxMac,INT16Usize);
//重置接收机的状态
INT8URxMac_ResetState(pRX_MACpRxMac);
//强制接收机flush
INT8URxMac_Flush(pRX_MACpRxMac);
//设置onFeeded
INT8URxMac_SetOnFeeded(pRX_MACpRxMac,RXMAC_FILTERonFeeded);
//设置onGetHeader
INT8URxMac_SetOnGetHeader(pRX_MACpRxMac,RXMAC_FLAG_EVENTonGetHeader);
//设置onFlushed
INT8URxMac_SetOnFlushed(pRX_MACpRxMac,RXMAC_FLUSH_EVENTonFlushed);

#endif//ofRX_MAC_H

源文件:

/*
*********************************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收状态机
*
*File:RxMac.c
*
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2018/05/29
*version:1.0
*History:
*NOTE(s):
*
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*INCLUDES
*********************************************************************************************************
*/
#include"RxMac.h"

#include
#include
/*
*********************************************************************************************************
*CONSTANT
*********************************************************************************************************
*/
//normalheader,RxMacwillonlycheckitinStepA
#defineFLAG_OPTBIT_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_HEADER0x02
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineFLAG_OPTBIT_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineFLAG_OPTBIT_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_ENDER0x10
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineFLAG_OPTBIT_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineFLAG_OPTBIT_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_UNIQUE0x80

#defineSTATEMASK_STEPA(FLAG_OPTBIT_HEADER|FLAG_OPTBIT_UNIQUE|FLAG_OPTBIT_STRONG_ENDER)
#defineSTATEMASK_STEPB(FLAG_OPTBIT_STRONG_UNIQUE|FLAG_OPTBIT_ENDER|FLAG_OPTBIT_STRONG_HEADER)
#defineFLAGMASK_USUHSH(FLAG_OPTBIT_HEADER|FLAG_OPTBIT_STRONG_HEADER|FLAG_OPTION_UNIQUE|FLAG_OPTBIT_STRONG_UNIQUE)

/*
*********************************************************************************************************
*LOCALFUNCITONDECLARATION
*********************************************************************************************************
*/
#if(RXMAC_SINGLETON_EN==FALSE)
#define_pRxMacpRxMac
#else
staticRX_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
staticpRB_BYTE_memcpy_internal(pRB_BYTEdest,pRB_BYTEsrc,size_tn);
#define_memcpy(dest,src,n)_memcpy_internal(dest,src,n)
//冲刷缓冲区
staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender);
//往接收机缓冲区内放数据
staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen);

/*
*********************************************************************************************************
*RxMac_Init()
*
*Description:ToinitializeaRxMac.初始化接收机
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收机结构体的指针
*Flagspointertotheflags(anarray);指向标志串(数组)的指针
*FlagsCntthecountoftheflags;有多少个标志串;
*maxLenOfFlagsthemaxlengthofflags;标志字符串最长的长度
*pBufpointertothebufferprovidedtotheRxMac;提供给接收机使用的缓存
*BufLenthesizeofthebuffer.缓存的大小
*onFeededthecallbackfuncthatwillbecalledwhenfeeded.
*每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
*onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader.
*当发现帧头时会调用的回调函数
*onFlushedthecallbackfuncthatwillbecalledwhenflushed.
*当Flush时会调用的回调函数
*
*Return:RXMAC_ERR_NONEifsuccess
*RXMAC_ERR_ARGUMENTifthelengthoflongestFlagsbiggerthanBuflen,oroneofthemis0
*RXMAC_ERR_POINTERNULLifemptypointer
*
*Note(s):sizeofbuffershouldbiggerthanthelongestflagplusthelongestframe
*thatmaybereceived(soatleast2*maxLenOfFlags).
*thebufferisallocateasfollow:
*<----------------------  BufLen  ---------------------->
*|RxBuffer||
*<------------- RxBufSize ------------><-maxLenOfFlags->
*
*voidonGetHeader(pRX_MACsender,pRX_FLAGpFlag):
*senderthepointertotheRxMacwhichcallthisfunction
*pFlagtheheadermatched
*
*voidonFeeded(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt):
*senderthepointertotheRxMacwhichcallthisfunction
*pCurCharpointtothecharinthebufferjustreceived.
*bytesCntthenumberofbytesinthebufferincludingthecharjustfeeded.
*
*voidonFlushed(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,RX_STATEstate,pRX_FLAGpHorU,
*pRX_FLAGpEnder);
*senderthepointertotheRxMacwhichcallthisfunction
*pBufthepointertotheframe.
*lenthelengthofframe.
*statethestateofframe.
*pHorUpointtotheheaderflagifstate.headerFound==1,oruniqueflagif
*state.uniqueFound==1.
*pEnderpointtotheenderflagifstate.enderFound==1.
*********************************************************************************************************
*/
INT8URxMac_Init
(pRX_MACpRxMac,RX_FLAGFlags[],INT8UFlagsCnt,INT8UmaxLenOfFlags,pRB_BYTEpBuf,INT16UBufLen,
RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed){
//INT8UmaxLen=0;
INT8Ui;
#if(RXMAC_ARGUMENT_CHECK_EN)
if(
#if(!RXMAC_SINGLETON_EN)
_pRxMac==NULL||
#endif
Flags==NULL||pBuf==NULL)
returnRXMAC_ERR_POINTERNULL;
#endif
//findoutthemaxlengthofflags.
//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)
returnRXMAC_ERR_ARGUMENT;
#endif
BufLen-=maxLenOfFlags;
//把buffer的最后一段分配给环形缓冲区
RingQueueInit(&_FlagQueue,pBuf+BufLen,maxLenOfFlags,&i);
_Flags=Flags;
_FlagsCnt=FlagsCnt;
_stateByte=0;
_pHorU=NULL;
_pRxBuf=pBuf;
_RxBufSize=BufLen;
_pCur=pBuf;
_onFeeded=onFeeded;
_onGetHeader=onGetHeader;
_onFlushed=onFlushed;
returnRXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*RxMac_FeedData()
*
*Description:TofeedRxMacthenextchar.用于给接收机下一个字符
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收机结构体的指针
*cthechartofeed;下一个字符
*
*Return:
*
*Note(s):
*********************************************************************************************************
*/
voidRxMac_FeedData(pRX_MACpRxMac,INT8Uc){
INT8Ui,mask;
pRX_FLAGpFlag=NULL;
#if(RXMAC_ONFEEDED_EN)
pRB_BYTEpCurChar=_pCur;
#endif
#if(RXMAC_ARGUMENT_CHECK_EN&&!RXMAC_SINGLETON_EN)
if(_pRxMac==NULL)
return;
#endif
*_pCur++=c;//填入缓冲区
#if(RXMAC_ONFEEDED_EN)
if(_onFeeded!=NULL)
_onFeeded(_pRxMac,pCurChar,_pCur-_pRxBuf);
RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#else
RingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#endif
//_state.headerFound==1说明在等待帧尾,否则在等待帧头
mask=(_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
//寻找匹配的标志串
for(i=0;i< _FlagsCnt; i++){
    if((_Flags[i].option & mask) && 
      (RingQueueMatch(&_FlagQueue,(pRQTYPE)_Flags[i].pBuf,_Flags[i].len) >=0)){
RingQueueClear(&_FlagQueue);
pFlag=&_Flags[i];
break;
}
}
//如果没有发现标志串,检查下有没满了,满了就Flush
if(pFlag==NULL){
if(_isRxBufFull()){
_state.isFull=1;
_flush(_pRxMac,NULL);
}
return;
}
//这4种标志串要_flush掉前面的东西
if(pFlag->option&FLAGMASK_USUHSH){
_pCur-=pFlag->len;
_flush(_pRxMac,NULL);
_pHorU=pFlag;
}
//如果是帧头的处理
if(pFlag->option&(FLAG_OPTION_STRONG_HEADER|FLAG_OPTION_HEADER)){
#if(RXMAC_NOTFILL_EN==TRUE)
if(!(pFlag->option&FLAG_OPTION_NOTFILL_HEADER))
#endif
_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
_state.headerFound=1;
if(_onGetHeader!=NULL)
_onGetHeader(_pRxMac,pFlag);
return;
}
//如果是Unique的处理
if(pFlag->option&(FLAG_OPTION_STRONG_UNIQUE|FLAG_OPTION_UNIQUE)){
_state.uniqueFound=1;
_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
_flush(_pRxMac,NULL);
}else{//能到这里说明是帧尾
_state.enderFound=1;
#if(RXMAC_NOTFILL_EN==TRUE)
if(pFlag->option&FLAG_OPTION_NOTFILL_ENDER)
_pCur-=pFlag->len;
#endif
_flush(_pRxMac,pFlag);
}
return;
}
/*
*********************************************************************************************************
*RxMac_ResetRxSize()
*
*Description:resetthesizeofRxBuftothemaxsize.重置接收缓冲区
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收机结构体的指针
*
*Return:RXMAC_ERR_NONEifSuccess;
*RXMAC_ERR_POINTERNULLifpRxMac==NULL
*RXMAC_ERR_INITifRxMachasn'tinitedoranyerrorininitialization
*Note(s):
*********************************************************************************************************
*/
INT8URxMac_ResetRxSize(pRX_MACpRxMac){
intsize;
#if(RXMAC_ARGUMENT_CHECK_EN&&!RXMAC_SINGLETON_EN)
if(_pRxMac==NULL)
returnRXMAC_ERR_POINTERNULL;
#endif
size=_FlagQueue.RingBuf-_pRxBuf;
#if(RXMAC_ARGUMENT_CHECK_EN)
if(size< 0)
    return RXMAC_ERR_INIT;
#endif
  _RxBufSize = (INT16U)size;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetRxSize()
*
* Description : set the size of RxBuf to the max size.   重置接收缓冲区
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*               size      the size to set;                
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*               RXMAC_ERR_ARGUMENT        if size is wrong.
* Note(s)     : the size shouldn't be bigger than the initial value, and should bigger than
*               the current number of chars in the RxBuf.
*               
*********************************************************************************************************
*/
INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size){
#if(RXMAC_ARGUMENT_CHECK_EN)
 #if (!RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
 #endif
  if(_FlagQueue.RingBuf - _pRxBuf < size || size <= _pCur - _pRxBuf)
    return RXMAC_ERR_ARGUMENT;
#endif
  _RxBufSize = size;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_ResetState()
*
* Description : reset the state of receive machine.   重置接收机的状态
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*********************************************************************************************************
*/
INT8U RxMac_ResetState(pRX_MAC pRxMac){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  // 复位接收机
  RingQueueClear(&_FlagQueue);
  _pCur = _pRxBuf;
  _stateByte = 0;
  _pHorU = NULL;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*********************************************************************************************************
*/
INT8U RxMac_Flush(pRX_MAC pRxMac){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _flush(_pRxMac,NULL);
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收机结构体的指针
*               onFeeded  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onFeeded = onFeeded;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收机结构体的指针
*               onGetHeader  the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onGetHeader = onGetHeader;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                        RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收机结构体的指针
*               onFlushed    the callback function to set;   要设置的回调函数
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/
INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed){
#if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN)
  if(_pRxMac == NULL)
    return RXMAC_ERR_POINTERNULL;
#endif
  _onFlushed = onFlushed;
  return RXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*                                   LOCAL  FUNCITON 
*********************************************************************************************************
*/
static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n){
  pRB_BYTE p = dest;
  while(n-- >0)
*p++=*src++;
returndest;
}

staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen){
_memcpy(_pCur,pBuf,len);
_pCur+=len;
}

staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender){
//触发回调
if(_pCur-_pRxBuf>0&&_onFlushed!=NULL)
_onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender);
//复位接收机
_pCur=_pRxBuf;
_stateByte=0;
_pHorU=NULL;
}

测试/示例代码

/*
*********************************************************************************************************
*uC/OS-II
*TheReal-TimeKernel
*Framework
*
*By:LinShijun
*Note:ThisisaframeworkforuCos-iiprojectwithonlyS12CPU,nonefloat,bankedmemorymodel.
*Youcanusethisframeworkwithsamemodificationasthestartpointofyourproject.
*I'veremovedtheos_probemodule,sinceIthoughtituselessinmostcase.
*Thisframeworkisadaptedfromtheofficialrelease.
*********************************************************************************************************
*/

#include"includes.h"
#include"SCI_def.h"
#include"RxMac.h"
/*
*********************************************************************************************************
*STACKSPACEDECLARATION
*********************************************************************************************************
*/
staticOS_STKAppTaskStartStk[APP_TASK_START_STK_SIZE];

/*
*********************************************************************************************************
*TASKFUNCTIONDECLARATION
*********************************************************************************************************
*/

staticvoidAppTaskStart(void*p_arg);

/*
*********************************************************************************************************
*CALLBACKFUNCITON
*********************************************************************************************************
*/
voidonGetData(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt){
//因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据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,"
Flushed:",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,"
Datas:",7,0);
  SCI_PutCharsB(SCI0,pBuf,len,0);
  SCI_PutCharsB(SCI0,"
",1,0);
  RxMac_ResetRxSize(sender);
}
void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){
  SCI_PutCharsB(SCI0,"
FoundHeader:",13,0);
  SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
SCI_PutCharsB(SCI0,"
",1,0);
}
voidonGetHeader2(pRX_MACsender,pRX_FLAGpFlag){
SCI_PutCharsB(SCI0,"
FoundHeader:",13,0);
SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
SCI_PutCharsB(SCI0,"
",1,0);
RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
*FLAGS
*********************************************************************************************************
*/
RX_MAC_rxmac;
#defineBUF_SIZE20
INT8Ubuffer[BUF_SIZE];
RX_FLAGflags[4];

//协议示例1:
//帧头:HEADER或者START
//强帧尾:END
//强特殊串: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);
}
//协议示例2:
//帧头:START
//帧头后的第1个字符表示后面还要接收多少个字符1-9,'4'表示4个,如果不是数字或为'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);
}

/*
*********************************************************************************************************
*MAINFUNCTION
*********************************************************************************************************
*/


voidmain(void){
INT8Uerr;
BSP_IntDisAll();/*DisableALLinterruptstotheinterruptcontroller*/
OSInit();/*InitializeuC/OS-II*/

err=OSTaskCreate(AppTaskStart,
NULL,
(OS_STK*)&AppTaskStartStk[APP_TASK_START_STK_SIZE-1],
APP_TASK_START_PRIO);
OSStart();
}

staticvoidAppTaskStart(void*p_arg)
{
INT8Uc,err;
(void)p_arg;/*Preventcompilerwarning*/
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);
}
}

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模块
    +关注

    关注

    7

    文章

    2607

    浏览量

    46987
  • 嵌入式
    +关注

    关注

    5042

    文章

    18797

    浏览量

    298271
  • 接收机
    +关注

    关注

    8

    文章

    1158

    浏览量

    53145
  • 函数
    +关注

    关注

    3

    文章

    4233

    浏览量

    61952
  • 状态机
    +关注

    关注

    2

    文章

    489

    浏览量

    27387

原文标题:[嵌入式开发模块]通用接收状态机模块

文章出处:【微信号:技术让梦想更伟大,微信公众号:技术让梦想更伟大】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式软件开发中常用的状态机编程实现

    嵌入式软件开发中,状态机编程是一个十分重要的编程思想,它也是嵌入式开发中一个常用的编程框架。掌握了状态机编程思想,可以更加逻辑清晰的实现复
    发表于 09-06 10:25 1757次阅读

    基于状态机嵌入式系统开发

    给大家分享下,基于状态机嵌入式系统开发,慢慢看吧
    发表于 12-22 19:44

    嵌入式开发

    嵌入式开发就是指在嵌入式操作系统下进行开发嵌入式Linux是以Linux为基础的嵌入式作业系统。这里提供了
    发表于 12-20 13:21
    <b class='flag-5'>嵌入式开发</b>

    [嵌入式开发板]iTOP-4412以模块的方式编译内核驱动

    [嵌入式开发板]iTOP-4412以模块的方式编译驱动。
    发表于 03-15 09:31 21次下载

    嵌入式软件中状态机的抽象与实现

    文中提出了 在嵌入式软件中把状态机作为一个独立模块从控制模块中抽象出来的思想 , 描述了 抽象出来的状态机
    发表于 03-22 15:47 1次下载

    有限状态机嵌入式系统中的实现及应用

    如何使嵌入式软件代码更加可靠 增强程序的可维护性 一直以来都是嵌入式程序员追 求的目标。论述了有限状态机的原理和其实现方法;采用状态机方法编写了一个按键扫描程序介绍了
    发表于 03-22 15:40 1次下载

    LabVIEW ARM嵌入式开发模块的详细介绍和使用手册中文资料概述

    LabVIEW ARM嵌入式开发模块是一个完整的图形化开发环境,由NI联合Keil公司开发而成,使用这个模块对ARM芯片
    发表于 06-19 08:00 16次下载
    LabVIEW ARM<b class='flag-5'>嵌入式开发</b><b class='flag-5'>模块</b>的详细介绍和使用手册中文资料概述

    嵌入式开发的产品有哪些_嵌入式开发的流程

    本文主要阐述了嵌入式开发的产品,其次介绍了嵌入式开发的流程。
    发表于 08-31 15:38 1.1w次阅读

    嵌入式LINUX系统内核和内核模块调试

    嵌入式LINUX系统内核和内核模块调试(嵌入式开发和硬件开发)-嵌入式LINUX系统内核和内核模块
    发表于 07-30 13:55 9次下载
    <b class='flag-5'>嵌入式</b>LINUX系统内核和内核<b class='flag-5'>模块</b>调试

    嵌入式开发(一):嵌入式开发新手入门

    本篇文章整理下嵌入式开发中一些入门的基础技能,都是根据以往的工程经验整理,适用于之前没做过嵌入式开发的新手。嵌入式开发流程一般如下,一般是在PC的Windows系统下安装Ubuntu
    发表于 10-14 10:58 79次下载
    <b class='flag-5'>嵌入式开发</b>(一):<b class='flag-5'>嵌入式开发</b>新手入门

    嵌入式开发资料免费分享

    嵌入式开发资料免费分享嵌入式工程师经验分享:如何学习嵌入式开发截取文档部分学习嵌入式工程师经验分享的资料分享给大家,文档上从、嵌入式系统的概
    发表于 10-21 11:07 46次下载
    <b class='flag-5'>嵌入式开发</b>资料免费分享

    嵌入式状态机的设置

    状态机嵌入式软件中随处可见,可能你会说状态机有什么难的,不就是 switch 吗?
    的头像 发表于 11-02 09:04 996次阅读

    嵌入式状态机的编程优点分析

    嵌入式状态机编程是真的好用,写出来的程序结构非常清晰!所以平时用的也比较多。
    的头像 发表于 02-25 16:21 764次阅读

    嵌入式状态机的设计与实现

    嵌入式状态机是一种常用的软件设计模式,它能够提高代码的可读性和可维护性。状态机是一个抽象的概念,它描述了一个系统或者组件的不同状态以及在不同状态
    的头像 发表于 04-14 11:55 1512次阅读

    单片开发嵌入式开发的区别

    单片开发嵌入式开发都是针对嵌入式系统的应用领域,但是两者有着不同的特点和应用场景。在本文中,我们将探讨单片
    的头像 发表于 04-14 16:36 2464次阅读