當(dāng)前位置:首頁 > 公眾號精選 > strongerHuang



前言

在軟件開發(fā)的過程中,只要涉及到通信,就會涉及到數(shù)據(jù)接收機(jī)的編寫,通信協(xié)議雖然多種多樣,但是數(shù)據(jù)包的形式確是很相似的(暫時(shí)沒看到特別復(fù)雜,此模塊解決不了的),為此可以把其中通用的部分抽象出來,然后就成了這個(gè)模塊。

模塊相關(guān)概念和邏輯

接收機(jī)狀態(tài)

接收機(jī)有兩個(gè)基本狀態(tài):

  • ? 狀態(tài)A:preRx 等待幀頭中,這個(gè)時(shí)候接收機(jī)會不斷判斷是否收到了特殊序列、幀頭和強(qiáng)幀尾。如果收到了幀頭,則(默認(rèn))會把幀頭填入緩沖區(qū)的最前面,然后進(jìn)入狀態(tài)B。

  • ? 狀態(tài)B:Rxing 等待幀尾中,收到的數(shù)據(jù)會按序填入接收緩沖區(qū),同時(shí)不斷查找?guī)?、?qiáng)幀頭以及強(qiáng)特殊序列,不管找到了哪一個(gè)都會觸發(fā)flush。如果,找到的是強(qiáng)幀頭,則仍然在狀態(tài)B,否則恢復(fù)狀態(tài)A。

不管在哪一個(gè)狀態(tài)下,如果接受緩沖區(qū)滿了,都會觸發(fā)flush并回到狀態(tài)A。

標(biāo)志字符序列

接收機(jī)定義了以下標(biāo)志序列類型:

對應(yīng)模塊中的結(jié)構(gòu)體為:

// receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option;
} RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag;

一般的流程中,初始化接收機(jī)前,用戶需要準(zhǔn)備好接收機(jī)使用的所有標(biāo)志序列,標(biāo)志好每個(gè)序列的類型。模塊提供宏函數(shù)以抽象這個(gè)過程:

// void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to  initialize a receive flag //    flag    point to the target RXFLAG_STRUCT. //    buf     pointer to the flag buffer //    size    size of flag  //    opt     see  RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt)     \
  {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);}

flush

每當(dāng)接收機(jī)根據(jù)標(biāo)志字符序列找到一個(gè)完整或不完整的數(shù)據(jù)包時(shí),接收機(jī)會進(jìn)行回調(diào)以通知用戶處理這個(gè)數(shù)據(jù)包,這個(gè)行為被稱為flush,這個(gè)回調(diào)函數(shù)叫做onFlushed。

此函數(shù)的原型如下:

typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
                                   RxFlag HorU,RxFlag Ender);

整個(gè)數(shù)據(jù)包為buf指向的長度為len的區(qū)域。

數(shù)據(jù)包的狀態(tài)可以通過state參數(shù)得知,RX_STATE 的類型定義如下:

typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull     : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState;

通過判斷每個(gè)標(biāo)志位是否置1,可以得知當(dāng)前數(shù)據(jù)包的狀態(tài)。

如果headerFound == 1,說明數(shù)據(jù)包是有幀頭的,可以通過pHorU獲得幀頭

如果enderFound == 1,說明數(shù)據(jù)包是有幀尾的,可以通過pEnder獲得幀尾

如果isFull == 1,說明此數(shù)據(jù)包是因?yàn)榻邮諈^(qū)滿了放不下了而產(chǎn)生的回調(diào),在一些需要根據(jù)某個(gè)字段來判斷數(shù)據(jù)包真正大小的協(xié)議里,可以通過調(diào)整接收緩沖區(qū)的大小來恰當(dāng)?shù)漠a(chǎn)生flush。

如果UniqueFound == 1,說明此數(shù)據(jù)包是標(biāo)志序列,這時(shí)緩沖區(qū)內(nèi)的內(nèi)容等于pHorU指向的那個(gè)標(biāo)志序列

接收機(jī)類

V1.0版本中要求用戶自己分配結(jié)構(gòu)體的空間,為了更加面向?qū)ο?,現(xiàn)已改為動(dòng)態(tài)分配,而把具體結(jié)構(gòu)體和對應(yīng)方法封裝在模塊內(nèi)部。

typedef struct RXMAC_STRUCT * RxMac;

模塊提供Create函數(shù)來創(chuàng)建接收機(jī)實(shí)例并返回指向?qū)嵗闹羔槨?

// to create an instance of RxMac //  flags       標(biāo)志字符串結(jié)構(gòu)體的數(shù)組 //  flagsCnt    標(biāo)志字符串結(jié)構(gòu)體的個(gè)數(shù) //  buf         用戶提供給接收機(jī)用的緩沖區(qū)  //  bufLen      緩沖區(qū)的大小(起碼應(yīng)該要能放的下最長的標(biāo)志字符串) //  onFeeded    在每次被Feed時(shí)觸發(fā) //  onGetHeader 獲得頭標(biāo)志位時(shí)觸發(fā)。 //  onFlushed   收到一幀數(shù)據(jù)時(shí)的回調(diào)函數(shù) RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, 
                RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed);

調(diào)用實(shí)例的方法時(shí)把這個(gè)指針作為第一個(gè)參數(shù)以模擬面向?qū)ο蟛僮鳌?

過濾器

接收機(jī)每次被feed時(shí),都會觸發(fā)onFeeded事件(可以在配置中取消這個(gè)事件以節(jié)省點(diǎn)代碼)。原型如下:

typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
  • ? pCurChar :指向接收區(qū)中剛收到的字符

  • ? bytesCnt :這個(gè)字符是接收區(qū)中的第幾個(gè)字符

此時(shí),接收機(jī)已經(jīng)將其放入接收區(qū)但是還沒進(jìn)一步進(jìn)行判斷,用戶可以修改字符/配置接收機(jī)以改變接收機(jī)的行為,比如將收到的字母全變?yōu)樾憽;蛘吒鶕?jù)收到的數(shù)據(jù)來決定還要收多少數(shù)據(jù)。

onGetHeader事件

當(dāng)找到任意幀頭時(shí)會觸發(fā)。

接收機(jī)運(yùn)行邏輯

接收機(jī)的運(yùn)作邏輯如下:

邊際條件

標(biāo)志序列盡量不要有重合,如果同時(shí)可能匹配兩個(gè)標(biāo)志序列,最終行為是未定義的,不保證正確執(zhí)行,最終結(jié)果可能與標(biāo)志序列的位置以及類型有關(guān)系。

同一個(gè)標(biāo)志串可以同時(shí)是多種類型,比如同時(shí)是幀頭與幀尾,但要小心類型間不要有沖突,否則不保證正確執(zhí)行。

對于標(biāo)志序列匹配到一半發(fā)生了接收緩沖區(qū)滿,從而導(dǎo)致發(fā)生標(biāo)志序列匹配時(shí),接收緩沖區(qū)中只有半個(gè)標(biāo)志序列的情況:

如果標(biāo)志序列是(強(qiáng))特殊序列或(強(qiáng))幀頭的情況,可以保證功能正常運(yùn)行。

如果標(biāo)志序列是強(qiáng)幀尾的情況,緩沖區(qū)內(nèi)會只剩下后半段的幀尾,但可以根據(jù)pEnder參數(shù)來得知真正的幀尾。幀尾不會發(fā)生這種邊際條件。

相關(guān)代碼 此模塊使用了我自己寫的Buffer模塊作為內(nèi)部緩沖區(qū)來判斷標(biāo)志字符串。

https://blog.csdn.net/lin_strong/article/details/88236566

接收機(jī)代碼

RxMac.h

/*
*******************************************************************************************
*
*
*                                  Universal Receive State Machine
*                                          通用接收狀態(tài)機(jī)
*
* File : RxMac.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 2018/05/29 1.0 the prototype
*          2019/01/23 2.0 modify the type names to more readable ones, though preserve
*                       the old-style for forward compatibility;
*                         change init method to create method which use malloc to alloc
*                       instance, and the corresponding destroy method.
*                         change the internal buffer module from RINGQUEUE to BufferArray,
*                       so user no longer need to know the internal flags management and
*                       allocate the space for it.
*                         add RxMac_FeedDatas method for convenient.
*          2019/03/07 2.1 some modification to the malloc configuration
*
* NOTE(s):  1. the receive process has two basic state
*              A. preRx: when haven't found any header, the RxMac will search for the unique
*                        flag, header and strong-ender. Only when a header is found will come
*                        to next step.
*              B. Rxing: the RxMac will put the successive bytes into the buffer, and search
*                        for the strong-unique, strong-header, ender. 
*           2. the module is drived by the RxMac_FeedData(), user should get the the char 
*              from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
*              or RxMac_FeedDatas().
*           3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
*              to notify the results; user can judge the frame through the state parameter; 
*               state.headerFound == 1:   find any header, the header is passed by HorU
*               state.enderFound  == 1:   find any ender,  the ender  is passed by Ender
*               state.isFull      == 1:   the buffer is full, maybe you should check headerFound
*                                         to see whether a header has been found.
*               state.uniqueFound == 1:   find any unique flag. In this case, other parameters will
*                                         always be 0 ,the data in the buffer will be the flag,
*                                         and the unique flag is passed by HorU.
*           4. To use this module, for each receive machine:
*              A. define malloc to configure the module, see CONFIGURATION
*              B. allocate the space for buffer and FLAGS.
*                   RXFLAG_STRUCT flags[2];
*                   uint8_t buf[300];
*              C. set the flags according to the protocol, define the callback functions
*                  according to your need.
*                   static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... };
*                   static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,
*                      RxState state,RxFlag HorU,RxFlag Ender){ ...... };
*                   const uint8_t HeaderFlag[] = "Header";
*                   const uint8_t EnderFlag[] = "\r\n";
*                   RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER);
*                   RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER |
*                                 RXFLAG_OPTION_NOTFILL_ENDER);
*              D. create the receive machine:
*                   RxMac mac;
*                   mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL, 
*                                 onGetHeader, onFlushed );
*              E. feed the receive machine:
*                   while(1){
*                     c = GetNextChar();
*                     RxMac_FeedData(mac,c);
*                   }
*              F. destroy the receive machine if need.
*                  RxMac_Destroy(mac);
*******************************************************************************************
*/ #ifndef RX_MAC_H #define RX_MAC_H /*
*******************************************************************************************
*                                       INCLUDES
*******************************************************************************************
*/ #include  /*
*******************************************************************************************
*                                  CONFIGURATION  配置
*******************************************************************************************
*/ // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module //#define RXMAC_ARGUMENT_CHECK_DISABLE // #define RXMAC_NOTFILL_DISABLE to disable the notFill option //#define RXMAC_NOTFILL_DISABLE // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event. //#define RXMAC_ONFEEDED_DISABLE // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is  // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate // buffer and call init(); //#define RXMAC_SINGLETON_EN // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer. // and don't forget to define CODEWARRIOR malloc //#define RXMAC_BUF_RPAGE /*
*******************************************************************************************
*                                 ADDRESSING MODE 尋址模式
*******************************************************************************************
*/ #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR #define RXMAC_BUF_ADDRESSING_MODE  __rptr #endif #endif #ifndef RXMAC_BUF_ADDRESSING_MODE #define RXMAC_BUF_ADDRESSING_MODE #endif typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr; /*
*********************************************************************************************
*                                    ERROR CODE
*********************************************************************************************
*/ #define RXMAC_ERR_NONE           0 #define RXMAC_ERR_ARGUMENT       1 #define RXMAC_ERR_POINTERNULL    2 #define RXMAC_ERR_UNKNOWN        3 #define RXMAC_ERR_INIT           4 /*
*********************************************************************************************
*                                RECEIVE FLAG STRUCT
*********************************************************************************************
*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTION_HEADER               0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_HEADER        0x03 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTION_NOTFILL_HEADER       0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTION_ENDER                0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTION_STRONG_ENDER         0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTION_NOTFILL_ENDER        0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTION_UNIQUE               0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTION_STRONG_UNIQUE        0xC0 // receive flag typedef struct RXFLAG_STRUCT{ uint8_t const * pBuf; uint8_t len; uint8_t option;
} RXFLAG_STRUCT; typedef RXFLAG_STRUCT const * RxFlag; // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt); // to  initialize a receive flag //    flag    point to the target RXFLAG_STRUCT. //    buf     pointer to the flag buffer //    size    size of flag  //    opt     see  RXFLAG_OPTION_XXXXX, bit mode #define RxFlag_Init(flag,buf,size,opt)     \
{(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);} /*
*********************************************************************************************
*                                   TYPE DEFINITION
*********************************************************************************************
*/ typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull     : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RxState; typedef struct RXMAC_STRUCT * RxMac; typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
                                   RxFlag HorU,RxFlag Ender); typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag); typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); /*
*******************************************************************************************
*                                  FUNCTION DECLARATION
*******************************************************************************************
*/ // to create an instance of RxMac //  flags       標(biāo)志字符串結(jié)構(gòu)體的數(shù)組 //  flagsCnt    標(biāo)志字符串結(jié)構(gòu)體的個(gè)數(shù) //  buf         用戶提供給接收機(jī)用的緩沖區(qū)  //  bufLen      緩沖區(qū)的大小(起碼應(yīng)該要能放的下最長的標(biāo)志字符串) //  onFeeded    在每次被Feed時(shí)觸發(fā) //  onGetHeader 獲得頭標(biāo)志位時(shí)觸發(fā)。 //  onFlushed   收到一幀數(shù)據(jù)時(shí)的回調(diào)函數(shù) RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收機(jī)內(nèi)喂字節(jié) void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收區(qū)長度為最長那個(gè)長度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 設(shè)置最大接收到多少個(gè)字節(jié) uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收機(jī)的狀態(tài) uint8_t RxMac_ResetState(RxMac mac); // 強(qiáng)制接收機(jī)flush uint8_t RxMac_Flush(RxMac mac); // 設(shè)置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 設(shè)置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 設(shè)置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H

RxMacPrivate.h

/*
*******************************************************************************************
*
*
*                       Private Declarations for Universal Receive State Machine
*
* File : RxMacPrivate.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 
* NOTE(s): 
*******************************************************************************************
*/ /*
*******************************************************************************************
*                                  FUNCTION DECLARATION
*******************************************************************************************
*/ // 打印內(nèi)部緩沖區(qū),返回緩沖區(qū)的長度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /*
*******************************************************************************************
*                                      RECEIVE FLAG STRUCT
*******************************************************************************************
*/ // struct of RXFLAG_STRUCT.option  /*typedef struct RXFLAG_OPTION{
  unsigned int isHeader : 1;  // 1: the flag is the head of the frame
  unsigned int strong_H : 1;  // 1: strong-header, RxMac will 
  unsigned int notfill_H: 1;  // 0: fill the flag into the buffer when found as header
  unsigned int isEnder  : 1;  // 1: the flag is the end of the frame
  unsigned int strong_E : 1;  // 
  unsigned int notfill_E: 1;  // 0: fill the flag into the buffer when found as ender
  unsigned int isUnique : 1;  // 1: the flag is a unique flag which is treated as single frame.
  unsigned int strong_U : 1;  // 0: when receiving a frame, RxMac will not 
}; //*/ // normal header, RxMac will only check it in Step A #define RXFLAG_OPTBIT_HEADER               0x01 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_HEADER        0x02 // the header will not be filled into buffer when found.(only valid when is header) #define RXFLAG_OPTBIT_NOTFILL_HEADER       0x04 // normal ender, RxMac will only check it in Step B #define RXFLAG_OPTBIT_ENDER                0x08 // strong header, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_ENDER         0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define RXFLAG_OPTBIT_NOTFILL_ENDER        0x20 // normal unique, RxMac will only check it in Step A #define RXFLAG_OPTBIT_UNIQUE               0x40 // strong unique, RxMac will always check it. #define RXFLAG_OPTBIT_STRONG_UNIQUE        0x80 #define STATEMASK_STEPA   \
  (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB   \
  (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER) #define RXFLAGMASK_USUHSH   \
  (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | \
  RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE) // BOOL _RxFlag_isHeader(RxFlag flag); #define _RxFlag_isHeader(flag)   \
  ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER)) // BOOL _RxFlag_isEnder(RxFlag flag); #define _RxFlag_isEnder(flag)    \
  ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER  | RXFLAG_OPTION_ENDER)) // BOOL _RxFlag_isUnique(RxFlag flag); #define _RxFlag_isUnique(flag)   \
  ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE)) // BOOL _RxFlag_dontFillHeader(RxFlag flag); #define _RxFlag_dontFillHeader(flag) \
  ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER) // BOOL _RxFlag_dontFillEnder(RxFlag flag); #define _RxFlag_dontFillEnder(flag) \
  ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER) /*
*******************************************************************************************
*                                    FORWARD COMPATIBILITY
*******************************************************************************************
*/ // 以下僅為前向兼容 typedef RxMacPtr          pRB_BYTE; typedef RXFLAG_STRUCT     RX_FLAG,*pRX_FLAG; typedef RxMac             pRX_MAC; typedef RxState           RX_STATE; #define FLAG_OPTION_HEADER             RXFLAG_OPTION_HEADER #define FLAG_OPTION_STRONG_HEADER      RXFLAG_OPTION_STRONG_HEADER #define FLAG_OPTION_NOTFILL_HEADER     RXFLAG_OPTION_NOTFILL_HEADER #define FLAG_OPTION_ENDER              RXFLAG_OPTION_ENDER #define FLAG_OPTION_STRONG_ENDER       RXFLAG_OPTION_STRONG_ENDER #define FLAG_OPTION_NOTFILL_ENDER      RXFLAG_OPTION_NOTFILL_ENDER #define FLAG_OPTION_UNIQUE             RXFLAG_OPTION_UNIQUE #define FLAG_OPTION_STRONG_UNIQUE      RXFLAG_OPTION_STRONG_UNIQUE #define RX_FLAG_INIT                   RxFlag_Init

RxMac.c

/*
*******************************************************************************************
*
*
*                         Implementation of the Universal Receive State Machine
*                                          通用接收狀態(tài)機(jī)
*
* File : RxMac.c
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 2018/05/29 1.0 the prototype
*          2019/01/23 2.0 In addition to the content in RxMac.h:
*                           abstract the flag management part as RxFlagMgr and the
*                          corresponding methods.
*                           refactor the code.
*          2019/03/07 2.1 some modification to the malloc configuration
* NOTE(s): 
*
*******************************************************************************************
*/ /*
*******************************************************************************************
*                                       INCLUDES
*******************************************************************************************
*/ #include  #include  #include  #include "RxMac.h" #include "BufferMallocArray.h" /*
*******************************************************************************************
*                                   RECEIVE FLAGS MANAGER
*******************************************************************************************
*/ typedef struct RXFLAGMGR_STRUCT { // buffer to hold the pre-data which hasn't matched any flag. BufferUINT8Indexed BufForFlag; // the flag array to be matched. RxFlag   Flags; // count of flags. uint8_t FlagsCnt; // current state, in which headerFound will influence the match behavior.  // controlled by the child class. RxState  state;
}RXFLAGMGR_STRUCT; static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte); static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen); static void _RxFlagMgr_Destroy(RxMac mac); static void _RxFlagMgr_Reset(RxMac mac); /*
*******************************************************************************************
*                                   STRUCT DIFINITION
*******************************************************************************************
*/ typedef struct RXMAC_STRUCT{ // manage the flag matches. RXFLAGMGR_STRUCT FlagMgr; // record the Header or Unique flag. RxFlag   pHorU; // internal buffer to hold data. RxMacPtr pRxBuf; // length of the internal buffer uint16_t RxBufSize; // Count of the bytes in the internal buffer/ the index for next feeded byte uint16_t RxCnt;
  RXMAC_FILTER onFeeded;
  RXMAC_FLAG_EVENT onGetHeader;
  RXMAC_FLUSH_EVENT onFlushed;
} RXMAC_STRUCT; /*
*******************************************************************************************
*                          LOCAL  FUNCITON  DECLARATION
*******************************************************************************************
*/ #ifndef RXMAC_SINGLETON_EN #define _pMac          mac #define _BufForFlag   (_pMac->FlagMgr.BufForFlag) #define _Flags        (_pMac->FlagMgr.Flags) #define _FlagsCnt     (_pMac->FlagMgr.FlagsCnt) #define _state        (_pMac->FlagMgr.state) #define _pHorU        (_pMac->pHorU) #define _pRxBuf       (_pMac->pRxBuf) #define _RxBufSize    (_pMac->RxBufSize) #define _RxCnt        (_pMac->RxCnt) #define _fonFeeded    (_pMac->onFeeded) #define _fonGetHeader (_pMac->onGetHeader) #define _fonFlushed   (_pMac->onFlushed) #define _RxMac_Destroy()    (free(mac)) #else static RXMAC_STRUCT _mac; // 單例模式中,這個(gè)指針用于標(biāo)識是否單例已初始化過 static RxMac _pMac = NULL; #define _BufForFlag   (_mac.FlagMgr.BufForFlag) #define _Flags        (_mac.FlagMgr.Flags) #define _FlagsCnt     (_mac.FlagMgr.FlagsCnt) #define _state        (_mac.FlagMgr.state) #define _pHorU        (_mac.pHorU) #define _pRxBuf       (_mac.pRxBuf) #define _RxBufSize    (_mac.RxBufSize) #define _RxCnt        (_mac.RxCnt) #define _fonFeeded    (_mac.onFeeded) #define _fonGetHeader (_mac.onGetHeader) #define _fonFlushed   (_mac.onFlushed) #define _RxMac_Destroy()  (_pMac = NULL) #endif #define _stateByte      (*(uint8_t *)(&_state)) #define _isRxBufFull()  (_RxCnt >= _RxBufSize) #ifndef RXMAC_ONFEEDED_DISABLE #define _onFeeded(pChar,cnt) if(_fonFeeded != NULL)  _fonFeeded(_pMac,pChar,cnt); #else #define _onFeeded(pChar,cnt) #endif #define _onGetHeader(headerFlag) if(_fonGetHeader != NULL) _fonGetHeader(_pMac,headerFlag); #undef _DONT_CHECK_MAC #ifdef RXMAC_ARGUMENT_CHECK_DISABLE #define _DONT_CHECK_MAC #endif #ifdef RXMAC_SINGLETON_EN #define _DONT_CHECK_MAC #endif #ifdef _DONT_CHECK_MAC #define _checkMacNotNull() #define _checkMacNotNull_void() #else #define _checkMacNotNull() if(_pMac == NULL)  return RXMAC_ERR_POINTERNULL; #define _checkMacNotNull_void() if(_pMac == NULL)  return; #endif #ifdef RXMAC_BUF_RPAGE #ifdef CODEWARRIOR static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n); #define memcpy(dest,src,n)   _memcpy_internal(dest,src,n) #endif #endif // 沖刷緩沖區(qū) static void _flush(RxMac mac,RxFlag ender); // 往接收機(jī)緩沖區(qū)內(nèi)放數(shù)據(jù) static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len); static void _RxMac_FlushIfFull(RxMac mac); static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot); static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot); static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot); static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot); /*
*******************************************************************************************
*                                      RxMac_Create()
*
* Description : To create a receive machine instance.    創(chuàng)建一個(gè)接收機(jī)實(shí)例
*
* Arguments   : flags      pointer to the flags(an array); 指向標(biāo)志串(數(shù)組)的指針
*               flagsCnt   the count of the flags;         有多少個(gè)標(biāo)志串;
*               buf        pointer to the buffer provided to the RxMac;提供給接收機(jī)使用的緩存
*               bufLen     the size of the buffer.         緩存的大小
*               onFeeded   the callback func that will be called everytime feeded, you
*                          can modify the feeded byte in this callback.
*                          每次被feed時(shí)會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標(biāo)志位的判斷
*               onGetHeader the callback func that will be called when find a header.
*                          當(dāng)發(fā)現(xiàn)幀頭時(shí)會調(diào)用的回調(diào)函數(shù)
*               onFlushed  the callback func that will be called when flushed.
*                          當(dāng)Flush時(shí)會調(diào)用的回調(diào)函數(shù)
*
* Return      : Pointer to the created instance.
*               NULL      if any error.
*
* Note(s)     : 1. size of buffer should bigger than the longest flag, or the flag will be 
*               useless.
*               2. if flagsCnt > 0, flags can't point to NULL.
*               3. you must provide a buffer.
*               4. if you enable the RXMAC_SINGLETON_EN, multi-create will pointer to the
*                  same instance initialized as the last create.
*
*               void onGetHeader(RxMac sender,RxFlag flag):
*                sender   the pointer to the RxMac which call this function
*                flag     the header matched
*
*               void onFeeded(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt):
*                sender    the pointer to the RxMac which call this function
*                pCurChar  point to the byte just received, you can change it before any other process.
*                bytesCnt  the number of bytes in the buffer including the char just feeded.
*
*               void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,RxState state,RxFlag HorU,
*                  RxFlag Ender);
*                sender    the pointer to the RxMac which call this function
*                buf       the pointer to the frame.
*                len       the length of frame.
*                state     the state of frame.
*                HorU      point to the header flag if state.headerFound == 1, or unique flag if 
*                          state.uniqueFound == 1.
*                Ender     point to the ender flag if state.enderFound == 1.
*******************************************************************************************
*/ RxMac RxMac_Create(RXFLAG_STRUCT const flags[],uint8_t flagsCnt,RxMacPtr buf,uint16_t bufLen,RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){ uint8_t i, maxLen = 0; #ifndef RXMAC_SINGLETON_EN RxMac mac; #endif #ifndef RXMAC_ARGUMENT_CHECK_DISABLE if((flags == NULL && flagsCnt > 0 ) || buf == NULL) return NULL; #endif // find out the max length of flags. for(i = 0; i < flagsCnt; i++){ if(flags[i].len > maxLen)
      maxLen = flags[i].len;
  } #ifndef RXMAC_ARGUMENT_CHECK_DISABLE if(bufLen < maxLen){ return NULL;
  } #endif #ifdef RXMAC_SINGLETON_EN if(_pMac != NULL) // if have created one instance, free the previous FlagBuf _RxFlagMgr_Destroy(&_mac); else _pMac = &_mac; #else if((mac = (RxMac)malloc(sizeof(RXMAC_STRUCT))) == NULL){ return NULL;
  } #endif if(!_RxFlagMgr_Init(_pMac,flags,flagsCnt,maxLen)){
    _RxMac_Destroy(); return NULL;
  }
  _pHorU = NULL;
  _pRxBuf = buf;
  _RxCnt = 0;
  _RxBufSize = bufLen;
  _fonFeeded = onFeeded;
  _fonGetHeader = onGetHeader;
  _fonFlushed = onFlushed; return _pMac;
} /*
*******************************************************************************************
*                                        RxMac_Destroy()
*
* Description : Destroy a receive machine instance.
*
* Arguments   : mac     the target receive machine.     目標(biāo)接收機(jī)
*
* 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).    用于給接收機(jī)下一個(gè)字符
*
* Arguments   : mac    the target receive machine.     目標(biāo)接收機(jī)
*               c      the char to feed;               下一個(gè)字符
*
* 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.   設(shè)置接收緩沖區(qū)的大小
*
* Arguments   : mac     the target receive machine.     目標(biāo)接收機(jī)
*               size    the size to set;
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*               RXMAC_ERR_ARGUMENT        if size is wrong.
* Note(s)     : the size should bigger than the current number of chars in the RxBuf.
*               
*******************************************************************************************
*/ uint8_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.   重置接收機(jī)的狀態(tài)
*
* Arguments   : mac    the target receive machine.    目標(biāo)接收機(jī)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*******************************************************************************************
*/ uint8_t RxMac_ResetState(RxMac mac){
  _checkMacNotNull(); // 復(fù)位接收機(jī) Buffer_Cleanup((Buffer)_BufForFlag);
  _RxCnt = 0;
  _stateByte = 0;
  _pHorU = NULL; return RXMAC_ERR_NONE;
} /*
*******************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : mac     the target receive machine.     目標(biāo)接收機(jī)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*******************************************************************************************
*/ uint8_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.     目標(biāo)接收機(jī)
*               onFeeded  the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/ uint8_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.     目標(biāo)接收機(jī)
*               onGetHeader  the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if mac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/ uint8_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.     目標(biāo)接收機(jī)
*               onFlushed    the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
******************************************************************************************
*/ uint8_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.
*               給開發(fā)者用于查看內(nèi)部緩存的
*
* Arguments   : mac          the target receive machine.     目標(biāo)接收機(jī)
*               onFlushed    the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : the len of buffer printed.
*
* Note(s)     :
*
******************************************************************************************
*/ uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf){ memcpy(buf,_pRxBuf,_RxCnt); return _RxCnt;
} /*
******************************************************************************************
*                                   LOCAL  FUNCITON 
******************************************************************************************
*/ static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n){
  RxMacPtr p = dest; while(n-- > 0)
    *p++ = *src++; return dest;
} static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len){ memcpy(_pRxBuf+_RxCnt,buf,len);
  _RxCnt += len;
} static void _flush(RxMac mac,RxFlag ender){ // 觸發(fā)回調(diào) if((_RxCnt > 0 || ender != NULL) && _fonFlushed != NULL)
    _fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender); // 復(fù)位接收機(jī) _RxCnt = 0;
  _stateByte = 0;
  _pHorU = NULL;
}

BOOL BufferUINT8Indexed_BackMatch(BufferUINT8Indexed buf,uint8_t const *toMatch,uint16_t len){ uint16_t cnt = _Buffer_getCount(buf); if(len > cnt) return FALSE; while(len > 0){ if(_BufferUINT8Indexed_get(buf,--cnt) != toMatch[--len]) return FALSE;
  } return TRUE;
} static void _RxMac_FlushIfFull(RxMac mac){ if(_isRxBufFull()){
    _state.isFull = 1;
    _flush(_pMac,NULL);
  }
} static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot){ if(flagJustGot->option & RXFLAGMASK_USUHSH){ if(_RxCnt > flagJustGot->len){
      _RxCnt -= flagJustGot->len;
      _flush(_pMac,NULL);
    }else{
      _RxCnt = 0;
    }
    _pHorU = flagJustGot;
  }
} static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot){ #ifndef RXMAC_NOTFILL_DISABLE if(!_RxFlag_dontFillHeader(flagJustGot)) #endif _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
  _state.headerFound = 1;
  _onGetHeader(flagJustGot);
  _RxMac_FlushIfFull(mac);
} static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot){
  _state.uniqueFound = 1;
  _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
  _flush(_pMac,NULL);
} static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot){
  _state.enderFound = 1; if(_RxCnt < flagJustGot->len){ // if part of the flag has been manually flushed. _RxCnt = 0; // restore the buffer. _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len); 
  } #ifndef RXMAC_NOTFILL_DISABLE if(_RxFlag_dontFillEnder(flagJustGot)) if(_RxCnt > flagJustGot->len)
      _RxCnt -= flagJustGot->len; else _RxCnt = 0; #endif _flush(_pMac,flagJustGot);
} static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte){ uint8_t i,mask; if(_Buffer_isFull(_BufForFlag))
    BufferUINT8_FrontOut((BufferUINT8)_BufForFlag);
  BufferUINT8_BackIn((BufferUINT8)_BufForFlag,nextByte); // mask to identify possible flag mask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA; for(i = 0; i < _FlagsCnt; i++){ if((_Flags[i].option & mask) && 
      BufferUINT8Indexed_BackMatch(_BufForFlag,_Flags[i].pBuf,_Flags[i].len)){
        Buffer_Cleanup((Buffer)_BufForFlag); return &_Flags[i];
    }
  } 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" /*
*********************************************************************************************************
*                                      LOCAL  FUNCTION  DECLARE
*********************************************************************************************************
*/ static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt); static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender); static void onGetHeader(RxMac sender,RxFlag flag); static void onGetHeader2(RxMac sender,RxFlag flag); /*
*********************************************************************************************************
*                                           LOVAL VARIABLE
*********************************************************************************************************
*/ static RxMac  mac = NULL; static RXFLAG_STRUCT flags[4]; #define BUF_SIZE  20 static uint8_t buffer[BUF_SIZE]; // 協(xié)議示例1: // 幀頭    :HEADER 或者 START // 強(qiáng)幀尾  :END // 強(qiáng)特殊串:12345  //  static void protocol1_init(void){
  RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
  RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
  mac = RxMac_Create(flags,4,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
} // 協(xié)議示例2: // 幀頭    : START // 幀頭后的第1個(gè)字符表示后面還要接收多少個(gè)字符 1-9,'4'表示4個(gè),如果不是數(shù)字或?yàn)?0',則等待幀尾 // 幀尾    : END // 特殊串:  NOW //  static void protocol2_init(void){
  RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
  RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
  mac = RxMac_Create(flags,3,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
} /*
*********************************************************************************************************
*                                           CALLBACK FUNCITON
*********************************************************************************************************
*/ static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt){ // 因?yàn)榘l(fā)現(xiàn)幀頭后才掛載事件,所以下一次回掉正好是說明字符數(shù)的那個(gè)字符,否則還得根據(jù)bytesCnt來判斷當(dāng)前位置 RxMac_SetOnFeeded(sender,NULL); if(*pCurChar > '0' && *pCurChar <= '9' ){ // bytesCnt是當(dāng)前收到了多少個(gè)字符,所以接收區(qū)大小為當(dāng)前字符數(shù)加上還要接收的 RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  }
} static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender){
  buf[len] = '\0'; printf("\nFlushed:"); if(state.headerFound) printf("headerFound,"); if(state.enderFound) printf("enderFound,"); if(state.isFull) printf("full,"); if(state.uniqueFound) printf("unique,"); printf("\nDatas:%s\n",buf);
  RxMac_SetRxSize(sender,BUF_SIZE);
} static void onGetHeader(RxMac sender,RxFlag flag){ printf("\nFoundHeader:%s\n",flag->pBuf);
} static void onGetHeader2(RxMac sender,RxFlag flag){ printf("\nFoundHeader:%s\n",flag->pBuf);
  RxMac_SetOnFeeded(sender,onGetData);
} /*
*********************************************************************************************************
*                                           MAIN FUNCTION
*********************************************************************************************************
*/ void main(void) { // 選擇想要實(shí)驗(yàn)的協(xié)議來初始化 protocol1_init(); // protocol2_init(); while (1) {
    c = getchar(); // 回顯 putchar(c);
    RxMac_FeedData(mac,c);
  }
}

示例協(xié)議1測試結(jié)果

示例協(xié)議2測試結(jié)果

可以看到,第二個(gè)協(xié)議中我們通過改變緩沖區(qū)大小成功控制了數(shù)據(jù)包的長度。

雖然這里的示例都是基于ASCII的,但這只是為了觀察起來方便,普通的基于二進(jìn)制的協(xié)議也是可以使用這個(gè)模塊的。

v1.0代碼

舊版代碼中引用了我自己寫的(現(xiàn)已棄用)環(huán)形緩沖區(qū)模塊:https://blog.csdn.net/lin_strong/article/details/73604561

接收機(jī)代碼

頭文件

/*
*********************************************************************************************************
*
*
*                                  Universal Receive State Machine
*                                          通用接收狀態(tài)機(jī)
*
* File : RxMac.h
*
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2018/05/29
* version: 1.0
* History: 2018/05/29     the prototype
* NOTE(s):  1. the receive process has two basic state
*              A. preRx: when haven't found any header, the RxMac will search for the unique
*                        flag, header and strong-ender. Only when a header is found will come
*                        to next step.
*              B. Rxing: the RxMac will put the successive bytes into the buffer, and search
*                        for the strong-unique, strong-header, ender. 
*           2. the module is drived by the RxMac_FeedData(), user should get the the char 
*              from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
*           3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
*              to notify the results; user can judge the frame through the state parameter; 
*               state.headerFound == 1:   find any header, the header is passed by pHorU
*               state.enderFound  == 1:   find any ender,  the ender  is passed by pEnder
*               state.isFull      == 1:   the buffer is full, maybe you should check headerFound
*                                         to see whether a header has been found.
*               state.uniqueFound == 1:   find any unique flag. In this case, other parameters will
*                                         always be 0 & the datas in the buffer will be the flag.
*           4. To use this module, for each receive machine:
*              A. allocate the space for buffer, RxMac & FLAGS
*                   RX_MAC _Mac;
*                   RX_FLAG flags[2];
*                   INT8U buf[300];
*              B. set the flags according to the protocol, define the callback funcitons
*                  according to your need.
*                   static void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){ ...... };
*                   static void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,
*                      RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){ ...... };
*                   const INT8U HeaderFlag[] = "Header";
*                   const INT8U EnderFlag[] = "\r\n";
*                   RX_FLAG_INIT(flags,HeaderFlag,StrSize(HeaderFlag),FLAG_OPTION_HEADER);
*                   RX_FLAG_INIT(&flags[1],EnderFlag,StrSize(EnderFlag),FLAG_OPTION_ENDER |
*                                 FLAG_OPTION_NOTFILL_ENDER);
*              C. init the receive machine:
*                   RxMac_Init(&_Mac,flags,2,6,buf,300,NULL, onGetHeader, onFlushed );
*              D. feed the receive machine:
*                   while(1){
*                     c = GetNextChar();
*                     RxMac_FeedData(&_Mac,c);
*                   }
*********************************************************************************************************
*/ #ifndef RX_MAC_H #define RX_MAC_H /*
*********************************************************************************************************
*                                       INCLUDES
*********************************************************************************************************
*/ #include "RingQueue.h" #include  //typedef unsigned char INT8U; //typedef unsigned short INT16U; /*
*********************************************************************************************************
*                                       ADDRESSING MODE 尋址模式
*********************************************************************************************************
*/ // the addressing mode for buffer #define RXMAC_BUF_ADDRESSING_MODE   RQ_ADDRESSING_MODE typedef INT8U     RB_BYTE; typedef RB_BYTE * RXMAC_BUF_ADDRESSING_MODE pRB_BYTE; /*
*********************************************************************************************************
*                                       CONFIGURATION  配置
*********************************************************************************************************
*/ #define RXMAC_ARGUMENT_CHECK_EN   TRUE #define RXMAC_NOTFILL_EN          TRUE #define RXMAC_ONFEEDED_EN         TRUE // TRUE: enable the onFeeded function. #define RXMAC_SINGLETON_EN        FALSE // TRUE: enable singleton pattern,so argument pRxMac of interfaces // is useless, and user don't need to allocate space for RX_MAC, // but you still need to allocate buffer and call init(); /*
*********************************************************************************************************
*                                       CONST
*********************************************************************************************************
*/ #define RXMAC_ERR_NONE           0 #define RXMAC_ERR_ARGUMENT       1 #define RXMAC_ERR_POINTERNULL    2 #define RXMAC_ERR_UNKNOWN        3 #define RXMAC_ERR_INIT           4 /*
*********************************************************************************************************
*                                 TYPE DEFINITION
*********************************************************************************************************
*/ // struct of RX_FLAG.option  /*typedef struct FLAG_OPTION{
  unsigned int isHeader : 1;  // 1: the flag is the head of the frame
  unsigned int strong_H : 1;  // 1: strong-header, RxMac will 
  unsigned int notfill_H: 1;  // 0: fill the flag into the buffer when found as header
  unsigned int isEnder  : 1;  // 1: the flag is the end of the frame
  unsigned int strong_E : 1;  // 
  unsigned int notfill_E: 1;  // 0: fill the flag into the buffer when found as ender
  unsigned int isUnique : 1;  // 1: the flag is a unique flag which is treated as single frame.
  unsigned int strong_U : 1;  // 0: when receiving a frame, RxMac will not 
}; //*/ // 接收標(biāo)志位 typedef struct rx_flag{
   INT8U const *pBuf;
   INT8U len;
   INT8U option;
} RX_FLAG,* pRX_FLAG; // normal header, RxMac will only check it in Step A #define FLAG_OPTION_HEADER               0x01 // strong header, RxMac will always check it. #define FLAG_OPTION_STRONG_HEADER        0x03 // the header will not be filled into buffer when found.(only valid when is header) #define FLAG_OPTION_NOTFILL_HEADER       0x04 // normal ender, RxMac will only check it in Step B #define FLAG_OPTION_ENDER                0x08 // strong header, RxMac will always check it. #define FLAG_OPTION_STRONG_ENDER         0x18 // the ender will not be filled into buffer when found.(only valid when is ender) #define FLAG_OPTION_NOTFILL_ENDER        0x20 // normal unique, RxMac will only check it in Step A #define FLAG_OPTION_UNIQUE               0x40 // strong unique, RxMac will always check it. #define FLAG_OPTION_STRONG_UNIQUE        0xC0 typedef struct rx_state{ unsigned int headerFound: 1; // 1: have get header unsigned int enderFound : 1; // 1: have get ender unsigned int isFull     : 1; // 1: the buffer is full unsigned int uniqueFound: 1; // 1: this is unique flag. } RX_STATE; typedef struct rx_mac RX_MAC, *pRX_MAC; typedef void (* RXMAC_FLUSH_EVENT)(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder); typedef void (* RXMAC_FLAG_EVENT)(pRX_MAC sender,pRX_FLAG pFlag); typedef void (* RXMAC_FILTER)(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt); struct rx_mac{
   RING_QUEUE FlagQueue; // 用于判斷標(biāo)志串的環(huán)形緩沖區(qū)對象 pRX_FLAG Flags; // 標(biāo)志數(shù)組 INT8U FlagsCnt; // 標(biāo)志數(shù)組的個(gè)數(shù) RX_STATE state; // 接收的狀態(tài)(內(nèi)部使用) pRX_FLAG pHorU; // 內(nèi)部使用 pRB_BYTE pRxBuf; // 存放數(shù)據(jù)的緩沖區(qū) INT16U RxBufSize; // 緩沖區(qū)的長度 pRB_BYTE pCur; // 指向緩沖區(qū)內(nèi)下一個(gè)填充字符的位置 RXMAC_FILTER onFeeded; // 當(dāng)被喂字符時(shí)觸發(fā),返回指向緩沖區(qū)中剛剛喂進(jìn)來的字符的指針以及是緩沖區(qū)內(nèi)的第幾個(gè)字符 RXMAC_FLAG_EVENT onGetHeader; // 獲得頭標(biāo)志位時(shí)觸發(fā)。 RXMAC_FLUSH_EVENT onFlushed; // 回調(diào)函數(shù) }; /*
*********************************************************************************************************
*                                  FUNCTION DECLARATION
*********************************************************************************************************
*/ // to set the flag's option //    pbuf     pointer to the flag buffer //    bufSize  size of flag  //    opt      see  FLAG_OPTION_XXXXX #define RX_FLAG_INIT(pFlag,pbuf,bufSize,opt)     \
         (pFlag)->pBuf =(pbuf);(pFlag)->len =(bufSize);(pFlag)->option = (opt); // to init the RxMac INT8U RxMac_Init(pRX_MAC pRxMac, // 需要用戶自己申請個(gè)UNI_RX_MACHINE對象的空間 RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags, // 提供標(biāo)志字符串的數(shù)組 pRB_BYTE pBuf,INT16U BufLen, // 用戶需要提供緩沖區(qū) (緩存區(qū)大小起碼應(yīng)該要能 // 放的下最長的Flag+最長的幀,最后部分會分配給RQ) RXMAC_FILTER onFeeded, // 在每次被Feed時(shí)觸發(fā) RXMAC_FLAG_EVENT onGetHeader, // 獲得頭標(biāo)志位時(shí)觸發(fā)。 RXMAC_FLUSH_EVENT onFlushed // 收到一幀數(shù)據(jù)時(shí)的回調(diào)函數(shù) ); // 向接收機(jī)內(nèi)喂字節(jié) void RxMac_FeedData(pRX_MAC pRxMac,INT8U c); // 重置接收區(qū)長度為最長那個(gè)長度 INT8U RxMac_ResetRxSize(pRX_MAC pRxMac); // 設(shè)置最大接收到多少個(gè)字節(jié) INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size); // 重置接收機(jī)的狀態(tài) INT8U RxMac_ResetState(pRX_MAC pRxMac); // 強(qiáng)制接收機(jī)flush INT8U RxMac_Flush(pRX_MAC pRxMac); // 設(shè)置onFeeded INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded); // 設(shè)置onGetHeader INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader); // 設(shè)置onFlushed INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed); #endif // of RX_MAC_H

源文件:

/*
*********************************************************************************************************
*
*
*                                  Universal Receive State Machine
*                                          通用接收狀態(tài)機(jī)
*
* File : RxMac.c
*
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2018/05/29
* version: 1.0
* History: 
* NOTE(s): 
*
*********************************************************************************************************
*/ /*
*********************************************************************************************************
*                                       INCLUDES
*********************************************************************************************************
*/ #include "RxMac.h" #include  #include  /*
*********************************************************************************************************
*                                       CONSTANT
*********************************************************************************************************
*/ // normal header, RxMac will only check it in Step A #define FLAG_OPTBIT_HEADER               0x01 // strong header, RxMac will always check it. #define FLAG_OPTBIT_STRONG_HEADER        0x02 // the header will not be filled into buffer when found.(only valid when is header) #define FLAG_OPTBIT_NOTFILL_HEADER       0x04 // normal ender, RxMac will only check it in Step B #define FLAG_OPTBIT_ENDER                0x08 // strong header, RxMac will always check it. #define FLAG_OPTBIT_STRONG_ENDER         0x10 // the ender will not be filled into buffer when found.(only valid when is ender) #define FLAG_OPTBIT_NOTFILL_ENDER        0x20 // normal unique, RxMac will only check it in Step A #define FLAG_OPTBIT_UNIQUE               0x40 // strong unique, RxMac will always check it. #define FLAG_OPTBIT_STRONG_UNIQUE        0x80 #define STATEMASK_STEPA   (FLAG_OPTBIT_HEADER | FLAG_OPTBIT_UNIQUE | FLAG_OPTBIT_STRONG_ENDER) #define STATEMASK_STEPB   (FLAG_OPTBIT_STRONG_UNIQUE | FLAG_OPTBIT_ENDER | FLAG_OPTBIT_STRONG_HEADER) #define FLAGMASK_USUHSH   (FLAG_OPTBIT_HEADER | FLAG_OPTBIT_STRONG_HEADER | FLAG_OPTION_UNIQUE | FLAG_OPTBIT_STRONG_UNIQUE) /*
*********************************************************************************************************
*                                   LOCAL  FUNCITON  DECLARATION
*********************************************************************************************************
*/ #if(RXMAC_SINGLETON_EN == FALSE) #define _pRxMac       pRxMac #else static RX_MAC _RxMac; #define _pRxMac       (&_RxMac) #endif #define _FlagQueue   (_pRxMac->FlagQueue) #define _Flags       (_pRxMac->Flags) #define _FlagsCnt    (_pRxMac->FlagsCnt) #define _state       (_pRxMac->state) #define _stateByte   (*(INT8U *)(&_state)) #define _pHorU       (_pRxMac->pHorU) #define _pRxBuf      (_pRxMac->pRxBuf) #define _RxBufSize   (_pRxMac->RxBufSize) #define _pCur        (_pRxMac->pCur) #define _onFeeded    (_pRxMac->onFeeded) #define _onGetHeader (_pRxMac->onGetHeader) #define _onFlushed   (_pRxMac->onFlushed) #define _isRxBufFull()  ((_pCur - _pRxBuf) >= _RxBufSize) // 因?yàn)椴荒鼙WC用戶把數(shù)據(jù)放在非分頁區(qū),只好自己實(shí)現(xiàn)一個(gè),實(shí)際使用中如果確定在非分頁區(qū)可以把下面的宏替換為庫函數(shù)memcpy static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n); #define _memcpy(dest,src,n)   _memcpy_internal(dest,src,n) // 沖刷緩沖區(qū) static void _flush(pRX_MAC pRxMac,pRX_FLAG ender); // 往接收機(jī)緩沖區(qū)內(nèi)放數(shù)據(jù) static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len); /*
*********************************************************************************************************
*                                        RxMac_Init()
*
* Description : To initialize a RxMac.    初始化接收機(jī)
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               Flags     pointer to the flags(an array); 指向標(biāo)志串(數(shù)組)的指針
*               FlagsCnt  the count of the flags;         有多少個(gè)標(biāo)志串;
*               maxLenOfFlags  the max length of flags;   標(biāo)志字符串最長的長度 
*               pBuf      pointer to the buffer provided to the RxMac;提供給接收機(jī)使用的緩存
*               BufLen    the size of the buffer.         緩存的大小
*               onFeeded   the callback func that will be called when feeded.
*                          每次被feed時(shí)會調(diào)用的回調(diào)函數(shù),如改變對應(yīng)數(shù)據(jù)值會影響標(biāo)志位的判斷
*               onGetHeader the callback func that will be called when find a header.
*                          當(dāng)發(fā)現(xiàn)幀頭時(shí)會調(diào)用的回調(diào)函數(shù)
*               onFlushed  the callback func that will be called when flushed.
*                          當(dāng)Flush時(shí)會調(diào)用的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE        if success
*               RXMAC_ERR_ARGUMENT    if the length of longest Flags bigger than Buflen,or one of them is 0
*               RXMAC_ERR_POINTERNULL if empty pointer 
*
* Note(s)     : size of buffer should bigger than  the longest flag plus the longest frame 
*               that may be received(so at least 2 * maxLenOfFlags).
*               the buffer is allocate as follow:
**                |                 RxBuffer             |                 |   
** 
*               void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag):
*                sender   the pointer to the RxMac which call this function
*                pFlag    the header matched
*
*               void onFeeded(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt):
*                sender    the pointer to the RxMac which call this function
*                pCurChar  point to the char in the buffer just received.
*                bytesCnt  the number of bytes in the buffer including the char just feeded.
*
*               void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,
*                  pRX_FLAG pEnder);
*                sender    the pointer to the RxMac which call this function
*                pBuf      the pointer to the frame.
*                len       the length of frame.
*                state     the state of frame.
*                pHorU     point to the header flag if state.headerFound == 1, or unique flag if 
*                          state.uniqueFound == 1.
*                pEnder    point to the ender flag if state.enderFound == 1.
*********************************************************************************************************
*/ INT8U RxMac_Init (pRX_MAC pRxMac,RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags,pRB_BYTE pBuf,INT16U BufLen,
    RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){ //INT8U maxLen = 0; INT8U i; #if(RXMAC_ARGUMENT_CHECK_EN) if( #if(!RXMAC_SINGLETON_EN) _pRxMac == NULL || #endif Flags == NULL || pBuf == NULL) return RXMAC_ERR_POINTERNULL; #endif // find out the max length of flags. //for(i = 0; i < FlagsCnt; i++){ //  if(Flags[i].len > maxLen) //    maxLen = Flags[i].len; //} #if(RXMAC_ARGUMENT_CHECK_EN) if(maxLenOfFlags == 0 || (maxLenOfFlags * 2) > BufLen || BufLen == 0 || FlagsCnt == 0 ||
      maxLenOfFlags == 0) return RXMAC_ERR_ARGUMENT; #endif BufLen -= maxLenOfFlags; // 把buffer的最后一段分配給環(huán)形緩沖區(qū) RingQueueInit(&_FlagQueue,pBuf + BufLen,maxLenOfFlags,&i);
    _Flags = Flags;
    _FlagsCnt = FlagsCnt;
    _stateByte = 0;
    _pHorU = NULL;
    _pRxBuf = pBuf;
    _RxBufSize = BufLen;
    _pCur = pBuf;
    _onFeeded = onFeeded;
    _onGetHeader = onGetHeader;
    _onFlushed = onFlushed; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_FeedData()
*
* Description : To feed RxMac the next char.    用于給接收機(jī)下一個(gè)字符
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               c         the char to feed;               下一個(gè)字符
*
* Return      : 
*
* Note(s)     : 
*********************************************************************************************************
*/ void RxMac_FeedData(pRX_MAC pRxMac,INT8U c){
  INT8U i,mask;
  pRX_FLAG pFlag = NULL; #if(RXMAC_ONFEEDED_EN) pRB_BYTE pCurChar = _pCur; #endif #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return; #endif *_pCur++ = c; // 填入緩沖區(qū) #if(RXMAC_ONFEEDED_EN) if(_onFeeded != NULL)
    _onFeeded(_pRxMac,pCurChar,_pCur - _pRxBuf);
  RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i); #else RingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i); #endif // _state.headerFound == 1  說明在等待幀尾,否則在等待幀頭 mask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA; // 尋找匹配的標(biāo)志串 for(i = 0; i < _FlagsCnt; i++){ if((_Flags[i].option & mask) && 
      (RingQueueMatch(&_FlagQueue,(pRQTYPE)_Flags[i].pBuf,_Flags[i].len) >= 0)){
        RingQueueClear(&_FlagQueue);
        pFlag = &_Flags[i]; break;
    }
  } // 如果沒有發(fā)現(xiàn)標(biāo)志串,檢查下有沒滿了,滿了就Flush if(pFlag == NULL){ if(_isRxBufFull()){
      _state.isFull = 1;
      _flush(_pRxMac,NULL);
    } return;
  } // 這4種標(biāo)志串要_flush掉前面的東西 if(pFlag->option & FLAGMASK_USUHSH){
    _pCur -= pFlag->len;
    _flush(_pRxMac,NULL);
    _pHorU = pFlag;
  } // 如果是幀頭的處理 if(pFlag->option & (FLAG_OPTION_STRONG_HEADER | FLAG_OPTION_HEADER)){ #if(RXMAC_NOTFILL_EN == TRUE) if(!(pFlag->option & FLAG_OPTION_NOTFILL_HEADER)) #endif _BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
    _state.headerFound = 1; if(_onGetHeader != NULL)
      _onGetHeader(_pRxMac,pFlag); return;
  } // 如果是Unique的處理 if(pFlag->option & (FLAG_OPTION_STRONG_UNIQUE | FLAG_OPTION_UNIQUE)){
    _state.uniqueFound = 1;
    _BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
    _flush(_pRxMac,NULL);
  }else{ // 能到這里說明是幀尾 _state.enderFound = 1; #if(RXMAC_NOTFILL_EN == TRUE) if(pFlag->option & FLAG_OPTION_NOTFILL_ENDER)
      _pCur -= pFlag->len; #endif _flush(_pRxMac,pFlag);
  } return;
} /*
*********************************************************************************************************
*                                        RxMac_ResetRxSize()
*
* Description : reset the size of RxBuf to the max size.   重置接收緩沖區(qū)
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*               RXMAC_ERR_INIT            if RxMac hasn't inited or any error in initialization
* Note(s)     : 
*********************************************************************************************************
*/ INT8U RxMac_ResetRxSize(pRX_MAC pRxMac){ int size; #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif size = _FlagQueue.RingBuf - _pRxBuf; #if(RXMAC_ARGUMENT_CHECK_EN) if(size < 0) return RXMAC_ERR_INIT; #endif _RxBufSize = (INT16U)size; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_SetRxSize()
*
* Description : set the size of RxBuf to the max size.   重置接收緩沖區(qū)
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               size      the size to set;                
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*               RXMAC_ERR_ARGUMENT        if size is wrong.
* Note(s)     : the size shouldn't be bigger than the initial value, and should bigger than
*               the current number of chars in the RxBuf.
*               
*********************************************************************************************************
*/ INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size){ #if(RXMAC_ARGUMENT_CHECK_EN) #if (!RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #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.   重置接收機(jī)的狀態(tài)
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
* Note(s)     : it will not trigger call-back of onFlush.
*********************************************************************************************************
*/ INT8U RxMac_ResetState(pRX_MAC pRxMac){ #if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif // 復(fù)位接收機(jī) RingQueueClear(&_FlagQueue);
  _pCur = _pRxBuf;
  _stateByte = 0;
  _pHorU = NULL; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_Flush()
*
* Description : force receive machine to flush.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     : it will force receive machine to flush, if there is any data in the RxBuffer,
*
*********************************************************************************************************
*/ INT8U RxMac_Flush(pRX_MAC pRxMac){ #if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif _flush(_pRxMac,NULL); return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_SetOnFeeded()
*
* Description : set the onFeeded callback function.
*
* Arguments   : pRxMac    pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               onFeeded  the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/ INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded){ #if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif _onFeeded = onFeeded; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_SetOnGetHeader()
*
* Description : set the onGetHeader callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               onGetHeader  the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/ INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader){ #if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif _onGetHeader = onGetHeader; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                        RxMac_SetOnFlushed()
*
* Description : set the onFlushed callback function.
*
* Arguments   : pRxMac       pointer to the RxMac struct;    指向接收機(jī)結(jié)構(gòu)體的指針
*               onFlushed    the callback function to set;   要設(shè)置的回調(diào)函數(shù)
*
* Return      : RXMAC_ERR_NONE            if Success;
*               RXMAC_ERR_POINTERNULL     if pRxMac == NULL
*
* Note(s)     :
*
*********************************************************************************************************
*/ INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed){ #if(RXMAC_ARGUMENT_CHECK_EN  && !RXMAC_SINGLETON_EN) if(_pRxMac == NULL) return RXMAC_ERR_POINTERNULL; #endif _onFlushed = onFlushed; return RXMAC_ERR_NONE;
} /*
*********************************************************************************************************
*                                   LOCAL  FUNCITON 
*********************************************************************************************************
*/ static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n){
  pRB_BYTE p = dest; while(n-- > 0)
    *p++ = *src++; return dest;
} static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len){
  _memcpy(_pCur,pBuf,len);
  _pCur += len;
} static void _flush(pRX_MAC pRxMac,pRX_FLAG ender){ // 觸發(fā)回調(diào) if(_pCur-_pRxBuf > 0 && _onFlushed != NULL)
    _onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender); // 復(fù)位接收機(jī) _pCur = _pRxBuf;
  _stateByte = 0;
  _pHorU = NULL;
}

測試/示例代碼

/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                               Framework
*
* By  : Lin Shijun
* Note: This is a framework for uCos-ii project with only S12CPU, none float, banked memory model.
*       You can use this framework with same modification as the start point of your project.
*       I've removed the os_probe module,since I thought it useless in most case.
*       This framework is adapted from the official release.
*********************************************************************************************************
*/ #include "includes.h" #include "SCI_def.h" #include "RxMac.h" /*
*********************************************************************************************************
*                                      STACK SPACE DECLARATION
*********************************************************************************************************
*/ static OS_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE]; /*
*********************************************************************************************************
*                                      TASK FUNCTION DECLARATION
*********************************************************************************************************
*/ static void AppTaskStart(void *p_arg); /*
*********************************************************************************************************
*                                           CALLBACK FUNCITON
*********************************************************************************************************
*/ void onGetData(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt){ // 因?yàn)榘l(fā)現(xiàn)幀頭后才掛載事件,所以下一次回掉正好是說明字符數(shù)的那個(gè)字符,否則還得根據(jù)bytesCnt來判斷當(dāng)前位置 RxMac_SetOnFeeded(sender,NULL); if(*pCurChar > '0' && *pCurChar <= '9' ){ // bytesCnt是當(dāng)前收到了多少個(gè)字符,所以接收區(qū)大小為當(dāng)前字符數(shù)加上還要接收的 RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  }
} void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){
  SCI_PutCharsB(SCI0,"\nFlushed:",9,0); if(state.headerFound)
    SCI_PutCharsB(SCI0,"headerFound,",12,0); if(state.enderFound)
    SCI_PutCharsB(SCI0,"enderFound,",11,0); if(state.isFull)
    SCI_PutCharsB(SCI0,"full,",5,0); if(state.uniqueFound)
    SCI_PutCharsB(SCI0,"unique,",7,0);
  SCI_PutCharsB(SCI0,"\nDatas:",7,0);
  SCI_PutCharsB(SCI0,pBuf,len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
  RxMac_ResetRxSize(sender);
} void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){
  SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
} void onGetHeader2(pRX_MAC sender,pRX_FLAG pFlag){
  SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  SCI_PutCharsB(SCI0,"\n",1,0);
  RxMac_SetOnFeeded(sender,onGetData);
} /*
*********************************************************************************************************
*                                           FLAGS
*********************************************************************************************************
*/ RX_MAC  _rxmac; #define BUF_SIZE  20 INT8U  buffer[BUF_SIZE];
RX_FLAG flags[4]; // 協(xié)議示例1: // 幀頭    :HEADER 或者 START // 強(qiáng)幀尾  :END // 強(qiáng)特殊串:12345  //  static void protocol1_init(){
  RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
  RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
  RxMac_Init(&_rxmac,flags,4,6,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
} // 協(xié)議示例2: // 幀頭    : START // 幀頭后的第1個(gè)字符表示后面還要接收多少個(gè)字符 1-9,'4'表示4個(gè),如果不是數(shù)字或?yàn)?0',則等待幀尾 // 幀尾    : END // 特殊串:  NOW //  static void protocol2_init(){
  RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
  RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
  RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
  RxMac_Init(&_rxmac,flags,3,5,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
} /*
*********************************************************************************************************
*                                           MAIN FUNCTION
*********************************************************************************************************
*/ void main(void) {
    INT8U  err;    
    BSP_IntDisAll(); /* Disable ALL interrupts to the interrupt controller       */ OSInit(); /* Initialize uC/OS-II                                      */ err = OSTaskCreate(AppTaskStart, NULL,
                          (OS_STK *)&AppTaskStartStk[APP_TASK_START_STK_SIZE - 1],
                          APP_TASK_START_PRIO);                     
    OSStart();
} static void AppTaskStart (void *p_arg)
{
  INT8U c,err;
  (void)p_arg; /* Prevent compiler warning  */ BSP_Init(); 
  SCI_Init(SCI0);
  SCI_EnableTrans(SCI0);
  SCI_EnableRecv(SCI0);
  SCI_EnableRxInt(SCI0);
  SCI_BufferInit(); // 選擇想要實(shí)驗(yàn)的協(xié)議來初始化 protocol1_init(); //protocol2_init(); while (DEF_TRUE) 
  { // 獲取下一個(gè)字符 c = SCI_GetCharB(SCI0,0,&err); // 回顯 SCI_PutCharB(SCI0,c,0); // 喂給接收機(jī) RxMac_FeedData(&_rxmac,c);
  }
}


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
關(guān)閉