FreakZ学习笔记:FreakZ通信网络发送过程详解

来源:互联网 发布:域名绑定ip 编辑:程序博客网 时间:2024/05/17 07:37

FreakZ发送过程详解

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

APP层需要发送一个广播信息时,首先会产生一个相应的发送进程函数PROCESS_THREAD(af_process, ev, data),通过process_post函数插入一个event_af_tx事件,

通过PROCESS_THREAD函数去响应发送机制,该函数相关代码如下:

PROCESS_THREAD(af_process, ev, data)

{

    PROCESS_BEGIN();

 

    //lint -e{716} Info 716: while(1) ...

    // looping forever on purpose

    while (1)

    {

        PROCESS_WAIT_EVENT();

        if (ev == event_af_rx)

        {

            af_rx_handler();

        }

        else if (ev == event_af_tx)

       {

           af_tx_handler();

       }

        else if (ev == event_af_conf)

        {

            af_conf_handler();

        }

    }

    PROCESS_END();

}

 

event_af_tx事件响应之后,会进入af_tx_handler函数,该函数的描述如下:

/*!

    This is the exit point of the AF's TX data path. The buffer and info

    are pulled from the AF TX data queue. An APS request is generated

    and the data is sent out to the APS layer.

*/

主要是生成一个APS层的数据请求并且把数据发送到APS层;af_tx_handler函数架构如下:

void af_tx_handler()

{

    mem_ptr_t *mem_ptr;

    aps_data_req_t req;

 

    if ((mem_ptr = af_tx_pop()) != NULL)//判断TX中的数据是否为空如果不为空,对相应的参数进行打包和传递

    {

        // generate the aps data request

        req.dest_addr_mode          = TX_ENTRY(mem_ptr)->mode;

 

        // switch up the addressing based on the address mode

        switch (req.dest_addr_mode)

        {

        case APS_DEST_ADDR_EP_NONE:

            // no address and ep info for this. this all comes from the binding table

            break;

 

        case APS_GROUP_ADDR_PRESENT:

            // this is gonna be a group frame. the group id goes into the dest addr

            // and we just add a dummy endpoint here. the ep will be stripped from

            // the frame in the APS when we build the aps header

            req.dest_addr.mode          = SHORT_ADDR;

            req.dest_addr.short_addr    = TX_ENTRY(mem_ptr)->dest_addr;

            req.dest_ep                 = 0;

            break;

 

        case APS_DEST_ADDR_16_EP_PRESENT:

            // standard frame with short address

            req.dest_addr.mode          = SHORT_ADDR;

            req.dest_addr.short_addr    = TX_ENTRY(mem_ptr)->dest_addr;

            req.dest_ep                 = TX_ENTRY(mem_ptr)->dest_ep;

            break;

 

        case APS_DEST_ADDR_64_EP_PRESENT:

            // not allowed. we are only using the network address for now.

            return;

        }

        req.prof_id                 = TX_ENTRY(mem_ptr)->prof_id;

        req.clust_id                = TX_ENTRY(mem_ptr)->clust;

        req.src_ep                  = TX_ENTRY(mem_ptr)->src_ep;

        req.asdu_len                = TX_ENTRY(mem_ptr)->buf->len;

        req.buf                     = TX_ENTRY(mem_ptr)->buf;

        req.handle                  = TX_ENTRY(mem_ptr)->handle;

        req.tx_opt                  = TX_ENTRY(mem_ptr)->tx_opt;

        req.radius                  = TX_ENTRY(mem_ptr)->radius;

        aps_data_req(&req);//发送aps数据请求

        af_tx_free(mem_ptr);

        //Added by LiuTianmin

        if(!af_tx_is_empty())//如果tx中的数据不为空,继续post event_af_tx事件;

           process_post(&af_process, event_af_tx, NULL);

        //Added by LiuTianmin

}

}

 

aps_data_req函数为发送APS数据请求,该函数描述如下:

/*!

    Request to send data to the APS layer. This function is called by the

    Application Framework when an outgoing frame moves from the AF to the

    APS layer. The header structure is filled out based on the request

    arguments. If binding is used, then the address is also looked up and

    added here. Once the relevant header information has been extracted,

    this function will pass the frame and the header struct to the APS transmit

    function.

*/

当一个APP层的数据包的数据包从AF发送到APS层时会调用aps_data_req函数,包的头结构是根据请求而添加的,如果使用绑定,地址的头部将会被添加到这个包里,一旦相关的头部信息被提取,该函数将会将包框架和包头结构传送给APS传输函数;aps_data_req函数原型如下所示:

U8 aps_data_req(const aps_data_req_t *req)

{

    aps_hdr_t hdr;

    mem_ptr_t *bnd_mem_ptr;

    U16 nwk_addr;

    U8 status = APS_SUCCESS;

//构建新的包结构

    hdr.aps_frm_ctrl.frm_type   = APS_DATA_FRM;

   hdr.aps_frm_ctrl.ack_req    = (req->tx_opt & (1<<APS_TX_REQ_ACK_TX_OFF)) >> APS_TX_REQ_ACK_TX_OFF;

   hdr.aps_frm_ctrl.security   = req->tx_opt & (1<<APS_TX_SECURITY_ENB_OFF);

   hdr.aps_frm_ctrl.ack_format = false;

   hdr.aps_frm_ctrl.ext_hdr    = false;

   hdr.src_ep                  = req->src_ep;

   hdr.clust_id                = req->clust_id;

   hdr.prof_id                 = req->prof_id;

   hdr.radius                  = req->radius;

   hdr.aps_ctr                 = aib.aps_ctr++;

   hdr.disc_rte                = (req->tx_opt & (1<<APS_TX_RTE_DISC_DISABLE)) ? 0 : 1;

   hdr.handle                  = req->handle;

 

    switch (req->dest_addr_mode)

    {

    case APS_DEST_ADDR_EP_NONE:

        // loop through binding table. we need to send frame to each matching entry in table.

        for (bnd_mem_ptr = aps_bind_get_head(); bnd_mem_ptr != NULL; bnd_mem_ptr = bnd_mem_ptr->next)

        {

            // if bind entry matches the src endpoint and cluster, then it's a bind match and we need to send it to the target

            if ((BIND_ENTRY(bnd_mem_ptr)->src_ep == req->src_ep) && (BIND_ENTRY(bnd_mem_ptr)->clust == req->clust_id))

            {

                // the delivery mode will be unicast since we're sending a frame to each individual matching dest in

                // the binding table

                hdr.aps_frm_ctrl.delivery_mode = APS_UNICAST;

                hdr.dest_ep = BIND_ENTRY(bnd_mem_ptr)->dest_ep;

 

                // get the address from the binding entry. if it's a long address, then curse the stupid person who used a long

                // address and try and match it up with its corresponding short address

                if (BIND_ENTRY(bnd_mem_ptr)->dest_addr.mode == SHORT_ADDR)

                {

                    hdr.dest_addr = BIND_ENTRY(bnd_mem_ptr)->dest_addr.short_addr;

                }

                else

                {

                    if ((nwk_addr = nwk_addr_map_get_nwk_addr(BIND_ENTRY(bnd_mem_ptr)->dest_addr.long_addr)) == INVALID_NWK_ADDR)

                    {

                        // can't find the matching nwk address to the ieee address. abort for now.

                        status = APS_NO_SHORT_ADDRESS;

                        break;

                    }

                    hdr.dest_addr = nwk_addr;

                }

                aps_tx(req->buf, &hdr);

            }

        }

        break;

 

    case APS_GROUP_ADDR_PRESENT:

        hdr.aps_frm_ctrl.delivery_mode  = APS_GROUP;

        hdr.dest_addr                   = NWK_BROADCAST_RXONIDLE;

        hdr.grp_addr                    = req->dest_addr.short_addr;

        aps_tx(req->buf, &hdr);

        break;

 

    case APS_DEST_ADDR_16_EP_PRESENT:

        hdr.aps_frm_ctrl.delivery_mode  = APS_UNICAST;

        hdr.dest_addr                   = req->dest_addr.short_addr;

        hdr.dest_ep                     = req->dest_ep;

        aps_tx(req->buf, &hdr);

        break;

 

    case APS_DEST_ADDR_64_EP_PRESENT:

        // fall through

    default:

        status = APS_NOT_SUPPORTED;

        break;

    }

    return status;

}

APS层包结构构建完成之后,会通过aps_tx函数将该通信包由APS层发送到NWK层;aps_tx函数原型如下所示:

void aps_tx(buffer_t *buf, aps_hdr_t *hdr)

{

    nwk_data_req_t req;

 

    // if ack request is set, then we need to add the hdr to the retry queue and set the

    // callback timer

    if (hdr->aps_frm_ctrl.ack_req)

    {

        buffer_t *retry_buf;

        U8 index;

 

        BUF_ALLOC(retry_buf, TX);

        index = retry_buf->index;

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

        retry_buf->index = index;

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

        aps_retry_add(retry_buf, hdr, hdr->handle);

    }

 

    // generate the aps header and prep the data request for the nwk layer

    aps_gen_header(buf, hdr);//构建APS层的头结构

    debug_dump_aps_hdr(hdr);

 

    req.buf                 = buf;

    req.dest_addr           = hdr->dest_addr;

    req.nsdu_handle         = hdr->handle;

    req.radius              = hdr->radius;

    req.disc_rte            = hdr->disc_rte;

    req.nwk_dest_addr_mode  = NWK_TX_UNICAST_BROADCAST; // no multicast support yet

    req.security_enb        = false;

    nwk_data_req(&req);

}

 

aps_tx函数执行完成之后,会跳转到nwk_data_req函数,该函数为NWK数据请求服务,接收APS层的数据并且加上NWK层的包头,然后将数据打包;函数原型如下:

void nwk_data_req(const nwk_data_req_t *req)

{

    nwk_hdr_t nwk_hdr;

 

    // Fill out and generate the nwk header

    memset(&nwk_hdr, 0, sizeof(nwk_hdr_t));

    nwk_hdr.nwk_frm_ctrl.frame_type     = NWK_DATA_FRM;

    nwk_hdr.nwk_frm_ctrl.disc_route     = req->disc_rte;

    nwk_hdr.nwk_frm_ctrl.protocol_ver   = ZIGBEE_PROTOCOL_VERSION;

    nwk_hdr.seq_num                     = nib.seq_num++;

    nwk_hdr.dest_addr                   = req->dest_addr;

    nwk_hdr.src_addr                    = nib.short_addr;

    nwk_hdr.radius                      = req->radius;

    nwk_hdr.handle                      = req->nsdu_handle;

 

    // if this is a brc frame that we're originating, we need to add it to the brc table.

    if ((nwk_hdr.dest_addr & NWK_BROADCAST_MASK) == 0xFFF0)

    {

        // set up the brc parameter, then start the brc transmission procedure

        nwk_hdr.nwk_frm_ctrl.disc_route = false;

        if (nwk_brc_start(req->buf, &nwk_hdr) != NWK_SUCCESS)

        {

            return;

        }

    }

 

    // send it to the fwd function for processing and possible routing

    nwk_fwd(req->buf, &nwk_hdr);

}

 

接下来会跳转到nwk_fwd函数,该函数是独立工作在NWK层的,就是说该函数并不向MAC层传输数据,它的主要功能是从当前的包结构或者包功能提取一个架构,然后根据目的地址去选择应该怎么传输该包文件,传送方式包括broadcastneighbor tablerouting table route discoverytree四种;该函数原型如下:

void nwk_fwd(buffer_t *buf, nwk_hdr_t *hdr_in)

{

    U16 next_hop;

    nwk_hdr_t hdr_out;

    mac_hdr_t mac_hdr_out;

    bool indirect = false;

    address_t dest_addr;

    mem_ptr_t *nbor_mem_ptr;

 

    hdr_out.mac_hdr         = &mac_hdr_out;

    dest_addr.mode          = SHORT_ADDR;

    dest_addr.short_addr    = hdr_in->dest_addr;

 

    // is it a broadcast?

    if ((hdr_in->dest_addr & NWK_BROADCAST_MASK) == 0xFFF0)

    {

        // the buffer data ptr (dptr) is pointing to the nwk payload now. calc the length of the nwk

        // payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down

        // the stack.

        //

        //lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)

        // its okay since we're subtracting a value from a constant

        buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);

 

        // need to change the mac dest address to broadcast in case it isn't. Also change the src

        // addr to the address of this device.

        hdr_out.mac_hdr->dest_addr.short_addr       = MAC_BROADCAST_ADDR;

        hdr_out.src_addr                            = hdr_in->src_addr;

    }

    // is the dest in our neighbor table?

    else if ((nbor_mem_ptr = nwk_neighbor_tbl_get_entry(&dest_addr)) != NULL)

    {

 

        // check to see if the dest address is in our neighbor table

        if (hdr_in->src_addr != nib.short_addr)

        {

            //lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)

            // its okay since we're subtracting a value from a constant

            buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);

        }

 

        // if the neighbor does not keep its rx on when idle (ie: sleeping), then we need to send

        // the frame indirectly.

        if (!NBOR_ENTRY(nbor_mem_ptr)->rx_on_when_idle)

        {

            indirect = true;

        }

 

        // set the mac dest addr to the neighbor address

        hdr_out.mac_hdr->dest_addr.short_addr       = hdr_in->dest_addr;

        hdr_out.src_addr                            = hdr_in->src_addr;

    }

    // is the dest in our routing table?

    else if ((next_hop = nwk_rte_tbl_get_next_hop(hdr_in->dest_addr)) != INVALID_NWK_ADDR)

    {

        // it's in the routing table. forward it.

        // the buffer dptr is pointing to the nwk payload now. calc the length of the nwk

        // payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down

        // the stack.

        //

        //lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)

        // its okay since we're subtracting a value from a constant

        buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);

 

        // set the mac dest addr to the next hop and the nwk src addr to the originator

        hdr_out.mac_hdr->dest_addr.short_addr       = next_hop;

        hdr_out.src_addr                            = hdr_in->src_addr;

    }

    // are we allowed to discover the route?

    else if (hdr_in->nwk_frm_ctrl.disc_route)

    {

        // the destination isn't in our routing tables. discover route is enabled for the

        // frame so we can buffer it and initiate route discovery.

        nwk_pend_add_new(buf, hdr_in);

        nwk_rte_mesh_disc_start(hdr_in->dest_addr);

        return;

    }

    // if all else fails, route it along the tree

    else

    {

        // tree routing is the default routing if everything else fails or we don't allow mesh routing.

        // we'll just recycle the frame buffer and send it on its way out.

        if ((next_hop = nwk_rte_tree_calc_next_hop(hdr_in->dest_addr)) == INVALID_NWK_ADDR)

        {

            // tree routing failed for some reason. collect the stat and go on with life.

            pcb.failed_tree_rte++;

            buf_free(buf);

            DBG_PRINT("NWK: No such neighbor exists.\n\r");

            return;

        }

        // the buffer dptr is pointing to the nwk payload now. calc the length of the nwk

        // payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down

        // the stack.

        //

        //lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)

        // its okay since we're subtracting a value from a constant

        buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);

 

        // set the mac dest addr to the spec'd neighbor addr and the nwk src addr to the originator

        hdr_out.mac_hdr->dest_addr.short_addr   = next_hop;

        hdr_out.src_addr                        = hdr_in->src_addr;

    }

 

    // fill out the rest of the fields that will be needed to forward this frame

    hdr_out.nwk_frm_ctrl.frame_type             = hdr_in->nwk_frm_ctrl.frame_type;

    hdr_out.seq_num                             = hdr_in->seq_num;

    hdr_out.nwk_frm_ctrl.disc_route             = hdr_in->nwk_frm_ctrl.disc_route;

    hdr_out.radius                              = hdr_in->radius;

    hdr_out.dest_addr                           = hdr_in->dest_addr;

    hdr_out.handle                              = hdr_in->handle;

    hdr_out.mac_hdr->src_addr.mode              = SHORT_ADDR;

    hdr_out.mac_hdr->dest_addr.mode             = SHORT_ADDR;

    hdr_out.mac_hdr->src_addr.short_addr        = nib.short_addr;

    nwk_tx(buf, &hdr_out, indirect);

}          

 

 

选择好传输方式之后,会跳转到nwk_tx函数,该函数为NWK层的发送函数,主要功能是添加相应的包头文件,然后将信息包传送到MAC层;代码架构如下:

 

void nwk_tx(buffer_t *buf, nwk_hdr_t *hdr, bool indirect)

{

    mac_pib_t *pib = mac_pib_get();

    mac_data_req_t req;

 

    // finish filling out the nwk hdr and generate it

    hdr->nwk_frm_ctrl.protocol_ver          = ZIGBEE_PROTOCOL_VERSION;

    hdr->nwk_frm_ctrl.mcast_flag            = false;        // multicast not supported

    hdr->nwk_frm_ctrl.security              = false;

    hdr->nwk_frm_ctrl.src_rte               = false;

    hdr->nwk_frm_ctrl.dest_ieee_addr_flag   = false;

    hdr->nwk_frm_ctrl.src_ieee_addr_flag    = false;

 

    nwk_gen_header(buf, hdr);//添加包头文件,重新打包

   debug_dump_nwk_hdr(hdr);

 

    req.src_addr.mode                       = SHORT_ADDR;

    req.dest_addr.mode                      = SHORT_ADDR;

    req.src_addr.short_addr                 = hdr->mac_hdr->src_addr.short_addr;

    req.dest_addr.short_addr                = hdr->mac_hdr->dest_addr.short_addr;

    req.src_pan_id                          = pib->pan_id;

    req.dest_pan_id                         = pib->pan_id;

    req.msdu_handle                         = hdr->handle;

    req.buf                                 = buf;

 

    // it its a broadcast, then no ack request. otherwise, ack requests on all other transfers.

    req.tx_options = (req.dest_addr.short_addr != 0xFFFF) ? MAC_ACK_REQUEST : 0x0;

    req.tx_options |= indirect ? MAC_INDIRECT_TRANS : 0x0;

 

    // kick it to the curb!

    mac_data_req(&req);

}

mac_data_req函数为MAC层的数据请求服务,接收NWK层的数据并且加上MAC层的包头,然后将数据打包;函数原型如下:

void mac_data_req(mac_data_req_t *req)

{

    mac_hdr_t hdr;

    bool indirect;

 

    memset(&hdr, 0, sizeof(mac_hdr_t));

    hdr.mac_frm_ctrl.frame_type     = MAC_DATA;

    hdr.mac_frm_ctrl.ack_req        = (bool)(req->tx_options & MAC_ACK_REQUEST);

    hdr.mac_frm_ctrl.frame_ver      = MAC_802_15_4_2006;

    hdr.dsn                         = pib.dsn++;

 

    hdr.dest_pan_id                 = req->dest_pan_id;

    hdr.src_pan_id                  = req->src_pan_id;

    memcpy(&hdr.src_addr, &req->src_addr, sizeof(address_t));

    memcpy(&hdr.dest_addr, &req->dest_addr, sizeof(address_t));

 

    // generate the header

    mac_gen_header(req->buf, &hdr);

    DBG_PRINT_RAW("\n<OUTGOING>\n");

    debug_dump_mac_hdr(&hdr);

 

    // send the frame to the tx handler for processing

    indirect = (req->tx_options & MAC_INDIRECT_TRANS);

    mac_tx_handler(req->buf, &hdr.dest_addr, indirect, hdr.mac_frm_ctrl.ack_req, hdr.dsn, req->msdu_handle);

}

 

mac_data_req函数执行完之后会跳转到mac_tx_handler函数,mac_tx_handler函数为一个处理实际框架的中间函数,它解析该包框架中的TX选项,如果它是一个直接传输,那么就会被直接发送到队列里;如果该包框架还需要一个ACK请求,那么它将会被放在队列缓冲区,直到请求的ASK到来之后再传送到发送队列里,该函数原型如下:

void mac_tx_handler(buffer_t *buf, address_t *addr, bool indir, bool ack_req, U8 dsn, U8 handle)

{

#if 1

    if (indir)

    {

        mac_indir_add(buf, addr, ack_req, dsn, handle);

        return;

    }

    mac_out(buf,addr, ack_req, dsn, handle);

#endif

}

 

mac_tx_handler函数执行完之后会跳转到mac_out函数,mac_out函数会选择一个合适的信道将包信息传递给Radio层,该函数原型如下:

void mac_out(buffer_t *buf, address_t *dest_addr, bool ack_req, U8 dsn, U8 handle)

{

#if 1

    U8 status;

    mac_pcb_t *pcb = mac_pcb_get();

    mac_pib_t *pib = mac_pib_get();

   

//    rmb_mac_tx_handle = handle;

    /*Send start callback funtion*/

    //tx_start_cb(handle);

   

    DBG_PRINT("MAC_EVENTHANDLER: tx end event occurred:  ");

 

    INTERRUPTS_DISABLE();

    rmb_mac_tx_handle = handle;

    memcpy(&rmb_dest_addr,dest_addr,sizeof(address_t));

    // transmit the frame and record the status

  /* Modified by Ann 2015/4/15*/

    //status = drvr_tx(buf);

    buf->dptr++;

    status = NETSTACK_CONF_RADIO.send(buf->dptr,buf->len);

   /*end modify */

  

    INTERRUPTS_ENABLE();

 

    // collect a transmit stat here

    pcb->total_xmit++;

 

// delete by ltm

//    switch (status)

//    {

//    case RADIO_SUCCESS:

//        if (pcb->mac_state == MLME_ASSOC_REQ)

//        {

//            ctimer_set(&pcb->mlme_tmr, pib->resp_wait_time/*CLOCK_SECOND*/, mac_poll_req, NULL);

//        }

//        else

//        {

//            mac_data_conf(MAC_SUCCESS, handle);

//        }

//        break;

//    case RADIO_NO_ACK:

//        mac_data_conf(MAC_NO_ACK, handle);

//

//        // collect a transmit fail stat here

//        pcb->total_fail++;

//        break;

//    default:

//        mac_data_conf(MAC_DENIED, handle);

//        break;

//    }

 

    buf_free(buf);

    status = status;

#endif

}

mac_out函数执行过程中会跳转到NETSTACK_CONF_RADIO.send(buf->dptr,buf->len)函数,NETSTACK_CONF_RADIO.send(buf->dptr,buf->len)该函数即为启动底层RF的收发函数,该函数之后会调用send函数,send函数原型如下:

static int

send(const void *payload, unsigned short payload_len)

{

  prepare(payload, payload_len);

  return transmit(payload_len);

}

send函数会跳转至prepare函数,prepare函数为发送信息包之前做最后的准备,代码原型如下所示:

static int

prepare(const void *payload, unsigned short payload_len)

{

  uint8_t i;

 

  PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN);

 

  /*

   * When we transmit in very quick bursts, make sure previous transmission

   * is not still in progress before re-writing to the TX FIFO

   */

  while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);

 

  if((rf_flags & RX_ACTIVE) == 0) {

    on();

  }

 

  CC2538_RF_CSP_ISFLUSHTX();

 

  PRINTF("RF: data = ");

  /* Send the phy length byte first */

  REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN;

 

 if(CC2538_RF_CONF_TX_USE_DMA) {

     PRINTF("<uDMA payload>");

 

    /* Set the transfer source's end address */

    udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN,

                         (uint32_t)(payload) + payload_len - 1);

 

    /* Configure the control word */

    udma_set_channel_control_word(CC2538_RF_CONF_TX_DMA_CHAN,

                                  UDMA_TX_FLAGS | udma_xfer_size(payload_len));

 

    /* Enabled the RF TX uDMA channel */

    udma_channel_enable(CC2538_RF_CONF_TX_DMA_CHAN);

 

    /* Trigger the uDMA transfer */

    udma_channel_sw_request(CC2538_RF_CONF_TX_DMA_CHAN);

 

    /*

     * No need to wait for this to end. Even if transmit() gets called

     * immediately, the uDMA controller will stream the frame to the TX FIFO

     * faster than transmit() can empty it

     */

  } else {

    for(i = 0; i < payload_len; i++) {

     REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i];

     PRINTF("%02x", ((unsigned char *)(payload))[i]);

   }

  }

  PRINTF("\n");

 

  return 0;

}

prepare函数主要的功能是将数据写入发送寄存器RFCORE_SFR_RFDATA,可以选择的写入方式有直接写入和通过DMA写入;

 

prepare函数之后会跳转至transmit函数,transmit函数即为最底层的发送函数,其函数原型如下:

static int

transmit(unsigned short transmit_len)

{

  uint8_t counter;

  int ret = RADIO_TX_ERR;

  rtimer_clock_t t0;

 

  PRINTF("RF: Transmit\n");

 

  if(!(rf_flags & RX_ACTIVE)) {

    t0 = RTIMER_NOW();

    on();

    rf_flags |= WAS_OFF;

    while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));

  }

 

  if(channel_clear() == CC2538_RF_CCA_BUSY) {//判断通道是否空闲

    RIMESTATS_ADD(contentiondrop);

    return RADIO_TX_COLLISION;

  }

 

  /*

   * prepare() double checked that TX_ACTIVE is low. If SFD is high we are

   * receiving. Abort transmission and bail out with RADIO_TX_COLLISION

   */

  if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD) {

    RIMESTATS_ADD(contentiondrop);

    return RADIO_TX_COLLISION;

  }

 

  /* Start the transmission */

  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);

  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);

 

  CC2538_RF_CSP_ISTXON();

 

  counter = 0;

  while(!((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE))

        && (counter++ < 3)) {

    clock_delay_usec(6);

  }

 

  if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) {

    PRINTF("RF: TX never active.\n");

    CC2538_RF_CSP_ISFLUSHTX();

    ret = RADIO_TX_ERR;

  } else {

    /* Wait for the transmission to finish */

    while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);

    ret = RADIO_TX_OK;

  }

  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);

  ENERGEST_ON(ENERGEST_TYPE_LISTEN);

 

  if(rf_flags & WAS_OFF) {

    rf_flags &= ~WAS_OFF;

    off();

  }

 

  RIMESTATS_ADD(lltx);

 

  return ret;

至此,整个发送过程已经完成,各个层次之间的数据传输主要是增加包头等信息文件,然后打包传输,一直从APS层到RF层。

 

2 0