一、串口终端1的数据,如何被节点1所接收,并且发送出去的?
串口数据是由HAL层来负责的,让我们从主循环 (osal_start_system) 的Hal_ProcessPoll函数找下去 ,Hal_ProcessPoll ==> HalUARTPoll ==> HalUARTPollDMA。在这个 HalUARTPollDMA 函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1, evt); 对dmaCfg.uartCB 这个函数进行了调用,dmaCfg结构体类型如下:
typedef struct {uint16 rxBuf[HAL_UART_DMA_RX_MAX];rxIdx_t rxHead;rxIdx_t rxTail;uint8 rxTick;uint8 rxShdw;uint8 txBuf[2][HAL_UART_DMA_TX_MAX];txIdx_t txIdx[2];volatile uint8 txSel;uint8 txMT;uint8 txTick;// 1-character time in 32kHz ticks according to baud rate,// to be used in calculating time lapse since DMA ISR// to allow delay margin before start firing DMA, so that// DMA does not overwrite UART DBUF of previous packetvolatile uint8 txShdw; // Sleep Timer LSB shadow.volatile uint8 txShdwValid; // TX shadow value is validuint8 txDMAPending;// UART TX DMA is pendinghalUARTCBack_t uartCB; } uartDMACfg_t;
由上可知,uartCB是一个类型为halUARTCBack_t的函数指针(回调函数),那这个函数指针在那里赋值的呢?请看下面这条线路。void SerialApp_Init( uint8 task_id )里面有如下语句halUARTCfg_t uartConfig;在接下来的给uartConfig这个结构体变量赋值的语句中有如下语句:uartConfig.callBackFunc = SerialApp_CallBack;即将uartConfig里的串口回调函数设置为SerialApp_CallBack,然后再通过HalUARTOpen (SERIAL_APP_PORT, &uartConfig);这个函数的调用(不再深入进去,有兴趣的同学可以进一步跟进)将uartConfig这个结构体变量的值转化为uartConfig这个结构体变量的值,注意两个结构体变量所属的类型不同,不能直接赋值,需要转化。
这样就保证了,SerialApp_CallBack函数每次循环中被调用一次,SerialApp_CallBack( ) ==> SerialApp_Send( ),在SerialApp_Send()函数里会调用HalUARTRead()函数,将 DMA 数据读至数据 buffer 并通过 AF_DataRequest ()函数发送出去,注意:发送出去的信息的 CLUSTERID(信息簇ID)号为 SERIALAPP_CLUSTERID1。
二、节点2 在收到空中的信号后,如何传递给与其相连的串口终端?
节点 2 从空中捕获到信号后, 会应用层任务处理函数上进入AF_INCOMING_MSG_CMD分支,进入 SerialApp_ProcessMSGCmd()函数里进入处理。
void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt ) //对从空中捕获到的信号进行处理 {uint8 stat;uint8 seqnb;uint8 delay;switch ( pkt->clusterId ){// A message with a serial data block to be transmitted on the serial port.case SERIALAPP_CLUSTERID1://节点一发送过来的信息的 CLUSTERID(信息簇ID)号为 SERIALAPP_CLUSTERID1// Store the address for sending and retrying.osal_memcpy(&SerialApp_RxAddr, &(pkt->srcAddr), sizeof( afAddrType_t ));seqnb = pkt->cmd.Data[0];// Keep message if not a repeat packetif ( (seqnb > SerialApp_RxSeq) ||// Normal((seqnb <</span> 0x80 ) && ( SerialApp_RxSeq > 0x80)) ) // Wrap-around{// Transmit the data on the serial port.if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) ) //通过串口发送数据到PC机{// Save for next incoming messageSerialApp_RxSeq = seqnb;stat = OTA_SUCCESS;}else{stat = OTA_SER_BUSY;}}else{stat = OTA_DUP_MSG;}// Select approproiate OTA flow-control delay.delay = (stat == OTA_SER_BUSY) ? SERIALAPP_NAK_DELAY : SERIALAPP_ACK_DELAY;// Build & send OTA response message.SerialApp_RspBuf[0] = stat;SerialApp_RspBuf[1] = seqnb;SerialApp_RspBuf[2] = LO_UINT16( delay );SerialApp_RspBuf[3] = HI_UINT16( delay );osal_set_event( SerialApp_TaskID, SERIALAPP_RESP_EVT ); //受到数据后,向节点1发送一个响应事件,跳到SerialApp_ProcessEvent()osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_RESP_EVT);break; ......} } UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events ) { ......if ( events & SERIALAPP_RESP_EVT )//串口响应事件,表示成功接受来自节点1的数据,{SerialApp_Resp();//向节点1发送 成功接受的responsereturn ( events ^ SERIALAPP_RESP_EVT );} ...... } static void SerialApp_Resp(void) {if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_RxAddr,//通过AF_DataRequest函数,讲接收成功响应从空中发送出去(endPointDesc_t *)&SerialApp_epDesc,SERIALAPP_CLUSTERID2,SERIAL_APP_RSP_CNT, SerialApp_RspBuf,&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS)){osal_set_event(SerialApp_TaskID, SERIALAPP_RESP_EVT);//如果发送失败,重新发送} }
节点1,接收到来自节点2的response。
UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events ) {......while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SerialApp_TaskID )) ){switch ( MSGpkt->hdr.event ){......case AF_INCOMING_MSG_CMD://在这个实验中,使用串口通讯时,触发的事件,从空中捕获到信号。SerialApp_ProcessMSGCmd( MSGpkt ); //处理这个消息break;......}} }
SERIALAPP_CLUSTERID2代表接收到发送成功的response,取消自动重发,如果不,自动重发。
void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt )
{
……
// A response to a received serial data block.
case SERIALAPP_CLUSTERID2: //SerialWsn_CLUSTERID2代表接收到发送成功的response
if ((pkt->cmd.Data[1] == SerialApp_TxSeq) &&
((pkt->cmd.Data[0] == OTA_SUCCESS) || (pkt->cmd.Data[0] == OTA_DUP_MSG)))
{
SerialApp_TxLen = 0;
osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_SEND_EVT); //当收到发送成功的response,停止自动从发
}
else
{
// Re-start timeout according to delay sent from other device.
delay = BUILD_UINT16( pkt->cmd.Data[2], pkt->cmd.Data[3] );
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_SEND_EVT, delay ); //没有收到成功的response,自动重发
}
break;
default:
break;
}
gaoyang9992006:
下面部分来自网络上另一篇文章
粗略的看了下这个程序,发现这个程序有一个EP(终端),每个终端有两个簇(SERIALAPP_CLUSTERID1、SERIALAPP_CLUSTERID2),可以在以下代码中定义
// This list should be filled with Application specific Cluster IDs.const cId_t SerialApp_ClusterList[SERIALAPP_MAX_CLUSTERS] ={ SERIALAPP_CLUSTERID1, SERIALAPP_CLUSTERID2};其中SERIALAPP_CLUSTERID1是负责数据的传输的,而SERIALAPP_CLUSTERID2则负责传输的反馈。在以下函数中可以看出
void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt ){uint8 stat;uint8 seqnb;uint8 delay;switch ( pkt->clusterId ){// A message with a serial data block to be transmitted on the serial port.case SERIALAPP_CLUSTERID1:// 处理数据// Store the address for sending and retrying.osal_memcpy(&SerialApp_RxAddr, &(pkt->srcAddr), sizeof( afAddrType_t ));// 保存来信地址seqnb = pkt->cmd.Data[0];// 保存计数(来自发送端,来用检验)// Keep message if not a repeat packetif ( (seqnb > SerialApp_RxSeq) ||// Normal, 是否是最新的数据((seqnb <</span> 0x80 ) && ( SerialApp_RxSeq > 0x80)) ) // Wrap-around,{#ifndefGEC_EP// Transmit the data on the serial port.if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) ){// Save for next incoming messageSerialApp_RxSeq = seqnb;// 保存计数stat = OTA_SUCCESS;}else{stat = OTA_SER_BUSY;}#else// 添加部分代码,实现数据回传显示到串口,没办法串口只有一个if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_RxAddr,(endPointDesc_t *)&SerialApp_epDesc,SERIALAPP_CLUSTERID1,SerialApp_TxLen+1, SerialApp_TxBuf,&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS)){osal_set_event(SerialApp_TaskID, SERIALAPP_SEND_EVT);}#endif}else{stat = OTA_DUP_MSG;}// Select approproiate OTA flow-control delay.delay = (stat == OTA_SER_BUSY) ? SERIALAPP_NAK_DELAY : SERIALAPP_ACK_DELAY; // UART忙则延时16ms,否则延时1ms// Build & send OTA response message.SerialApp_RspBuf[0] = stat;// 接收状态SerialApp_RspBuf[1] = seqnb;// 计数SerialApp_RspBuf[2] = LO_UINT16( delay );SerialApp_RspBuf[3] = HI_UINT16( delay );osal_set_event( SerialApp_TaskID, SERIALAPP_RESP_EVT );// 发送反馈信息osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_RESP_EVT);// 停止反馈定时器break;// A response to a received serial data block.case SERIALAPP_CLUSTERID2:// 处理反馈if ((pkt->cmd.Data[1] == SerialApp_TxSeq) &&// 反馈回来的是刚才发的((pkt->cmd.Data[0] == OTA_SUCCESS) || (pkt->cmd.Data[0] == OTA_DUP_MSG)))// 成功或者过期{SerialApp_TxLen = 0;// 准备下一次发送osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_SEND_EVT);// 无需重发,关闭定时器}else// 需要重发{// Re-start timeout according to delay sent from other device.delay = BUILD_UINT16( pkt->cmd.Data[2], pkt->cmd.Data[3] );// 延时发送osal_start_timerEx( SerialApp_TaskID, SERIALAPP_SEND_EVT, delay );//}break;default:break;}}总结一下以上的代码,当SERIALAPP_CLUSTERID1收到数据的时候,将会检验这个数据包是否是新的,由于逻辑有点复杂,下面用伪代码描述if (新数据包){ if (UART发送成功) { 反馈成功信息; } else 否则反馈UART忙;}else 反馈此包过期;同样,对于SERIALAPP_CLUSTERID2的信息处理也可以这样描述if (刚才发送的包 && (成功 || 过期)) { 关闭定时器,注备下一次的发送,也就是说没有收到确认信息,不会进行下一次的发送}else{ 给我延时重发去}
Susan Yang:
回复 gaoyang9992006:
谢谢分享!也可以参考serial app
qingquan chen:
回复 Susan Yang:
哪里有:serial APP呢?