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层传输数据,它的主要功能是从当前的包结构或者包功能提取一个架构,然后根据目的地址去选择应该怎么传输该包文件,传送方式包括broadcast、neighbor table、routing table、 route discovery、tree四种;该函数原型如下:
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层。
- FreakZ学习笔记:FreakZ通信网络发送过程详解
- FreakZ学习笔记:FreakZ通信网络接收过程详解
- FreakZ学习笔记:路由发现机制
- FreakZ学习笔记:路由应答机制
- FreakZ Open Source Zigbee Stack
- freakz移植到IAR的CC2530工程
- freakz在cc2530上的移植,第一篇
- 通信网络学习笔记
- [原创]奥特曼Zigbee读书日记(八)--freakz移植之物理层
- Qt网络通信学习笔记
- 网络通信学习笔记-Java
- Android网络通信--学习笔记
- Android 网络与通信学习过程
- android网络通信 接收和发送数据详解
- android网络通信 接收和发送数据详解
- android网络通信 接收和发送数据详解
- iOS 开发 网络编程详解之基本网络通信过程
- java学习笔记---Socket应用网络通信
- 鼠标的左击、中击、右击事件及Frame的关闭
- POJ Common Subsequence
- jquery 对 Json 的各种遍历
- 发送结构体数据转序
- vim配置
- FreakZ学习笔记:FreakZ通信网络发送过程详解
- Three Jugs(辗转相除法求GCD)
- 不相交集ADT
- CDN(内容分发网络)技术原理
- mac 终端 常用命令
- 关于短信拦截、电话拦截的一些注意点
- 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: 共享内存提供程序, error: 0
- 二维数组作为函数参数深度详解
- 函数的递归调用(阶乘函数&斐波那契数列)