热度 3
2013-12-23 17:46
3332 次阅读|
0 个评论
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 = LEN_Token; state = CMD_STATE1; //正确后跳转至CMD0 } else { state = SOP_STATE; return; } break; case CMD_STATE1: // CMD_STATE1 pMsg-msg = ch; state = CMD_STATE2; //跳转至CMD_STATE2 break; case CMD_STATE2: // CMD_STATE2 pMsg-msg = 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 = 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 , bytesInRxBuffer); tempDataLen += bytesInRxBuffer; } else { HalUARTRead (port, pMsg-msg , 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 , 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 ,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 ) 这两个函数中还有解析,改天继续写!