基于状态机的通用接收模块

发布时间:2024-12-14  



前言

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

模块相关概念和逻辑

接收机状态

接收机有两个基本状态:

  • • 状态A:preRx 等待帧头中,这个时候接收机会不断判断是否收到了特殊序列、帧头和强帧尾。如果收到了帧头,则(默认)会把帧头填入缓冲区的最前面,然后进入状态B。

  • • 状态B:Rxing 等待帧尾中,收到的数据会按序填入接收缓冲区,同时不断查找帧尾、强帧头以及强特殊序列,不管找到了哪一个都会触发flush。如果,找到的是强帧头,则仍然在状态B,否则恢复状态A。

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

标志字符序列

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

对应模块中的结构体为:

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

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

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

flush

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

此函数的原型如下:

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

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

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

typedef struct RXSTATE_STRUCT{ unsigned int headerFound: 1; // 1: have get 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;

通过判断每个标志位是否置1,可以得知当前数据包的状态。

如果headerFound == 1,说明数据包是有帧头的,可以通过pHorU获得帧头

如果enderFound == 1,说明数据包是有帧尾的,可以通过pEnder获得帧尾

如果isFull == 1,说明此数据包是因为接收区满了放不下了而产生的回调,在一些需要根据某个字段来判断数据包真正大小的协议里,可以通过调整接收缓冲区的大小来恰当的产生flush。

如果UniqueFound == 1,说明此数据包是标志序列,这时缓冲区内的内容等于pHorU指向的那个标志序列

接收机类

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

typedef struct RXMAC_STRUCT * RxMac;

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

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

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

过滤器

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

typedef void (* RXMAC_FILTER)(RxMac sender,uint8_t * pCurChar,uint16_t bytesCnt);
  • • pCurChar :指向接收区中刚收到的字符

  • • bytesCnt :这个字符是接收区中的第几个字符

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

onGetHeader事件

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

接收机运行逻辑

接收机的运作逻辑如下:

边际条件

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

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

对于标志序列匹配到一半发生了接收缓冲区满,从而导致发生标志序列匹配时,接收缓冲区中只有半个标志序列的情况:

如果标志序列是(强)特殊序列或(强)帧头的情况,可以保证功能正常运行。

如果标志序列是强帧尾的情况,缓冲区内会只剩下后半段的帧尾,但可以根据pEnder参数来得知真正的帧尾。帧尾不会发生这种边际条件。

相关代码 此模块使用了我自己写的Buffer模块作为内部缓冲区来判断标志字符串。

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

接收机代码

RxMac.h

/*
*******************************************************************************************
*
*
*                                  Universal Receive State Machine
*                                          通用接收状态机
*
* File : RxMac.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 2018/05/29 1.0 the prototype
*          2019/01/23 2.0 modify the type names to more readable ones, though preserve
*                       the old-style for forward compatibility;
*                         change init method to create method which use malloc to alloc
*                       instance, and the corresponding destroy method.
*                         change the internal buffer module from RINGQUEUE to BufferArray,
*                       so user no longer need to know the internal flags management and
*                       allocate the space for it.
*                         add RxMac_FeedDatas method for convenient.
*          2019/03/07 2.1 some modification to the malloc configuration
*
* NOTE(s):  1. the receive process has two basic state
*              A. preRx: when haven't found any header, the RxMac will search for the unique
*                        flag, header and strong-ender. Only when a header is found will come
*                        to next step.
*              B. Rxing: the RxMac will put the successive bytes into the buffer, and search
*                        for the strong-unique, strong-header, ender. 
*           2. the module is drived by the RxMac_FeedData(), user should get the the char 
*              from data stream and pass the data one by one to the RxMac through RxMac_FeedData()
*              or RxMac_FeedDatas().
*           3. each time RxMac find a frame(complete or incomplete),it will call the onFlushed
*              to notify the results; user can judge the frame through the state parameter; 
*               state.headerFound == 1:   find any header, the header is passed by HorU
*               state.enderFound  == 1:   find any ender,  the ender  is passed by Ender
*               state.isFull      == 1:   the buffer is full, maybe you should check headerFound
*                                         to see whether a header has been found.
*               state.uniqueFound == 1:   find any unique flag. In this case, other parameters will
*                                         always be 0 ,the data in the buffer will be the flag,
*                                         and the unique flag is passed by HorU.
*           4. To use this module, for each receive machine:
*              A. define malloc to configure the module, see CONFIGURATION
*              B. allocate the space for buffer and FLAGS.
*                   RXFLAG_STRUCT flags[2];
*                   uint8_t buf[300];
*              C. set the flags according to the protocol, define the callback functions
*                  according to your need.
*                   static void onGetHeader(RxMac sender,RxFlag pFlag){ ...... };
*                   static void onFlushed(RxMac sender,RxMacPtr pBuf,uint16_t len,
*                      RxState state,RxFlag HorU,RxFlag Ender){ ...... };
*                   const uint8_t HeaderFlag[] = "Header";
*                   const uint8_t EnderFlag[] = "
";
*                   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       标志字符串结构体的数组 //  flagsCnt    标志字符串结构体的个数 //  buf         用户提供给接收机用的缓冲区  //  bufLen      缓冲区的大小(起码应该要能放的下最长的标志字符串) //  onFeeded    在每次被Feed时触发 //  onGetHeader 获得头标志位时触发。 //  onFlushed   收到一帧数据时的回调函数 RxMac RxMac_Create(RXFLAG_STRUCT const flags[], uint8_t flagsCnt, RxMacPtr buf, uint16_t bufLen, RXMAC_FILTER onFeeded, RXMAC_FLAG_EVENT onGetHeader, RXMAC_FLUSH_EVENT onFlushed); // to destroy the RxMac void RxMac_Destroy(RxMac mac); // 向接收机内喂字节 void RxMac_FeedDatas(RxMac mac, uint8_t const * buf, uint16_t len); void RxMac_FeedData(RxMac mac, uint8_t c); // 重置接收区长度为最长那个长度 //uint8_t RxMac_ResetRxSize(RxMac mac); // 设置最大接收到多少个字节 uint8_t RxMac_SetRxSize(RxMac mac, uint16_t size); // 重置接收机的状态 uint8_t RxMac_ResetState(RxMac mac); // 强制接收机flush uint8_t RxMac_Flush(RxMac mac); // 设置onFeeded uint8_t RxMac_SetOnFeeded(RxMac mac, RXMAC_FILTER onFeeded); // 设置onGetHeader uint8_t RxMac_SetOnGetHeader(RxMac mac, RXMAC_FLAG_EVENT onGetHeader); // 设置onFlushed uint8_t RxMac_SetOnFlushed(RxMac mac, RXMAC_FLUSH_EVENT onFlushed); #include "RxMacPrivate.h" #endif // of RX_MAC_H

RxMacPrivate.h

/*
*******************************************************************************************
*
*
*                       Private Declarations for Universal Receive State Machine
*
* File : RxMacPrivate.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2019/03/07
* version: 2.1
* History: 
* NOTE(s): 
*******************************************************************************************
*/ /*
*******************************************************************************************
*                                  FUNCTION DECLARATION
*******************************************************************************************
*/ // 打印内部缓冲区,返回缓冲区的长度 uint16_t _RxMac_printBuffer(RxMac mac,uint8_t * buf); /*
*******************************************************************************************
*                                      RECEIVE FLAG STRUCT
*******************************************************************************************
*/ // struct of RXFLAG_STRUCT.option  /*typedef struct RXFLAG_OPTION{
  unsigned int isHeader : 1;  // 1: the flag is the head of the 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
*                                          通用接收状态机
*
* 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; // 单例模式中,这个指针用于标识是否单例已初始化过 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) 文章来源于:21IC    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>