Contiki 2.6

cc2520.c

00001 /*
00002  * Copyright (c) 2011, Swedish Institute of Computer Science
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  */
00031 /*
00032  * This code is almost device independent and should be easy to port.
00033  */
00034 
00035 #include "contiki.h"
00036 
00037 #include "dev/spi.h"
00038 #include "dev/cc2520.h"
00039 #include "dev/cc2520_const.h"
00040 
00041 #include "net/packetbuf.h"
00042 #include "net/rime/rimestats.h"
00043 #include "net/netstack.h"
00044 
00045 #include "sys/timetable.h"
00046 #include <string.h>
00047 
00048 #ifndef CC2520_CONF_AUTOACK
00049 #define CC2520_CONF_AUTOACK 0
00050 #endif /* CC2520_CONF_AUTOACK */
00051 
00052 #define WITH_SEND_CCA 1
00053 
00054 #define FOOTER_LEN 2
00055 
00056 #define FOOTER1_CRC_OK      0x80
00057 #define FOOTER1_CORRELATION 0x7f
00058 
00059 #include <stdio.h>
00060 #define DEBUG 0
00061 #if DEBUG
00062 #define PRINTF(...) printf(__VA_ARGS__)
00063 #else
00064 #define PRINTF(...) do {} while (0)
00065 #endif
00066 
00067 #if 0 && DEBUG
00068 #include "dev/leds.h"
00069 #define LEDS_ON(x) leds_on(x)
00070 #define LEDS_OFF(x) leds_off(x)
00071 #else
00072 #define LEDS_ON(x)
00073 #define LEDS_OFF(x)
00074 #endif
00075 
00076 void cc2520_arch_init(void);
00077 
00078 /* XXX hack: these will be made as Chameleon packet attributes */
00079 rtimer_clock_t cc2520_time_of_arrival, cc2520_time_of_departure;
00080 
00081 int cc2520_authority_level_of_sender;
00082 
00083 int cc2520_packets_seen, cc2520_packets_read;
00084 
00085 #define BUSYWAIT_UNTIL(cond, max_time)                                  \
00086   do {                                                                  \
00087     rtimer_clock_t t0;                                                  \
00088     t0 = RTIMER_NOW();                                                  \
00089     while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)));   \
00090   } while(0)
00091 
00092 volatile uint8_t cc2520_sfd_counter;
00093 volatile uint16_t cc2520_sfd_start_time;
00094 volatile uint16_t cc2520_sfd_end_time;
00095 
00096 static volatile uint16_t last_packet_timestamp;
00097 /*---------------------------------------------------------------------------*/
00098 PROCESS(cc2520_process, "CC2520 driver");
00099 /*---------------------------------------------------------------------------*/
00100 
00101 
00102 int cc2520_on(void);
00103 int cc2520_off(void);
00104 
00105 static int cc2520_read(void *buf, unsigned short bufsize);
00106 
00107 static int cc2520_prepare(const void *data, unsigned short len);
00108 static int cc2520_transmit(unsigned short len);
00109 static int cc2520_send(const void *data, unsigned short len);
00110 
00111 static int cc2520_receiving_packet(void);
00112 static int pending_packet(void);
00113 static int cc2520_cca(void);
00114 /* static int detected_energy(void); */
00115 
00116 signed char cc2520_last_rssi;
00117 uint8_t cc2520_last_correlation;
00118 
00119 const struct radio_driver cc2520_driver =
00120   {
00121     cc2520_init,
00122     cc2520_prepare,
00123     cc2520_transmit,
00124     cc2520_send,
00125     cc2520_read,
00126     /* cc2520_set_channel, */
00127     /* detected_energy, */
00128     cc2520_cca,
00129     cc2520_receiving_packet,
00130     pending_packet,
00131     cc2520_on,
00132     cc2520_off,
00133   };
00134 
00135 static uint8_t receive_on;
00136 
00137 static int channel;
00138 
00139 /*---------------------------------------------------------------------------*/
00140 
00141 static void
00142 getrxdata(void *buf, int len)
00143 {
00144   CC2520_READ_FIFO_BUF(buf, len);
00145 }
00146 static void
00147 getrxbyte(uint8_t *byte)
00148 {
00149   CC2520_READ_FIFO_BYTE(*byte);
00150 }
00151 static void
00152 flushrx(void)
00153 {
00154   uint8_t dummy;
00155 
00156   CC2520_READ_FIFO_BYTE(dummy);
00157   CC2520_STROBE(CC2520_INS_SFLUSHRX);
00158   CC2520_STROBE(CC2520_INS_SFLUSHRX);
00159 }
00160 /*---------------------------------------------------------------------------*/
00161 static void
00162 strobe(uint8_t regname)
00163 {
00164   CC2520_STROBE(regname);
00165 }
00166 /*---------------------------------------------------------------------------*/
00167 static unsigned int
00168 status(void)
00169 {
00170   uint8_t status;
00171   CC2520_GET_STATUS(status);
00172   return status;
00173 }
00174 /*---------------------------------------------------------------------------*/
00175 static uint8_t locked, lock_on, lock_off;
00176 
00177 static void
00178 on(void)
00179 {
00180   CC2520_ENABLE_FIFOP_INT();
00181   strobe(CC2520_INS_SRXON);
00182 
00183   BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 100);
00184 
00185   ENERGEST_ON(ENERGEST_TYPE_LISTEN);
00186   receive_on = 1;
00187 }
00188 static void
00189 off(void)
00190 {
00191   /*  PRINTF("off\n");*/
00192   receive_on = 0;
00193 
00194   /* Wait for transmission to end before turning radio off. */
00195   BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10);
00196 
00197   ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00198   strobe(CC2520_INS_SRFOFF);
00199   CC2520_DISABLE_FIFOP_INT();
00200 
00201   if(!CC2520_FIFOP_IS_1) {
00202     flushrx();
00203   }
00204 }
00205 /*---------------------------------------------------------------------------*/
00206 #define GET_LOCK() locked++
00207 static void RELEASE_LOCK(void) {
00208   if(locked == 1) {
00209     if(lock_on) {
00210       on();
00211       lock_on = 0;
00212     }
00213     if(lock_off) {
00214       off();
00215       lock_off = 0;
00216     }
00217   }
00218   locked--;
00219 }
00220 /*---------------------------------------------------------------------------*/
00221 static uint8_t
00222 getreg(uint16_t regname)
00223 {
00224   uint8_t reg;
00225   CC2520_READ_REG(regname, reg);
00226   return reg;
00227 }
00228 /*---------------------------------------------------------------------------*/
00229 static void
00230 setreg(uint16_t regname, uint8_t value)
00231 {
00232   CC2520_WRITE_REG(regname, value);
00233 }
00234 /*---------------------------------------------------------------------------*/
00235 static void
00236 set_txpower(uint8_t power)
00237 {
00238   setreg(CC2520_TXPOWER, power);
00239 }
00240 /*---------------------------------------------------------------------------*/
00241 #define AUTOCRC (1 << 6)
00242 #define AUTOACK (1 << 5)
00243 #define FRAME_MAX_VERSION ((1 << 3) | (1 << 2))
00244 #define FRAME_FILTER_ENABLE (1 << 0)
00245 #define CORR_THR(n) (((n) & 0x1f) << 6)
00246 #define FIFOP_THR(n) ((n) & 0x7f)
00247 /*---------------------------------------------------------------------------*/
00248 int
00249 cc2520_init(void)
00250 {
00251   {
00252     int s = splhigh();
00253     cc2520_arch_init();         /* Initalize ports and SPI. */
00254     CC2520_DISABLE_FIFOP_INT();
00255     CC2520_FIFOP_INT_INIT();
00256     splx(s);
00257   }
00258 
00259   SET_VREG_INACTIVE();
00260   clock_delay(250);
00261   /* Turn on voltage regulator and reset. */
00262   SET_VREG_ACTIVE();
00263   clock_delay(250);
00264   SET_RESET_ACTIVE();
00265   clock_delay(127);
00266   SET_RESET_INACTIVE();
00267   clock_delay(125);
00268   /* Turn on the crystal oscillator. */
00269   strobe(CC2520_INS_SXOSCON);
00270   clock_delay(125);
00271 
00272   BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 100);
00273 
00274   /* Change default values as recommended in the data sheet, */
00275   /* correlation threshold = 20, RX bandpass filter = 1.3uA.*/
00276 
00277   setreg(CC2520_TXCTRL,      0x94);
00278   setreg(CC2520_TXPOWER,     0x13);    // Output power 1 dBm
00279 
00280   /*
00281 
00282         valeurs de TXPOWER
00283           0x03 -> -18 dBm
00284           0x2C -> -7 dBm
00285           0x88 -> -4 dBm
00286           0x81 -> -2 dBm
00287           0x32 -> 0 dBm
00288           0x13 -> 1 dBm
00289           0x32 -> 0 dBm
00290           0x13 -> 1 dBm
00291           0xAB -> 2 dBm
00292           0xF2 -> 3 dBm
00293           0xF7 -> 5 dBm
00294   */
00295   setreg(CC2520_CCACTRL0,    0xF8);  // CCA treshold -80dBm
00296 
00297   // Recommended RX settings
00298   setreg(CC2520_MDMCTRL0,    0x84);  // Controls modem
00299   setreg(CC2520_MDMCTRL1,    0x14);  // Controls modem
00300   setreg(CC2520_RXCTRL,      0x3F);  // Adjust currents in RX related analog modules
00301   setreg(CC2520_FSCTRL,      0x5A);  // Adjust currents in synthesizer.
00302   setreg(CC2520_FSCAL1,      0x2B);  // Adjust currents in VCO
00303   setreg(CC2520_AGCCTRL1,    0x11);  // Adjust target value for AGC control loop
00304   setreg(CC2520_AGCCTRL2,    0xEB);
00305 
00306   //  Disable external clock
00307   setreg(CC2520_EXTCLOCK,    0x00);
00308 
00309   //  Tune ADC performance
00310   setreg(CC2520_ADCTEST0,    0x10);
00311   setreg(CC2520_ADCTEST1,    0x0E);
00312   setreg(CC2520_ADCTEST2,    0x03);
00313 
00314   /* Set auto CRC on frame. */
00315 #if CC2520_CONF_AUTOACK
00316   setreg(CC2520_FRMCTRL0,    AUTOCRC | AUTOACK);
00317   setreg(CC2520_FRMFILT0,    FRAME_MAX_VERSION|FRAME_FILTER_ENABLE);
00318 #else
00319   /* setreg(CC2520_FRMCTRL0,    0x60); */
00320   setreg(CC2520_FRMCTRL0,    AUTOCRC);
00321   /* Disable filter on @ (remove if you want to address specific wismote) */
00322   setreg(CC2520_FRMFILT0,    0x00);
00323 #endif /* CC2520_CONF_AUTOACK */
00324   /* SET_RXENMASK_ON_TX */
00325   setreg(CC2520_FRMCTRL1,          1);
00326   /* Set FIFOP threshold to maximum .*/
00327   setreg(CC2520_FIFOPCTRL,   FIFOP_THR(0x7F));
00328 
00329   cc2520_set_pan_addr(0xffff, 0x0000, NULL);
00330   cc2520_set_channel(26);
00331 
00332   flushrx();
00333 
00334   process_start(&cc2520_process, NULL);
00335   return 1;
00336 }
00337 /*---------------------------------------------------------------------------*/
00338 static int
00339 cc2520_transmit(unsigned short payload_len)
00340 {
00341   int i, txpower;
00342 
00343   GET_LOCK();
00344 
00345   txpower = 0;
00346   if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) {
00347     /* Remember the current transmission power */
00348     txpower = cc2520_get_txpower();
00349     /* Set the specified transmission power */
00350     set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1);
00351   }
00352 
00353   /* The TX FIFO can only hold one packet. Make sure to not overrun
00354    * FIFO by waiting for transmission to start here and synchronizing
00355    * with the CC2520_TX_ACTIVE check in cc2520_send.
00356    *
00357    * Note that we may have to wait up to 320 us (20 symbols) before
00358    * transmission starts.
00359    */
00360 #ifndef CC2520_CONF_SYMBOL_LOOP_COUNT
00361 #error CC2520_CONF_SYMBOL_LOOP_COUNT needs to be set!!!
00362 #else
00363 #define LOOP_20_SYMBOLS CC2520_CONF_SYMBOL_LOOP_COUNT
00364 #endif
00365 
00366 #if WITH_SEND_CCA
00367   strobe(CC2520_INS_SRXON);
00368   BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID) , RTIMER_SECOND / 10);
00369   strobe(CC2520_INS_STXONCCA);
00370 #else /* WITH_SEND_CCA */
00371   strobe(CC2520_INS_STXON);
00372 #endif /* WITH_SEND_CCA */
00373   for(i = LOOP_20_SYMBOLS; i > 0; i--) {
00374     if(CC2520_SFD_IS_1) {
00375       {
00376         rtimer_clock_t sfd_timestamp;
00377         sfd_timestamp = cc2520_sfd_start_time;
00378         if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00379            PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP) {
00380           /* Write timestamp to last two bytes of packet in TXFIFO. */
00381           CC2520_WRITE_RAM(&sfd_timestamp, CC2520RAM_TXFIFO + payload_len - 1, 2);
00382         }
00383       }
00384 
00385       if(!(status() & BV(CC2520_TX_ACTIVE))) {
00386         /* SFD went high but we are not transmitting. This means that
00387            we just started receiving a packet, so we drop the
00388            transmission. */
00389         RELEASE_LOCK();
00390         return RADIO_TX_COLLISION;
00391       }
00392       if(receive_on) {
00393         ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00394       }
00395       ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
00396       /* We wait until transmission has ended so that we get an
00397          accurate measurement of the transmission time.*/
00398      //BUSYWAIT_UNTIL(getreg(CC2520_EXCFLAG0) & TX_FRM_DONE , RTIMER_SECOND / 100);
00399       BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10);
00400 
00401 #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS
00402       ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2520_get_txpower());
00403 #endif
00404       ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
00405       if(receive_on) {
00406         ENERGEST_ON(ENERGEST_TYPE_LISTEN);
00407       } else {
00408         /* We need to explicitly turn off the radio,
00409          * since STXON[CCA] -> TX_ACTIVE -> RX_ACTIVE */
00410         off();
00411       }
00412 
00413       if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) {
00414         /* Restore the transmission power */
00415         set_txpower(txpower & 0xff);
00416       }
00417 
00418       RELEASE_LOCK();
00419 
00420       return RADIO_TX_OK;
00421     }
00422   }
00423 
00424   /* If we are using WITH_SEND_CCA, we get here if the packet wasn't
00425      transmitted because of other channel activity. */
00426   RIMESTATS_ADD(contentiondrop);
00427   PRINTF("cc2520: do_send() transmission never started\n");
00428 
00429   if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) {
00430     /* Restore the transmission power */
00431     set_txpower(txpower & 0xff);
00432   }
00433 
00434   RELEASE_LOCK();
00435   return RADIO_TX_COLLISION;
00436 }
00437 /*---------------------------------------------------------------------------*/
00438 static int
00439 cc2520_prepare(const void *payload, unsigned short payload_len)
00440 {
00441   uint8_t total_len;
00442   GET_LOCK();
00443 
00444   PRINTF("cc2520: sending %d bytes\n", payload_len);
00445   /*int i;
00446   for(i = 0; i < payload_len;i++)
00447           printf("%x",((uint8_t *) payload)[i]);
00448   printf("\n");*/
00449   RIMESTATS_ADD(lltx);
00450 
00451   /* Wait for any previous transmission to finish. */
00452   /*  while(status() & BV(CC2520_TX_ACTIVE));*/
00453 
00454   /* Write packet to TX FIFO. */
00455   strobe(CC2520_INS_SFLUSHTX);
00456 
00457   total_len = payload_len + FOOTER_LEN;
00458   CC2520_WRITE_FIFO_BUF(&total_len, 1);
00459   CC2520_WRITE_FIFO_BUF(payload, payload_len);
00460 
00461   RELEASE_LOCK();
00462   return 0;
00463 }
00464 /*---------------------------------------------------------------------------*/
00465 static int
00466 cc2520_send(const void *payload, unsigned short payload_len)
00467 {
00468   cc2520_prepare(payload, payload_len);
00469   return cc2520_transmit(payload_len);
00470 }
00471 /*---------------------------------------------------------------------------*/
00472 int
00473 cc2520_off(void)
00474 {
00475   /* Don't do anything if we are already turned off. */
00476   if(receive_on == 0) {
00477     return 1;
00478   }
00479 
00480   /* If we are called when the driver is locked, we indicate that the
00481      radio should be turned off when the lock is unlocked. */
00482   if(locked) {
00483     /*    printf("Off when locked (%d)\n", locked);*/
00484     lock_off = 1;
00485     return 1;
00486   }
00487 
00488   GET_LOCK();
00489   /* If we are currently receiving a packet (indicated by SFD == 1),
00490      we don't actually switch the radio off now, but signal that the
00491      driver should switch off the radio once the packet has been
00492      received and processed, by setting the 'lock_off' variable. */
00493   if(status() & BV(CC2520_TX_ACTIVE)) {
00494     lock_off = 1;
00495   } else {
00496     off();
00497   }
00498   RELEASE_LOCK();
00499   return 1;
00500 }
00501 /*---------------------------------------------------------------------------*/
00502 int
00503 cc2520_on(void)
00504 {
00505   if(receive_on) {
00506     return 1;
00507   }
00508   if(locked) {
00509     lock_on = 1;
00510     return 1;
00511   }
00512 
00513   GET_LOCK();
00514   on();
00515   RELEASE_LOCK();
00516   return 1;
00517 }
00518 /*---------------------------------------------------------------------------*/
00519 int
00520 cc2520_get_channel(void)
00521 {
00522   return channel;
00523 }
00524 /*---------------------------------------------------------------------------*/
00525 int
00526 cc2520_set_channel(int c)
00527 {
00528   uint16_t f;
00529 
00530   GET_LOCK();
00531   /*
00532    * Subtract the base channel (11), multiply by 5, which is the
00533    * channel spacing. 357 is 2405-2048 and 0x4000 is LOCK_THR = 1.
00534    */
00535   channel = c;
00536 
00537   f = MIN_CHANNEL + ((channel - MIN_CHANNEL) * CHANNEL_SPACING);
00538   /*
00539    * Writing RAM requires crystal oscillator to be stable.
00540    */
00541   BUSYWAIT_UNTIL((status() & (BV(CC2520_XOSC16M_STABLE))), RTIMER_SECOND / 10);
00542 
00543   /* Wait for any transmission to end. */
00544   BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10);
00545 
00546   /* Define radio channel (between 11 and 25) */
00547   setreg(CC2520_FREQCTRL, f);
00548 
00549   /* If we are in receive mode, we issue an SRXON command to ensure
00550      that the VCO is calibrated. */
00551   if(receive_on) {
00552     strobe(CC2520_INS_SRXON);
00553   }
00554 
00555   RELEASE_LOCK();
00556   return 1;
00557 }
00558 /*---------------------------------------------------------------------------*/
00559 void
00560 cc2520_set_pan_addr(unsigned pan,
00561                     unsigned addr,
00562                     const uint8_t *ieee_addr)
00563 {
00564   uint8_t tmp[2];
00565 
00566   GET_LOCK();
00567 
00568   /*
00569    * Writing RAM requires crystal oscillator to be stable.
00570    */
00571   BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 10);
00572 
00573   tmp[0] = pan & 0xff;
00574   tmp[1] = pan >> 8;
00575   CC2520_WRITE_RAM(&tmp, CC2520RAM_PANID, 2);
00576 
00577 
00578   tmp[0] = addr & 0xff;
00579   tmp[1] = addr >> 8;
00580   CC2520_WRITE_RAM(&tmp, CC2520RAM_SHORTADDR, 2);
00581   if(ieee_addr != NULL) {
00582     int f;
00583     uint8_t tmp_addr[8];
00584     // LSB first, MSB last for 802.15.4 addresses in CC2520
00585     for (f = 0; f < 8; f++) {
00586       tmp_addr[7 - f] = ieee_addr[f];
00587     }
00588     CC2520_WRITE_RAM(tmp_addr, CC2520RAM_IEEEADDR, 8);
00589   }
00590   RELEASE_LOCK();
00591 }
00592 /*---------------------------------------------------------------------------*/
00593 /*
00594  * Interrupt leaves frame intact in FIFO.
00595  */
00596 #if CC2520_TIMETABLE_PROFILING
00597 #define cc2520_timetable_size 16
00598 TIMETABLE(cc2520_timetable);
00599 TIMETABLE_AGGREGATE(aggregate_time, 10);
00600 #endif /* CC2520_TIMETABLE_PROFILING */
00601 int
00602 cc2520_interrupt(void)
00603 {
00604   CC2520_CLEAR_FIFOP_INT();
00605   process_poll(&cc2520_process);
00606 #if CC2520_TIMETABLE_PROFILING
00607   timetable_clear(&cc2520_timetable);
00608   TIMETABLE_TIMESTAMP(cc2520_timetable, "interrupt");
00609 #endif /* CC2520_TIMETABLE_PROFILING */
00610 
00611   last_packet_timestamp = cc2520_sfd_start_time;
00612   cc2520_packets_seen++;
00613   return 1;
00614 }
00615 /*---------------------------------------------------------------------------*/
00616 PROCESS_THREAD(cc2520_process, ev, data)
00617 {
00618   int len;
00619   PROCESS_BEGIN();
00620 
00621   PRINTF("cc2520_process: started\n");
00622 
00623   while(1) {
00624     PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
00625 #if CC2520_TIMETABLE_PROFILING
00626     TIMETABLE_TIMESTAMP(cc2520_timetable, "poll");
00627 #endif /* CC2520_TIMETABLE_PROFILING */
00628 
00629     PRINTF("cc2520_process: calling receiver callback\n");
00630 
00631     packetbuf_clear();
00632     packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, last_packet_timestamp);
00633     len = cc2520_read(packetbuf_dataptr(), PACKETBUF_SIZE);
00634     packetbuf_set_datalen(len);
00635 
00636     NETSTACK_RDC.input();
00637     /* flushrx(); */
00638 #if CC2520_TIMETABLE_PROFILING
00639     TIMETABLE_TIMESTAMP(cc2520_timetable, "end");
00640     timetable_aggregate_compute_detailed(&aggregate_time,
00641                                          &cc2520_timetable);
00642     timetable_clear(&cc2520_timetable);
00643 #endif /* CC2520_TIMETABLE_PROFILING */
00644   }
00645 
00646   PROCESS_END();
00647 }
00648 /*---------------------------------------------------------------------------*/
00649 static int
00650 cc2520_read(void *buf, unsigned short bufsize)
00651 {
00652   uint8_t footer[2];
00653   uint8_t len;
00654 
00655   if(!CC2520_FIFOP_IS_1) {
00656     return 0;
00657   }
00658 
00659   GET_LOCK();
00660 
00661   cc2520_packets_read++;
00662 
00663   getrxbyte(&len);
00664 
00665   if(len > CC2520_MAX_PACKET_LEN) {
00666     /* Oops, we must be out of sync. */
00667     flushrx();
00668     RIMESTATS_ADD(badsynch);
00669     RELEASE_LOCK();
00670     return 0;
00671   }
00672 
00673   if(len <= FOOTER_LEN) {
00674     flushrx();
00675     RIMESTATS_ADD(tooshort);
00676     RELEASE_LOCK();
00677     return 0;
00678   }
00679 
00680   if(len - FOOTER_LEN > bufsize) {
00681     flushrx();
00682     RIMESTATS_ADD(toolong);
00683     RELEASE_LOCK();
00684     return 0;
00685   }
00686 
00687   getrxdata(buf, len - FOOTER_LEN);
00688   getrxdata(footer, FOOTER_LEN);
00689 
00690   if(footer[1] & FOOTER1_CRC_OK) {
00691     cc2520_last_rssi = footer[0];
00692     cc2520_last_correlation = footer[1] & FOOTER1_CORRELATION;
00693 
00694 
00695     packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2520_last_rssi);
00696     packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2520_last_correlation);
00697 
00698     RIMESTATS_ADD(llrx);
00699 
00700   } else {
00701     RIMESTATS_ADD(badcrc);
00702     len = FOOTER_LEN;
00703   }
00704 
00705   if(CC2520_FIFOP_IS_1) {
00706     if(!CC2520_FIFO_IS_1) {
00707       /* Clean up in case of FIFO overflow!  This happens for every
00708        * full length frame and is signaled by FIFOP = 1 and FIFO =
00709        * 0. */
00710       flushrx();
00711     } else {
00712       /* Another packet has been received and needs attention. */
00713       process_poll(&cc2520_process);
00714     }
00715   }
00716 
00717   RELEASE_LOCK();
00718 
00719   if(len < FOOTER_LEN) {
00720     return 0;
00721   }
00722 
00723   return len - FOOTER_LEN;
00724 }
00725 /*---------------------------------------------------------------------------*/
00726 void
00727 cc2520_set_txpower(uint8_t power)
00728 {
00729   GET_LOCK();
00730   set_txpower(power);
00731   RELEASE_LOCK();
00732 }
00733 /*---------------------------------------------------------------------------*/
00734 int
00735 cc2520_get_txpower(void)
00736 {
00737   uint8_t power;
00738   GET_LOCK();
00739   power = getreg(CC2520_TXPOWER);
00740   RELEASE_LOCK();
00741   return power;
00742 }
00743 /*---------------------------------------------------------------------------*/
00744 int
00745 cc2520_rssi(void)
00746 {
00747   int rssi;
00748   int radio_was_off = 0;
00749 
00750   if(locked) {
00751     return 0;
00752   }
00753 
00754   GET_LOCK();
00755 
00756   if(!receive_on) {
00757     radio_was_off = 1;
00758     cc2520_on();
00759   }
00760   BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID), RTIMER_SECOND / 100);
00761 
00762   rssi = (int)((signed char)getreg(CC2520_RSSI));
00763 
00764   if(radio_was_off) {
00765     cc2520_off();
00766   }
00767   RELEASE_LOCK();
00768   return rssi;
00769 }
00770 /*---------------------------------------------------------------------------*/
00771 /*
00772 static int
00773 detected_energy(void)
00774 {
00775   return cc2520_rssi();
00776 }
00777 */
00778 /*---------------------------------------------------------------------------*/
00779 int
00780 cc2520_cca_valid(void)
00781 {
00782   int valid;
00783   if(locked) {
00784     return 1;
00785   }
00786   GET_LOCK();
00787   valid = !!(status() & BV(CC2520_RSSI_VALID));
00788   RELEASE_LOCK();
00789   return valid;
00790 }
00791 /*---------------------------------------------------------------------------*/
00792 static int
00793 cc2520_cca(void)
00794 {
00795   int cca;
00796   int radio_was_off = 0;
00797 
00798   /* If the radio is locked by an underlying thread (because we are
00799      being invoked through an interrupt), we preted that the coast is
00800      clear (i.e., no packet is currently being transmitted by a
00801      neighbor). */
00802   if(locked) {
00803     return 1;
00804   }
00805 
00806   GET_LOCK();
00807   if(!receive_on) {
00808     radio_was_off = 1;
00809     cc2520_on();
00810   }
00811 
00812   /* Make sure that the radio really got turned on. */
00813   if(!receive_on) {
00814     RELEASE_LOCK();
00815     if(radio_was_off) {
00816       cc2520_off();
00817     }
00818     return 1;
00819   }
00820 
00821   BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID), RTIMER_SECOND / 100);
00822 
00823   cca = CC2520_CCA_IS_1;
00824 
00825   if(radio_was_off) {
00826     cc2520_off();
00827   }
00828   RELEASE_LOCK();
00829   return cca;
00830 }
00831 /*---------------------------------------------------------------------------*/
00832 int
00833 cc2520_receiving_packet(void)
00834 {
00835   return CC2520_SFD_IS_1;
00836 }
00837 /*---------------------------------------------------------------------------*/
00838 static int
00839 pending_packet(void)
00840 {
00841   return CC2520_FIFOP_IS_1;
00842 }
00843 /*---------------------------------------------------------------------------*/
00844 void
00845 cc2520_set_cca_threshold(int value)
00846 {
00847   GET_LOCK();
00848   setreg(CC2520_CCACTRL0, value & 0xff);
00849   RELEASE_LOCK();
00850 }
00851 /*---------------------------------------------------------------------------*/