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层的四种包结构,分别为COMMAND、BEACON、ACK和DATA,四种包的处理过程根据各自的特性虽然有所区别,但大体方法是一样的,都是在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接收数据并在各个通信层之间处理的整个过程,如有不恰当之处,欢迎大家交流和指正。