Rime笔记

1850阅读 0评论2013-04-25 jsjkj
分类:嵌入式

Overview

1. All Rime layers conform to the POSIX standard, which mainly consists of 4 interfaces, open/close/send/recv.
2. The header for lower layer will be added at the beginning of the packet and vice versa.
3. For each layer, the send function forms a new header with specific information, and then pass it to the lower layer. The recv function decodes the header and store the information at the device driver.
4. Moreover, user may directly call the send function in each level, but unable to call the recv function, which can only called by the lower level functions.
5. Particularly to Contiki source code, the send function for each level is direct call, while the recv functions are all callbacks. More specifically, the lower level defines a callback struct, which consists of two function pointers, denoting the operation after reception and sending. The struct is assigned with actual function in upper level source code, however, the functions can still called with the name of the function pointer. So you have to keep an eye on the callback structure.

Codes

We starts from the broadcast function. This is the most fundamental function you may wanna use. The following lines are yanked from the file broadcast.c.

  1. static const struct abc_callbacks broadcast = {recv_from_abc, sent_by_abc};
  2. static void
  3. recv_from_abc(struct abc_conn *bc)
  4. {
  5.   rimeaddr_t sender;
  6.   struct broadcast_conn *c = (struct broadcast_conn *)bc;
  7.   rimeaddr_copy(&sender, packetbuf_addr(PACKETBUF_ADDR_SENDER));
  8.   c->u->recv(c, &sender);
  9. }
The referred struct abc_conn and abc_callbacks is defined in the file abc.h

  1. struct abc_callbacks {
  2.   void (* recv)(struct abc_conn *ptr);
  3.   void (* sent)(struct abc_conn *ptr, int status, int num_tx);
  4. };
  5.  
  6. struct abc_conn {
  7.   struct channel channel;
  8.   const struct abc_callbacks *u;
  9. };
Then we see the function with regarding to receiving in abc.c

  1. void
  2. abc_open(struct abc_conn *c, uint16_t channelno,
  3.       const struct abc_callbacks *callbacks)
  4. {
  5.   channel_open(&c->channel, channelno);
  6.   c->u = callbacks;
  7.   channel_set_attributes(channelno, attributes);
  8. }
  9.  
  10. void
  11. abc_input(struct channel *channel)
  12. {
  13.   struct abc_conn *c = (struct abc_conn *)channel;
  14.   c->u->recv(c);
  15. }
1. abc_open is called when the platform initialization, so the abc_callbacks has been attached with the structure abc_conn.
2. The struct channel appears in the first position of abc_open, hence their address (or pointer value) should be identical.
3. the unique value of struct abc_callbacks is attached with abc_conn in abc.c,and reassigned with the two callback functions in broadcast.c. Hence the line "c->u->recv(c)" actually calls the function recv_from_abc.
4. We may notice that the recv_from_abc contains the "c->u->recv" as well, then we may infer that all recv function calls the succeeding recv functions in same manner. So in order to find the initiator of recv, we need to find who calls the function abc_input. The answer is in rime.c

  1. static void
  2. input(void)
  3. {
  4.   struct rime_sniffer *s;
  5.   struct channel *c;

  6.   RIMESTATS_ADD(rx);
  7.   c = chameleon_parse();

  8.   for(s = list_head(sniffers); s != NULL; s = list_item_next(s)) {
  9.     if(s->input_callback != NULL) {
  10.       s->input_callback();
  11.     }
  12.   }

  13.   if(c != NULL) {
  14.     abc_input(c);
  15.   }
  16. }
Then in the bottom of the file,

  1. const struct network_driver rime_driver = {
  2.   "Rime",
  3.   init,
  4.   input
  5. };
so we are gonna find the actual member names of network_driver in the corresponding positions. We find that the definition of network_driver is located in file netstack.h

  1. struct network_driver {
  2.   char *name;
  3.  
  4.   /** Initialize the network driver */
  5.   void (* init)(void);
  6.  
  7.   /** Callback for getting notified of incoming packet. */
  8.   void (* input)(void);
  9. };
and in the following definition, network_driver is declared as NETSTACK_NETWORK. so we gotta find who uses NETSTACK_NETWORK.input. We may easily find it's csma.c, simply

  1. static void
  2. input_packet(void)
  3. {
  4.   NETSTACK_NETWORK.input();
  5. }
We find that

  1. const struct mac_driver csma_driver = {
  2.   "CSMA",
  3.   init,
  4.   send_packet,
  5.   input_packet,
  6.   on,
  7.   off,
  8.   channel_check_interval,
  9. };
and

  1. #ifndef NETSTACK_CONF_MAC
  2. #define NETSTACK_CONF_MAC csma_driver
  3. #endif /* NETSTACK_CONF_MAC */
and

  1. struct mac_driver {
  2.   char *name;
  3.  
  4.   /** Initialize the MAC driver */
  5.   void (* init)(void);
  6.  
  7.   /** Send a packet from the Rime buffer */
  8.   void (* send)(mac_callback_t sent_callback, void *ptr);
  9.  
  10.   /** Callback for getting notified of incoming packet. */
  11.   void (* input)(void);
  12.  
  13.   /** Turn the MAC layer on. */
  14.   int (* on)(void);
  15.  
  16.   /** Turn the MAC layer off. */
  17.   int (* off)(int keep_radio_on);
  18.  
  19.   /** Returns the channel check interval, expressed in clock_time_t ticks. */
  20.   unsigned short (* channel_check_interval)(void);
  21. };

Thus the lower guy must calls NETSTACK_MAC.input. This function is found at contikimac.c, which is specified as

  1. static void
  2. input_packet(void)
  3. {
  4.   /* We have received the packet, so we can go back to being
  5.      asleep. */
  6.   off();
  7.  
  8.   /* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/
  9.  
  10.  
  11.   if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) {
  12.  
  13. #if WITH_CONTIKIMAC_HEADER
  14.     struct hdr *chdr;
  15.     chdr = packetbuf_dataptr();
  16.     if(chdr->id != CONTIKIMAC_ID) {
  17.       PRINTF("contikimac: failed to parse hdr (%u)\n", packetbuf_totlen());
  18.       return;
  19.     }
  20.     packetbuf_hdrreduce(sizeof(struct hdr));
  21.     packetbuf_set_datalen(chdr->len);
  22. #endif /* WITH_CONTIKIMAC_HEADER */
  23.  
  24.     if(packetbuf_datalen() > 0 &&
  25.        packetbuf_totlen() > 0 &&
  26.        (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
  27.                      &rimeaddr_node_addr) ||
  28.         rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
  29.                      &rimeaddr_null))) {
  30.       /* This is a regular packet that is destined to us or to the
  31.          broadcast address. */
  32.  
  33. #if WITH_PHASE_OPTIMIZATION
  34.       /* If the sender has set its pending flag, it has its radio
  35.          turned on and we should drop the phase estimation that we
  36.          have from before. */
  37.       if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) {
  38.         phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER));
  39.       }
  40. #endif /* WITH_PHASE_OPTIMIZATION */
  41.  
  42.       /* Check for duplicate packet by comparing the sequence number
  43.          of the incoming packet with the last few ones we saw. */
  44.       {
  45.         int i;
  46.         for(i = 0; i < MAX_SEQNOS; ++i) {
  47.           if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
  48.              rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
  49.                           &received_seqnos[i].sender)) {
  50.             /* Drop the packet. */
  51.             /* printf("Drop duplicate ContikiMAC layer packet\n");*/
  52.             return;
  53.           }
  54.         }
  55.         for(i = MAX_SEQNOS - 1; i > 0; --i) {
  56.           memcpy(&received_seqnos[i], &received_seqnos[i - 1],
  57.                  sizeof(struct seqno));
  58.         }
  59.         received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
  60.         rimeaddr_copy(&received_seqnos[0].sender,
  61.                       packetbuf_addr(PACKETBUF_ADDR_SENDER));
  62.       }
  63.  
  64. #if CONTIKIMAC_CONF_COMPOWER
  65.       /* Accumulate the power consumption for the packet reception. */
  66.       compower_accumulate(&current_packet);
  67.       /* Convert the accumulated power consumption for the received
  68.          packet to packet attributes so that the higher levels can
  69.          keep track of the amount of energy spent on receiving the
  70.          packet. */
  71.       compower_attrconv(&current_packet);
  72.  
  73.       /* Clear the accumulated power consumption so that it is ready
  74.          for the next packet. */
  75.       compower_clear(&current_packet);
  76. #endif /* CONTIKIMAC_CONF_COMPOWER */
  77.  
  78.       PRINTDEBUG("contikimac: data (%u)\n", packetbuf_datalen());
  79.       NETSTACK_MAC.input();
  80.       return;
  81.     } else {
  82.       PRINTDEBUG("contikimac: data not for us\n");
  83.     }
  84.   } else {
  85.     PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen());
  86.   }
  87. }
Obviously this function does most of the packet parsing payload. and more over...

  1. const struct rdc_driver contikimac_driver = {
  2.   "ContikiMAC",
  3.   init,
  4.   qsend_packet,
  5.   input_packet,
  6.   turn_on,
  7.   turn_off,
  8.   duty_cycle,
  9. };
rdc_driver is located at the file rdc.h, which looks like

  1. struct rdc_driver {
  2.   char *name;
  3.  
  4.   /** Initialize the RDC driver */
  5.   void (* init)(void);
  6.  
  7.   /** Send a packet from the Rime buffer */
  8.   void (* send)(mac_callback_t sent_callback, void *ptr);
  9.  
  10.   /** Callback for getting notified of incoming packet. */
  11.   void (* input)(void);
  12.  
  13.   /** Turn the MAC layer on. */
  14.   int (* on)(void);
  15.  
  16.   /** Turn the MAC layer off. */
  17.   int (* off)(int keep_radio_on);
  18.  
  19.   /** Returns the channel check interval, expressed in clock_time_t ticks. */
  20.   unsigned short (* channel_check_interval)(void);
  21. };
Much similar to mac_driver, then the NETSTACK_RDC.input appears at...
cc2420.c! Finally we touched the lowest level!!!

  1. PROCESS_THREAD(cc2420_process, ev, data)
  2. {
  3.   int len;
  4.   PROCESS_BEGIN();
  5.  
  6.   PRINTF("cc2420_process: started\n");
  7.  
  8.   while(1) {
  9.     PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
  10. #if CC2420_TIMETABLE_PROFILING
  11.     TIMETABLE_TIMESTAMP(cc2420_timetable, "poll");
  12. #endif /* CC2420_TIMETABLE_PROFILING */
  13.  
  14.     PRINTF("cc2420_process: calling receiver callback\n");
  15.  
  16.     packetbuf_clear();
  17.     packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, last_packet_timestamp);
  18.     len = cc2420_read(packetbuf_dataptr(), PACKETBUF_SIZE);
  19.  
  20.     packetbuf_set_datalen(len);
  21.  
  22.     NETSTACK_RDC.input();
  23. #if CC2420_TIMETABLE_PROFILING
  24.     TIMETABLE_TIMESTAMP(cc2420_timetable, "end");
  25.     timetable_aggregate_compute_detailed(&aggregate_time,
  26.                                          &cc2420_timetable);
  27.       timetable_clear(&cc2420_timetable);
  28. #endif /* CC2420_TIMETABLE_PROFILING */
  29.   }
  30.  
  31.   PROCESS_END();
  32. }
上一篇:Contiki OS MICAz 平台开发
下一篇:基于mini2440 i2c总线之平台设备注册分析