CC2530之串列埠接收回撥函式MT_UartProcessZToolData()
需要測試程式碼的可以留下郵箱,或者關注微信公眾號 小白技術棧 後臺回覆【cc2530串列埠回撥函式】獲取。
CC2530使用MT層實現串列埠讀操作,在MT_UART.c檔案定義回撥函式:
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
uartConfig.callBackFunc = MT_UartProcessZToolData;
在串列埠接收回撥函式MT_UartProcessZToolData()中,Zstack採用狀態機接收的方式對串列埠接收資料進行處理,看似比較複雜,但其實這樣接收資料還能校驗資料的準確性,而且還有osal_msg_send( App_TaskID, (byte *)pMsg )傳送機制,處理資料比較方便。
其接收資料格式為 0xFE + 資料長度(僅是data的長度)+ 命令欄位 + data[] + 校驗和
程式碼註釋如下:
/***************************************************************************************************
* @fn MT_UartProcessZToolData
*
* @brief | SOP | Data Length | CMD | Data | FCS |
* | 1 | 1 | 2 | 0-Len | 1 |
*
* Parses the data and determine either is SPI or just simply serial data
* then send the data to correct place (MT or APP)
*
* @param port - UART port
* event - Event that causes the callback
*
*
* @return None
***************************************************************************************************/
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
uint8 ch;
uint8 bytesInRxBuffer;
(void)event; // Intentionally unreferenced parameter
while (Hal_UART_RxBufLen(port)) //判斷是否有資料
{
HalUARTRead (port, &ch, 1); //每次接收一個資料
switch (state)
{
case SOP_STATE: //初始狀態state = 0,判斷幀頭是否為SOP_STATE(0xFE)
if (ch == MT_UART_SOF)
state = LEN_STATE; //若幀頭正確,狀態機狀態改為LEN_STATE
break;
case LEN_STATE: //接收第二位元組時,進入LEN_STATE
LEN_Token = ch; //將第二位元組(傳輸資料data[]的長度)賦值給LEN_Token
tempDataLen = 0; //初始化臨時資料計數器tempDataLen為零
/* Allocate memory for the data */
pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +
MT_RPC_FRAME_HDR_SZ + LEN_Token ); //分配存放訊息的空間,由3位元組(1位元組資料長度位+2位元組CMD欄位)+ data[]長度
if (pMsg) //若有訊息接收
{
/* Fill up what we can */
pMsg->hdr.event = CMD_SERIAL_MSG; //事件ID,供應用層查詢使用
pMsg->msg = (uint8*)(pMsg+1); //加1的目的是為了分配存放資料末尾的1位元組校驗和
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token; //將資料長度存放到msg[0]
state = CMD_STATE1; //修改狀態機狀態為CMD_STATE1
}
else //無訊息則回到狀態機起始狀態
{
state = SOP_STATE;
return;
}
break;
case CMD_STATE1:
pMsg->msg[MT_RPC_POS_CMD0] = ch; //第三位元組為命令欄位一
state = CMD_STATE2;
break;
case CMD_STATE2:
pMsg->msg[MT_RPC_POS_CMD1] = ch; //第四位元組為命令欄位二
/* If there is no data, skip to FCS state */
if (LEN_Token) //如果有資料接收,則狀態機改為DATA_STATE
{
state = DATA_STATE;
}
else //如果無資料接收,則狀態機改為FCS_STATE校驗模式
{
state = FCS_STATE;
}
break;
case DATA_STATE:
/* Fill in the buffer the first byte of the data */
pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch; //開始存放data[]
/* Check number of bytes left in the Rx buffer */
bytesInRxBuffer = Hal_UART_RxBufLen(port);
/* If the remain of the data is there, read them all, otherwise, just read enough */
if (bytesInRxBuffer <= LEN_Token - tempDataLen) //如果緩衝區剩餘位元組數不大於分配 的空間,則將剩餘位元組全部存放到msg
{
HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer);
tempDataLen += bytesInRxBuffer;
}
else //根據剩餘空間大小存放資料
{
HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen);
tempDataLen += (LEN_Token - tempDataLen);
}
/* If number of bytes read is equal to data length, time to move on to FCS */
if ( tempDataLen == LEN_Token )
state = FCS_STATE; //修改狀態為校驗狀態
break;
case FCS_STATE:
FSC_Token = ch; //將最後一個位元組(校驗和)賦值給FSC_Token
/* Make sure it's correct */
if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token)) //校驗成功,則將訊息傳送出去
{
osal_msg_send( App_TaskID, (byte *)pMsg ); //將訊息傳送到應用層
}
else
{
/* deallocate the msg */
osal_msg_deallocate ( (uint8 *)pMsg ); //此函式用於釋放訊息緩衝區。此函式由任務(或處理元素)在處理完接收到的訊息後呼叫
}
/* Reset the state, send or discard the buffers at this point */
state = SOP_STATE; //恢復到初始化狀態,等待下次接收
break;
default:
break;
}
}
}
然後在SampleApp.c檔案uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )函式狀態機中新增如下:
mtOSALSerialData_t *UartMsg;
.
.
.
case CMD_SERIAL_MSG:
UartMsg = (mtOSALSerialData_t *)MSGpkt;
memcpy(uartRecvBuf, UartMsg->msg, UartMsg->msg[0] + 3);
SampleApp_Send_P2P_Message();
memset(uartRecvBuf, 0, UartMsg->msg[0] + 3);
將串列埠接收到的訊息傳送到協調器,通過協調器列印出來。
cc2530串列埠接收資料由stm32傳送測試,其測試程式碼為:
uint8_t MT_UartCalcFCS( uint8_t *msg_ptr, uint8_t len )
{
uint8_t x;
uint8_t xorResult;
xorResult = 0;
for ( x = 0; x < len; x++, msg_ptr++ )
xorResult = xorResult ^ *msg_ptr;
return ( xorResult );
}
/*********************************************************************
* @fn led_entry
*
* @brief Led run.
*
* @param parameter - none
*
* @return none
*/
void led_entry(void *parameter)
{
uint8_t led_state = LED_ON;
uint8_t test_buf[13] = {0xFE, 0x08, 0x03, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00};
test_buf[11] = 0xff;
while(1)
{
LED(led_state);
led_state = ~led_state;
test_buf[12] = MT_UartCalcFCS((uint8_t*)&test_buf[1], 11);
HAL_UART_Transmit(&huart1, test_buf, 13, 0xFF);
test_buf[4]++;
rt_thread_mdelay(1000);
}
}
相關文章
- JS之回撥函式(callback)JS函式
- c#之回撥函式C#函式
- 函式指標之回撥函式和轉移表函式指標
- 回撥函式函式
- 回撥函式,求積函式函式
- JavaScript 回撥函式JavaScript函式
- JavaScript回撥函式JavaScript函式
- JS—回撥函式JS函式
- 動畫回撥函式動畫函式
- java回撥函式Java函式
- 回撥函式(CallBack)函式
- 回撥函式 與 函式閉包函式
- 函式指標&回撥函式Callback函式指標
- JS閉包函式和回撥函式JS函式
- 回撥函式的作用函式
- TLS回撥函式(Note)TLS函式
- java 回撥函式示例Java函式
- Python回撥函式Python函式
- android回撥函式Android函式
- 函式回撥(C++)函式C++
- [JS]回撥函式和回撥地獄JS函式
- u-boot不接串列埠不能啟動kernel問題boot串列埠
- 函式指標的重要用途——回撥函式函式指標
- 【知識點】inline函式、回撥函式、普通函式inline函式
- Android之串列埠程式設計Android串列埠程式設計
- C++回撥函式 用法C++函式
- 回撥函式的理解(一)函式
- Python/OpenCV:回撥函式PythonOpenCV函式
- java回撥函式機制Java函式
- js中的回撥函式JS函式
- js函式回撥錯誤JS函式
- c++回撥函式(下)C++函式
- Java回撥函式的理解Java函式
- C++回撥函式示例C++函式
- 回撥函式快速使用 (轉)函式
- Python技法3:匿名函式、回撥函式和高階函式Python函式
- 003 通過連結串列學Rust之給連結串列新增函式Rust函式
- 003 透過連結串列學Rust之給連結串列新增函式Rust函式