前言
在軟件開發(fā)的過程中,只要涉及到通信,就會涉及到數(shù)據(jù)接收機的編寫,通信協(xié)議雖然多種多樣,但是數(shù)據(jù)包的形式確是很相似的(暫時沒看到特別復(fù)雜,此模塊解決不了的),為此可以把其中通用的部分抽象出來,然后就成了這個模塊。
模塊相關(guān)概念和邏輯
接收機狀態(tài)
接收機有兩個基本狀態(tài):
狀態(tài)A:preRx 等待幀頭中,這個時候接收機會不斷判斷是否收到了特殊序列、幀頭和強幀尾。如果收到了幀頭,則(默認)會把幀頭填入緩沖區(qū)的最前面,然后進入狀態(tài)B。
狀態(tài)B:Rxing 等待幀尾中,收到的數(shù)據(jù)會按序填入接收緩沖區(qū),同時不斷查找?guī)病妿^以及強特殊序列,不管找到了哪一個都會觸發(fā)flush。如果,找到的是強幀頭,則仍然在狀態(tài)B,否則恢復(fù)狀態(tài)A。
不管在哪一個狀態(tài)下,如果接受緩沖區(qū)滿了,都會觸發(fā)flush并回到狀態(tài)A。
標志字符序列
接收機定義了以下標志序列類型:
類型 | 模塊中標記 | 描述 |
---|---|---|
幀頭 | header | 只在狀態(tài)A起作用;找到時會導致之前接收區(qū)內(nèi)的數(shù)據(jù)被flush,然后默認會填入接收區(qū)的最前面,可以通過選項來改變這個行為,然后接收機進入狀態(tài)B。 |
強幀頭 | strong-header | 在狀態(tài)B也會起作用,其他行為與普通幀頭一樣 |
幀尾 | ender | 只在狀態(tài)B起作用;找到時會導致當前接收區(qū)內(nèi)的數(shù)據(jù)被flush,默認會處于回調(diào)時給用戶的buffer的最后面,可以通過選項來改變這個行為,然后接收機回到狀態(tài)A。 |
強幀頭 | strong-header | 在狀態(tài)A也會起作用,其他行為與普通幀尾一樣 |
特殊序列 | unique | 只在狀態(tài)A起作用;找到時會導致之前接收區(qū)內(nèi)的數(shù)據(jù)被flush,然后自己被填入接收區(qū)內(nèi)后再次觸發(fā)flush,然后接收機回到狀態(tài)A。 |
強特殊序列 | strong-unique | 在狀態(tài)B也會起作用,其他行為與特殊序列一樣 |
對應(yīng)模塊中的結(jié)構(gòu)體為:
//receiveflag typedefstructRXFLAG_STRUCT{ uint8_tconst*pBuf; uint8_tlen; uint8_toption; }RXFLAG_STRUCT; typedefRXFLAG_STRUCTconst*RxFlag; 1234567
一般的流程中,初始化接收機前,用戶需要準備好接收機使用的所有標志序列,標志好每個序列的類型。模塊提供宏函數(shù)以抽象這個過程:
//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
每當接收機根據(jù)標志字符序列找到一個完整或不完整的數(shù)據(jù)包時,接收機會進行回調(diào)以通知用戶處理這個數(shù)據(jù)包,這個行為被稱為flush,這個回調(diào)函數(shù)叫做onFlushed。
此函數(shù)的原型如下
typedefvoid(*RXMAC_FLUSH_EVENT)(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate, RxFlagHorU,RxFlagEnder);
整個數(shù)據(jù)包為buf指向的長度為len的區(qū)域。
數(shù)據(jù)包的狀態(tài)可以通過state參數(shù)得知,RX_STATE 的類型定義如下
typedefstructRXSTATE_STRUCT{ unsignedintheaderFound:1;//1:havegetheader unsignedintenderFound:1;//1:havegetender unsignedintisFull:1;//1:thebufferisfull unsignedintuniqueFound:1;//1:thisisuniqueflag. }RxState;
通過判斷每個標志位是否置1,可以得知當前數(shù)據(jù)包的狀態(tài)。
如果headerFound == 1,說明數(shù)據(jù)包是有幀頭的,可以通過pHorU獲得幀頭
如果enderFound == 1,說明數(shù)據(jù)包是有幀尾的,可以通過pEnder獲得幀尾
如果isFull == 1,說明此數(shù)據(jù)包是因為接收區(qū)滿了放不下了而產(chǎn)生的回調(diào),在一些需要根據(jù)某個字段來判斷數(shù)據(jù)包真正大小的協(xié)議里,可以通過調(diào)整接收緩沖區(qū)的大小來恰當?shù)漠a(chǎn)生flush。
如果UniqueFound == 1,說明此數(shù)據(jù)包是標志序列,這時緩沖區(qū)內(nèi)的內(nèi)容等于pHorU指向的那個標志序列
接收機類
V1.0版本中要求用戶自己分配結(jié)構(gòu)體的空間,為了更加面向?qū)ο螅F(xiàn)已改為動態(tài)分配,而把具體結(jié)構(gòu)體和對應(yīng)方法封裝在模塊內(nèi)部。
typedefstructRXMAC_STRUCT*RxMac;
模塊提供Create函數(shù)來創(chuàng)建接收機實例并返回指向?qū)嵗闹羔槨?/p>
//tocreateaninstanceofRxMac //flags標志字符串結(jié)構(gòu)體的數(shù)組 //flagsCnt標志字符串結(jié)構(gòu)體的個數(shù) //buf用戶提供給接收機用的緩沖區(qū) //bufLen緩沖區(qū)的大小(起碼應(yīng)該要能放的下最長的標志字符串) //onFeeded在每次被Feed時觸發(fā) //onGetHeader獲得頭標志位時觸發(fā)。 //onFlushed收到一幀數(shù)據(jù)時的回調(diào)函數(shù) RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen, RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed);
調(diào)用實例的方法時把這個指針作為第一個參數(shù)以模擬面向?qū)ο蟛僮鳌?/p>
過濾器
接收機每次被feed時,都會觸發(fā)onFeeded事件(可以在配置中取消這個事件以節(jié)省點代碼)。原型如下:
typedefvoid(*RXMAC_FILTER)(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);
pCurChar :指向接收區(qū)中剛收到的字符
bytesCnt :這個字符是接收區(qū)中的第幾個字符
此時,接收機已經(jīng)將其放入接收區(qū)但是還沒進一步進行判斷,用戶可以修改字符/配置接收機以改變接收機的行為,比如將收到的字母全變?yōu)樾憽;蛘吒鶕?jù)收到的數(shù)據(jù)來決定還要收多少數(shù)據(jù)。
onGetHeader事件
當找到任意幀頭時會觸發(fā)。
接收機運行邏輯
接收機的運作邏輯如下:
img
邊際條件
標志序列盡量不要有重合,如果同時可能匹配兩個標志序列,最終行為是未定義的,不保證正確執(zhí)行,最終結(jié)果可能與標志序列的位置以及類型有關(guān)系。
同一個標志串可以同時是多種類型,比如同時是幀頭與幀尾,但要小心類型間不要有沖突,否則不保證正確執(zhí)行。
對于標志序列匹配到一半發(fā)生了接收緩沖區(qū)滿,從而導致發(fā)生標志序列匹配時,接收緩沖區(qū)中只有半個標志序列的情況:
如果標志序列是(強)特殊序列或(強)幀頭的情況,可以保證功能正常運行。
如果標志序列是強幀尾的情況,緩沖區(qū)內(nèi)會只剩下后半段的幀尾,但可以根據(jù)pEnder參數(shù)來得知真正的幀尾。
幀尾不會發(fā)生這種邊際條件。
相關(guān)代碼
此模塊使用了我自己寫的Buffer模塊作為內(nèi)部緩沖區(qū)來判斷標志字符串。
[嵌入式開發(fā)模塊]環(huán)形緩沖區(qū)/循環(huán)隊列 C語言實現(xiàn)
接收機代碼
RxMac.h
/* ******************************************************************************************* * * *UniversalReceiveStateMachine *通用接收狀態(tài)機 * *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標志字符串結(jié)構(gòu)體的數(shù)組 //flagsCnt標志字符串結(jié)構(gòu)體的個數(shù) //buf用戶提供給接收機用的緩沖區(qū) //bufLen緩沖區(qū)的大小(起碼應(yīng)該要能放的下最長的標志字符串) //onFeeded在每次被Feed時觸發(fā) //onGetHeader獲得頭標志位時觸發(fā)。 //onFlushed收到一幀數(shù)據(jù)時的回調(diào)函數(shù) RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed); //todestroytheRxMac voidRxMac_Destroy(RxMacmac); //向接收機內(nèi)喂字節(jié) voidRxMac_FeedDatas(RxMacmac,uint8_tconst*buf,uint16_tlen); voidRxMac_FeedData(RxMacmac,uint8_tc); //重置接收區(qū)長度為最長那個長度 //uint8_tRxMac_ResetRxSize(RxMacmac); //設(shè)置最大接收到多少個字節(jié) uint8_tRxMac_SetRxSize(RxMacmac,uint16_tsize); //重置接收機的狀態(tài) uint8_tRxMac_ResetState(RxMacmac); //強制接收機flush uint8_tRxMac_Flush(RxMacmac); //設(shè)置onFeeded uint8_tRxMac_SetOnFeeded(RxMacmac,RXMAC_FILTERonFeeded); //設(shè)置onGetHeader uint8_tRxMac_SetOnGetHeader(RxMacmac,RXMAC_FLAG_EVENTonGetHeader); //設(shè)置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 ******************************************************************************************* */ //打印內(nèi)部緩沖區(qū),返回緩沖區(qū)的長度 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 *通用接收狀態(tài)機 * *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 //沖刷緩沖區(qū) staticvoid_flush(RxMacmac,RxFlagender); //往接收機緩沖區(qū)內(nèi)放數(shù)據(jù) 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.創(chuàng)建一個接收機實例 * *Arguments:flagspointertotheflags(anarray);指向標志串(數(shù)組)的指針 *flagsCntthecountoftheflags;有多少個標志串; *bufpointertothebufferprovidedtotheRxMac;提供給接收機使用的緩存 *bufLenthesizeofthebuffer.緩存的大小 *onFeededthecallbackfuncthatwillbecalledeverytimefeeded,you *canmodifythefeededbyteinthiscallback. *每次被feed時會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標志位的判斷 *onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader. *當發(fā)現(xiàn)幀頭時會調(diào)用的回調(diào)函數(shù) *onFlushedthecallbackfuncthatwillbecalledwhenflushed. *當Flush時會調(diào)用的回調(diào)函數(shù) * *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;imaxLen) maxLen=flags[i].len; } #ifndefRXMAC_ARGUMENT_CHECK_DISABLE if(bufLen0) *p++=*src++; returndest; } staticvoid_BufIn(RxMacmac,RxMacPtrbuf,uint16_tlen){ memcpy(_pRxBuf+_RxCnt,buf,len); _RxCnt+=len; } staticvoid_flush(RxMacmac,RxFlagender){ //觸發(fā)回調(diào) if((_RxCnt>0||ender!=NULL)&&_fonFlushed!=NULL) _fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender); //復(fù)位接收機 _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(_RxCntlen){//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
測試/示例代碼
已略去非必要代碼
#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]; //協(xié)議示例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); } //協(xié)議示例2: //幀頭:START //幀頭后的第1個字符表示后面還要接收多少個字符1-9,'4'表示4個,如果不是數(shù)字或為'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){ //因為發(fā)現(xiàn)幀頭后才掛載事件,所以下一次回掉正好是說明字符數(shù)的那個字符,否則還得根據(jù)bytesCnt來判斷當前位置 RxMac_SetOnFeeded(sender,NULL); if(*pCurChar>'0'&&*pCurChar<=?'9'?){ ????//?bytesCnt是當前收到了多少個字符,所以接收區(qū)大小為當前字符數(shù)加上還要接收的 ????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){ //選擇想要實驗的協(xié)議來初始化 protocol1_init(); //protocol2_init(); while(1){ c=getchar(); //回顯 putchar(c); RxMac_FeedData(mac,c); } }
示例協(xié)議1測試結(jié)果
示例協(xié)議2測試結(jié)果可以看到,第二個協(xié)議中我們通過改變緩沖區(qū)大小成功控制了數(shù)據(jù)包的長度。
雖然這里的示例都是基于ASCII的,但這只是為了觀察起來方便,普通的基于二進制的協(xié)議也是可以使用這個模塊的。
v1.0代碼
舊版代碼中引用了我自己寫的(現(xiàn)已棄用)環(huán)形緩沖區(qū)模塊:
https://blog.csdn.net/lin_strong/article/details/73604561接收機代碼
頭文件
/* ********************************************************************************************************* * * *UniversalReceiveStateMachine *通用接收狀態(tài)機 * *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;//用于判斷標志串的環(huán)形緩沖區(qū)對象 pRX_FLAGFlags;//標志數(shù)組 INT8UFlagsCnt;//標志數(shù)組的個數(shù) RX_STATEstate;//接收的狀態(tài)(內(nèi)部使用) pRX_FLAGpHorU;//內(nèi)部使用 pRB_BYTEpRxBuf;//存放數(shù)據(jù)的緩沖區(qū) INT16URxBufSize;//緩沖區(qū)的長度 pRB_BYTEpCur;//指向緩沖區(qū)內(nèi)下一個填充字符的位置 RXMAC_FILTERonFeeded;//當被喂字符時觸發(fā),返回指向緩沖區(qū)中剛剛喂進來的字符的指針以及是緩沖區(qū)內(nèi)的第幾個字符 RXMAC_FLAG_EVENTonGetHeader;//獲得頭標志位時觸發(fā)。 RXMAC_FLUSH_EVENTonFlushed;//回調(diào)函數(shù) }; /* ********************************************************************************************************* *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,//提供標志字符串的數(shù)組 pRB_BYTEpBuf,INT16UBufLen,//用戶需要提供緩沖區(qū)(緩存區(qū)大小起碼應(yīng)該要能 //放的下最長的Flag+最長的幀,最后部分會分配給RQ) RXMAC_FILTERonFeeded,//在每次被Feed時觸發(fā) RXMAC_FLAG_EVENTonGetHeader,//獲得頭標志位時觸發(fā)。 RXMAC_FLUSH_EVENTonFlushed//收到一幀數(shù)據(jù)時的回調(diào)函數(shù) ); //向接收機內(nèi)喂字節(jié) voidRxMac_FeedData(pRX_MACpRxMac,INT8Uc); //重置接收區(qū)長度為最長那個長度 INT8URxMac_ResetRxSize(pRX_MACpRxMac); //設(shè)置最大接收到多少個字節(jié) INT8URxMac_SetRxSize(pRX_MACpRxMac,INT16Usize); //重置接收機的狀態(tài) INT8URxMac_ResetState(pRX_MACpRxMac); //強制接收機flush INT8URxMac_Flush(pRX_MACpRxMac); //設(shè)置onFeeded INT8URxMac_SetOnFeeded(pRX_MACpRxMac,RXMAC_FILTERonFeeded); //設(shè)置onGetHeader INT8URxMac_SetOnGetHeader(pRX_MACpRxMac,RXMAC_FLAG_EVENTonGetHeader); //設(shè)置onFlushed INT8URxMac_SetOnFlushed(pRX_MACpRxMac,RXMAC_FLUSH_EVENTonFlushed); #endif//ofRX_MAC_H
源文件:
/* ********************************************************************************************************* * * *UniversalReceiveStateMachine *通用接收狀態(tài)機 * *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) //因為不能保證用戶把數(shù)據(jù)放在非分頁區(qū),只好自己實現(xiàn)一個,實際使用中如果確定在非分頁區(qū)可以把下面的宏替換為庫函數(shù)memcpy staticpRB_BYTE_memcpy_internal(pRB_BYTEdest,pRB_BYTEsrc,size_tn); #define_memcpy(dest,src,n)_memcpy_internal(dest,src,n) //沖刷緩沖區(qū) staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender); //往接收機緩沖區(qū)內(nèi)放數(shù)據(jù) staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen); /* ********************************************************************************************************* *RxMac_Init() * *Description:ToinitializeaRxMac.初始化接收機 * *Arguments:pRxMacpointertotheRxMacstruct;指向接收機結(jié)構(gòu)體的指針 *Flagspointertotheflags(anarray);指向標志串(數(shù)組)的指針 *FlagsCntthecountoftheflags;有多少個標志串; *maxLenOfFlagsthemaxlengthofflags;標志字符串最長的長度 *pBufpointertothebufferprovidedtotheRxMac;提供給接收機使用的緩存 *BufLenthesizeofthebuffer.緩存的大小 *onFeededthecallbackfuncthatwillbecalledwhenfeeded. *每次被feed時會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標志位的判斷 *onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader. *當發(fā)現(xiàn)幀頭時會調(diào)用的回調(diào)函數(shù) *onFlushedthecallbackfuncthatwillbecalledwhenflushed. *當Flush時會調(diào)用的回調(diào)函數(shù) * *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;imaxLen) //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的最后一段分配給環(huán)形緩沖區(qū) RingQueueInit(&_FlagQueue,pBuf+BufLen,maxLenOfFlags,&i); _Flags=Flags; _FlagsCnt=FlagsCnt; _stateByte=0; _pHorU=NULL; _pRxBuf=pBuf; _RxBufSize=BufLen; _pCur=pBuf; _onFeeded=onFeeded; _onGetHeader=onGetHeader; _onFlushed=onFlushed; returnRXMAC_ERR_NONE; } /* ********************************************************************************************************* *RxMac_FeedData() * *Description:TofeedRxMacthenextchar.用于給接收機下一個字符 * *Arguments:pRxMacpointertotheRxMacstruct;指向接收機結(jié)構(gòu)體的指針 *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;//填入緩沖區(qū) #if(RXMAC_ONFEEDED_EN) if(_onFeeded!=NULL) _onFeeded(_pRxMac,pCurChar,_pCur-_pRxBuf); RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i); #else RingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i); #endif //_state.headerFound==1說明在等待幀尾,否則在等待幀頭 mask=(_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA; //尋找匹配的標志串 for(i=0;i=0)){ RingQueueClear(&_FlagQueue); pFlag=&_Flags[i]; break; } } //如果沒有發(fā)現(xiàn)標志串,檢查下有沒滿了,滿了就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.重置接收緩沖區(qū) * *Arguments:pRxMacpointertotheRxMacstruct;指向接收機結(jié)構(gòu)體的指針 * *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(size0) ????return?RXMAC_ERR_INIT; #endif ??_RxBufSize?=?(INT16U)size; ??return?RXMAC_ERR_NONE; } /* ********************************************************************************************************* *????????????????????????????????????????RxMac_SetRxSize() * *?Description?:?set?the?size?of?RxBuf?to?the?max?size.???重置接收緩沖區(qū) * *?Arguments???:?pRxMac????pointer?to?the?RxMac?struct;????指向接收機結(jié)構(gòu)體的指針 *???????????????size??????the?size?to?set;???????????????? * *?Return??????:?RXMAC_ERR_NONE????????????if?Success; *???????????????RXMAC_ERR_POINTERNULL?????if?pRxMac?==?NULL *???????????????RXMAC_ERR_ARGUMENT????????if?size?is?wrong. *?Note(s)?????:?the?size?shouldn't?be?bigger?than?the?initial?value,?and?should?bigger?than *???????????????the?current?number?of?chars?in?the?RxBuf. *??????????????? ********************************************************************************************************* */ INT8U?RxMac_SetRxSize(pRX_MAC?pRxMac,?INT16U?size){ #if(RXMAC_ARGUMENT_CHECK_EN) ?#if?(!RXMAC_SINGLETON_EN) ??if(_pRxMac?==?NULL) ????return?RXMAC_ERR_POINTERNULL; ?#endif ??if(_FlagQueue.RingBuf?-?_pRxBuf?0) *p++=*src++; returndest; } staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen){ _memcpy(_pCur,pBuf,len); _pCur+=len; } staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender){ //觸發(fā)回調(diào) if(_pCur-_pRxBuf>0&&_onFlushed!=NULL) _onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender); //復(fù)位接收機 _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){ //因為發(fā)現(xiàn)幀頭后才掛載事件,所以下一次回掉正好是說明字符數(shù)的那個字符,否則還得根據(jù)bytesCnt來判斷當前位置 RxMac_SetOnFeeded(sender,NULL); if(*pCurChar>'0'&&*pCurChar<=?'9'?){ ????//?bytesCnt是當前收到了多少個字符,所以接收區(qū)大小為當前字符數(shù)加上還要接收的 ????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]; //協(xié)議示例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); } //協(xié)議示例2: //幀頭:START //幀頭后的第1個字符表示后面還要接收多少個字符1-9,'4'表示4個,如果不是數(shù)字或為'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(); //選擇想要實驗的協(xié)議來初始化 protocol1_init(); //protocol2_init(); while(DEF_TRUE) { //獲取下一個字符 c=SCI_GetCharB(SCI0,0,&err); //回顯 SCI_PutCharB(SCI0,c,0); //喂給接收機 RxMac_FeedData(&_rxmac,c); } }
審核編輯:湯梓紅
-
模塊
+關(guān)注
關(guān)注
7文章
2735瀏覽量
47751 -
嵌入式
+關(guān)注
關(guān)注
5092文章
19178瀏覽量
307698 -
接收機
+關(guān)注
關(guān)注
8文章
1184瀏覽量
53636 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
62977 -
狀態(tài)機
+關(guān)注
關(guān)注
2文章
492瀏覽量
27649
原文標題:[嵌入式開發(fā)模塊]通用接收狀態(tài)機模塊
文章出處:【微信號:技術(shù)讓夢想更偉大,微信公眾號:技術(shù)讓夢想更偉大】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論