码迷,mamicode.com
首页 > 其他好文 > 详细

FreakZ学习笔记:FreakZ通信网络接收过程详解

时间:2015-05-18 18:58:57      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

FreakZ接收过程详解

FreakZ的接收过程与发送过程刚好相反,层次关系依次为Radio->PHY->MAC->NWK->APS,下面就具体流程做阐述说明;

Radio层接收到广播信号时,首先会触发中断函数cc2538_rf_rx_tx_isr,该中断函数会跳转到cc2538_rf_process这个进程,process_poll是触发该进程函数,优先级高于process_event

void

cc2538_rf_rx_tx_isr(void)

{

  ENERGEST_ON(ENERGEST_TYPE_IRQ);

  process_poll(&cc2538_rf_process);

  /* We only acknowledge FIFOP so we can safely wipe out the entire SFR */

  REG(RFCORE_SFR_RFIRQF0) = 0;

  ENERGEST_OFF(ENERGEST_TYPE_IRQ);}

 

中断函数触发之后,进入进程执行函数PROCESS_THREAD(cc2538_rf_process, ev, data),该函数的相关描述如下:

/**

 * \brief Implementation of the cc2538 RF driver process

 *

 *        This process is started by init(). It simply sits there waiting for

 *        an event. Upon frame reception, the RX ISR will poll this process.

 *        Subsequently, the contiki core will generate an event which will

 *        call this process so that the received frame can be picked up from

 *        the RF RX FIFO

 */

意思是RX中断触发引起该进程响应,同时把RF RX FIFO里的数据读出来;PROCESS_THREAD(cc2538_rf_process, ev, data)函数部分代码如下:

while(1) {

    PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);

 

    packetbuf_clear();

    len = read(packetbuf_dataptr(), PACKETBUF_SIZE);

        

         //void *buffer = packetbuf_dataptr();//add by panxin 2015/05/15

         hal_frame_read(packetbuf_dataptr() ,len);//add by zhangpeng , 20150514 传递RF RX FIFO读出来的数据;

         process_post(&mac_process, event_mac_rx, NULL);//add by zhangpeng , 20150515,运行event_mac_rx事件;

if(len > 0) {…}

}

event_mac_rx事件响应之后,进入到static void mac_eventhandler(process_event_t event,process_data_t data)函数,该函数描述如下:

/**************************************************************************/

/*!

    Handle the rx events from the mac process. If the driver receives a valid frame,

    it will send an event to the mac

    process. The mac process will then call the event handler which retrieves

    the frame from the rx queue and parses it. Once parsed, it will be handled

    according to the frame type. If its a command frame, it gets sent to the

    command handler, a data frame gets sent to the next higher layer, etc...

*/

/**************************************************************************/

意思是处理从mac_process触发的event_mac_rx,然后解析该帧的框架,如果是一个指令帧,它就发送给指令处理函数,如果是一个数据帧,它就发送给更高层,也就是NWK层;mac_eventhandler部分代码如下:

static void mac_eventhandler(process_event_t event,process_data_t data)

{

    buffer_t *buf; //*buf_out;

    mac_hdr_t hdr;

    mac_cmd_t cmd;

    //bool frm_pend;

    mac_pcb_t *pcb = mac_pcb_get();

    mac_pib_t *pib = mac_pib_get();

 

    if (event == event_mac_rx)

    {

        DBG_PRINT_RAW("\n\r");

        DBG_PRINT("MAC_EVENTHANDLER: Rx event occurred.\n\r");

 

        if ((buf = mac_queue_buf_pop()) != NULL)

        {

            DBG_PRINT_RAW("<INCOMING>");

            //debug_dump_buf(buf->dptr, buf->len);

 

            // decode the packet

            mac_parse_hdr(buf, &hdr);

            debug_dump_mac_hdr(&hdr);

            switch(hdr.mac_frm_ctrl.frame_type)

            {

            case MAC_COMMAND:

                if ((pcb->mac_state != MLME_SCAN)||(pcb->mac_state == MLME_SCAN && pcb->scan_type == MAC_ORPHAN_SCAN))

                {

                  

                    if ((pcb->mac_state == MLME_DATA_REQ)  &&

                        (hdr.src_addr.mode       == SHORT_ADDR)     &&

                        (hdr.src_addr.short_addr == pib->coord_addr.short_addr))

                    {

                        ctimer_stop(&pcb->mlme_tmr);

                        mac_poll_conf(MAC_SUCCESS);

                    }

 

                    mac_parse_cmd(buf, &cmd);

                    mac_cmd_handler(&cmd, &hdr);

                }

                buf_free(buf);

                break;

            case MAC_BEACON:

                //  discard the beacon if we‘re not doing a scan.

                if (pcb->mac_state == MLME_SCAN)

                {

                    mac_parse_beacon(buf, &hdr);

                    mac_beacon_notify_ind(buf, mac_scan_descr_find_addr(&hdr.src_addr));

                }

                buf_free(buf);

                break;

            case MAC_ACK:

                buf_free(buf);

                break;

            case MAC_DATA:

                if (pcb->mac_state != MLME_SCAN)

                {/*Discard all packets recieved in MLME_SCAN mode*/

                    // need to handle the case that this is an indirect transfer, which means that

                    // we need to stop the poll timer and send a status to the poll confirm.

                    if ((pcb->mac_state          == MLME_DATA_REQ)  &&

                        (hdr.src_addr.mode       == SHORT_ADDR)     &&

                        (hdr.src_addr.short_addr == pib->coord_addr.short_addr))

                    {/*If in data resqest mode and the source address was parent‘s so we recieve request successful*/

                        ctimer_stop(&pcb->mlme_tmr);

                        mac_poll_conf(MAC_SUCCESS);

                        pcb->mac_state = MLME_IDLE;/////

                    }

                    //Added by LiuTianmin

                    if(!hdr.no_mac_payload)//成立说明这不是一个空数据包

                    //Added by LiuTianmin

                       mac_data_ind(buf, &hdr);

                    else

                       buf_free(buf);

                }

                else

                {

                    buf_free(buf);

                }

                break;

            default:

                // TODO: Add a statistic here to capture an error‘d rx

                break;

            }

        }

        // there‘s a possibility that more than one frame is in the buffer

        // if they came in before this function gets executed. So process until

        // the queue is empty.

        if (!mac_queue_is_empty())

        {

            while (process_post(&mac_process, event_mac_rx, NULL) != PROCESS_ERR_OK);

        }

    }

    else 

    {….

    }

}

 

mac_eventhandler事件处理包含了mac层的四种包结构,分别为COMMANDBEACONACKDATA,四种包的处理过程根据各自的特性虽然有所区别,但大体方法是一样的,都是在MAC层经过相应的处理之后,或者是向上层发送请求,或者是向上层打包数据,这里着重讲解一下DATA指令的处理过程,该指令下的主要处理函数为mac_data_ind(buf, &hdr);函数描述如下:

/**************************************************************************/

/*!

    This function handles the incoming rx data to the NWK layer. There are only

    two types of frames, command and data. A command frame will be parsed and

    routed to the appropriate command function handler. A data frame will be

    checked to see if this device is its destination. If so, then it will

    be sent to the next higher layer. If not, then it will be sent to the

    nwk_fwd function to be forwarded to the next device.

*/

功能为把RX传送过来的数据发送给NWK层,这里只有两中类型,即指令包和数据包,如果是指令包将会被路由到相应的指令处理函数,如果是数据包将会检测其目的地址是否与该节点地址匹配,如果是,该数据包将会被发送到下一个更高的层,如果不是,该数据包将会被传送到nwk_fwd函数去转发到下一个设备;函数原型如下:

void mac_data_ind(buffer_t *buf, mac_hdr_t *mac_hdr)

{

    nwk_hdr_t hdr;

    buffer_t *buf_in;

    nwk_cmd_t cmd;

    U8 index; 

    // assign incoming mac hdr to the data struct, then parse the frame for the nwk hdr

    hdr.mac_hdr = mac_hdr;

    nwk_parse_hdr(buf, &hdr);

    debug_dump_nwk_hdr(&hdr);

 

    // if it‘s a broadcast and the device type doesn‘t match our device, then discard it.

    if ((hdr.dest_addr & NWK_BROADCAST_MASK) == NWK_BROADCAST_MASK)

    {

        if (!nwk_brc_check_dev_match(hdr.dest_addr))

        {

            buf_free(buf);

            return;

        }

    }

    switch(hdr.nwk_frm_ctrl.frame_type)

    {

    case NWK_DATA_FRM:

        // How we handle this depends on the destination address

        if (hdr.dest_addr == nib.short_addr)

        {

            // we‘re the dest. send it up for further processing.

            nwk_data_ind(buf, &hdr);

 

            // check for the radius here. we can‘t let a frame with a 0 radius get sent out again.

            // if the radius is zero, then drop the frame.

            if (hdr.radius == 0)

            {

                buf_free(buf);

                return;

            }

 

            // decrement the radius

            hdr.radius--;

            break;

        }

        else if ((hdr.dest_addr & NWK_BROADCAST_MASK) == 0xFFF0)

        {

            // make copy of brc frame, adjust the data pointer, and then send it up

            BUF_ALLOC(buf_in, RX);

            index = buf_in->index;

            memcpy(buf_in, buf, sizeof(buffer_t));

            buf_in->index = index;

            buf_in->dptr = buf_in->buf + (buf->dptr - buf->buf);

            nwk_data_ind(buf_in, &hdr);

 

            // check for the radius here. we can‘t let a frame with a 0 radius get sent out again.

            // if the radius is zero, then drop the frame.

            if (hdr.radius == 0)

            {

                buf_free(buf);

                return;

            }

 

            // decrement the radius

            hdr.radius--;

 

            // check to see if the sender is in our brc table. if not, then add the senders addr.

            nwk_brc_add_new_sender(hdr.src_addr, hdr.seq_num);

 

            // now check if its a new brc. if its not, then just discard the frame.

            if (hdr.seq_num == pcb.brc_seq)

            {

                buf_free(buf);

                return;

            }

 

            // looks like its a new brc. initiate the brc params and start the brc transmission procedure.

            // note: the header src address gets changed inside the brc_start function.

            if (nwk_brc_start(buf, &hdr) != NWK_SUCCESS)

            {

                return;

            }

        }

 

        // we‘re not the destination. forward it to the dest address.

        nwk_fwd(buf, &hdr);

        break;

 

    case NWK_CMD_FRM:

        // Parse command frame and then send to appropriate handler

        nwk_parse_cmd(buf, &cmd);

        debug_dump_nwk_cmd(&cmd);

 

        // Free the buffer since we‘re finished with it now. Then handle the command.

        buf_free(buf);

 

        // command frame handler

        switch (cmd.cmd_frm_id)

        {

        case NWK_CMD_RTE_REQ:

            if(nib.dev_type != NWK_END_DEVICE)//Added by LiuTianmin

            {   

                nwk_rte_mesh_rreq_handler(&hdr, &cmd);

            }

            break;

 

        case NWK_CMD_RTE_REP:

            if(nib.dev_type != NWK_END_DEVICE)//Added by LiuTianmin

            { 

                nwk_rte_mesh_rrep_handler(&hdr, &cmd);

            }

            break;

 

        case NWK_CMD_LEAVE:

            nwk_leave_handler(&hdr, &cmd);

            break;

 

        default:

            break;

        }

        break;

 

    default:

        break;

    }

}

当目的地址与该节点的地址匹配时,会将该数据包继续向上层传输,传输函数为nwk_data_ind,函数描述如下:

/**************************************************************************/

/*!

    This function is called by the NWK layer when incoming data is passed

    to the APS layer. Once the frame arrives, we parse the APS header

    and fill out the aps header struct.

 

    If it‘s an ACK frame, then we handle the ACK and then discard the frame.

 

    Otherwise, if the frame has an ack request on it, then we immediately

    send out an ACK. And finally, we send the frame up to the AF where it

    will be routed to the correct endpoint.

*/

/**************************************************************************/

该函数主要是解析从MAC层输入到NWK层的数据,并且把它发送给APS层,函数原型如下:

void nwk_data_ind(buffer_t *buf, const nwk_hdr_t *nwk_hdr)

{

    aps_hdr_t hdr_in;

    aps_hdr_t hdr_out;

    buffer_t *buf_out;

 

    memset(&hdr_in, 0, sizeof(aps_hdr_t));

    hdr_in.dest_addr    = nwk_hdr->dest_addr;

    hdr_in.src_addr     = nwk_hdr->src_addr;

    hdr_in.radius       = nwk_hdr->radius;

    aps_parse_hdr(buf, &hdr_in);

    debug_dump_aps_hdr(&hdr_in);

 

    // check the frame to see if its in the duplicate rejection table. If it is, then

    // discard it.

    if (aps_dupe_reject(hdr_in.src_addr, hdr_in.aps_ctr))

    {

        buf_free(buf);

        return;

    }

 

    // process the frame based on the info in the header

    if (hdr_in.aps_frm_ctrl.frm_type == APS_ACK_FRM)

    {

        // If its an ACK frame, then send it to the handler. we will process the ack there

        // and send the data confirm.

        aps_retry_ack_handler(&hdr_in);

        buf_free(buf);

        return;

    }

    else if (hdr_in.aps_frm_ctrl.ack_req)

    {

        // the incoming frame has its ack request set. first generate the ack request and send it out.

        // then send the frame to the next higher layer.

 

        // copy the in hdr to the out hdr. we can reuse some of the fields.

        memset(&hdr_out, 0, sizeof(aps_hdr_t));

        memcpy(&hdr_out, &hdr_in, sizeof(aps_hdr_t));

        hdr_out.aps_frm_ctrl.frm_type       = APS_ACK_FRM;

        hdr_out.dest_addr                   = hdr_in.src_addr;

        hdr_out.disc_rte                    = true;

        hdr_out.radius                      = hdr_in.radius;

 

        if (!hdr_in.aps_frm_ctrl.ack_format)

        {

            // this is an ack to a data frame. need to set the dest/src ep and clust/profile id

            hdr_out.dest_ep     = hdr_in.src_ep;

            hdr_out.src_ep      = hdr_in.dest_ep;

            hdr_out.clust_id    = hdr_in.clust_id;

            hdr_out.prof_id     = hdr_in.prof_id;

        }

 

        // send out the ack first before forwarding the frame to the next higher layer.

        BUF_ALLOC(buf_out, TX);

        aps_tx(buf_out, &hdr_out);

    }

    // endpoint from there.

    af_rx(buf, &hdr_in);}

函数nwk_data_ind执行完之后,APS层会将数据发送给APP层,然后APP层进行最后的数据解析和处理。

以上便是freakz接收数据并在各个通信层之间处理的整个过程,如有不恰当之处,欢迎大家交流和指正。

FreakZ学习笔记:FreakZ通信网络接收过程详解

标签:

原文地址:http://blog.csdn.net/broadce/article/details/45824439

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!