UART函数:MT_UART.c >> void MT_UartProcessZToolData ( uint8 port, uint8 event )
该函数是串口MT协议解析函数,解析接收到的串口数据,并确定是程序启动函数,还是简单的串口数据,然后发送数据到正确的地方(MT或APP)。Ti的协议栈中的MT的指令结构比较简单(一般还会在校验后面加帧尾,有的还会在数据里与帧头相同的数据后面加转义字符),如下图:帧头、数据、校验和。
(怎么传不了图片啊,只能这样了)
| SOP | MT CMD | FCS |
| 1 | 3-256 | 1 |
,但是MT CMD里面有包含了不少没什么用的数据,内容就比较复杂了。不过他的整个处理还是非常好的。
开始先检测缓冲区内是否有数据,然后从DMA中将数据读出,虽然是一个一个数据读取的,可能有人觉得比较麻烦,但是仔细往下看就不会有这种感觉了。这样做的目的只是在接下来使用状态机的方式把数据解析出来,这样方便简单单,又能检测数据的正确性。下面对整个结构有详细的注解,大家交流交流啊!
原函数:(函数来源于:Z-Stack Lighting 1.0.1)
/***************************************************************************************************
* @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: //SOF位
if (ch == MT_UART_SOF)
state = LEN_STATE; //确认后跳转状态
break;
case LEN_STATE: //数据长度位
LEN_Token = ch;
tempDataLen = 0;
/* Allocate memory for the data *///建立一个存储空间
pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +
MT_RPC_FRAME_HDR_SZ + LEN_Token );
if (pMsg)
{
/* Fill up what we can */
pMsg->hdr.event = CMD_SERIAL_MSG;
pMsg->msg = (uint8*)(pMsg+1);
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
state = CMD_STATE1; //正确后跳转至CMD0
}
else
{
state = SOP_STATE;
return;
}
break;
case CMD_STATE1: // CMD_STATE1
pMsg->msg[MT_RPC_POS_CMD0] = ch;
state = CMD_STATE2; //跳转至CMD_STATE2
break;
case CMD_STATE2: // CMD_STATE2
pMsg->msg[MT_RPC_POS_CMD1] = ch;
/* If there is no data, skip to FCS state */
if (LEN_Token)
{
state = DATA_STATE;//跳转至数据接收状态
}
else
{
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;
/* 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)
{
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;
/* 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;
}
#if TEST //自己加的,接收到的数据在发送回串口助手
//For test UART
HalUARTWrite(HAL_UART_PORT_0,(uint8*)&pMsg->msg[0],MT_RPC_FRAME_HDR_SZ + LEN_Token);
#endif //end TEST
}
}
注:
1.状态机:是通信里经常会有到的一种协议解析方式。
2.这个只是UART接收时的数据处理相当于底层的解析,还有更多指令解析在 zllInitiator_event_loop ( uint8 task_id, uint16 events )和zllSampleRemote_event_loop ( uint8 task_id, uint16 events ) 这两个函数中还有解析,改天继续写!
文章评论(0条评论)
登录后参与讨论