A work-in-progress rework of the Contiki MAC and radio layers. The

main ideas are:

* Separates the Contiki low-layer network stack into four layers:
  network (e.g. sicslowpan / rime), Medium Access Control MAC
  (e.g. CSMA), Radio Duty Cycling RDC (e.g. ContikiMAC, X-MAC), and
  radio (e.g. cc2420).
* Introduces a new way to configure the network stack. Four #defines
  that specify what mechanism/protocol/driver to use at the four
  layers: NETSTACK_CONF_NETWORK, NETSTACK_CONF_MAC, NETSTACK_CONF_RDC,
  NETSTACK_CONF_RADIO.
* Adds a callback mechanism to inform the MAC and network layers about
  the fate of a transmitted packet: if the packet was not possible to
  transmit, the cause of the failure is reported, and if the packets
  was successfully transmitted, the number of tries before it was
  finally transmitted is reported.
* NULL-protocols at both the MAC and RDC layers: nullmac and nullrdc,
  which can be used when MAC and RDC functionality is not needed.
* Extends the radio API with three new functions that enable more
  efficient radio duty cycling protocols: channel check, pending
  packet, and receiving packet.
* New initialization mechanism, which takes advantage of the NETSTACK
  #defines.
This commit is contained in:
adamdunkels 2010-02-18 21:48:39 +00:00
parent 1817acae15
commit e34eb54960
29 changed files with 1176 additions and 768 deletions

View file

@ -28,7 +28,7 @@
*
* This file is part of the Contiki operating system.
*
* @(#)$Id: cc2420.c,v 1.37 2010/01/14 23:32:05 adamdunkels Exp $
* @(#)$Id: cc2420.c,v 1.38 2010/02/18 21:48:39 adamdunkels Exp $
*/
/*
* This code is almost device independent and should be easy to port.
@ -52,11 +52,13 @@
#include "net/rime/packetbuf.h"
#include "net/rime/rimestats.h"
#include "net/netstack.h"
#include "sys/timetable.h"
#define WITH_SEND_CCA 0
#include "cc2420-arch-sfd.h"
#if CC2420_CONF_TIMESTAMPS
#include "net/rime/timesynch.h"
@ -112,30 +114,41 @@ static unsigned long total_time_for_transmission, total_transmission_len;
static int num_transmissions;
#endif /* CC2420_CONF_TIMESTAMPS */
int cc2420_packets_seen, cc2420_packets_read;
static uint8_t volatile pending;
/*---------------------------------------------------------------------------*/
PROCESS(cc2420_process, "CC2420 driver");
/*---------------------------------------------------------------------------*/
static void (* receiver_callback)(const struct radio_driver *);
int cc2420_on(void);
int cc2420_off(void);
int cc2420_read(void *buf, unsigned short bufsize);
static int cc2420_read(void *buf, unsigned short bufsize);
int cc2420_send(const void *data, unsigned short len);
void cc2420_set_receiver(void (* recv)(const struct radio_driver *d));
static int cc2420_prepare(const void *data, unsigned short len);
static int cc2420_transmit(unsigned short len);
static int cc2420_send(const void *data, unsigned short len);
static int cc2420_receiving_packet(void);
static int pending_packet(void);
static int cc2420_cca(void);
signed char cc2420_last_rssi;
uint8_t cc2420_last_correlation;
const struct radio_driver cc2420_driver =
{
cc2420_init,
cc2420_prepare,
cc2420_transmit,
cc2420_send,
cc2420_read,
cc2420_set_receiver,
cc2420_cca,
cc2420_receiving_packet,
pending_packet,
cc2420_on,
cc2420_off,
};
@ -257,13 +270,7 @@ set_txpower(uint8_t power)
#define FIFOP_THR(n) ((n) & 0x7f)
#define RXBPF_LOCUR (1 << 13);
/*---------------------------------------------------------------------------*/
void
cc2420_set_receiver(void (* recv)(const struct radio_driver *))
{
receiver_callback = recv;
}
/*---------------------------------------------------------------------------*/
void
int
cc2420_init(void)
{
uint16_t reg;
@ -315,10 +322,11 @@ cc2420_init(void)
cc2420_set_channel(26);
process_start(&cc2420_process, NULL);
return 1;
}
/*---------------------------------------------------------------------------*/
int
cc2420_send(const void *payload, unsigned short payload_len)
static int
cc2420_transmit(unsigned short payload_len)
{
int i, txpower;
uint8_t total_len;
@ -328,6 +336,7 @@ cc2420_send(const void *payload, unsigned short payload_len)
#if CC2420_CONF_CHECKSUM
uint16_t checksum;
#endif /* CC2420_CONF_CHECKSUM */
GET_LOCK();
txpower = 0;
@ -338,32 +347,8 @@ cc2420_send(const void *payload, unsigned short payload_len)
set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1);
}
PRINTF("cc2420: sending %d bytes\n", payload_len);
RIMESTATS_ADD(lltx);
/* Wait for any previous transmission to finish. */
while(status() & BV(CC2420_TX_ACTIVE));
/* Write packet to TX FIFO. */
strobe(CC2420_SFLUSHTX);
#if CC2420_CONF_CHECKSUM
checksum = crc16_data(payload, payload_len, 0);
#endif /* CC2420_CONF_CHECKSUM */
total_len = payload_len + AUX_LEN;
FASTSPI_WRITE_FIFO(&total_len, 1);
FASTSPI_WRITE_FIFO(payload, payload_len);
#if CC2420_CONF_CHECKSUM
FASTSPI_WRITE_FIFO(&checksum, CHECKSUM_LEN);
#endif /* CC2420_CONF_CHECKSUM */
#if CC2420_CONF_TIMESTAMPS
timestamp.authority_level = timesynch_authority_level();
timestamp.time = timesynch_time();
FASTSPI_WRITE_FIFO(&timestamp, TIMESTAMP_LEN);
#endif /* CC2420_CONF_TIMESTAMPS */
/* The TX FIFO can only hold one packet. Make sure to not overrun
* FIFO by waiting for transmission to start here and synchronizing
* with the CC2420_TX_ACTIVE check in cc2420_send.
@ -387,12 +372,6 @@ cc2420_send(const void *payload, unsigned short payload_len)
for(i = LOOP_20_SYMBOLS; i > 0; i--) {
if(SFD_IS_1) {
if(!(status() & BV(CC2420_TX_ACTIVE))) {
/* SFD went high yet we are not transmitting!
* => We started receiving a packet right now */
return RADIO_TX_ERR;
}
#if CC2420_CONF_TIMESTAMPS
rtimer_clock_t txtime = timesynch_time();
#endif /* CC2420_CONF_TIMESTAMPS */
@ -435,7 +414,7 @@ cc2420_send(const void *payload, unsigned short payload_len)
}
RELEASE_LOCK();
return RADIO_TX_OK;
return 0;
}
}
@ -450,7 +429,56 @@ cc2420_send(const void *payload, unsigned short payload_len)
}
RELEASE_LOCK();
return RADIO_TX_ERR; /* Transmission never started! */
return -3; /* Transmission never started! */
}
/*---------------------------------------------------------------------------*/
static int
cc2420_prepare(const void *payload, unsigned short payload_len)
{
uint8_t total_len;
#if CC2420_CONF_TIMESTAMPS
struct timestamp timestamp;
#endif /* CC2420_CONF_TIMESTAMPS */
#if CC2420_CONF_CHECKSUM
uint16_t checksum;
#endif /* CC2420_CONF_CHECKSUM */
GET_LOCK();
PRINTF("cc2420: sending %d bytes\n", payload_len);
RIMESTATS_ADD(lltx);
/* Wait for any previous transmission to finish. */
while(status() & BV(CC2420_TX_ACTIVE));
/* Write packet to TX FIFO. */
strobe(CC2420_SFLUSHTX);
#if CC2420_CONF_CHECKSUM
checksum = crc16_data(payload, payload_len, 0);
#endif /* CC2420_CONF_CHECKSUM */
total_len = payload_len + AUX_LEN;
FASTSPI_WRITE_FIFO(&total_len, 1);
FASTSPI_WRITE_FIFO(payload, payload_len);
#if CC2420_CONF_CHECKSUM
FASTSPI_WRITE_FIFO(&checksum, CHECKSUM_LEN);
#endif /* CC2420_CONF_CHECKSUM */
#if CC2420_CONF_TIMESTAMPS
timestamp.authority_level = timesynch_authority_level();
timestamp.time = timesynch_time();
FASTSPI_WRITE_FIFO(&timestamp, TIMESTAMP_LEN);
#endif /* CC2420_CONF_TIMESTAMPS */
RELEASE_LOCK();
return 0;
}
/*---------------------------------------------------------------------------*/
static int
cc2420_send(const void *payload, unsigned short payload_len)
{
cc2420_prepare(payload, payload_len);
return cc2420_transmit(payload_len);
}
/*---------------------------------------------------------------------------*/
int
@ -534,8 +562,8 @@ cc2420_set_channel(int c)
/*---------------------------------------------------------------------------*/
void
cc2420_set_pan_addr(unsigned pan,
unsigned addr,
const uint8_t *ieee_addr)
unsigned addr,
const uint8_t *ieee_addr)
{
uint16_t f = 0;
/*
@ -572,10 +600,8 @@ int
cc2420_interrupt(void)
{
#if CC2420_CONF_TIMESTAMPS
if(!interrupt_time_set) {
interrupt_time = timesynch_time();
interrupt_time_set = 1;
}
interrupt_time = timesynch_time();
interrupt_time_set = 1;
#endif /* CC2420_CONF_TIMESTAMPS */
CLEAR_FIFOP_INT();
@ -584,11 +610,16 @@ cc2420_interrupt(void)
timetable_clear(&cc2420_timetable);
TIMETABLE_TIMESTAMP(cc2420_timetable, "interrupt");
#endif /* CC2420_TIMETABLE_PROFILING */
pending = 1;
cc2420_packets_seen++;
return 1;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(cc2420_process, ev, data)
{
int len;
PROCESS_BEGIN();
PRINTF("cc2420_process: started\n");
@ -599,25 +630,28 @@ PROCESS_THREAD(cc2420_process, ev, data)
TIMETABLE_TIMESTAMP(cc2420_timetable, "poll");
#endif /* CC2420_TIMETABLE_PROFILING */
if(receiver_callback != NULL) {
PRINTF("cc2420_process: calling receiver callback\n");
receiver_callback(&cc2420_driver);
pending = 0;
PRINTF("cc2420_process: calling receiver callback\n");
packetbuf_clear();
len = cc2420_read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(len > 0) {
packetbuf_set_datalen(len);
NETSTACK_RDC.input();
#if CC2420_TIMETABLE_PROFILING
TIMETABLE_TIMESTAMP(cc2420_timetable, "end");
timetable_aggregate_compute_detailed(&aggregate_time,
&cc2420_timetable);
&cc2420_timetable);
timetable_clear(&cc2420_timetable);
#endif /* CC2420_TIMETABLE_PROFILING */
} else {
PRINTF("cc2420_process not receiving function\n");
flushrx();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
int
static int
cc2420_read(void *buf, unsigned short bufsize)
{
uint8_t footer[2];
@ -630,12 +664,23 @@ cc2420_read(void *buf, unsigned short bufsize)
#endif /* CC2420_CONF_TIMESTAMPS */
if(!FIFOP_IS_1) {
/* If FIFO is 0, there is no packet in the RXFIFO. */
/* If FIFOP is 0, there is no packet in the RXFIFO. */
return 0;
}
#if CC2420_CONF_TIMESTAMPS
if(interrupt_time_set) {
cc2420_time_of_arrival = interrupt_time;
interrupt_time_set = 0;
} else {
cc2420_time_of_arrival = 0;
}
cc2420_time_of_departure = 0;
#endif /* CC2420_CONF_TIMESTAMPS */
GET_LOCK();
cc2420_packets_read++;
getrxbyte(&len);
if(len > CC2420_MAX_PACKET_LEN) {
@ -647,6 +692,7 @@ cc2420_read(void *buf, unsigned short bufsize)
}
if(len <= AUX_LEN) {
printf("len <= AUX_LEN\n");
flushrx();
RIMESTATS_ADD(tooshort);
RELEASE_LOCK();
@ -654,6 +700,7 @@ cc2420_read(void *buf, unsigned short bufsize)
}
if(len - AUX_LEN > bufsize) {
printf("len - AUX_LEN > bufsize\n");
flushrx();
RIMESTATS_ADD(toolong);
RELEASE_LOCK();
@ -690,19 +737,12 @@ cc2420_read(void *buf, unsigned short bufsize)
RIMESTATS_ADD(llrx);
#if CC2420_CONF_TIMESTAMPS
if(interrupt_time_set) {
cc2420_time_of_arrival = interrupt_time;
cc2420_time_of_departure =
t.time +
setup_time_for_transmission +
(total_time_for_transmission * (len - 2)) / total_transmission_len;
cc2420_authority_level_of_sender = t.authority_level;
interrupt_time_set = 0;
} else {
/* Bypass timesynch */
cc2420_authority_level_of_sender = timesynch_authority_level();
}
cc2420_time_of_departure =
t.time +
setup_time_for_transmission +
(total_time_for_transmission * (len - 2)) / total_transmission_len;
cc2420_authority_level_of_sender = t.authority_level;
packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, t.time);
#endif /* CC2420_CONF_TIMESTAMPS */
@ -720,6 +760,7 @@ cc2420_read(void *buf, unsigned short bufsize)
flushrx();
} else if(FIFOP_IS_1) {
/* Another packet has been received and needs attention. */
/* printf("attention\n");*/
process_poll(&cc2420_process);
}
@ -768,3 +809,67 @@ cc2420_rssi(void)
return rssi;
}
/*---------------------------------------------------------------------------*/
static int
cc2420_cca(void)
{
int cca;
int radio_was_off = 0;
/* If the radio is locked by an underlying thread (because we are
being invoked through an interrupt), we preted that the coast is
clear (i.e., no packet is currently being transmitted by a
neighbor). */
if(locked) {
return 1;
}
if(!receive_on) {
radio_was_off = 1;
cc2420_on();
}
while(!(status() & BV(CC2420_RSSI_VALID))) {
/* printf("cc2420_rssi: RSSI not valid.\n"); */
}
cca = CCA_IS_1;
if(radio_was_off) {
cc2420_off();
}
return cca;
}
/*---------------------------------------------------------------------------*/
int
cc2420_receiving_packet(void)
{
return SFD_IS_1;
}
/*---------------------------------------------------------------------------*/
static int
pending_packet(void)
{
return pending;
}
/*---------------------------------------------------------------------------*/
void
cc2420_ugly_hack_send_only_one_symbol(void)
{
uint8_t len;
GET_LOCK();
/* Write packet to TX FIFO. */
strobe(CC2420_SFLUSHTX);
len = 1;
FASTSPI_WRITE_FIFO(&len, 1);
FASTSPI_WRITE_FIFO(&len, 1);
strobe(CC2420_STXON);
while(!SFD_IS_1);
/* Turn radio off immediately after sending the first symbol. */
strobe(CC2420_SRFOFF);
RELEASE_LOCK();
return;
}
/*---------------------------------------------------------------------------*/