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

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接收数据并在各个通信层之间处理的整个过程,如有不恰当之处,欢迎大家交流和指正。

时间: 2024-08-14 20:47:49

FreakZ学习笔记:FreakZ通信网络接收过程详解的相关文章

算法学习笔记 KMP算法之 next 数组详解

最近回顾了下字符串匹配 KMP 算法,相对于朴素匹配算法,KMP算法核心改进就在于:待匹配串指针 i 不发生回溯,模式串指针 j 跳转到 next[j],即变为了 j = next[j]. 由此时间复杂度由朴素匹配的 O(m*n) 降到了 O(m+n), 其中模式串长度 m, 待匹配文本串长 n. 其中,比较难理解的地方就是 next 数组的求法.next 数组的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀,也可看作有限状态自动机的状态,而且从自动机的角度反而更容易推导一些. "前

Kinect学习笔记之三Kinect开发环境配置详解

0.前言: 首先说一下我的开发环境,Visual Studio是2013的,系统是win8的64位版本,SDK是Kinect for windows SDK 1.8版本.虽然前一篇博文费了半天劲,翻译了2.0SDK的新特性,但我还是决定要回退一个版本. 其实我之前一直在用2.0的SDK在调试Kinect,但无奈实验室提供的Kinect是for Windows 1.0版本的,而且Kinect从1.8之后就好像是一个分水岭,就比如win8和win7有很大的差别,2.0版的Kinect和SDK都是相较

Cocos2d-x学习笔记(十四)CCAutoreleasePool详解

原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38964637 前言 之前学了那么多的内容,几乎所有的控件都要涉及内存管理类CCAutoreleasePool,所以这一次的学习笔记,我们一起来看看CCAutoreleasePool,先从CCObject的autorelease方法入手. CCObject::autorelease CCObject* CCObject::autorelease(void) { // 将

sql学习笔记(16)----------mysql存储过程详解

mysql存储过程详解 1.     存储过程简介   我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它. 一个存储过程是一个可编程的函数,它在数据库中创建并保存.它可以有SQL语句和一些特殊的控制结构组成.当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的.

java网络编程学习笔记(二):socket详解

1.Socket有多种构造方法,大多数构造方法在构造的时候就指定了连接的主机和端口号.当客户端的构造方法与服务器连接的时候,可能需要等待一段时间,因为需要建立连接.默认情况下,Socket的构造方法会一直等待下去,直到连接成功或者是出现异常.Socket的构造方法请求连接的时候,受到底层网络传输速度的影响,可能长时间处于等待状态.如果希望限定等待时间,就需要一个无参的构造方法,可以如下做: Socket socket=new Socket(); SocketAdress remoteAddr=n

JQuery学习笔记系列(一)----选择器详解

笔者好长时间没有更新过博客园的笔记了,一部分原因是去年刚刚开始工作一段时间忙碌的加班,体会了一种每天加班到凌晨的充实感,之后闲暇时间了也因为自己懒惰没有坚持记笔记的习惯,现在重新拾起来. 借用古人的一段话与诸君共勉: 人之为学,不日进则日退,独学无友,则孤陋而难成:久处一方,则习染而不自觉.不幸而在穷僻之域,无车马之资,犹当博学审问, 古人与稽,以求其是非之所在.庶几可得十之五六.若既不出户,又不读书,则是面墙之士,虽子羔.原宪之贤,终无济于天下. 翻译为:人们求学(或做学问),不能天天上进,就

网络寻址过程详解

今天了解一下arp协议,即ARP(Address Resolution Protocol).是根据IP地址获取物理地址的一个TCP/IP协议.IP间的通讯一来MAC地址,通讯双方在一个局域网内的情况极少,通常需要多台服务器或网络设备之间的中转才能到达.在中转时会需要下一站中转设备的MAC地址来搜索下一个中转目标.这时就会用到arp协议. 交换机它维护了一张 MAC 地址表,用来反映各端口和 MAC 地址的对应关系,以便做好数据转发工作.下面我们来看一下路由器的工作原理,在路由器中也要维护一张表格

IP地址和子网划分学习笔记之《超网合并详解》

一.超网的概念 超网(Supernetting)是与子网类似的概念,IP地址根据子网掩码被分为独立的网络地址和主机地址.超网,也称无类别域间路由选择(CIDR),它是集合多个同类互联网地址的一种方法. 与子网划分(把大网络分成若干小网络)相反,它是把一些小网络组合成一个大网络,就是超网. 二.超网合并网段 1.合并网段 示例:某企业有一个网段,该网段有200台主机,使用192.168.0.0 255.255.255.0网段. 后来计算机数量增加到400台,为后来增加的200台主机使用192.16

深度学习笔记——PCA原理与数学推倒详解

PCA目的:这里举个例子,如果假设我有m个点,{x(1),...,x(m)},那么我要将它们存在我的内存中,或者要对着m个点进行一次机器学习,但是这m个点的维度太大了,如果要进行机器学习的话参数太多,或者说我要存在内存中会占用我的较大内存,那么我就需要对这些个点想一个办法来降低它们的维度,或者说,如果把这些点的每一个维度看成是一个特征的话,我就要减少一些特征来减少我的内存或者是减少我的训练参数.但是要减少特征或者说是减少维度,那么肯定要损失一些信息量.这就要求我在减少特征或者维度的过程当中呢,尽