加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

zigbee 组网(三)(转载)

(2013-08-04 20:32:33)
第三个功能:实现两个节点间的串口通信
“串口终端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;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有