Contiki-Inga 3.x
cc2530-rf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, George Oikonomou - <oikonomou@users.sourceforge.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * Implementation of the cc2530 RF driver
35  *
36  * \author
37  * George Oikonomou - <oikonomou@users.sourceforge.net>
38  */
39 #include "contiki.h"
40 #include "dev/radio.h"
41 #include "dev/cc2530-rf.h"
42 #include "cc253x.h"
43 #include "sfr-bits.h"
44 #include "sys/clock.h"
45 #include "sys/rtimer.h"
46 
47 #include "net/packetbuf.h"
48 #include "net/rime/rimestats.h"
49 #include "net/linkaddr.h"
50 #include "net/netstack.h"
51 
52 #include <string.h>
53 /*---------------------------------------------------------------------------*/
54 #define CHECKSUM_LEN 2
55 /*---------------------------------------------------------------------------*/
56 #if CC2530_RF_CONF_LEDS
57 #define CC2530_RF_LEDS CC2530_RF_CONF_LEDS
58 #else
59 #define CC2530_RF_LEDS 0
60 #endif
61 
62 #if CC2530_RF_LEDS
63 #include "dev/leds.h"
64 #define RF_RX_LED_ON() leds_on(LEDS_RED);
65 #define RF_RX_LED_OFF() leds_off(LEDS_RED);
66 #define RF_TX_LED_ON() leds_on(LEDS_GREEN);
67 #define RF_TX_LED_OFF() leds_off(LEDS_GREEN);
68 #else
69 #define RF_RX_LED_ON()
70 #define RF_RX_LED_OFF()
71 #define RF_TX_LED_ON()
72 #define RF_TX_LED_OFF()
73 #endif
74 /*---------------------------------------------------------------------------*/
75 #define DEBUG 0
76 #if DEBUG
77 #include "debug.h"
78 #define PUTSTRING(...) putstring(__VA_ARGS__)
79 #define PUTHEX(...) puthex(__VA_ARGS__)
80 #else
81 #define PUTSTRING(...)
82 #define PUTHEX(...)
83 #endif
84 /*---------------------------------------------------------------------------*/
85 /* Local RF Flags */
86 #define RX_ACTIVE 0x80
87 #define WAS_OFF 0x10
88 #define RF_ON 0x01
89 
90 /* Bit Masks for the last byte in the RX FIFO */
91 #define CRC_BIT_MASK 0x80
92 #define LQI_BIT_MASK 0x7F
93 /* RSSI Offset */
94 #define RSSI_OFFSET 73
95 
96 /* 192 ms, radio off -> on interval */
97 #define ONOFF_TIME RTIMER_ARCH_SECOND / 3125
98 
99 /*---------------------------------------------------------------------------*/
100 #if CC2530_RF_CONF_HEXDUMP
101 #include "dev/io-arch.h"
102 static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /* Snif */
103 #endif
104 /*---------------------------------------------------------------------------*/
105 #ifdef CC2530_RF_CONF_AUTOACK
106 #define CC2530_RF_AUTOACK CC2530_RF_CONF_AUTOACK
107 #else
108 #define CC2530_RF_AUTOACK 1
109 #endif
110 /*---------------------------------------------------------------------------*/
111 static uint8_t CC_AT_DATA rf_flags;
112 
113 static int on(void); /* prepare() needs our prototype */
114 static int off(void); /* transmit() needs our prototype */
115 static int channel_clear(void); /* transmit() needs our prototype */
116 /*---------------------------------------------------------------------------*/
117 int8_t
118 cc2530_rf_channel_set(uint8_t channel)
119 {
120  PUTSTRING("RF: Set Chan\n");
121 
122  if((channel < CC2530_RF_CHANNEL_MIN) || (channel > CC2530_RF_CHANNEL_MAX)) {
123  return -1;
124  }
125 
126  /* Changes to FREQCTRL take effect after the next recalibration */
127  off();
128  FREQCTRL = (CC2530_RF_CHANNEL_MIN
129  + (channel - CC2530_RF_CHANNEL_MIN) * CC2530_RF_CHANNEL_SPACING);
130  on();
131 
132  return (int8_t) channel;
133 }
134 /*---------------------------------------------------------------------------*/
135 uint8_t
136 cc2530_rf_power_set(uint8_t new_power)
137 {
138  PUTSTRING("RF: Set Power\n");
139  /* off() */
140  TXPOWER = new_power;
141  /* on() */
142 
143  return TXPOWER;
144 }
145 /*---------------------------------------------------------------------------*/
146 void
147 cc2530_rf_set_addr(uint16_t pan)
148 {
149 #if LINKADDR_SIZE==8 /* EXT_ADDR[7:0] is ignored when using short addresses */
150  int i;
151  for(i = (LINKADDR_SIZE - 1); i >= 0; --i) {
152  ((uint8_t *)&EXT_ADDR0)[i] = linkaddr_node_addr.u8[LINKADDR_SIZE - 1 - i];
153  }
154 #endif
155 
156  PAN_ID0 = pan & 0xFF;
157  PAN_ID1 = pan >> 8;
158 
159  SHORT_ADDR0 = linkaddr_node_addr.u8[LINKADDR_SIZE - 1];
160  SHORT_ADDR1 = linkaddr_node_addr.u8[LINKADDR_SIZE - 2];
161 }
162 /*---------------------------------------------------------------------------*/
163 /* Netstack API radio driver functions */
164 /*---------------------------------------------------------------------------*/
165 static int
166 init(void)
167 {
168  PUTSTRING("RF: Init\n");
169 
170  if(rf_flags & RF_ON) {
171  return 0;
172  }
173 
174 #if CC2530_RF_LOW_POWER_RX
175  /* Reduce RX power consumption current to 20mA at the cost of sensitivity */
176  RXCTRL = 0x00;
177  FSCTRL = 0x50;
178 #else
179  RXCTRL = 0x3F;
180  FSCTRL = 0x55;
181 #endif /* CC2530_RF_LOW_POWER_RX */
182 
183  CCACTRL0 = CC2530_RF_CCA_THRES;
184 
185  /*
186  * According to the user guide, these registers must be updated from their
187  * defaults for optimal performance
188  *
189  * Table 23-6, Sec. 23.15.1, p. 259
190  */
191  TXFILTCFG = 0x09; /* TX anti-aliasing filter */
192  AGCCTRL1 = 0x15; /* AGC target value */
193  FSCAL1 = 0x00; /* Reduce the VCO leakage */
194 
195  /* Auto ACKs and CRC calculation, default RX and TX modes with FIFOs */
196  FRMCTRL0 = FRMCTRL0_AUTOCRC;
197 #if CC2530_RF_AUTOACK
198  FRMCTRL0 |= FRMCTRL0_AUTOACK;
199 #endif
200 
201  /* Disable source address matching and autopend */
202  SRCMATCH = 0; /* investigate */
203 
204  /* MAX FIFOP threshold */
205  FIFOPCTRL = CC2530_RF_MAX_PACKET_LEN;
206 
207  cc2530_rf_power_set(CC2530_RF_TX_POWER);
208  cc2530_rf_channel_set(CC2530_RF_CHANNEL);
209 
210  RF_TX_LED_OFF();
211  RF_RX_LED_OFF();
212 
213  rf_flags |= RF_ON;
214 
215  return 1;
216 }
217 /*---------------------------------------------------------------------------*/
218 static int
219 prepare(const void *payload, unsigned short payload_len)
220 {
221  uint8_t i;
222 
223  PUTSTRING("RF: Prepare 0x");
224  PUTHEX(payload_len + CHECKSUM_LEN);
225  PUTSTRING(" bytes\n");
226 
227  /*
228  * When we transmit in very quick bursts, make sure previous transmission
229  * is not still in progress before re-writing to the TX FIFO
230  */
231  while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
232 
233  if((rf_flags & RX_ACTIVE) == 0) {
234  on();
235  }
236 
237  CC2530_CSP_ISFLUSHTX();
238 
239  PUTSTRING("RF: data = ");
240  /* Send the phy length byte first */
241  RFD = payload_len + CHECKSUM_LEN; /* Payload plus FCS */
242  for(i = 0; i < payload_len; i++) {
243  RFD = ((unsigned char *)(payload))[i];
244  PUTHEX(((unsigned char *)(payload))[i]);
245  }
246  PUTSTRING("\n");
247 
248  /* Leave space for the FCS */
249  RFD = 0;
250  RFD = 0;
251 
252  return 0;
253 }
254 /*---------------------------------------------------------------------------*/
255 static int
256 transmit(unsigned short transmit_len)
257 {
258  uint8_t counter;
259  int ret = RADIO_TX_ERR;
260  rtimer_clock_t t0;
261  transmit_len; /* hush the warning */
262 
263  if(!(rf_flags & RX_ACTIVE)) {
264  t0 = RTIMER_NOW();
265  on();
266  rf_flags |= WAS_OFF;
267  while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
268  }
269 
270  if(channel_clear() == CC2530_RF_CCA_BUSY) {
271  RIMESTATS_ADD(contentiondrop);
272  return RADIO_TX_COLLISION;
273  }
274 
275  /*
276  * prepare() double checked that TX_ACTIVE is low. If SFD is high we are
277  * receiving. Abort transmission and bail out with RADIO_TX_COLLISION
278  */
279  if(FSMSTAT1 & FSMSTAT1_SFD) {
280  RIMESTATS_ADD(contentiondrop);
281  return RADIO_TX_COLLISION;
282  }
283 
284  /* Start the transmission */
285  RF_TX_LED_ON();
286  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
287  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
288 
289  CC2530_CSP_ISTXON();
290 
291  counter = 0;
292  while(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE) && (counter++ < 3)) {
293  clock_delay_usec(6);
294  }
295 
296  if(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE)) {
297  PUTSTRING("RF: TX never active.\n");
298  CC2530_CSP_ISFLUSHTX();
299  ret = RADIO_TX_ERR;
300  } else {
301  /* Wait for the transmission to finish */
302  while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
303  ret = RADIO_TX_OK;
304  }
305  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
306  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
307 
308  if(rf_flags & WAS_OFF) {
309  off();
310  }
311 
312  RIMESTATS_ADD(lltx);
313 
314  RF_TX_LED_OFF();
315 
316  /* OK, sent. We are now ready to send more */
317  return ret;
318 }
319 /*---------------------------------------------------------------------------*/
320 static int
321 send(void *payload, unsigned short payload_len)
322 {
323  prepare(payload, payload_len);
324  return transmit(payload_len);
325 }
326 /*---------------------------------------------------------------------------*/
327 static int
328 read(void *buf, unsigned short bufsize)
329 {
330  uint8_t i;
331  uint8_t len;
332  uint8_t crc_corr;
333  int8_t rssi;
334 
335  PUTSTRING("RF: Read\n");
336 
337  /* Check the length */
338  len = RFD;
339 
340  /* Check for validity */
341  if(len > CC2530_RF_MAX_PACKET_LEN) {
342  /* Oops, we must be out of sync. */
343  PUTSTRING("RF: bad sync\n");
344 
345  RIMESTATS_ADD(badsynch);
346  CC2530_CSP_ISFLUSHRX();
347  return 0;
348  }
349 
350  if(len <= CC2530_RF_MIN_PACKET_LEN) {
351  PUTSTRING("RF: too short\n");
352 
353  RIMESTATS_ADD(tooshort);
354  CC2530_CSP_ISFLUSHRX();
355  return 0;
356  }
357 
358  if(len - CHECKSUM_LEN > bufsize) {
359  PUTSTRING("RF: too long\n");
360 
361  RIMESTATS_ADD(toolong);
362  CC2530_CSP_ISFLUSHRX();
363  return 0;
364  }
365 
366 #if CC2530_RF_CONF_HEXDUMP
367  /* If we reach here, chances are the FIFO is holding a valid frame */
368  io_arch_writeb(magic[0]);
369  io_arch_writeb(magic[1]);
370  io_arch_writeb(magic[2]);
371  io_arch_writeb(magic[3]);
372  io_arch_writeb(len);
373 #endif
374 
375  RF_RX_LED_ON();
376 
377  PUTSTRING("RF: read (0x");
378  PUTHEX(len);
379  PUTSTRING(" bytes) = ");
380  len -= CHECKSUM_LEN;
381  for(i = 0; i < len; ++i) {
382  ((unsigned char *)(buf))[i] = RFD;
383 #if CC2530_RF_CONF_HEXDUMP
384  io_arch_writeb(((unsigned char *)(buf))[i]);
385 #endif
386  PUTHEX(((unsigned char *)(buf))[i]);
387  }
388  PUTSTRING("\n");
389 
390  /* Read the RSSI and CRC/Corr bytes */
391  rssi = ((int8_t) RFD) - RSSI_OFFSET;
392  crc_corr = RFD;
393 
394 #if CC2530_RF_CONF_HEXDUMP
395  io_arch_writeb(rssi);
396  io_arch_writeb(crc_corr);
397  io_arch_flush();
398 #endif
399 
400  /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
401  if(crc_corr & CRC_BIT_MASK) {
402  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
403  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
404  RIMESTATS_ADD(llrx);
405  } else {
406  RIMESTATS_ADD(badcrc);
407  CC2530_CSP_ISFLUSHRX();
408  RF_RX_LED_OFF();
409  return 0;
410  }
411 
412  /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */
413  if((FSMSTAT1 & (FSMSTAT1_FIFO | FSMSTAT1_FIFOP)) == FSMSTAT1_FIFOP) {
414  /*
415  * If we reach here means that there might be more intact packets in the
416  * FIFO despite the overflow. This can happen with bursts of small packets.
417  *
418  * Only flush if the FIFO is actually empty. If not, then next pass we will
419  * pick up one more packet or flush due to an error.
420  */
421  if(!RXFIFOCNT) {
422  CC2530_CSP_ISFLUSHRX();
423  }
424  }
425 
426  RF_RX_LED_OFF();
427 
428  return (len);
429 }
430 /*---------------------------------------------------------------------------*/
431 static int
432 channel_clear(void)
433 {
434  if(FSMSTAT1 & FSMSTAT1_CCA) {
435  return CC2530_RF_CCA_CLEAR;
436  }
437  return CC2530_RF_CCA_BUSY;
438 }
439 /*---------------------------------------------------------------------------*/
440 static int
441 receiving_packet(void)
442 {
443  PUTSTRING("RF: Receiving\n");
444 
445  /*
446  * SFD high while transmitting and receiving.
447  * TX_ACTIVE high only when transmitting
448  *
449  * FSMSTAT1 & (TX_ACTIVE | SFD) == SFD <=> receiving
450  */
451  return (FSMSTAT1 & (FSMSTAT1_TX_ACTIVE | FSMSTAT1_SFD) == FSMSTAT1_SFD);
452 }
453 /*---------------------------------------------------------------------------*/
454 static int
455 pending_packet(void)
456 {
457  return (FSMSTAT1 & FSMSTAT1_FIFOP);
458 }
459 /*---------------------------------------------------------------------------*/
460 static int
461 on(void)
462 {
463  if(!(rf_flags & RX_ACTIVE)) {
464  CC2530_CSP_ISFLUSHRX();
465  CC2530_CSP_ISRXON();
466 
467  rf_flags |= RX_ACTIVE;
468  }
469 
470  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
471  return 1;
472 }
473 /*---------------------------------------------------------------------------*/
474 static int
475 off(void)
476 {
477  CC2530_CSP_ISRFOFF();
478  CC2530_CSP_ISFLUSHRX();
479 
480  rf_flags &= ~RX_ACTIVE;
481 
482  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
483  return 1;
484 }
485 /*---------------------------------------------------------------------------*/
486 const struct radio_driver cc2530_rf_driver = {
487  init,
488  prepare,
489  transmit,
490  send,
491  read,
495  on,
496  off,
497 };
498 /*---------------------------------------------------------------------------*/