tag 标签: contiki

相关博文
  • 热度 19
    2014-7-6 22:41
    1254 次阅读|
    0 个评论
    在现有 http://www.myexception.cn/mobile/1436453.html 关于几个Timer的一个总结 Contiki源代码(Contiki版本3.X)中,在调用rtimer时,需要调用者获取当前的RITMER_NOW,然后在此基础上加上需要的time然后进行定时器调度。但是这样里边,如果存在多个定时任务的时候,如何处理呢?而且如果后一个定时任务的time正好小于前一个,又如何保证后一个被调用呢?在现有的rtimer中,没有看到这样的代码。由这份邮件列表的内容可以看到截止2013年11月16日,Contiki的Rtimer只支持1个Rtimer.   Message: 4 Date: Sat, 16 Nov 2013 17:35:16 +0100 (CET) From: Beno?t Th?baudeau benoit.thebaudeau@advansee.com Subject: Rtimer  limitations To: Contiki developer mailing list         contiki-developers@lists.sourceforge.net Message-ID:         1772566825.397867.1384619716871.JavaMail.zimbra@advansee.com Content-Type: text/plain; charset=utf-8 Hi all, Rtimers are very useful in order to schedule hard real-time tasks, while Ctimers may be delayed. However, looking at their implementation in core/sys/ rtimer .{ c |h}, it seems that only a single  Rtimer  instance is supported at once. This is a big issue since it means that only a single  Rtimer  can be used in the firmware, or that  Rtimer  users have to know each other in order not to make Rtimers collide. Is it the expected behavior? Moreover, this limitation is not documented. Any comment? Best regards, Beno?t ------------------------------ Message: 5 Date: Sat, 16 Nov 2013 17:41:24 +0100 From: Adam Dunkels adam@thingsquare.com Subject: Re: Rtimer  limitations To: Contiki developer mailing list         contiki-developers@lists.sourceforge.net Message-ID:         CAEW- RJ5WHcsMjoTPXSFNMLhmyboJXV6L63 ctJ5xkCgJ66j= GHw@mail.gmail.com Content-Type: text/plain; charset="iso-8859-1" The  rtimer  API is supposed to support multiple rtimers but, yeah, the implementation only supports one. Until we've got stable code for multiple rtimers, this is what we have. /adam On Sat, Nov 16, 2013 at 5:35 PM, Beno?t Th?baudeau benoit.thebaudeau@advansee.com wrote:
  • 热度 16
    2014-7-6 22:40
    1153 次阅读|
    0 个评论
    Contiki的NETWORK层之间的数据流路径: Send: Network-Mac-Rdc(-Frame802154)-Radio Recv: Radio-Rdc(-Frame802154)-Mac-Network 注:在此结构中,802154应该是属于RDC层的, 如果不将RDC算作一层,应该是介于Mac和Radio之间。是Mac层的出口。这也是Contiki的一项重要模块之一。在Contiki中ContikiMAC.c模块实现了RDC功能。论文《The ContikiMAC Radio Duty Cycling Protocol》详细描述了RDC的实现与理论基础。   在Contiki中接收采用事件驱动方式。接收通过一个PThread任务,等待数据到来事件,如果数据到来事件触发,则将数据则取出来。这个事件触发是在Radio的中断中设置的。 即:NETSTACK_RDC.input()的调用一般都是在Radio的一个PThread中,由于在Network.open的时候已经将每一层的回调函数设置完备,所以当接收到数据的时候,通过每一层的回调,将数据传递到Network_Network处,即协议栈的最顶部应用层处理。   以contiki\cpu\avr\radio\rf230bb\rf230bb.c文件为例 rf230_interrupt()函数中判断接收到数据, 调用process_poll(rf230_process),发送PROCESS_EVENT_POLL事件。   在rf230_process PThread中收到PROCESS_EVENT_POLL,调用NETSTACK_RDC.input()进入数据接收处理流程。最后在Radio文件中,找到了调用process_poll()函数来,poll一个PROCESS_EVENT_POLL。 +aux_len;i++) 附1: 以Contiki中example-mesh.c历程为例: examples/example-mesh.c/example_mesh_process/mesh_open   send: (在rime中: mesh.c/mesh_send() multihop_send() unicast_send() broadcast_send() abc_send()(abc_send中调用rime_output) ) rime.c/rime_output()/NETSTACK_MAC.send nullmac.c/NETSTACK_RDC.send (NETSTACK_FRAMER.create 生成framer) nullrdc.c/NET_RADIO.send nullrdc.c/mac_call_sent_callback 处理发送结束后的状态。   recv: tf230bb/fr230bb.c/rf230_interrupt  调用process_poll产生PROCESS_EVENT_POLL。 pthread rf230bb.c/rf230_process任务/NETSTACK_RDC.input (NETSTACK_FRAMER.parse解析收到的数据帧,是否符合MAC层要求) nullrdc.c/NETSTACK_MAC.input nullmac.c/NETSTACK_NETWORK.input 调用rime.c/input()/abc_input() 通过rime协议栈的回调传递给 mesh.c/data_packet_received()此函数回调应用层的接收处理函数 example-mesh.c/example_recv()处理接收数据。   附2: stunicast.c中 对于重发的处理,由在发送过程中设置timer如果在规定的时间内,如果没有数据返回则通过timer调用回调处理函数,如果有数据返回则在在recv_from_stunicast()调用stunicast_cancel()取消timer,避免调用回调。 在Contiki中,数据的发送与接收分别使用一个任务,这样可以避免之间的冲突问题。 NETWORK协议栈层之间的数据交互,通过buf来实现。这一点与Linux的sk_buff很像,所以导致了很多不必要的内存拷贝,这也是为什么Contiki内存占用很小的原因之一。  
  • 热度 17
    2013-7-9 12:58
    1178 次阅读|
    0 个评论
      Chameleon结构的作用在Chameleon的pack_header()函数中体现了出来(这里的打包方式像以前自己讨论过的一个问题,是在组织数据时直接将数据写入发送缓冲区中,还是保存在一个结构体中到最后一起打包)。Chameleon的方式,属于将需要打包的数据先放在一个结构体中,在最后将要发送时,调用pack_header函数将数据写入发送缓冲区中。这样会浪费一些内存。但是,折中的结果是通过Chameleon我们可以同时兼容多种协议,也是Contiki的最大优势。有一利,有一弊。取舍之间,适合的就是最好的。 在Chameleon在进行pack_header时,将存放在packetbuf_attrs,packetbuf_addrs,数组中的数据提取出来,放在将要发送的packetbuf的报文头部。 应该说,这里packetbuf中使用的打包方式确实浪费了不少内存。 首先,是分配静态的 struct packetbuf_attr packetbuf_attrs ; struct packetbuf_addr packetbuf_addrs ; 而它们需要消耗,48字节内存。 /*-------------------------------------------------------------------------------------------------------------------------------------*/ 2013-5-2 19:31 Contiki中chameleon机制中, 有一个raw没有经过优化的.c文件, 有一个bitopt即位优化过的.c文件, 这两个文件可以配置选择。 对于channel机制中是通过一个list进行管理, 打开一个channel即是添加一个list node,其他的操作,是通过channel封装了list的各种操作; 这里边关于数据的组织,与解析(pack,unpack)都是通过packetbuf模块进行的数据操作;   在packetbuf中, packetbufptr默认是指向packetbuf , 当指向其他地方时,packetbufptr不等于packetbuf 以此来判断是否,packetbufptr指向的是否为external_data; packetbuf是由PACKETBUF_SIZE和PACKETBUF_HDR_SIZE两个值来组成的,即一个packetbuf包含了header和data; 这次对于packetbuf.c文件理解清楚了,这里边就是对于一个数组的封装操作;实现了各种便于pack与unpack的操作。
  • 热度 17
    2013-7-9 12:58
    1016 次阅读|
    0 个评论
      2013-7-5 19:02   首先关于里边的一个变量: buflen指的是payload(packetbuf的数据部分)的长度, bufptr指的是payload(packetbuf的数据部分)的起始位置; hdrptr指的是报文头的起始位置(在packetbuf的报文头部分); packetbuf实际大小是PACKETBUF_HDR_SIZE+PACKETBUF_SIZE(即默认为128+48)。   关于packetbuf使用缓冲区的方式,以及关于为什么,发送和接收存放不一致,确实值得分析一下。 对于发送而言,报文头使用内存是从后往前,payload是从前往后,是因为在发送时不用再去调整报文头和payload的位置,即使需要调整,也只是根据bufptr将payload调整为以PACKETBUF_HDR_SIZE开始的packetbuf(即报文头的尾部)。方便于组织与打包数据。(现在理解到这个,是因为之前在一次写通信协议的打包的时候,自己也这样做过。现在再看,这里的使用确实很是巧妙,而当时自己只是为了解决一个打包问题,而临时使用的一个方式。当时还以为这样做不可取。没想到,Contiki中整个的数据打包都是基于这种方式。) 对于接收而言,在没有进行解包前,我们不知道哪里是报文头,无法进行分开存放,这样全部放在packetbuf的数据区也是合适的,也正因为这样才有了packetbuf_hdrreduce解包函数,用来提取各自的报文头。   bufptr与buflen作用: 为了在接收数据时,从incoming packet中提取出报文头和数据,即在接收数据解包时找到报文头和数据的起始位置。 因为发送时,报文头和payload是很开放置的,一个放置在packetbuf报文头缓冲区,一个放置在packetbuf数据缓冲区,但是接收回的数据都是在packetbuf数据缓冲区中放置的,所以在提取报文头的时候,将buflen减了size,正好将前size字节的报文头提取出来。而对于bufptr加了size,正好跳过size字节的报文头,而这个时候bufptr指向的位置,正好是下一次要提取的报文头或者payload(即报文中数据部分)的开始。 在接收函数中会先调用packetbuf_hdrreduce(因为发送时的packet_compact,将bufptr已经置为0,所以这里接收到的数据帧放置在PACKETBUF_HDR_SIZE起始的packetbuf中)。这里调用packetbuf_hdrreduce(size),正好将各层自己的报文头提取出来,这里的size正好是每层各自报文头的长度。在packetbuf_hdrreduce(size)函数中, bufptr+=size; buflen-=size; 这样,bufptr的位置,正好是下一次要提取的报文头或者payload的起始地址,而buflen则是剩下的数据长度。 这也既是,为什么在发送函数前会有一个packet_compact,调整数据的存放,将payload放置在PACKETBUF_HDR_SIZE开始的packetbuf中,也即payload的起始地址;在解包函数中,都会有一个packetbuf_hdrreduce,提取报文头。   关于 packetbuf_set_addr() packetbuf_set_attr() 每一层都会设置相应的addr,和attr。channel是在chameleon中设置的。最后在packet_header时,从packetbuf_attrs,packetbuf_addrs静态数组中提取,组织到packetbuf中准备发送; 注: http://blog.chinaunix.net/uid-9112803-id-3277952.html 给了很多启发
  • 热度 14
    2013-7-9 12:57
    1330 次阅读|
    0 个评论
      一 分析Rime的大概思路   在Rime中,理解Rime Stack的工作原理,首先要理解整体框架; 之后要理解这里边的list,memb,packetbuf,channel,等几个部分; 之后要明白chameleon的结构,以及一些具体实现; 这几个部分中,以packetbuf和chameleon最为重要。   像packetbuf.c,packetqueue.c是最基本的几个函数(当然list.c,memb.c,ctimer.c也是)。在此之上,形成了Rime的各个primitive,即广播帧,单播帧,级跳等的发送。同时,Chameleon结构的设计,使得Rime Stack能够打包任意协议类型的帧数据。这也是Rime Stack的优势所在。故,Chameleon结构在Rime Stack中占有很重要的地位。最后的发送帧打包都是借助于Chameleon实现的。 当然,Rime Stack只是一个帧发送与接收的stack,自身无法进行数据采集,组网等应用。如果要这些应用,需要在Rime之上实现router,实现collect,实现Trickle,实现mesh。 理解好Rime有两个文件必须理解,chameleon.c,packetbuf.c这两个文件的源代码以及Adam关于它们的论文。 如果只是分析Rime Stack,则再继续将abc,ibc,ubc等各种发送帧的文件理解了,明白里边的回调函数调用,基本上可以从大体上理解Rime的结构,此时根据Contiki中的Rime例程,可以垂直追踪并分析代码。根据作者的实际使用,会对这些理解更深入。 当然,这些只是Rime Stack+Chameleon,如果深入看MAC结构,就需要分析以下几个:   #define NETSTACK_CONF_MAC                       csma_driver #define NETSTACK_CONF_RDC                       contikimac_driver #define NETSTACK_CONF_FRAMER                    framer_802154 #define NETSTACK_CONF_RADIO                     stm32w_radio_driver   二 追踪Rime中的几个帧发送文件 Rime中的各个primitive最终都是在abc中打开channel,建立一个channel; 同时,设置这个channel的头长度; 不同的层,设置不同的hdrsize; channel_set_attributes must be after the open. 每一层继承了上一层的hdrsize并根据自己的需要添加了额外的hdrsize; 计算最后的hdrsize,由chameleon的header_size完成。 而这些最基本的attribute定义在packetbuf.h中。由此,chameleon结构的作用体现出来。根据不同层的attribute设置相应的attribute值,最后根据hdrsize将所有有关的attribute,pack在buf中。由此,完成pack。最后packetbuf完成数据的整理工作。至此,从Rime到Chameleon完成了,他们的工作。 每一层的callback,是为了下一层收到或者发送时,用来实现上一层需要的功能。 关于Contiki中Memb内存的使用,采用了预分配的方式: 在memb内存分配使用中,使用了预先分配内存的方式来管理内存; 首先,通过memb()宏静态分配一个二维较大的内存; 之后,根据需要一次内存,并记录本次使用的内存; 最后,当释放内存后,将内存使用记录清楚;   三 实例代码追踪(example-mesh.c)   Rime and Chameleon Chameleon结构中,packetbuf的操作也是基础。所以无论对于Rime,还是Chameleon,甚至于后来的MAC层的数据打包发送与接收,都与packetbuf有着莫大的联系。所以彻底弄明白packetbuf在理解好Contiki中的协议有很大的帮助。   在数据离开Rime后,进入Chameleon,离开Chameleon后进入CSMA,离开CSMA后进入RDC(contikimac),离开RDC后进入Frame802154打包为802154协议的帧数据,最后进入Radio的driver准备发送。   而这里边,发送是通过一层层调用下一级发送函数进行发送,而接收是通过回调函数,在底层实现上层需要的动作。 /---------------------------------Rime+Chameleon---------------------------------------/ mesh_send(mesh.c)----multihop_send(multihop.c)----unicast_send(unicast.c) ----broadcast_send(broadcast.c)----abc_send(abc.c)----rime_output(rime.c) ----chameleon_create+packetbuf_compact(chameleon.c) /----------------------------------MAC--------------------------------------------/ ----NETSTACK_MAC.send(packet_sent, c)(here the NETSTACK_MAC macro is csma. Therefore, the send is send_packet(csma.c)) ----NETSTACK_RDC.send(sent, ptr);(here the NETSTACK_RDC macro is contikimac. In a result, the send is qsend_packet(contikimac.c)) ----NETSTACK_FRAMER.create();(the function is create() in framer-802154.c) ----NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len);(send the frame through the NETSTACK_RADIO) /---------------------------------------------------------------------------------/ 四 应用 Rime仅仅是帮助我们将数据发送出去,具体的应用就需要熟悉mesh,router,collect等算法了。如果要做低功耗,还要熟悉Contiki的RDC机制及应用层还有Coap协议。
相关资源