[嵌入式开发模块]通用接收状态机模块

本是古典 何须时尚 2022-05-23 00:13 351阅读 0赞

文章目录

  • 前言
  • 模块相关概念和逻辑
    • 接收机状态
    • 标志字符序列
    • flush
    • 接收机类
    • 过滤器
    • onGetHeader事件
    • 接收机运行逻辑
    • 边际条件
  • 相关代码
    • 接收机代码
      • RxMac.h
      • RxMacPrivate.h
      • RxMac.c
    • 测试/示例代码
  • v1.0代码
    • 接收机代码
    • 测试/示例代码
  • 后记
  • 更新历史

前言

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

模块相关概念和逻辑

接收机状态

接收机有两个基本状态:

  • 状态A:preRx 等待帧头中,这个时候接收机会不断判断是否收到了特殊序列、帧头和强帧尾。如果收到了帧头,则(默认)会把帧头填入缓冲区的最前面,然后进入状态B。
  • 状态B:Rxing 等待帧尾中,收到的数据会按序填入接收缓冲区,同时不断查找帧尾、强帧头以及强特殊序列,不管找到了哪一个都会触发flush。如果,找到的是强帧头,则仍然在状态B,否则恢复状态A。

不管在哪一个状态下,如果接受缓冲区满了,都会触发flush并回到状态A。

标志字符序列

接收机定义了以下标志序列类型:









































类型 模块中标记 描述
帧头 header 只在状态A起作用;找到时会导致之前接收区内的数据被flush,然后默认会填入接收区的最前面,可以通过选项来改变这个行为,然后接收机进入状态B。
强帧头 strong-header 在状态B也会起作用,其他行为与普通帧头一样
帧尾 ender 只在状态B起作用;找到时会导致当前接收区内的数据被flush,默认会处于回调时给用户的buffer的最后面,可以通过选项来改变这个行为,然后接收机回到状态A。
强帧头 strong-header 在状态A也会起作用,其他行为与普通帧尾一样
特殊序列 unique 只在状态A起作用;找到时会导致之前接收区内的数据被flush,然后自己被填入接收区内后再次触发flush,然后接收机回到状态A。
强特殊序列 strong-unique 在状态B也会起作用,其他行为与特殊序列一样

对应模块中的结构体为:

  1. // receive flag
  2. typedef struct RXFLAG_STRUCT{
  3. uint8_t const * pBuf;
  4. uint8_t len;
  5. uint8_t option;
  6. } RXFLAG_STRUCT;
  7. typedef RXFLAG_STRUCT const * RxFlag;

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

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

flush

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

此函数的原型如下

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

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

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

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

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

接收机类

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

  1. typedef struct RXMAC_STRUCT * RxMac;

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

  1. // to create an instance of RxMac
  2. // flags 标志字符串结构体的数组
  3. // flagsCnt 标志字符串结构体的个数
  4. // buf 用户提供给接收机用的缓冲区
  5. // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串)
  6. // onFeeded 在每次被Feed时触发
  7. // onGetHeader 获得头标志位时触发。
  8. // onFlushed 收到一帧数据时的回调函数
  9. RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen,
  10. RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed);

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

过滤器

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

  1. typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);

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

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

onGetHeader事件

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

接收机运行逻辑

接收机的运作逻辑如下:

70

边际条件

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

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

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

相关代码

此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。
https://blog.csdn.net/lin_strong/article/details/88236566

接收机代码

RxMac.h

  1. /*
  2. *******************************************************************************************
  3. *
  4. *
  5. * Universal Receive State Machine
  6. * 通用接收状态机
  7. *
  8. * File : RxMac.h
  9. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  10. * Date: 2019/03/07
  11. * version: 2.1
  12. * History: 2018/05/29 1.0 the prototype
  13. * 2019/01/23 2.0 modify the type names to more readable ones, though preserve
  14. * the old-style for forward compatibility;
  15. * change init method to create method which use malloc to alloc
  16. * instance, and the corresponding destroy method.
  17. * change the internal buffer module from RINGQUEUE to BufferArray,
  18. * so user no longer need to know the internal flags management and
  19. * allocate the space for it.
  20. * add RxMac_FeedDatas method for convenient.
  21. * 2019/03/07 2.1 some modification to the malloc configuration
  22. *
  23. * NOTE(s): 1. the receive process has two basic state
  24. * A. preRx: when haven't found any header, the RxMac will search for the unique
  25. * flag, header and strong-ender. Only when a header is found will come
  26. * to next step.
  27. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search
  28. * for the strong-unique, strong-header, ender.
  29. * 2. the module is drived by the RxMac_FeedData(), user should get the the char
  30. * from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
  31. * or RxMac_FeedDatas().
  32. * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
  33. * to notify the results; user can judge the frame through the state parameter;
  34. * state.headerFound == 1: find any header, the header is passed by HorU
  35. * state.enderFound == 1: find any ender, the ender is passed by Ender
  36. * state.isFull == 1: the buffer is full, maybe you should check headerFound
  37. * to see whether a header has been found.
  38. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will
  39. * always be 0 ,the data in the buffer will be the flag,
  40. * and the unique flag is passed by HorU.
  41. * 4. To use this module, for each receive machine:
  42. * A. define malloc to configure the module, see CONFIGURATION
  43. * B. allocate the space for buffer and FLAGS.
  44. * RXFLAG_STRUCT flags[2];
  45. * uint8_t buf[300];
  46. * C. set the flags according to the protocol, define the callback functions
  47. * according to your need.
  48. * static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... };
  49. * static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,
  50. * RxState state,RxFlag HorU,RxFlag Ender){ ...... };
  51. * const uint8_t HeaderFlag[] = "Header";
  52. * const uint8_t EnderFlag[] = "\r\n";
  53. * RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER);
  54. * RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER |
  55. * RXFLAG_OPTION_NOTFILL_ENDER);
  56. * D. create the receive machine:
  57. * RxMac mac;
  58. * mac = RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL,
  59. * onGetHeader, onFlushed );
  60. * E. feed the receive machine:
  61. * while(1){
  62. * c = GetNextChar();
  63. * RxMac_FeedData(mac,c);
  64. * }
  65. * F. destroy the receive machine if need.
  66. * RxMac_Destroy(mac);
  67. *******************************************************************************************
  68. */
  69. #ifndef RX_MAC_H
  70. #define RX_MAC_H
  71. /*
  72. *******************************************************************************************
  73. * INCLUDES
  74. *******************************************************************************************
  75. */
  76. #include <stdint.h>
  77. /*
  78. *******************************************************************************************
  79. * CONFIGURATION 配置
  80. *******************************************************************************************
  81. */
  82. // #define RXMAC_ARGUMENT_CHECK_DISABLE to disable the argument check functions of this module
  83. //#define RXMAC_ARGUMENT_CHECK_DISABLE
  84. // #define RXMAC_NOTFILL_DISABLE to disable the notFill option
  85. //#define RXMAC_NOTFILL_DISABLE
  86. // #define RXMAC_ONFEEDED_DISABLE to disable the onFeeded event.
  87. //#define RXMAC_ONFEEDED_DISABLE
  88. // #define RXMAC_SINGLETON_EN to use singleton pattern,so argument pRxMac of interfaces is
  89. // useless, and user don't need to allocate space for RX_MAC, but you still need to allocate
  90. // buffer and call init();
  91. //#define RXMAC_SINGLETON_EN
  92. // #define RXMAC_BUF_RPAGE if you want receive machine use the paged array as buffer.
  93. // and don't forget to define CODEWARRIOR malloc
  94. //#define RXMAC_BUF_RPAGE
  95. /*
  96. *******************************************************************************************
  97. * ADDRESSING MODE 寻址模式
  98. *******************************************************************************************
  99. */
  100. #ifdef RXMAC_BUF_RPAGE
  101. #ifdef CODEWARRIOR
  102. #define RXMAC_BUF_ADDRESSING_MODE __rptr
  103. #endif
  104. #endif
  105. #ifndef RXMAC_BUF_ADDRESSING_MODE
  106. #define RXMAC_BUF_ADDRESSING_MODE
  107. #endif
  108. typedef uint8_t * RXMAC_BUF_ADDRESSING_MODE RxMacPtr;
  109. /*
  110. *********************************************************************************************
  111. * ERROR CODE
  112. *********************************************************************************************
  113. */
  114. #define RXMAC_ERR_NONE 0
  115. #define RXMAC_ERR_ARGUMENT 1
  116. #define RXMAC_ERR_POINTERNULL 2
  117. #define RXMAC_ERR_UNKNOWN 3
  118. #define RXMAC_ERR_INIT 4
  119. /*
  120. *********************************************************************************************
  121. * RECEIVE FLAG STRUCT
  122. *********************************************************************************************
  123. */
  124. // normal header, RxMac will only check it in Step A
  125. #define RXFLAG_OPTION_HEADER 0x01
  126. // strong header, RxMac will always check it.
  127. #define RXFLAG_OPTION_STRONG_HEADER 0x03
  128. // the header will not be filled into buffer when found.(only valid when is header)
  129. #define RXFLAG_OPTION_NOTFILL_HEADER 0x04
  130. // normal ender, RxMac will only check it in Step B
  131. #define RXFLAG_OPTION_ENDER 0x08
  132. // strong header, RxMac will always check it.
  133. #define RXFLAG_OPTION_STRONG_ENDER 0x18
  134. // the ender will not be filled into buffer when found.(only valid when is ender)
  135. #define RXFLAG_OPTION_NOTFILL_ENDER 0x20
  136. // normal unique, RxMac will only check it in Step A
  137. #define RXFLAG_OPTION_UNIQUE 0x40
  138. // strong unique, RxMac will always check it.
  139. #define RXFLAG_OPTION_STRONG_UNIQUE 0xC0
  140. // receive flag
  141. typedef struct RXFLAG_STRUCT{
  142. uint8_t const * pBuf;
  143. uint8_t len;
  144. uint8_t option;
  145. } RXFLAG_STRUCT;
  146. typedef RXFLAG_STRUCT const * RxFlag;
  147. // void RxFlag_Init(RXFLAG_STRUCT * flag,uint8_t const * buf,uint8_t len,uint8_t opt);
  148. // to initialize a receive flag
  149. // flag point to the target RXFLAG_STRUCT.
  150. // buf pointer to the flag buffer
  151. // size size of flag
  152. // opt see RXFLAG_OPTION_XXXXX, bit mode
  153. #define RxFlag_Init(flag,buf,size,opt) \
  154. {(flag)->pBuf =(buf);(flag)->len =(size);(flag)->option = (opt);}
  155. /*
  156. *********************************************************************************************
  157. * TYPE DEFINITION
  158. *********************************************************************************************
  159. */
  160. typedef struct RXSTATE_STRUCT{
  161. unsigned int headerFound: 1; // 1: have get header
  162. unsigned int enderFound : 1; // 1: have get ender
  163. unsigned int isFull : 1; // 1: the buffer is full
  164. unsigned int uniqueFound: 1; // 1: this is unique flag.
  165. } RxState;
  166. typedef struct RXMAC_STRUCT * RxMac;
  167. typedef void (* RXMAC_FLUSH_EVENT)(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
  168. RxFlag HorU,RxFlag Ender);
  169. typedef void (* RXMAC_FLAG_EVENT)(RxMac sender,RxFlag flag);
  170. typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
  171. /*
  172. *******************************************************************************************
  173. * FUNCTION DECLARATION
  174. *******************************************************************************************
  175. */
  176. // to create an instance of RxMac
  177. // flags 标志字符串结构体的数组
  178. // flagsCnt 标志字符串结构体的个数
  179. // buf 用户提供给接收机用的缓冲区
  180. // bufLen 缓冲区的大小(起码应该要能放的下最长的标志字符串)
  181. // onFeeded 在每次被Feed时触发
  182. // onGetHeader 获得头标志位时触发。
  183. // onFlushed 收到一帧数据时的回调函数
  184. 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);
  185. // to destroy the RxMac
  186. void RxMac_Destroy(RxMac mac);
  187. // 向接收机内喂字节
  188. void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len);
  189. void RxMac_FeedData(RxMac mac, uint8_t c);
  190. // 重置接收区长度为最长那个长度
  191. //uint8_t RxMac_ResetRxSize(RxMac mac);
  192. // 设置最大接收到多少个字节
  193. uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size);
  194. // 重置接收机的状态
  195. uint8_t RxMac_ResetState(RxMac mac);
  196. // 强制接收机flush
  197. uint8_t RxMac_Flush(RxMac mac);
  198. // 设置onFeeded
  199. uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded);
  200. // 设置onGetHeader
  201. uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader);
  202. // 设置onFlushed
  203. uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed);
  204. #include "RxMacPrivate.h"
  205. #endif // of RX_MAC_H

RxMacPrivate.h

  1. /*
  2. *******************************************************************************************
  3. *
  4. *
  5. * Private Declarations for Universal Receive State Machine
  6. *
  7. * File : RxMacPrivate.h
  8. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  9. * Date: 2019/03/07
  10. * version: 2.1
  11. * History:
  12. * NOTE(s):
  13. *******************************************************************************************
  14. */
  15. /*
  16. *******************************************************************************************
  17. * FUNCTION DECLARATION
  18. *******************************************************************************************
  19. */
  20. // 打印内部缓冲区,返回缓冲区的长度
  21. uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf);
  22. /*
  23. *******************************************************************************************
  24. * RECEIVE FLAG STRUCT
  25. *******************************************************************************************
  26. */
  27. // struct of RXFLAG_STRUCT.option
  28. /*typedef struct RXFLAG_OPTION{
  29. unsigned int isHeader : 1; // 1: the flag is the head of the frame
  30. unsigned int strong_H : 1; // 1: strong-header, RxMac will
  31. unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header
  32. unsigned int isEnder : 1; // 1: the flag is the end of the frame
  33. unsigned int strong_E : 1; //
  34. unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender
  35. unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame.
  36. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not
  37. }; //*/
  38. // normal header, RxMac will only check it in Step A
  39. #define RXFLAG_OPTBIT_HEADER 0x01
  40. // strong header, RxMac will always check it.
  41. #define RXFLAG_OPTBIT_STRONG_HEADER 0x02
  42. // the header will not be filled into buffer when found.(only valid when is header)
  43. #define RXFLAG_OPTBIT_NOTFILL_HEADER 0x04
  44. // normal ender, RxMac will only check it in Step B
  45. #define RXFLAG_OPTBIT_ENDER 0x08
  46. // strong header, RxMac will always check it.
  47. #define RXFLAG_OPTBIT_STRONG_ENDER 0x10
  48. // the ender will not be filled into buffer when found.(only valid when is ender)
  49. #define RXFLAG_OPTBIT_NOTFILL_ENDER 0x20
  50. // normal unique, RxMac will only check it in Step A
  51. #define RXFLAG_OPTBIT_UNIQUE 0x40
  52. // strong unique, RxMac will always check it.
  53. #define RXFLAG_OPTBIT_STRONG_UNIQUE 0x80
  54. #define STATEMASK_STEPA \
  55. (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_ENDER)
  56. #define STATEMASK_STEPB \
  57. (RXFLAG_OPTBIT_STRONG_UNIQUE | RXFLAG_OPTBIT_ENDER | RXFLAG_OPTBIT_STRONG_HEADER)
  58. #define RXFLAGMASK_USUHSH \
  59. (RXFLAG_OPTBIT_HEADER | RXFLAG_OPTBIT_STRONG_HEADER | \
  60. RXFLAG_OPTBIT_UNIQUE | RXFLAG_OPTBIT_STRONG_UNIQUE)
  61. // BOOL _RxFlag_isHeader(RxFlag flag);
  62. #define _RxFlag_isHeader(flag) \
  63. ((flag)->option & (RXFLAG_OPTION_STRONG_HEADER | RXFLAG_OPTION_HEADER))
  64. // BOOL _RxFlag_isEnder(RxFlag flag);
  65. #define _RxFlag_isEnder(flag) \
  66. ((flag)->option & (RXFLAG_OPTION_STRONG_ENDER | RXFLAG_OPTION_ENDER))
  67. // BOOL _RxFlag_isUnique(RxFlag flag);
  68. #define _RxFlag_isUnique(flag) \
  69. ((flag)->option & (RXFLAG_OPTION_STRONG_UNIQUE | RXFLAG_OPTION_UNIQUE))
  70. // BOOL _RxFlag_dontFillHeader(RxFlag flag);
  71. #define _RxFlag_dontFillHeader(flag) \
  72. ((flag)->option & RXFLAG_OPTBIT_NOTFILL_HEADER)
  73. // BOOL _RxFlag_dontFillEnder(RxFlag flag);
  74. #define _RxFlag_dontFillEnder(flag) \
  75. ((flag)->option & RXFLAG_OPTBIT_NOTFILL_ENDER)
  76. /*
  77. *******************************************************************************************
  78. * FORWARD COMPATIBILITY
  79. *******************************************************************************************
  80. */
  81. // 以下仅为前向兼容
  82. typedef RxMacPtr pRB_BYTE;
  83. typedef RXFLAG_STRUCT RX_FLAG,*pRX_FLAG;
  84. typedef RxMac pRX_MAC;
  85. typedef RxState RX_STATE;
  86. #define FLAG_OPTION_HEADER RXFLAG_OPTION_HEADER
  87. #define FLAG_OPTION_STRONG_HEADER RXFLAG_OPTION_STRONG_HEADER
  88. #define FLAG_OPTION_NOTFILL_HEADER RXFLAG_OPTION_NOTFILL_HEADER
  89. #define FLAG_OPTION_ENDER RXFLAG_OPTION_ENDER
  90. #define FLAG_OPTION_STRONG_ENDER RXFLAG_OPTION_STRONG_ENDER
  91. #define FLAG_OPTION_NOTFILL_ENDER RXFLAG_OPTION_NOTFILL_ENDER
  92. #define FLAG_OPTION_UNIQUE RXFLAG_OPTION_UNIQUE
  93. #define FLAG_OPTION_STRONG_UNIQUE RXFLAG_OPTION_STRONG_UNIQUE
  94. #define RX_FLAG_INIT RxFlag_Init

RxMac.c

  1. /*
  2. *******************************************************************************************
  3. *
  4. *
  5. * Implementation of the Universal Receive State Machine
  6. * 通用接收状态机
  7. *
  8. * File : RxMac.c
  9. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  10. * Date: 2019/03/07
  11. * version: 2.1
  12. * History: 2018/05/29 1.0 the prototype
  13. * 2019/01/23 2.0 In addition to the content in RxMac.h:
  14. * abstract the flag management part as RxFlagMgr and the
  15. * corresponding methods.
  16. * refactor the code.
  17. * 2019/03/07 2.1 some modification to the malloc configuration
  18. * NOTE(s):
  19. *
  20. *******************************************************************************************
  21. */
  22. /*
  23. *******************************************************************************************
  24. * INCLUDES
  25. *******************************************************************************************
  26. */
  27. #include <stddef.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "RxMac.h"
  31. #include "BufferMallocArray.h"
  32. /*
  33. *******************************************************************************************
  34. * RECEIVE FLAGS MANAGER
  35. *******************************************************************************************
  36. */
  37. typedef struct RXFLAGMGR_STRUCT {
  38. // buffer to hold the pre-data which hasn't matched any flag.
  39. BufferUINT8Indexed BufForFlag;
  40. // the flag array to be matched.
  41. RxFlag Flags;
  42. // count of flags.
  43. uint8_t FlagsCnt;
  44. // current state, in which headerFound will influence the match behavior.
  45. // controlled by the child class.
  46. RxState state;
  47. }RXFLAGMGR_STRUCT;
  48. static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte);
  49. static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen);
  50. static void _RxFlagMgr_Destroy(RxMac mac);
  51. static void _RxFlagMgr_Reset(RxMac mac);
  52. /*
  53. *******************************************************************************************
  54. * STRUCT DIFINITION
  55. *******************************************************************************************
  56. */
  57. typedef struct RXMAC_STRUCT{
  58. // manage the flag matches.
  59. RXFLAGMGR_STRUCT FlagMgr;
  60. // record the Header or Unique flag.
  61. RxFlag pHorU;
  62. // internal buffer to hold data.
  63. RxMacPtr pRxBuf;
  64. // length of the internal buffer
  65. uint16_t RxBufSize;
  66. // Count of the bytes in the internal buffer/ the index for next feeded byte
  67. uint16_t RxCnt;
  68. RXMAC_FILTER onFeeded;
  69. RXMAC_FLAG_EVENT onGetHeader;
  70. RXMAC_FLUSH_EVENT onFlushed;
  71. } RXMAC_STRUCT;
  72. /*
  73. *******************************************************************************************
  74. * LOCAL FUNCITON DECLARATION
  75. *******************************************************************************************
  76. */
  77. #ifndef RXMAC_SINGLETON_EN
  78. #define _pMac mac
  79. #define _BufForFlag (_pMac->FlagMgr.BufForFlag)
  80. #define _Flags (_pMac->FlagMgr.Flags)
  81. #define _FlagsCnt (_pMac->FlagMgr.FlagsCnt)
  82. #define _state (_pMac->FlagMgr.state)
  83. #define _pHorU (_pMac->pHorU)
  84. #define _pRxBuf (_pMac->pRxBuf)
  85. #define _RxBufSize (_pMac->RxBufSize)
  86. #define _RxCnt (_pMac->RxCnt)
  87. #define _fonFeeded (_pMac->onFeeded)
  88. #define _fonGetHeader (_pMac->onGetHeader)
  89. #define _fonFlushed (_pMac->onFlushed)
  90. #define _RxMac_Destroy() (free(mac))
  91. #else
  92. static RXMAC_STRUCT _mac;
  93. // 单例模式中,这个指针用于标识是否单例已初始化过
  94. static RxMac _pMac = NULL;
  95. #define _BufForFlag (_mac.FlagMgr.BufForFlag)
  96. #define _Flags (_mac.FlagMgr.Flags)
  97. #define _FlagsCnt (_mac.FlagMgr.FlagsCnt)
  98. #define _state (_mac.FlagMgr.state)
  99. #define _pHorU (_mac.pHorU)
  100. #define _pRxBuf (_mac.pRxBuf)
  101. #define _RxBufSize (_mac.RxBufSize)
  102. #define _RxCnt (_mac.RxCnt)
  103. #define _fonFeeded (_mac.onFeeded)
  104. #define _fonGetHeader (_mac.onGetHeader)
  105. #define _fonFlushed (_mac.onFlushed)
  106. #define _RxMac_Destroy() (_pMac = NULL)
  107. #endif
  108. #define _stateByte (*(uint8_t *)(&_state))
  109. #define _isRxBufFull() (_RxCnt >= _RxBufSize)
  110. #ifndef RXMAC_ONFEEDED_DISABLE
  111. #define _onFeeded(pChar,cnt) if(_fonFeeded != NULL) _fonFeeded(_pMac,pChar,cnt);
  112. #else
  113. #define _onFeeded(pChar,cnt)
  114. #endif
  115. #define _onGetHeader(headerFlag) if(_fonGetHeader != NULL) _fonGetHeader(_pMac,headerFlag);
  116. #undef _DONT_CHECK_MAC
  117. #ifdef RXMAC_ARGUMENT_CHECK_DISABLE
  118. #define _DONT_CHECK_MAC
  119. #endif
  120. #ifdef RXMAC_SINGLETON_EN
  121. #define _DONT_CHECK_MAC
  122. #endif
  123. #ifdef _DONT_CHECK_MAC
  124. #define _checkMacNotNull()
  125. #define _checkMacNotNull_void()
  126. #else
  127. #define _checkMacNotNull() if(_pMac == NULL) return RXMAC_ERR_POINTERNULL;
  128. #define _checkMacNotNull_void() if(_pMac == NULL) return;
  129. #endif
  130. #ifdef RXMAC_BUF_RPAGE
  131. #ifdef CODEWARRIOR
  132. static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n);
  133. #define memcpy(dest,src,n) _memcpy_internal(dest,src,n)
  134. #endif
  135. #endif
  136. // 冲刷缓冲区
  137. static void _flush(RxMac mac,RxFlag ender);
  138. // 往接收机缓冲区内放数据
  139. static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len);
  140. static void _RxMac_FlushIfFull(RxMac mac);
  141. static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot);
  142. static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot);
  143. static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot);
  144. static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot);
  145. /*
  146. *******************************************************************************************
  147. * RxMac_Create()
  148. *
  149. * Description : To create a receive machine instance. 创建一个接收机实例
  150. *
  151. * Arguments : flags pointer to the flags(an array); 指向标志串(数组)的指针
  152. * flagsCnt the count of the flags; 有多少个标志串;
  153. * buf pointer to the buffer provided to the RxMac;提供给接收机使用的缓存
  154. * bufLen the size of the buffer. 缓存的大小
  155. * onFeeded the callback func that will be called everytime feeded, you
  156. * can modify the feeded byte in this callback.
  157. * 每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
  158. * onGetHeader the callback func that will be called when find a header.
  159. * 当发现帧头时会调用的回调函数
  160. * onFlushed the callback func that will be called when flushed.
  161. * 当Flush时会调用的回调函数
  162. *
  163. * Return : Pointer to the created instance.
  164. * NULL if any error.
  165. *
  166. * Note(s) : 1. size of buffer should bigger than the longest flag, or the flag will be
  167. * useless.
  168. * 2. if flagsCnt > 0, flags can't point to NULL.
  169. * 3. you must provide a buffer.
  170. * 4. if you enable the RXMAC_SINGLETON_EN, multi-create will pointer to the
  171. * same instance initialized as the last create.
  172. *
  173. * void onGetHeader(RxMac sender,RxFlag flag):
  174. * sender the pointer to the RxMac which call this function
  175. * flag the header matched
  176. *
  177. * void onFeeded(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt):
  178. * sender the pointer to the RxMac which call this function
  179. * pCurChar point to the byte just received, you can change it before any other process.
  180. * bytesCnt the number of bytes in the buffer including the char just feeded.
  181. *
  182. * void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,RxState state,RxFlag HorU,
  183. * RxFlag Ender);
  184. * sender the pointer to the RxMac which call this function
  185. * buf the pointer to the frame.
  186. * len the length of frame.
  187. * state the state of frame.
  188. * HorU point to the header flag if state.headerFound == 1, or unique flag if
  189. * state.uniqueFound == 1.
  190. * Ender point to the ender flag if state.enderFound == 1.
  191. *******************************************************************************************
  192. */
  193. 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){
  194. uint8_t i, maxLen = 0;
  195. #ifndef RXMAC_SINGLETON_EN
  196. RxMac mac;
  197. #endif
  198. #ifndef RXMAC_ARGUMENT_CHECK_DISABLE
  199. if((flags == NULL && flagsCnt > 0 ) || buf == NULL)
  200. return NULL;
  201. #endif
  202. // find out the max length of flags.
  203. for(i = 0; i < flagsCnt; i++){
  204. if(flags[i].len > maxLen)
  205. maxLen = flags[i].len;
  206. }
  207. #ifndef RXMAC_ARGUMENT_CHECK_DISABLE
  208. if(bufLen < maxLen){
  209. return NULL;
  210. }
  211. #endif
  212. #ifdef RXMAC_SINGLETON_EN
  213. if(_pMac != NULL) // if have created one instance, free the previous FlagBuf
  214. _RxFlagMgr_Destroy(&_mac);
  215. else
  216. _pMac = &_mac;
  217. #else
  218. if((mac = (RxMac)malloc(sizeof(RXMAC_STRUCT))) == NULL){
  219. return NULL;
  220. }
  221. #endif
  222. if(!_RxFlagMgr_Init(_pMac,flags,flagsCnt,maxLen)){
  223. _RxMac_Destroy();
  224. return NULL;
  225. }
  226. _pHorU = NULL;
  227. _pRxBuf = buf;
  228. _RxCnt = 0;
  229. _RxBufSize = bufLen;
  230. _fonFeeded = onFeeded;
  231. _fonGetHeader = onGetHeader;
  232. _fonFlushed = onFlushed;
  233. return _pMac;
  234. }
  235. /*
  236. *******************************************************************************************
  237. * RxMac_Destroy()
  238. *
  239. * Description : Destroy a receive machine instance.
  240. *
  241. * Arguments : mac the target receive machine. 目标接收机
  242. *
  243. * Return :
  244. *
  245. * Note(s) :
  246. *
  247. *******************************************************************************************
  248. */
  249. void RxMac_Destroy(RxMac mac){
  250. if(_pMac == NULL)
  251. return;
  252. _RxFlagMgr_Destroy(mac);
  253. _RxMac_Destroy();
  254. }
  255. /*
  256. *******************************************************************************************
  257. * RxMac_FeedData(s)
  258. *
  259. * Description : To feed RxMac the next char(s). 用于给接收机下一个字符
  260. *
  261. * Arguments : mac the target receive machine. 目标接收机
  262. * c the char to feed; 下一个字符
  263. *
  264. * Return :
  265. *
  266. * Note(s) :
  267. *******************************************************************************************
  268. */
  269. void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len){
  270. uint16_t i;
  271. for(i = 0; i < len; i++)
  272. RxMac_FeedData(mac,buf[i]);
  273. }
  274. void RxMac_FeedData(RxMac mac,uint8_t c){
  275. RxFlag curFlag;
  276. _checkMacNotNull_void();
  277. _onFeeded(&c,_RxCnt + 1);
  278. _pRxBuf[_RxCnt++] = c;
  279. curFlag = _RxFlagMgr_GetNextMatchedAtThisState(mac,c);
  280. if(curFlag == NULL){
  281. // if no flag match
  282. _RxMac_FlushIfFull(mac);
  283. return;
  284. }
  285. _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(mac,curFlag);
  286. if(_RxFlag_isHeader(curFlag)){
  287. _RxMac_GetHeaderProcess(mac,curFlag);
  288. }else if(_RxFlag_isUnique(curFlag)){
  289. _RxMac_GetUniqueProcess(mac,curFlag);
  290. }else{
  291. // if(_RxFlag_isEnder(curFlag))
  292. _RxMac_GetEnderProcess(mac,curFlag);
  293. }
  294. }
  295. /*
  296. *******************************************************************************************
  297. * RxMac_SetRxSize()
  298. *
  299. * Description : set the size of RxBuf. 设置接收缓冲区的大小
  300. *
  301. * Arguments : mac the target receive machine. 目标接收机
  302. * size the size to set;
  303. *
  304. * Return : RXMAC_ERR_NONE if Success;
  305. * RXMAC_ERR_POINTERNULL if mac == NULL
  306. * RXMAC_ERR_ARGUMENT if size is wrong.
  307. * Note(s) : the size should bigger than the current number of chars in the RxBuf.
  308. *
  309. *******************************************************************************************
  310. */
  311. uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size){
  312. _checkMacNotNull();
  313. #ifndef RXMAC_ARGUMENT_CHECK_DISABLE
  314. if(size <= _RxCnt)
  315. return RXMAC_ERR_ARGUMENT;
  316. #endif
  317. _RxBufSize = size;
  318. return RXMAC_ERR_NONE;
  319. }
  320. /*
  321. *******************************************************************************************
  322. * RxMac_ResetState()
  323. *
  324. * Description : reset the state of receive machine. 重置接收机的状态
  325. *
  326. * Arguments : mac the target receive machine. 目标接收机
  327. *
  328. * Return : RXMAC_ERR_NONE if Success;
  329. * RXMAC_ERR_POINTERNULL if mac == NULL
  330. * Note(s) : it will not trigger call-back of onFlush.
  331. *******************************************************************************************
  332. */
  333. uint8_t RxMac_ResetState(RxMac mac){
  334. _checkMacNotNull();
  335. // 复位接收机
  336. Buffer_Cleanup((Buffer)_BufForFlag);
  337. _RxCnt = 0;
  338. _stateByte = 0;
  339. _pHorU = NULL;
  340. return RXMAC_ERR_NONE;
  341. }
  342. /*
  343. *******************************************************************************************
  344. * RxMac_Flush()
  345. *
  346. * Description : force receive machine to flush.
  347. *
  348. * Arguments : mac the target receive machine. 目标接收机
  349. *
  350. * Return : RXMAC_ERR_NONE if Success;
  351. * RXMAC_ERR_POINTERNULL if mac == NULL
  352. *
  353. * Note(s) : it will force receive machine to flush, if there is any data in the RxBuffer,
  354. *
  355. *******************************************************************************************
  356. */
  357. uint8_t RxMac_Flush(RxMac mac){
  358. _checkMacNotNull();
  359. _flush(_pMac,NULL);
  360. return RXMAC_ERR_NONE;
  361. }
  362. /*
  363. ******************************************************************************************
  364. * RxMac_SetOnFeeded()
  365. *
  366. * Description : set the onFeeded callback function.
  367. *
  368. * Arguments : mac the target receive machine. 目标接收机
  369. * onFeeded the callback function to set; 要设置的回调函数
  370. *
  371. * Return : RXMAC_ERR_NONE if Success;
  372. * RXMAC_ERR_POINTERNULL if mac == NULL
  373. *
  374. * Note(s) :
  375. *
  376. ******************************************************************************************
  377. */
  378. uint8_t RxMac_SetOnFeeded(RxMac mac,RXMAC_FILTER onFeeded){
  379. _checkMacNotNull();
  380. _fonFeeded = onFeeded;
  381. return RXMAC_ERR_NONE;
  382. }
  383. /*
  384. ******************************************************************************************
  385. * RxMac_SetOnGetHeader()
  386. *
  387. * Description : set the onGetHeader callback function.
  388. *
  389. * Arguments : mac the target receive machine. 目标接收机
  390. * onGetHeader the callback function to set; 要设置的回调函数
  391. *
  392. * Return : RXMAC_ERR_NONE if Success;
  393. * RXMAC_ERR_POINTERNULL if mac == NULL
  394. *
  395. * Note(s) :
  396. *
  397. ******************************************************************************************
  398. */
  399. uint8_t RxMac_SetOnGetHeader(RxMac mac,RXMAC_FLAG_EVENT onGetHeader){
  400. _checkMacNotNull();
  401. _fonGetHeader = onGetHeader;
  402. return RXMAC_ERR_NONE;
  403. }
  404. /*
  405. ******************************************************************************************
  406. * RxMac_SetOnFlushed()
  407. *
  408. * Description : set the onFlushed callback function.
  409. *
  410. * Arguments : mac the target receive machine. 目标接收机
  411. * onFlushed the callback function to set; 要设置的回调函数
  412. *
  413. * Return : RXMAC_ERR_NONE if Success;
  414. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  415. *
  416. * Note(s) :
  417. *
  418. ******************************************************************************************
  419. */
  420. uint8_t RxMac_SetOnFlushed(RxMac mac,RXMAC_FLUSH_EVENT onFlushed){
  421. _checkMacNotNull();
  422. _fonFlushed = onFlushed;
  423. return RXMAC_ERR_NONE;
  424. }
  425. /*
  426. ******************************************************************************************
  427. * _RxMac_printBuffer()
  428. *
  429. * Description : print the internal buffer, just for developer.
  430. * 给开发者用于查看内部缓存的
  431. *
  432. * Arguments : mac the target receive machine. 目标接收机
  433. * onFlushed the callback function to set; 要设置的回调函数
  434. *
  435. * Return : the len of buffer printed.
  436. *
  437. * Note(s) :
  438. *
  439. ******************************************************************************************
  440. */
  441. uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf){
  442. memcpy(buf,_pRxBuf,_RxCnt);
  443. return _RxCnt;
  444. }
  445. /*
  446. ******************************************************************************************
  447. * LOCAL FUNCITON
  448. ******************************************************************************************
  449. */
  450. static RxMacPtr _memcpy_internal(RxMacPtr dest, RxMacPtr src, size_t n){
  451. RxMacPtr p = dest;
  452. while(n-- > 0)
  453. *p++ = *src++;
  454. return dest;
  455. }
  456. static void _BufIn(RxMac mac,RxMacPtr buf,uint16_t len){
  457. memcpy(_pRxBuf+_RxCnt,buf,len);
  458. _RxCnt += len;
  459. }
  460. static void _flush(RxMac mac,RxFlag ender){
  461. // 触发回调
  462. if((_RxCnt > 0 || ender != NULL) && _fonFlushed != NULL)
  463. _fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender);
  464. // 复位接收机
  465. _RxCnt = 0;
  466. _stateByte = 0;
  467. _pHorU = NULL;
  468. }
  469. BOOL BufferUINT8Indexed_BackMatch(BufferUINT8Indexed buf,uint8_t const *toMatch,uint16_t len){
  470. uint16_t cnt = _Buffer_getCount(buf);
  471. if(len > cnt)
  472. return FALSE;
  473. while(len > 0){
  474. if(_BufferUINT8Indexed_get(buf,--cnt) != toMatch[--len])
  475. return FALSE;
  476. }
  477. return TRUE;
  478. }
  479. static void _RxMac_FlushIfFull(RxMac mac){
  480. if(_isRxBufFull()){
  481. _state.isFull = 1;
  482. _flush(_pMac,NULL);
  483. }
  484. }
  485. static void _RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMac mac,RxFlag flagJustGot){
  486. if(flagJustGot->option & RXFLAGMASK_USUHSH){
  487. if(_RxCnt > flagJustGot->len){
  488. _RxCnt -= flagJustGot->len;
  489. _flush(_pMac,NULL);
  490. }else{
  491. _RxCnt = 0;
  492. }
  493. _pHorU = flagJustGot;
  494. }
  495. }
  496. static void _RxMac_GetHeaderProcess(RxMac mac,RxFlag flagJustGot){
  497. #ifndef RXMAC_NOTFILL_DISABLE
  498. if(!_RxFlag_dontFillHeader(flagJustGot))
  499. #endif
  500. _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
  501. _state.headerFound = 1;
  502. _onGetHeader(flagJustGot);
  503. _RxMac_FlushIfFull(mac);
  504. }
  505. static void _RxMac_GetUniqueProcess(RxMac mac,RxFlag flagJustGot){
  506. _state.uniqueFound = 1;
  507. _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
  508. _flush(_pMac,NULL);
  509. }
  510. static void _RxMac_GetEnderProcess(RxMac mac,RxFlag flagJustGot){
  511. _state.enderFound = 1;
  512. if(_RxCnt < flagJustGot->len){
  513. // if part of the flag has been manually flushed.
  514. _RxCnt = 0; // restore the buffer.
  515. _BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
  516. }
  517. #ifndef RXMAC_NOTFILL_DISABLE
  518. if(_RxFlag_dontFillEnder(flagJustGot))
  519. if(_RxCnt > flagJustGot->len)
  520. _RxCnt -= flagJustGot->len;
  521. else
  522. _RxCnt = 0;
  523. #endif
  524. _flush(_pMac,flagJustGot);
  525. }
  526. static RxFlag _RxFlagMgr_GetNextMatchedAtThisState(RxMac mac,uint8_t nextByte){
  527. uint8_t i,mask;
  528. if(_Buffer_isFull(_BufForFlag))
  529. BufferUINT8_FrontOut((BufferUINT8)_BufForFlag);
  530. BufferUINT8_BackIn((BufferUINT8)_BufForFlag,nextByte);
  531. // mask to identify possible flag
  532. mask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
  533. for(i = 0; i < _FlagsCnt; i++){
  534. if((_Flags[i].option & mask) &&
  535. BufferUINT8Indexed_BackMatch(_BufForFlag,_Flags[i].pBuf,_Flags[i].len)){
  536. Buffer_Cleanup((Buffer)_BufForFlag);
  537. return &_Flags[i];
  538. }
  539. }
  540. return NULL;
  541. }
  542. static BOOL _RxFlagMgr_Init(RxMac mac,RxFlag flags,uint8_t flagsCnt,uint8_t maxLen){
  543. if(_BufForFlag = (BufferIndexed)BufferUINT8MallocArray_Create(maxLen)){
  544. _Flags = flags;
  545. _FlagsCnt = flagsCnt;
  546. _stateByte = 0;
  547. }
  548. return _BufForFlag != NULL;
  549. }
  550. static void _RxFlagMgr_Destroy(RxMac mac){
  551. Buffer_Destroy(_BufForFlag);
  552. }
  553. static void _RxFlagMgr_Reset(RxMac mac){
  554. Buffer_Cleanup((Buffer)_BufForFlag);
  555. }

测试/示例代码

已略去非必要代码

  1. #include <stdio.h>
  2. #include "RxMac.h"
  3. /*
  4. *********************************************************************************************************
  5. * LOCAL FUNCTION DECLARE
  6. *********************************************************************************************************
  7. */
  8. static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
  9. static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender);
  10. static void onGetHeader(RxMac sender,RxFlag flag);
  11. static void onGetHeader2(RxMac sender,RxFlag flag);
  12. /*
  13. *********************************************************************************************************
  14. * LOVAL VARIABLE
  15. *********************************************************************************************************
  16. */
  17. static RxMac mac = NULL;
  18. static RXFLAG_STRUCT flags[4];
  19. #define BUF_SIZE 20
  20. static uint8_t buffer[BUF_SIZE];
  21. // 协议示例1:
  22. // 帧头 :HEADER 或者 START
  23. // 强帧尾 :END
  24. // 强特殊串:12345
  25. //
  26. static void protocol1_init(void){
  27. RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
  28. RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
  29. RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
  30. RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
  31. mac = RxMac_Create(flags,4,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
  32. }
  33. // 协议示例2:
  34. // 帧头 : START
  35. // 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾
  36. // 帧尾 : END
  37. // 特殊串: NOW
  38. //
  39. static void protocol2_init(void){
  40. RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
  41. RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
  42. RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
  43. mac = RxMac_Create(flags,3,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
  44. }
  45. /*
  46. *********************************************************************************************************
  47. * CALLBACK FUNCITON
  48. *********************************************************************************************************
  49. */
  50. static void onGetData(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt){
  51. // 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytesCnt来判断当前位置
  52. RxMac_SetOnFeeded(sender,NULL);
  53. if(*pCurChar > '0' && *pCurChar <= '9' ){
  54. // bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的
  55. RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  56. }
  57. }
  58. static void onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,RxFlag HorU,RxFlag Ender){
  59. buf[len] = '\0';
  60. printf("\nFlushed:");
  61. if(state.headerFound)
  62. printf("headerFound,");
  63. if(state.enderFound)
  64. printf("enderFound,");
  65. if(state.isFull)
  66. printf("full,");
  67. if(state.uniqueFound)
  68. printf("unique,");
  69. printf("\nDatas:%s\n",buf);
  70. RxMac_SetRxSize(sender,BUF_SIZE);
  71. }
  72. static void onGetHeader(RxMac sender,RxFlag flag){
  73. printf("\nFoundHeader:%s\n",flag->pBuf);
  74. }
  75. static void onGetHeader2(RxMac sender,RxFlag flag){
  76. printf("\nFoundHeader:%s\n",flag->pBuf);
  77. RxMac_SetOnFeeded(sender,onGetData);
  78. }
  79. /*
  80. *********************************************************************************************************
  81. * MAIN FUNCTION
  82. *********************************************************************************************************
  83. */
  84. void main(void) {
  85. // 选择想要实验的协议来初始化
  86. protocol1_init();
  87. // protocol2_init();
  88. while (1) {
  89. c = getchar();
  90. // 回显
  91. putchar(c);
  92. RxMac_FeedData(mac,c);
  93. }
  94. }

示例协议1测试结果
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70

示例协议2测试结果
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 1
可以看到,第二个协议中我们通过改变缓冲区大小成功控制了数据包的长度。

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

v1.0代码

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

接收机代码

头文件

  1. /*
  2. *********************************************************************************************************
  3. *
  4. *
  5. * Universal Receive State Machine
  6. * 通用接收状态机
  7. *
  8. * File : RxMac.h
  9. *
  10. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  11. * Date: 2018/05/29
  12. * version: 1.0
  13. * History: 2018/05/29 the prototype
  14. * NOTE(s): 1. the receive process has two basic state
  15. * A. preRx: when haven't found any header, the RxMac will search for the unique
  16. * flag, header and strong-ender. Only when a header is found will come
  17. * to next step.
  18. * B. Rxing: the RxMac will put the successive bytes into the buffer, and search
  19. * for the strong-unique, strong-header, ender.
  20. * 2. the module is drived by the RxMac_FeedData(), user should get the the char
  21. * from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
  22. * 3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
  23. * to notify the results; user can judge the frame through the state parameter;
  24. * state.headerFound == 1: find any header, the header is passed by pHorU
  25. * state.enderFound == 1: find any ender, the ender is passed by pEnder
  26. * state.isFull == 1: the buffer is full, maybe you should check headerFound
  27. * to see whether a header has been found.
  28. * state.uniqueFound == 1: find any unique flag. In this case, other parameters will
  29. * always be 0 & the datas in the buffer will be the flag.
  30. * 4. To use this module, for each receive machine:
  31. * A. allocate the space for buffer, RxMac & FLAGS
  32. * RX_MAC _Mac;
  33. * RX_FLAG flags[2];
  34. * INT8U buf[300];
  35. * B. set the flags according to the protocol, define the callback funcitons
  36. * according to your need.
  37. * static void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){ ...... };
  38. * static void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,
  39. * RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){ ...... };
  40. * const INT8U HeaderFlag[] = "Header";
  41. * const INT8U EnderFlag[] = "\r\n";
  42. * RX_FLAG_INIT(flags,HeaderFlag,StrSize(HeaderFlag),FLAG_OPTION_HEADER);
  43. * RX_FLAG_INIT(&flags[1],EnderFlag,StrSize(EnderFlag),FLAG_OPTION_ENDER |
  44. * FLAG_OPTION_NOTFILL_ENDER);
  45. * C. init the receive machine:
  46. * RxMac_Init(&_Mac,flags,2,6,buf,300,NULL, onGetHeader, onFlushed );
  47. * D. feed the receive machine:
  48. * while(1){
  49. * c = GetNextChar();
  50. * RxMac_FeedData(&_Mac,c);
  51. * }
  52. *********************************************************************************************************
  53. */
  54. #ifndef RX_MAC_H
  55. #define RX_MAC_H
  56. /*
  57. *********************************************************************************************************
  58. * INCLUDES
  59. *********************************************************************************************************
  60. */
  61. #include "RingQueue.h"
  62. #include <os_cpu.h>
  63. //typedef unsigned char INT8U;
  64. //typedef unsigned short INT16U;
  65. /*
  66. *********************************************************************************************************
  67. * ADDRESSING MODE 寻址模式
  68. *********************************************************************************************************
  69. */
  70. // the addressing mode for buffer
  71. #define RXMAC_BUF_ADDRESSING_MODE RQ_ADDRESSING_MODE
  72. typedef INT8U RB_BYTE;
  73. typedef RB_BYTE * RXMAC_BUF_ADDRESSING_MODE pRB_BYTE;
  74. /*
  75. *********************************************************************************************************
  76. * CONFIGURATION 配置
  77. *********************************************************************************************************
  78. */
  79. #define RXMAC_ARGUMENT_CHECK_EN TRUE
  80. #define RXMAC_NOTFILL_EN TRUE
  81. #define RXMAC_ONFEEDED_EN TRUE // TRUE: enable the onFeeded function.
  82. #define RXMAC_SINGLETON_EN FALSE // TRUE: enable singleton pattern,so argument pRxMac of interfaces
  83. // is useless, and user don't need to allocate space for RX_MAC,
  84. // but you still need to allocate buffer and call init();
  85. /*
  86. *********************************************************************************************************
  87. * CONST
  88. *********************************************************************************************************
  89. */
  90. #define RXMAC_ERR_NONE 0
  91. #define RXMAC_ERR_ARGUMENT 1
  92. #define RXMAC_ERR_POINTERNULL 2
  93. #define RXMAC_ERR_UNKNOWN 3
  94. #define RXMAC_ERR_INIT 4
  95. /*
  96. *********************************************************************************************************
  97. * TYPE DEFINITION
  98. *********************************************************************************************************
  99. */
  100. // struct of RX_FLAG.option
  101. /*typedef struct FLAG_OPTION{
  102. unsigned int isHeader : 1; // 1: the flag is the head of the frame
  103. unsigned int strong_H : 1; // 1: strong-header, RxMac will
  104. unsigned int notfill_H: 1; // 0: fill the flag into the buffer when found as header
  105. unsigned int isEnder : 1; // 1: the flag is the end of the frame
  106. unsigned int strong_E : 1; //
  107. unsigned int notfill_E: 1; // 0: fill the flag into the buffer when found as ender
  108. unsigned int isUnique : 1; // 1: the flag is a unique flag which is treated as single frame.
  109. unsigned int strong_U : 1; // 0: when receiving a frame, RxMac will not
  110. }; //*/
  111. // 接收标志位
  112. typedef struct rx_flag{
  113. INT8U const *pBuf;
  114. INT8U len;
  115. INT8U option;
  116. } RX_FLAG,* pRX_FLAG;
  117. // normal header, RxMac will only check it in Step A
  118. #define FLAG_OPTION_HEADER 0x01
  119. // strong header, RxMac will always check it.
  120. #define FLAG_OPTION_STRONG_HEADER 0x03
  121. // the header will not be filled into buffer when found.(only valid when is header)
  122. #define FLAG_OPTION_NOTFILL_HEADER 0x04
  123. // normal ender, RxMac will only check it in Step B
  124. #define FLAG_OPTION_ENDER 0x08
  125. // strong header, RxMac will always check it.
  126. #define FLAG_OPTION_STRONG_ENDER 0x18
  127. // the ender will not be filled into buffer when found.(only valid when is ender)
  128. #define FLAG_OPTION_NOTFILL_ENDER 0x20
  129. // normal unique, RxMac will only check it in Step A
  130. #define FLAG_OPTION_UNIQUE 0x40
  131. // strong unique, RxMac will always check it.
  132. #define FLAG_OPTION_STRONG_UNIQUE 0xC0
  133. typedef struct rx_state{
  134. unsigned int headerFound: 1; // 1: have get header
  135. unsigned int enderFound : 1; // 1: have get ender
  136. unsigned int isFull : 1; // 1: the buffer is full
  137. unsigned int uniqueFound: 1; // 1: this is unique flag.
  138. } RX_STATE;
  139. typedef struct rx_mac RX_MAC, *pRX_MAC;
  140. typedef void (* RXMAC_FLUSH_EVENT)(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder);
  141. typedef void (* RXMAC_FLAG_EVENT)(pRX_MAC sender,pRX_FLAG pFlag);
  142. typedef void (* RXMAC_FILTER)(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt);
  143. struct rx_mac{
  144. RING_QUEUE FlagQueue; // 用于判断标志串的环形缓冲区对象
  145. pRX_FLAG Flags; // 标志数组
  146. INT8U FlagsCnt; // 标志数组的个数
  147. RX_STATE state; // 接收的状态(内部使用)
  148. pRX_FLAG pHorU; // 内部使用
  149. pRB_BYTE pRxBuf; // 存放数据的缓冲区
  150. INT16U RxBufSize; // 缓冲区的长度
  151. pRB_BYTE pCur; // 指向缓冲区内下一个填充字符的位置
  152. RXMAC_FILTER onFeeded; // 当被喂字符时触发,返回指向缓冲区中刚刚喂进来的字符的指针以及是缓冲区内的第几个字符
  153. RXMAC_FLAG_EVENT onGetHeader; // 获得头标志位时触发。
  154. RXMAC_FLUSH_EVENT onFlushed; // 回调函数
  155. };
  156. /*
  157. *********************************************************************************************************
  158. * FUNCTION DECLARATION
  159. *********************************************************************************************************
  160. */
  161. // to set the flag's option
  162. // pbuf pointer to the flag buffer
  163. // bufSize size of flag
  164. // opt see FLAG_OPTION_XXXXX
  165. #define RX_FLAG_INIT(pFlag,pbuf,bufSize,opt) \
  166. (pFlag)->pBuf =(pbuf);(pFlag)->len =(bufSize);(pFlag)->option = (opt);
  167. // to init the RxMac
  168. INT8U RxMac_Init(pRX_MAC pRxMac, // 需要用户自己申请个UNI_RX_MACHINE对象的空间
  169. RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags, // 提供标志字符串的数组
  170. pRB_BYTE pBuf,INT16U BufLen, // 用户需要提供缓冲区 (缓存区大小起码应该要能
  171. // 放的下最长的Flag+最长的帧,最后部分会分配给RQ)
  172. RXMAC_FILTER onFeeded, // 在每次被Feed时触发
  173. RXMAC_FLAG_EVENT onGetHeader, // 获得头标志位时触发。
  174. RXMAC_FLUSH_EVENT onFlushed // 收到一帧数据时的回调函数
  175. );
  176. // 向接收机内喂字节
  177. void RxMac_FeedData(pRX_MAC pRxMac,INT8U c);
  178. // 重置接收区长度为最长那个长度
  179. INT8U RxMac_ResetRxSize(pRX_MAC pRxMac);
  180. // 设置最大接收到多少个字节
  181. INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size);
  182. // 重置接收机的状态
  183. INT8U RxMac_ResetState(pRX_MAC pRxMac);
  184. // 强制接收机flush
  185. INT8U RxMac_Flush(pRX_MAC pRxMac);
  186. // 设置onFeeded
  187. INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded);
  188. // 设置onGetHeader
  189. INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader);
  190. // 设置onFlushed
  191. INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed);
  192. #endif // of RX_MAC_H

源文件:

  1. /*
  2. *********************************************************************************************************
  3. *
  4. *
  5. * Universal Receive State Machine
  6. * 通用接收状态机
  7. *
  8. * File : RxMac.c
  9. *
  10. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  11. * Date: 2018/05/29
  12. * version: 1.0
  13. * History:
  14. * NOTE(s):
  15. *
  16. *********************************************************************************************************
  17. */
  18. /*
  19. *********************************************************************************************************
  20. * INCLUDES
  21. *********************************************************************************************************
  22. */
  23. #include "RxMac.h"
  24. #include <string.h>
  25. #include <stddef.h>
  26. /*
  27. *********************************************************************************************************
  28. * CONSTANT
  29. *********************************************************************************************************
  30. */
  31. // normal header, RxMac will only check it in Step A
  32. #define FLAG_OPTBIT_HEADER 0x01
  33. // strong header, RxMac will always check it.
  34. #define FLAG_OPTBIT_STRONG_HEADER 0x02
  35. // the header will not be filled into buffer when found.(only valid when is header)
  36. #define FLAG_OPTBIT_NOTFILL_HEADER 0x04
  37. // normal ender, RxMac will only check it in Step B
  38. #define FLAG_OPTBIT_ENDER 0x08
  39. // strong header, RxMac will always check it.
  40. #define FLAG_OPTBIT_STRONG_ENDER 0x10
  41. // the ender will not be filled into buffer when found.(only valid when is ender)
  42. #define FLAG_OPTBIT_NOTFILL_ENDER 0x20
  43. // normal unique, RxMac will only check it in Step A
  44. #define FLAG_OPTBIT_UNIQUE 0x40
  45. // strong unique, RxMac will always check it.
  46. #define FLAG_OPTBIT_STRONG_UNIQUE 0x80
  47. #define STATEMASK_STEPA (FLAG_OPTBIT_HEADER | FLAG_OPTBIT_UNIQUE | FLAG_OPTBIT_STRONG_ENDER)
  48. #define STATEMASK_STEPB (FLAG_OPTBIT_STRONG_UNIQUE | FLAG_OPTBIT_ENDER | FLAG_OPTBIT_STRONG_HEADER)
  49. #define FLAGMASK_USUHSH (FLAG_OPTBIT_HEADER | FLAG_OPTBIT_STRONG_HEADER | FLAG_OPTION_UNIQUE | FLAG_OPTBIT_STRONG_UNIQUE)
  50. /*
  51. *********************************************************************************************************
  52. * LOCAL FUNCITON DECLARATION
  53. *********************************************************************************************************
  54. */
  55. #if(RXMAC_SINGLETON_EN == FALSE)
  56. #define _pRxMac pRxMac
  57. #else
  58. static RX_MAC _RxMac;
  59. #define _pRxMac (&_RxMac)
  60. #endif
  61. #define _FlagQueue (_pRxMac->FlagQueue)
  62. #define _Flags (_pRxMac->Flags)
  63. #define _FlagsCnt (_pRxMac->FlagsCnt)
  64. #define _state (_pRxMac->state)
  65. #define _stateByte (*(INT8U *)(&_state))
  66. #define _pHorU (_pRxMac->pHorU)
  67. #define _pRxBuf (_pRxMac->pRxBuf)
  68. #define _RxBufSize (_pRxMac->RxBufSize)
  69. #define _pCur (_pRxMac->pCur)
  70. #define _onFeeded (_pRxMac->onFeeded)
  71. #define _onGetHeader (_pRxMac->onGetHeader)
  72. #define _onFlushed (_pRxMac->onFlushed)
  73. #define _isRxBufFull() ((_pCur - _pRxBuf) >= _RxBufSize)
  74. // 因为不能保证用户把数据放在非分页区,只好自己实现一个,实际使用中如果确定在非分页区可以把下面的宏替换为库函数memcpy
  75. static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n);
  76. #define _memcpy(dest,src,n) _memcpy_internal(dest,src,n)
  77. // 冲刷缓冲区
  78. static void _flush(pRX_MAC pRxMac,pRX_FLAG ender);
  79. // 往接收机缓冲区内放数据
  80. static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len);
  81. /*
  82. *********************************************************************************************************
  83. * RxMac_Init()
  84. *
  85. * Description : To initialize a RxMac. 初始化接收机
  86. *
  87. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  88. * Flags pointer to the flags(an array); 指向标志串(数组)的指针
  89. * FlagsCnt the count of the flags; 有多少个标志串;
  90. * maxLenOfFlags the max length of flags; 标志字符串最长的长度
  91. * pBuf pointer to the buffer provided to the RxMac;提供给接收机使用的缓存
  92. * BufLen the size of the buffer. 缓存的大小
  93. * onFeeded the callback func that will be called when feeded.
  94. * 每次被feed时会调用的回调函数,如改变对应数据值会影响标志位的判断
  95. * onGetHeader the callback func that will be called when find a header.
  96. * 当发现帧头时会调用的回调函数
  97. * onFlushed the callback func that will be called when flushed.
  98. * 当Flush时会调用的回调函数
  99. *
  100. * Return : RXMAC_ERR_NONE if success
  101. * RXMAC_ERR_ARGUMENT if the length of longest Flags bigger than Buflen,or one of them is 0
  102. * RXMAC_ERR_POINTERNULL if empty pointer
  103. *
  104. * Note(s) : size of buffer should bigger than the longest flag plus the longest frame
  105. * that may be received(so at least 2 * maxLenOfFlags).
  106. * the buffer is allocate as follow:
  107. * <---------------------- BufLen ---------------------->
  108. * | RxBuffer | |
  109. * <------------- RxBufSize ------------> <-maxLenOfFlags->
  110. *
  111. * void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag):
  112. * sender the pointer to the RxMac which call this function
  113. * pFlag the header matched
  114. *
  115. * void onFeeded(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt):
  116. * sender the pointer to the RxMac which call this function
  117. * pCurChar point to the char in the buffer just received.
  118. * bytesCnt the number of bytes in the buffer including the char just feeded.
  119. *
  120. * void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,
  121. * pRX_FLAG pEnder);
  122. * sender the pointer to the RxMac which call this function
  123. * pBuf the pointer to the frame.
  124. * len the length of frame.
  125. * state the state of frame.
  126. * pHorU point to the header flag if state.headerFound == 1, or unique flag if
  127. * state.uniqueFound == 1.
  128. * pEnder point to the ender flag if state.enderFound == 1.
  129. *********************************************************************************************************
  130. */
  131. INT8U RxMac_Init
  132. (pRX_MAC pRxMac,RX_FLAG Flags[],INT8U FlagsCnt,INT8U maxLenOfFlags,pRB_BYTE pBuf,INT16U BufLen,
  133. RXMAC_FILTER onFeeded,RXMAC_FLAG_EVENT onGetHeader,RXMAC_FLUSH_EVENT onFlushed){
  134. //INT8U maxLen = 0;
  135. INT8U i;
  136. #if(RXMAC_ARGUMENT_CHECK_EN)
  137. if(
  138. #if(!RXMAC_SINGLETON_EN)
  139. _pRxMac == NULL ||
  140. #endif
  141. Flags == NULL || pBuf == NULL)
  142. return RXMAC_ERR_POINTERNULL;
  143. #endif
  144. // find out the max length of flags.
  145. //for(i = 0; i < FlagsCnt; i++){
  146. // if(Flags[i].len > maxLen)
  147. // maxLen = Flags[i].len;
  148. //}
  149. #if(RXMAC_ARGUMENT_CHECK_EN)
  150. if(maxLenOfFlags == 0 || (maxLenOfFlags * 2) > BufLen || BufLen == 0 || FlagsCnt == 0 ||
  151. maxLenOfFlags == 0)
  152. return RXMAC_ERR_ARGUMENT;
  153. #endif
  154. BufLen -= maxLenOfFlags;
  155. // 把buffer的最后一段分配给环形缓冲区
  156. RingQueueInit(&_FlagQueue,pBuf + BufLen,maxLenOfFlags,&i);
  157. _Flags = Flags;
  158. _FlagsCnt = FlagsCnt;
  159. _stateByte = 0;
  160. _pHorU = NULL;
  161. _pRxBuf = pBuf;
  162. _RxBufSize = BufLen;
  163. _pCur = pBuf;
  164. _onFeeded = onFeeded;
  165. _onGetHeader = onGetHeader;
  166. _onFlushed = onFlushed;
  167. return RXMAC_ERR_NONE;
  168. }
  169. /*
  170. *********************************************************************************************************
  171. * RxMac_FeedData()
  172. *
  173. * Description : To feed RxMac the next char. 用于给接收机下一个字符
  174. *
  175. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  176. * c the char to feed; 下一个字符
  177. *
  178. * Return :
  179. *
  180. * Note(s) :
  181. *********************************************************************************************************
  182. */
  183. void RxMac_FeedData(pRX_MAC pRxMac,INT8U c){
  184. INT8U i,mask;
  185. pRX_FLAG pFlag = NULL;
  186. #if(RXMAC_ONFEEDED_EN)
  187. pRB_BYTE pCurChar = _pCur;
  188. #endif
  189. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  190. if(_pRxMac == NULL)
  191. return;
  192. #endif
  193. *_pCur++ = c; // 填入缓冲区
  194. #if(RXMAC_ONFEEDED_EN)
  195. if(_onFeeded != NULL)
  196. _onFeeded(_pRxMac,pCurChar,_pCur - _pRxBuf);
  197. RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
  198. #else
  199. RingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
  200. #endif
  201. // _state.headerFound == 1 说明在等待帧尾,否则在等待帧头
  202. mask = (_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
  203. // 寻找匹配的标志串
  204. for(i = 0; i < _FlagsCnt; i++){
  205. if((_Flags[i].option & mask) &&
  206. (RingQueueMatch(&_FlagQueue,(pRQTYPE)_Flags[i].pBuf,_Flags[i].len) >= 0)){
  207. RingQueueClear(&_FlagQueue);
  208. pFlag = &_Flags[i];
  209. break;
  210. }
  211. }
  212. // 如果没有发现标志串,检查下有没满了,满了就Flush
  213. if(pFlag == NULL){
  214. if(_isRxBufFull()){
  215. _state.isFull = 1;
  216. _flush(_pRxMac,NULL);
  217. }
  218. return;
  219. }
  220. // 这4种标志串要_flush掉前面的东西
  221. if(pFlag->option & FLAGMASK_USUHSH){
  222. _pCur -= pFlag->len;
  223. _flush(_pRxMac,NULL);
  224. _pHorU = pFlag;
  225. }
  226. // 如果是帧头的处理
  227. if(pFlag->option & (FLAG_OPTION_STRONG_HEADER | FLAG_OPTION_HEADER)){
  228. #if(RXMAC_NOTFILL_EN == TRUE)
  229. if(!(pFlag->option & FLAG_OPTION_NOTFILL_HEADER))
  230. #endif
  231. _BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
  232. _state.headerFound = 1;
  233. if(_onGetHeader != NULL)
  234. _onGetHeader(_pRxMac,pFlag);
  235. return;
  236. }
  237. // 如果是Unique的处理
  238. if(pFlag->option & (FLAG_OPTION_STRONG_UNIQUE | FLAG_OPTION_UNIQUE)){
  239. _state.uniqueFound = 1;
  240. _BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
  241. _flush(_pRxMac,NULL);
  242. }else{
  243. // 能到这里说明是帧尾
  244. _state.enderFound = 1;
  245. #if(RXMAC_NOTFILL_EN == TRUE)
  246. if(pFlag->option & FLAG_OPTION_NOTFILL_ENDER)
  247. _pCur -= pFlag->len;
  248. #endif
  249. _flush(_pRxMac,pFlag);
  250. }
  251. return;
  252. }
  253. /*
  254. *********************************************************************************************************
  255. * RxMac_ResetRxSize()
  256. *
  257. * Description : reset the size of RxBuf to the max size. 重置接收缓冲区
  258. *
  259. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  260. *
  261. * Return : RXMAC_ERR_NONE if Success;
  262. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  263. * RXMAC_ERR_INIT if RxMac hasn't inited or any error in initialization
  264. * Note(s) :
  265. *********************************************************************************************************
  266. */
  267. INT8U RxMac_ResetRxSize(pRX_MAC pRxMac){
  268. int size;
  269. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  270. if(_pRxMac == NULL)
  271. return RXMAC_ERR_POINTERNULL;
  272. #endif
  273. size = _FlagQueue.RingBuf - _pRxBuf;
  274. #if(RXMAC_ARGUMENT_CHECK_EN)
  275. if(size < 0)
  276. return RXMAC_ERR_INIT;
  277. #endif
  278. _RxBufSize = (INT16U)size;
  279. return RXMAC_ERR_NONE;
  280. }
  281. /*
  282. *********************************************************************************************************
  283. * RxMac_SetRxSize()
  284. *
  285. * Description : set the size of RxBuf to the max size. 重置接收缓冲区
  286. *
  287. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  288. * size the size to set;
  289. *
  290. * Return : RXMAC_ERR_NONE if Success;
  291. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  292. * RXMAC_ERR_ARGUMENT if size is wrong.
  293. * Note(s) : the size shouldn't be bigger than the initial value, and should bigger than
  294. * the current number of chars in the RxBuf.
  295. *
  296. *********************************************************************************************************
  297. */
  298. INT8U RxMac_SetRxSize(pRX_MAC pRxMac, INT16U size){
  299. #if(RXMAC_ARGUMENT_CHECK_EN)
  300. #if (!RXMAC_SINGLETON_EN)
  301. if(_pRxMac == NULL)
  302. return RXMAC_ERR_POINTERNULL;
  303. #endif
  304. if(_FlagQueue.RingBuf - _pRxBuf < size || size <= _pCur - _pRxBuf)
  305. return RXMAC_ERR_ARGUMENT;
  306. #endif
  307. _RxBufSize = size;
  308. return RXMAC_ERR_NONE;
  309. }
  310. /*
  311. *********************************************************************************************************
  312. * RxMac_ResetState()
  313. *
  314. * Description : reset the state of receive machine. 重置接收机的状态
  315. *
  316. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  317. *
  318. * Return : RXMAC_ERR_NONE if Success;
  319. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  320. * Note(s) : it will not trigger call-back of onFlush.
  321. *********************************************************************************************************
  322. */
  323. INT8U RxMac_ResetState(pRX_MAC pRxMac){
  324. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  325. if(_pRxMac == NULL)
  326. return RXMAC_ERR_POINTERNULL;
  327. #endif
  328. // 复位接收机
  329. RingQueueClear(&_FlagQueue);
  330. _pCur = _pRxBuf;
  331. _stateByte = 0;
  332. _pHorU = NULL;
  333. return RXMAC_ERR_NONE;
  334. }
  335. /*
  336. *********************************************************************************************************
  337. * RxMac_Flush()
  338. *
  339. * Description : force receive machine to flush.
  340. *
  341. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  342. *
  343. * Return : RXMAC_ERR_NONE if Success;
  344. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  345. *
  346. * Note(s) : it will force receive machine to flush, if there is any data in the RxBuffer,
  347. *
  348. *********************************************************************************************************
  349. */
  350. INT8U RxMac_Flush(pRX_MAC pRxMac){
  351. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  352. if(_pRxMac == NULL)
  353. return RXMAC_ERR_POINTERNULL;
  354. #endif
  355. _flush(_pRxMac,NULL);
  356. return RXMAC_ERR_NONE;
  357. }
  358. /*
  359. *********************************************************************************************************
  360. * RxMac_SetOnFeeded()
  361. *
  362. * Description : set the onFeeded callback function.
  363. *
  364. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  365. * onFeeded the callback function to set; 要设置的回调函数
  366. *
  367. * Return : RXMAC_ERR_NONE if Success;
  368. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  369. *
  370. * Note(s) :
  371. *
  372. *********************************************************************************************************
  373. */
  374. INT8U RxMac_SetOnFeeded(pRX_MAC pRxMac,RXMAC_FILTER onFeeded){
  375. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  376. if(_pRxMac == NULL)
  377. return RXMAC_ERR_POINTERNULL;
  378. #endif
  379. _onFeeded = onFeeded;
  380. return RXMAC_ERR_NONE;
  381. }
  382. /*
  383. *********************************************************************************************************
  384. * RxMac_SetOnGetHeader()
  385. *
  386. * Description : set the onGetHeader callback function.
  387. *
  388. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  389. * onGetHeader the callback function to set; 要设置的回调函数
  390. *
  391. * Return : RXMAC_ERR_NONE if Success;
  392. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  393. *
  394. * Note(s) :
  395. *
  396. *********************************************************************************************************
  397. */
  398. INT8U RxMac_SetOnGetHeader(pRX_MAC pRxMac,RXMAC_FLAG_EVENT onGetHeader){
  399. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  400. if(_pRxMac == NULL)
  401. return RXMAC_ERR_POINTERNULL;
  402. #endif
  403. _onGetHeader = onGetHeader;
  404. return RXMAC_ERR_NONE;
  405. }
  406. /*
  407. *********************************************************************************************************
  408. * RxMac_SetOnFlushed()
  409. *
  410. * Description : set the onFlushed callback function.
  411. *
  412. * Arguments : pRxMac pointer to the RxMac struct; 指向接收机结构体的指针
  413. * onFlushed the callback function to set; 要设置的回调函数
  414. *
  415. * Return : RXMAC_ERR_NONE if Success;
  416. * RXMAC_ERR_POINTERNULL if pRxMac == NULL
  417. *
  418. * Note(s) :
  419. *
  420. *********************************************************************************************************
  421. */
  422. INT8U RxMac_SetOnFlushed(pRX_MAC pRxMac,RXMAC_FLUSH_EVENT onFlushed){
  423. #if(RXMAC_ARGUMENT_CHECK_EN && !RXMAC_SINGLETON_EN)
  424. if(_pRxMac == NULL)
  425. return RXMAC_ERR_POINTERNULL;
  426. #endif
  427. _onFlushed = onFlushed;
  428. return RXMAC_ERR_NONE;
  429. }
  430. /*
  431. *********************************************************************************************************
  432. * LOCAL FUNCITON
  433. *********************************************************************************************************
  434. */
  435. static pRB_BYTE _memcpy_internal(pRB_BYTE dest, pRB_BYTE src, size_t n){
  436. pRB_BYTE p = dest;
  437. while(n-- > 0)
  438. *p++ = *src++;
  439. return dest;
  440. }
  441. static void _BufIn(pRX_MAC pRxMac,pRB_BYTE pBuf,INT16U len){
  442. _memcpy(_pCur,pBuf,len);
  443. _pCur += len;
  444. }
  445. static void _flush(pRX_MAC pRxMac,pRX_FLAG ender){
  446. // 触发回调
  447. if(_pCur-_pRxBuf > 0 && _onFlushed != NULL)
  448. _onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender);
  449. // 复位接收机
  450. _pCur = _pRxBuf;
  451. _stateByte = 0;
  452. _pHorU = NULL;
  453. }

测试/示例代码

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * Framework
  6. *
  7. * By : Lin Shijun
  8. * Note: This is a framework for uCos-ii project with only S12CPU, none float, banked memory model.
  9. * You can use this framework with same modification as the start point of your project.
  10. * I've removed the os_probe module,since I thought it useless in most case.
  11. * This framework is adapted from the official release.
  12. *********************************************************************************************************
  13. */
  14. #include "includes.h"
  15. #include "SCI_def.h"
  16. #include "RxMac.h"
  17. /*
  18. *********************************************************************************************************
  19. * STACK SPACE DECLARATION
  20. *********************************************************************************************************
  21. */
  22. static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
  23. /*
  24. *********************************************************************************************************
  25. * TASK FUNCTION DECLARATION
  26. *********************************************************************************************************
  27. */
  28. static void AppTaskStart(void *p_arg);
  29. /*
  30. *********************************************************************************************************
  31. * CALLBACK FUNCITON
  32. *********************************************************************************************************
  33. */
  34. void onGetData(pRX_MAC sender,pRB_BYTE pCurChar,INT16U bytesCnt){
  35. // 因为发现帧头后才挂载事件,所以下一次回掉正好是说明字符数的那个字符,否则还得根据bytesCnt来判断当前位置
  36. RxMac_SetOnFeeded(sender,NULL);
  37. if(*pCurChar > '0' && *pCurChar <= '9' ){
  38. // bytesCnt是当前收到了多少个字符,所以接收区大小为当前字符数加上还要接收的
  39. RxMac_SetRxSize(sender,*pCurChar - '0' + bytesCnt);
  40. }
  41. }
  42. void onFlushed(pRX_MAC sender,pRB_BYTE pBuf,INT16U len,RX_STATE state,pRX_FLAG pHorU,pRX_FLAG pEnder){
  43. SCI_PutCharsB(SCI0,"\nFlushed:",9,0);
  44. if(state.headerFound)
  45. SCI_PutCharsB(SCI0,"headerFound,",12,0);
  46. if(state.enderFound)
  47. SCI_PutCharsB(SCI0,"enderFound,",11,0);
  48. if(state.isFull)
  49. SCI_PutCharsB(SCI0,"full,",5,0);
  50. if(state.uniqueFound)
  51. SCI_PutCharsB(SCI0,"unique,",7,0);
  52. SCI_PutCharsB(SCI0,"\nDatas:",7,0);
  53. SCI_PutCharsB(SCI0,pBuf,len,0);
  54. SCI_PutCharsB(SCI0,"\n",1,0);
  55. RxMac_ResetRxSize(sender);
  56. }
  57. void onGetHeader(pRX_MAC sender,pRX_FLAG pFlag){
  58. SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  59. SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  60. SCI_PutCharsB(SCI0,"\n",1,0);
  61. }
  62. void onGetHeader2(pRX_MAC sender,pRX_FLAG pFlag){
  63. SCI_PutCharsB(SCI0,"\nFoundHeader:",13,0);
  64. SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
  65. SCI_PutCharsB(SCI0,"\n",1,0);
  66. RxMac_SetOnFeeded(sender,onGetData);
  67. }
  68. /*
  69. *********************************************************************************************************
  70. * FLAGS
  71. *********************************************************************************************************
  72. */
  73. RX_MAC _rxmac;
  74. #define BUF_SIZE 20
  75. INT8U buffer[BUF_SIZE];
  76. RX_FLAG flags[4];
  77. // 协议示例1:
  78. // 帧头 :HEADER 或者 START
  79. // 强帧尾 :END
  80. // 强特殊串:12345
  81. //
  82. static void protocol1_init(){
  83. RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
  84. RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
  85. RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
  86. RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
  87. RxMac_Init(&_rxmac,flags,4,6,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
  88. }
  89. // 协议示例2:
  90. // 帧头 : START
  91. // 帧头后的第1个字符表示后面还要接收多少个字符 1-9,'4'表示4个,如果不是数字或为'0',则等待帧尾
  92. // 帧尾 : END
  93. // 特殊串: NOW
  94. //
  95. static void protocol2_init(){
  96. RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
  97. RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
  98. RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
  99. RxMac_Init(&_rxmac,flags,3,5,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
  100. }
  101. /*
  102. *********************************************************************************************************
  103. * MAIN FUNCTION
  104. *********************************************************************************************************
  105. */
  106. void main(void) {
  107. INT8U err;
  108. BSP_IntDisAll(); /* Disable ALL interrupts to the interrupt controller */
  109. OSInit(); /* Initialize uC/OS-II */
  110. err = OSTaskCreate(AppTaskStart,
  111. NULL,
  112. (OS_STK *)&AppTaskStartStk[APP_TASK_START_STK_SIZE - 1],
  113. APP_TASK_START_PRIO);
  114. OSStart();
  115. }
  116. static void AppTaskStart (void *p_arg)
  117. {
  118. INT8U c,err;
  119. (void)p_arg; /* Prevent compiler warning */
  120. BSP_Init();
  121. SCI_Init(SCI0);
  122. SCI_EnableTrans(SCI0);
  123. SCI_EnableRecv(SCI0);
  124. SCI_EnableRxInt(SCI0);
  125. SCI_BufferInit();
  126. // 选择想要实验的协议来初始化
  127. protocol1_init();
  128. //protocol2_init();
  129. while (DEF_TRUE)
  130. {
  131. // 获取下一个字符
  132. c = SCI_GetCharB(SCI0,0,&err);
  133. // 回显
  134. SCI_PutCharB(SCI0,c,0);
  135. // 喂给接收机
  136. RxMac_FeedData(&_rxmac,c);
  137. }
  138. }

后记

此模块已经通过单元测试,但难保不会有一些未发现的bug,如果使用中发现任何问题或者有任何建议意见请立刻联系我,谢谢。

更新历史

2018/05/29 V1.0
2019/03/07 V2.1

发表评论

表情:
评论列表 (有 0 条评论,351人围观)

还没有评论,来说两句吧...

相关阅读