Zigbee实现两个节点间的串口通信

“串口终端1”的数据,如何被“节点 1”所接收,并且发送出去的?

串口数据是由哪层来负责的呢?--HAL。 。 。恩,猜对了。但这个肯定不是靠猜的,其中的过程

就不讲了。 让我们从主循环 (osal_start_system) 的Hal_ProcessPoll函数找下去 (用source  insight

的同学可以用 ctrl +) ,Hal_ProcessPoll ==> HalUARTPoll ==> HalUARTPollDMA

这个 HalUARTPollDMA 函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1,  evt); 对dmaCfg.uartCB 这个函数进行了调用,ctrl  / 搜索这个 dmaCfg.uartCB,发现 SerialApp_Init 函数有两句话:

uartConfig.callBackFunc         = SerialApp_CallBack;

    HalUARTOpen (SERIAL_APP_PORT, &uartConfig);

此处将 dmaCfg.uartCB 这个函数注册成为 SerialApp_CallBack, 也就是说 SerialApp_CallBack函数每次循环中被调用一次,对串口的内容进行查询,如果 DMA 中接收到了数据,则调用HalUARTRead,将 DMA 数据读至数据 buffer 并通过 AF_DataRequest 函数发送出去,注意:出去的信息的 CLUSTERID(信息簇ID)号为 SERIALAPP_CLUSTERID1。 总结一下这个过程:
     串口数据==>DMA接收==>主循环中通过SerialApp_CallBack 查询==>从 DMA获取并发送到空中。 
具体流程如下:

void SerialApp_Init( uint8 task_id )

{
......

  uartConfig.configured           = TRUE;              // 2x30 don't care - see uart driver.

  uartConfig.baudRate             = SERIAL_APP_BAUD;

  uartConfig.flowControl          = TRUE;

  uartConfig.flowControlThreshold = SERIAL_APP_THRESH; // 2x30 don't care - see uart driver.

  uartConfig.rx.maxBufSize        = SERIAL_APP_RX_SZ;  // 2x30 don't care - see uart driver.

  uartConfig.tx.maxBufSize        = SERIAL_APP_TX_SZ;  // 2x30 don't care - see uart driver.

  uartConfig.idleTimeout          = SERIAL_APP_IDLE;   // 2x30 don't care - see uart driver.

  uartConfig.intEnable            = TRUE;              // 2x30 don't care - see uart driver.

  uartConfig.callBackFunc         = SerialApp_CallBack;      //调用SerialApp_CallBack函数,对串口内容进行查询

  HalUARTOpen (SERIAL_APP_PORT, &uartConfig);
......
}

static void SerialApp_CallBack(uint8 port, uint8 event)

{

  (void)port;

//如果 DMA 中接收到了数据

  if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&

#if SERIAL_APP_LOOPBACK

      (SerialApp_TxLen < SERIAL_APP_TX_MAX))

#else

      !SerialApp_TxLen)

#endif

  {

SerialApp_Send();   //调用串口发送函数,将从串口接受到的数据,发送出去

  }

}

static void SerialApp_Send(void)

{

#if SERIAL_APP_LOOPBACK         //初始化时,SERIAL_APP_LOOPBACK=false ,所以不执行if这个预编译,转到else去执行

  if (SerialApp_TxLen < SERIAL_APP_TX_MAX)

  {

    SerialApp_TxLen += HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+SerialApp_TxLen+1,

                                                    SERIAL_APP_TX_MAX-SerialApp_TxLen);

  }

  if (SerialApp_TxLen)

  {

    (void)SerialApp_TxAddr;

    if (HalUARTWrite(SERIAL_APP_PORT, SerialApp_TxBuf+1, SerialApp_TxLen))

    {

      SerialApp_TxLen = 0;

    }

    else

    {

      osal_set_event(SerialApp_TaskID, SERIALAPP_SEND_EVT);

    }

  }

#else

  if (!SerialApp_TxLen &&

      (SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1, SERIAL_APP_TX_MAX)))

  {

    // Pre-pend sequence number to the Tx message.

    SerialApp_TxBuf[0] = ++SerialApp_TxSeq;

  }

  if (SerialApp_TxLen)

  {

    if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_TxAddr,        //通过AF_DataRequest()函数,将数据从空中发送出去

                                           (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

}

UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events ) 

{

    if ( events & SERIALAPP_SEND_EVT )       //当数据没有发送成功时

      {

SerialApp_Send();

         return ( events ^ SERIALAPP_SEND_EVT );

      }
}
节点2 在收到空中的信号后,如何传递给与其相连的串口终端?

节点 2 从空中捕获到信号后, 在应用层上首先收到信息的就是 SerialApp_ProcessEvent 这个函数了,它收到一个 AF_INCOMING_MSG_CMD 的事件,并通知 SerialApp_ProcessMSGCmd,执行以下代码 :

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;
       ......
      }
    }
}

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 packet

    if ( (seqnb > SerialApp_RxSeq) ||                    // Normal

        ((seqnb < 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 message

        SerialApp_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发送  成功接受的response

    return ( 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;

}

上一篇:Zigbee之CC2530最小系统及寄存器配置(1)


下一篇:Zigbee基础知识