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.-
static const struct abc_callbacks broadcast = {recv_from_abc, sent_by_abc};
-
static void
-
recv_from_abc(struct abc_conn *bc)
-
{
-
rimeaddr_t sender;
-
struct broadcast_conn *c = (struct broadcast_conn *)bc;
-
rimeaddr_copy(&sender, packetbuf_addr(PACKETBUF_ADDR_SENDER));
-
c->u->recv(c, &sender);
- }
-
struct abc_callbacks {
-
void (* recv)(struct abc_conn *ptr);
-
void (* sent)(struct abc_conn *ptr, int status, int num_tx);
-
};
-
-
struct abc_conn {
-
struct channel channel;
-
const struct abc_callbacks *u;
- };
-
void
-
abc_open(struct abc_conn *c, uint16_t channelno,
-
const struct abc_callbacks *callbacks)
-
{
-
channel_open(&c->channel, channelno);
-
c->u = callbacks;
-
channel_set_attributes(channelno, attributes);
-
}
-
-
void
-
abc_input(struct channel *channel)
-
{
-
struct abc_conn *c = (struct abc_conn *)channel;
-
c->u->recv(c);
- }
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
-
static void
-
input(void)
-
{
-
struct rime_sniffer *s;
-
struct channel *c;
-
-
RIMESTATS_ADD(rx);
-
c = chameleon_parse();
-
-
for(s = list_head(sniffers); s != NULL; s = list_item_next(s)) {
-
if(s->input_callback != NULL) {
-
s->input_callback();
-
}
-
}
-
-
if(c != NULL) {
-
abc_input(c);
-
}
- }
-
const struct network_driver rime_driver = {
-
"Rime",
-
init,
-
input
- };
-
struct network_driver {
-
char *name;
-
-
/** Initialize the network driver */
-
void (* init)(void);
-
-
/** Callback for getting notified of incoming packet. */
-
void (* input)(void);
- };
-
static void
-
input_packet(void)
-
{
-
NETSTACK_NETWORK.input();
- }
-
const struct mac_driver csma_driver = {
-
"CSMA",
-
init,
-
send_packet,
-
input_packet,
-
on,
-
off,
-
channel_check_interval,
- };
-
#ifndef NETSTACK_CONF_MAC
-
#define NETSTACK_CONF_MAC csma_driver
- #endif /* NETSTACK_CONF_MAC */
-
struct mac_driver {
-
char *name;
-
-
/** Initialize the MAC driver */
-
void (* init)(void);
-
-
/** Send a packet from the Rime buffer */
-
void (* send)(mac_callback_t sent_callback, void *ptr);
-
-
/** Callback for getting notified of incoming packet. */
-
void (* input)(void);
-
-
/** Turn the MAC layer on. */
-
int (* on)(void);
-
-
/** Turn the MAC layer off. */
-
int (* off)(int keep_radio_on);
-
-
/** Returns the channel check interval, expressed in clock_time_t ticks. */
-
unsigned short (* channel_check_interval)(void);
- };
Thus the lower guy must calls NETSTACK_MAC.input. This function is found at contikimac.c, which is specified as
-
static void
-
input_packet(void)
-
{
-
/* We have received the packet, so we can go back to being
-
asleep. */
-
off();
-
-
/* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/
-
-
-
if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) {
-
-
#if WITH_CONTIKIMAC_HEADER
-
struct hdr *chdr;
-
chdr = packetbuf_dataptr();
-
if(chdr->id != CONTIKIMAC_ID) {
-
PRINTF("contikimac: failed to parse hdr (%u)\n", packetbuf_totlen());
-
return;
-
}
-
packetbuf_hdrreduce(sizeof(struct hdr));
-
packetbuf_set_datalen(chdr->len);
-
#endif /* WITH_CONTIKIMAC_HEADER */
-
-
if(packetbuf_datalen() > 0 &&
-
packetbuf_totlen() > 0 &&
-
(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
-
&rimeaddr_node_addr) ||
-
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
-
&rimeaddr_null))) {
-
/* This is a regular packet that is destined to us or to the
-
broadcast address. */
-
-
#if WITH_PHASE_OPTIMIZATION
-
/* If the sender has set its pending flag, it has its radio
-
turned on and we should drop the phase estimation that we
-
have from before. */
-
if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) {
-
phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER));
-
}
-
#endif /* WITH_PHASE_OPTIMIZATION */
-
-
/* Check for duplicate packet by comparing the sequence number
-
of the incoming packet with the last few ones we saw. */
-
{
-
int i;
-
for(i = 0; i < MAX_SEQNOS; ++i) {
-
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
-
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
-
&received_seqnos[i].sender)) {
-
/* Drop the packet. */
-
/* printf("Drop duplicate ContikiMAC layer packet\n");*/
-
return;
-
}
-
}
-
for(i = MAX_SEQNOS - 1; i > 0; --i) {
-
memcpy(&received_seqnos[i], &received_seqnos[i - 1],
-
sizeof(struct seqno));
-
}
-
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
-
rimeaddr_copy(&received_seqnos[0].sender,
-
packetbuf_addr(PACKETBUF_ADDR_SENDER));
-
}
-
-
#if CONTIKIMAC_CONF_COMPOWER
-
/* Accumulate the power consumption for the packet reception. */
-
compower_accumulate(¤t_packet);
-
/* Convert the accumulated power consumption for the received
-
packet to packet attributes so that the higher levels can
-
keep track of the amount of energy spent on receiving the
-
packet. */
-
compower_attrconv(¤t_packet);
-
-
/* Clear the accumulated power consumption so that it is ready
-
for the next packet. */
-
compower_clear(¤t_packet);
-
#endif /* CONTIKIMAC_CONF_COMPOWER */
-
-
PRINTDEBUG("contikimac: data (%u)\n", packetbuf_datalen());
-
NETSTACK_MAC.input();
-
return;
-
} else {
-
PRINTDEBUG("contikimac: data not for us\n");
-
}
-
} else {
-
PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen());
-
}
- }
-
const struct rdc_driver contikimac_driver = {
-
"ContikiMAC",
-
init,
-
qsend_packet,
-
input_packet,
-
turn_on,
-
turn_off,
-
duty_cycle,
- };
-
struct rdc_driver {
-
char *name;
-
-
/** Initialize the RDC driver */
-
void (* init)(void);
-
-
/** Send a packet from the Rime buffer */
-
void (* send)(mac_callback_t sent_callback, void *ptr);
-
-
/** Callback for getting notified of incoming packet. */
-
void (* input)(void);
-
-
/** Turn the MAC layer on. */
-
int (* on)(void);
-
-
/** Turn the MAC layer off. */
-
int (* off)(int keep_radio_on);
-
-
/** Returns the channel check interval, expressed in clock_time_t ticks. */
-
unsigned short (* channel_check_interval)(void);
- };
cc2420.c! Finally we touched the lowest level!!!
-
PROCESS_THREAD(cc2420_process, ev, data)
-
{
-
int len;
-
PROCESS_BEGIN();
-
-
PRINTF("cc2420_process: started\n");
-
-
while(1) {
-
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
-
#if CC2420_TIMETABLE_PROFILING
-
TIMETABLE_TIMESTAMP(cc2420_timetable, "poll");
-
#endif /* CC2420_TIMETABLE_PROFILING */
-
-
PRINTF("cc2420_process: calling receiver callback\n");
-
-
packetbuf_clear();
-
packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, last_packet_timestamp);
-
len = cc2420_read(packetbuf_dataptr(), PACKETBUF_SIZE);
-
-
packetbuf_set_datalen(len);
-
-
NETSTACK_RDC.input();
-
#if CC2420_TIMETABLE_PROFILING
-
TIMETABLE_TIMESTAMP(cc2420_timetable, "end");
-
timetable_aggregate_compute_detailed(&aggregate_time,
-
&cc2420_timetable);
-
timetable_clear(&cc2420_timetable);
-
#endif /* CC2420_TIMETABLE_PROFILING */
-
}
-
-
PROCESS_END();
- }