2009-09-08 22:07:35 +02:00
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
* CC2430 RF driver
|
|
|
|
* \author
|
2012-03-05 17:28:06 +01:00
|
|
|
* Zach Shelby <zach@sensinode.com> (Original)
|
|
|
|
* George Oikonomou - <oikonomou@users.sourceforge.net>
|
|
|
|
* (port to the netstack API, hexdump output, RX FIFO overflow fixes
|
|
|
|
* code cleanup, ...)
|
2010-01-26 00:12:09 +01:00
|
|
|
*
|
|
|
|
* bankable code for cc2430 rf driver. this code can be placed in any bank.
|
|
|
|
*
|
2009-09-08 22:07:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "contiki.h"
|
|
|
|
#include "dev/radio.h"
|
|
|
|
#include "dev/cc2430_rf.h"
|
|
|
|
#include "cc2430_sfr.h"
|
|
|
|
#include "sys/clock.h"
|
2012-03-05 17:28:06 +01:00
|
|
|
#include "sys/rtimer.h"
|
2009-09-08 22:07:35 +02:00
|
|
|
|
2010-06-14 21:19:16 +02:00
|
|
|
#include "net/packetbuf.h"
|
2009-09-08 22:07:35 +02:00
|
|
|
#include "net/rime/rimestats.h"
|
2012-03-05 17:28:06 +01:00
|
|
|
#include "net/netstack.h"
|
2009-09-08 22:07:35 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
#define CC2430_RF_TX_POWER_RECOMMENDED 0x5F
|
|
|
|
#ifdef CC2430_RF_CONF_TX_POWER
|
|
|
|
#define CC2430_RF_TX_POWER CC2430_RF_CONF_TX_POWER
|
|
|
|
#else
|
|
|
|
#define CC2430_RF_TX_POWER CC2430_RF_TX_POWER_RECOMMENDED
|
2009-09-08 22:07:35 +02:00
|
|
|
#endif
|
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
#ifdef CC2430_RF_CONF_CHANNEL
|
|
|
|
#define CC2430_RF_CHANNEL CC2430_RF_CONF_CHANNEL
|
|
|
|
#else
|
|
|
|
#define CC2430_RF_CHANNEL 18
|
|
|
|
#endif /* CC2430_RF_CONF_CHANNEL */
|
|
|
|
#define CC2430_CHANNEL_MIN 11
|
|
|
|
#define CC2430_CHANNEL_MAX 26
|
|
|
|
|
|
|
|
#ifdef CC2430_RF_CONF_AUTOACK
|
|
|
|
#define CC2430_RF_AUTOACK CC2430_RF_CONF_AUTOACK
|
|
|
|
#else
|
|
|
|
#define CC2430_RF_AUTOACK 1
|
2009-09-08 22:07:35 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CC2430_CONF_CHECKSUM
|
|
|
|
#define CC2430_CONF_CHECKSUM 0
|
|
|
|
#endif /* CC2420_CONF_CHECKSUM */
|
|
|
|
|
|
|
|
#if CC2430_CONF_CHECKSUM
|
|
|
|
#include "lib/crc16.h"
|
|
|
|
#define CHECKSUM_LEN 2
|
|
|
|
#else
|
2009-10-15 14:43:53 +02:00
|
|
|
#define CHECKSUM_LEN 2
|
2009-09-08 22:07:35 +02:00
|
|
|
#endif /* CC2430_CONF_CHECKSUM */
|
2010-01-29 20:15:44 +01:00
|
|
|
#if DEBUG_LEDS
|
|
|
|
/* moved leds code to BANK1 to make space for cc2430_rf_process in HOME */
|
|
|
|
/* can't call code in BANK1 from alternate banks unless it is marked with __banked */
|
|
|
|
#include "dev/leds.h"
|
2012-03-05 17:28:06 +01:00
|
|
|
#define RF_RX_LED_ON() leds_on(LEDS_RED);
|
|
|
|
#define RF_RX_LED_OFF() leds_off(LEDS_RED);
|
|
|
|
#define RF_TX_LED_ON() leds_on(LEDS_GREEN);
|
|
|
|
#define RF_TX_LED_OFF() leds_off(LEDS_GREEN);
|
2010-01-29 20:15:44 +01:00
|
|
|
#else
|
2012-03-05 17:28:06 +01:00
|
|
|
#define RF_RX_LED_ON()
|
|
|
|
#define RF_RX_LED_OFF()
|
|
|
|
#define RF_TX_LED_ON()
|
|
|
|
#define RF_TX_LED_OFF()
|
2010-01-29 20:15:44 +01:00
|
|
|
#endif
|
2010-04-10 21:59:37 +02:00
|
|
|
#define DEBUG 0
|
2009-09-08 22:07:35 +02:00
|
|
|
#if DEBUG
|
|
|
|
#define PRINTF(...) printf(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define PRINTF(...) do {} while (0)
|
|
|
|
#endif
|
|
|
|
|
2012-04-30 18:21:23 +02:00
|
|
|
/* rf_flags bits */
|
|
|
|
#define RX_ACTIVE 0x80
|
|
|
|
#define TX_ACK 0x40
|
|
|
|
#define TX_ON_AIR 0x20
|
|
|
|
#define WAS_OFF 0x10
|
|
|
|
#define INITIALISED 0x01
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
#define RX_NO_DMA
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Bits of the last byte in the RX FIFO */
|
|
|
|
#define CRC_BIT_MASK 0x80
|
|
|
|
#define LQI_BIT_MASK 0x7F
|
|
|
|
|
|
|
|
/* 192 ms, radio off -> on interval */
|
|
|
|
#define ONOFF_TIME ((RTIMER_ARCH_SECOND / 3125) + 4)
|
|
|
|
|
|
|
|
#if CC2430_RF_CONF_HEXDUMP
|
|
|
|
#include "uart1.h"
|
|
|
|
static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /* Snif */
|
|
|
|
#endif
|
2009-09-08 22:07:35 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_RF_ERROR
|
|
|
|
uint8_t rf_error = 0;
|
|
|
|
#endif
|
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2012-03-05 17:28:06 +01:00
|
|
|
PROCESS(cc2430_rf_process, "CC2430 RF driver");
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-09-07 15:48:15 +02:00
|
|
|
static uint8_t CC_AT_DATA rf_flags;
|
2012-04-30 18:04:55 +02:00
|
|
|
static uint8_t rf_channel;
|
2009-09-08 22:07:35 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
static int on(void); /* prepare() needs our prototype */
|
|
|
|
static int off(void); /* transmit() needs our prototype */
|
|
|
|
static int channel_clear(void); /* transmit() needs our prototype */
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
/**
|
|
|
|
* Execute a single CSP command.
|
|
|
|
*
|
|
|
|
* \param command command to execute
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cc2430_rf_command(uint8_t command)
|
|
|
|
{
|
|
|
|
if(command >= 0xE0) { /*immediate strobe*/
|
|
|
|
uint8_t fifo_count;
|
|
|
|
switch (command) { /*hardware bug workaround*/
|
|
|
|
case ISRFOFF:
|
|
|
|
case ISRXON:
|
|
|
|
case ISTXON:
|
|
|
|
fifo_count = RXFIFOCNT;
|
|
|
|
RFST = command;
|
2012-04-30 14:30:34 +02:00
|
|
|
clock_delay_usec(2);
|
2012-03-05 17:28:06 +01:00
|
|
|
if(fifo_count != RXFIFOCNT) {
|
|
|
|
RFST = ISFLUSHRX;
|
|
|
|
RFST = ISFLUSHRX;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
RFST = command;
|
|
|
|
}
|
|
|
|
} else if(command == SSTART) {
|
|
|
|
RFIF &= ~IRQ_CSP_STOP; /*clear IRQ flag*/
|
|
|
|
RFST = SSTOP; /*make sure there is a stop in the end*/
|
|
|
|
RFST = ISSTART; /*start execution*/
|
|
|
|
while((RFIF & IRQ_CSP_STOP) == 0);
|
|
|
|
} else {
|
|
|
|
RFST = command; /*write command*/
|
|
|
|
}
|
|
|
|
}
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
static void
|
|
|
|
flush_rx()
|
|
|
|
{
|
|
|
|
cc2430_rf_command(ISFLUSHRX);
|
|
|
|
cc2430_rf_command(ISFLUSHRX);
|
2009-09-08 22:07:35 +02:00
|
|
|
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2012-03-05 17:28:06 +01:00
|
|
|
IEN2 |= RFIE;
|
|
|
|
#endif
|
|
|
|
#if CC2430_RFERR_INTERRUPT
|
|
|
|
IEN0 |= RFERRIE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
RFIF &= ~IRQ_FIFOP;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* Select RF channel.
|
|
|
|
*
|
|
|
|
* \param channel channel number to select
|
|
|
|
*
|
|
|
|
* \return channel value or negative (invalid channel number)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* channel freqdiv = (2048 + FSCTRL(9:0)) / 4
|
|
|
|
freq = (2048 + FSCTRL(9:0)) MHz */
|
|
|
|
|
|
|
|
int8_t
|
|
|
|
cc2430_rf_channel_set(uint8_t channel)
|
|
|
|
{
|
|
|
|
uint16_t freq;
|
|
|
|
|
|
|
|
if((channel < 11) || (channel > 26)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc2430_rf_command(ISSTOP); /*make sure CSP is not running*/
|
|
|
|
cc2430_rf_command(ISRFOFF);
|
|
|
|
/* Channel values: 11-26 */
|
|
|
|
freq = (uint16_t) channel - 11;
|
|
|
|
freq *= 5; /*channel spacing*/
|
|
|
|
freq += 357; /*correct channel range*/
|
|
|
|
freq |= 0x4000; /*LOCK_THR = 1*/
|
|
|
|
FSCTRLH = (freq >> 8);
|
|
|
|
FSCTRLL = (uint8_t)freq;
|
|
|
|
|
|
|
|
cc2430_rf_command(ISRXON);
|
|
|
|
|
2012-04-30 18:04:55 +02:00
|
|
|
rf_channel = channel;
|
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
return (int8_t) channel;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-04-30 18:04:55 +02:00
|
|
|
uint8_t
|
|
|
|
cc2430_rf_channel_get()
|
|
|
|
{
|
|
|
|
return rf_channel;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
/**
|
|
|
|
* Select RF transmit power.
|
|
|
|
*
|
|
|
|
* \param new_power new power level
|
|
|
|
*
|
|
|
|
* \return new level
|
|
|
|
*/
|
|
|
|
uint8_t
|
|
|
|
cc2430_rf_power_set(uint8_t new_power)
|
|
|
|
{
|
|
|
|
/* Set transmitter power */
|
|
|
|
TXCTRLL = new_power;
|
|
|
|
|
|
|
|
return TXCTRLL;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#if 0 /* unused */
|
|
|
|
/**
|
|
|
|
* Enable RF transmitter.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* \return pdTRUE
|
|
|
|
* \return pdFALSE bus not free
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
cc2430_rf_tx_enable(void)
|
|
|
|
{
|
|
|
|
DMAARM = 0x80 + (1 << 0); /*ABORT + channel bit*/
|
2009-09-08 22:07:35 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
/**
|
|
|
|
* Set MAC addresses
|
|
|
|
*
|
|
|
|
* \param pan The PAN address to set
|
2012-04-20 11:45:34 +02:00
|
|
|
* \param addr The short address to set
|
2012-03-05 17:28:06 +01:00
|
|
|
* \param ieee_addr The 64-bit IEEE address to set
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cc2430_rf_set_addr(unsigned pan, unsigned addr, const uint8_t *ieee_addr)
|
|
|
|
{
|
|
|
|
uint8_t f;
|
|
|
|
__xdata unsigned char *ptr;
|
|
|
|
|
|
|
|
PANIDH = pan >> 8;
|
|
|
|
PANIDL = pan & 0xff;
|
|
|
|
|
|
|
|
SHORTADDRH = addr >> 8;
|
|
|
|
SHORTADDRL = addr & 0xff;
|
|
|
|
|
|
|
|
if(ieee_addr != NULL) {
|
|
|
|
ptr = &IEEE_ADDR7;
|
|
|
|
/* LSB first, MSB last for 802.15.4 addresses in CC2420 */
|
|
|
|
for (f = 0; f < 8; f++) {
|
|
|
|
*ptr-- = ieee_addr[f];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if 0 /* currently unused */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* Channel energy detect.
|
|
|
|
*
|
|
|
|
* Coordinator use this function detect best channel for PAN-network.
|
|
|
|
* \return RSSI-energy level dBm.
|
|
|
|
* \return 0 operation failed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int8_t
|
|
|
|
cc2430_rf_analyze_rssi(void)
|
|
|
|
{
|
|
|
|
int8_t retval = -128;
|
|
|
|
/*pause_us(128);*/
|
|
|
|
|
|
|
|
retval = (int8_t)RSSIL;
|
|
|
|
retval -= 45;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif /* currently unused */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* Send ACK.
|
|
|
|
*
|
|
|
|
*\param pending set up pending flag if pending > 0.
|
|
|
|
*/
|
2009-09-08 22:07:35 +02:00
|
|
|
void
|
2012-03-05 17:28:06 +01:00
|
|
|
cc2430_rf_send_ack(uint8_t pending)
|
|
|
|
{
|
|
|
|
if(pending) {
|
|
|
|
cc2430_rf_command(ISACKPEND);
|
|
|
|
} else {
|
|
|
|
cc2430_rf_command(ISACK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Netstack API radio driver functions */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
|
|
init(void)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-04-30 18:21:23 +02:00
|
|
|
if(rf_flags & INITIALISED) {
|
2012-03-05 17:28:06 +01:00
|
|
|
return 0;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("cc2430_rf_init called\n");
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
RFPWR &= ~RREG_RADIO_PD; /*make sure it's powered*/
|
2009-09-08 22:07:35 +02:00
|
|
|
while((RFPWR & ADI_RADIO_PD) == 1);
|
2012-03-05 17:28:06 +01:00
|
|
|
while((RFIF & IRQ_RREG_ON) == 0); /*wait for power up*/
|
2009-09-08 22:07:35 +02:00
|
|
|
SLEEP &= ~OSC_PD; /*Osc on*/
|
2012-03-05 17:28:06 +01:00
|
|
|
while((SLEEP & XOSC_STB) == 0); /*wait for power up*/
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
rf_flags = 0;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
FSMTC1 = 1; /*don't abort reception, if enable called, accept ack, auto rx after tx*/
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
MDMCTRL0H = 0x0A; /* Generic client, standard hysteresis, decoder on 0x0a */
|
|
|
|
MDMCTRL0L = 0xE2; /* automatic CRC, standard CCA and preamble 0xE2 */
|
|
|
|
#if CC2430_RF_AUTOACK
|
|
|
|
MDMCTRL0L |= 0x10;
|
|
|
|
#endif
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
MDMCTRL1H = 0x30; /* Defaults */
|
2009-09-08 22:07:35 +02:00
|
|
|
MDMCTRL1L = 0x0;
|
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
RXCTRL0H = 0x32; /* RX tuning optimized */
|
2009-09-08 22:07:35 +02:00
|
|
|
RXCTRL0L = 0xf5;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
cc2430_rf_channel_set(CC2430_RF_CHANNEL);
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISFLUSHTX);
|
|
|
|
cc2430_rf_command(ISFLUSHRX);
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Temporary values, main() will sort this out later on */
|
2009-09-11 10:07:12 +02:00
|
|
|
cc2430_rf_set_addr(0xffff, 0x0000, NULL);
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
RFIM = IRQ_FIFOP;
|
|
|
|
RFIF &= ~(IRQ_FIFOP);
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
S1CON &= ~(RFIF_0 | RFIF_1);
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2009-09-08 22:07:35 +02:00
|
|
|
IEN2 |= RFIE;
|
2012-03-05 17:28:06 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If contiki-conf.h turns on the RFERR interrupt, enable it here */
|
|
|
|
#if CC2430_RFERR_INTERRUPT
|
|
|
|
IEN0 |= RFERRIE;
|
|
|
|
#endif
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
RF_TX_LED_OFF();
|
|
|
|
RF_RX_LED_OFF();
|
2012-04-30 18:21:23 +02:00
|
|
|
|
|
|
|
rf_flags |= INITIALISED;
|
2012-03-05 17:28:06 +01:00
|
|
|
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2009-09-08 22:07:35 +02:00
|
|
|
process_start(&cc2430_rf_process, NULL);
|
2012-03-05 17:28:06 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
cc2430_rf_power_set(CC2430_RF_TX_POWER);
|
|
|
|
|
|
|
|
return 1;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
static int
|
|
|
|
prepare(const void *payload, unsigned short payload_len)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
uint8_t i;
|
|
|
|
/*
|
|
|
|
* When we transmit in very quick bursts, make sure previous transmission
|
|
|
|
* is not still in progress before re-writing in the TX FIFO
|
|
|
|
*/
|
|
|
|
while(RFSTATUS & TX_ACTIVE);
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
if(rf_flags & TX_ACK) {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-05 17:28:06 +01:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
if((rf_flags & RX_ACTIVE) == 0) {
|
2012-03-05 17:28:06 +01:00
|
|
|
on();
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
PRINTF("cc2430_rf: sending %u byte payload\n", payload_len);
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISFLUSHTX);
|
2012-03-05 17:28:06 +01:00
|
|
|
PRINTF("cc2430_rf: data = ");
|
2009-10-15 14:43:53 +02:00
|
|
|
/* Send the phy length byte first */
|
2012-03-05 17:28:06 +01:00
|
|
|
RFD = payload_len + CHECKSUM_LEN; /* Payload plus FCS */
|
2009-10-15 14:43:53 +02:00
|
|
|
PRINTF("(%d)", payload_len+CHECKSUM_LEN);
|
2012-03-05 17:28:06 +01:00
|
|
|
for(i = 0; i < payload_len; i++) {
|
|
|
|
RFD = ((unsigned char*) (payload))[i];
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("%02X", ((unsigned char*)(payload))[i]);
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("\n");
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-10-15 14:43:53 +02:00
|
|
|
/* Leave space for the FCS */
|
|
|
|
RFD = 0;
|
|
|
|
RFD = 0;
|
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
|
|
transmit(unsigned short transmit_len)
|
|
|
|
{
|
|
|
|
uint8_t counter;
|
|
|
|
int ret = RADIO_TX_ERR;
|
|
|
|
|
|
|
|
if(!(rf_flags & RX_ACTIVE)) {
|
|
|
|
on();
|
|
|
|
rf_flags |= WAS_OFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(channel_clear() == CC2430_CCA_BUSY) {
|
|
|
|
RIMESTATS_ADD(contentiondrop);
|
|
|
|
return RADIO_TX_COLLISION;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prepare() double checked that TX_ACTIVE is low. If SFD is high we are
|
|
|
|
* receiving. Abort transmission and bail out with RADIO_TX_COLLISION
|
|
|
|
*/
|
|
|
|
if(RFSTATUS & SFD) {
|
|
|
|
RIMESTATS_ADD(contentiondrop);
|
|
|
|
return RADIO_TX_COLLISION;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
/* Start the transmission */
|
2012-03-05 17:28:06 +01:00
|
|
|
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
|
|
|
ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISTXON);
|
|
|
|
counter = 0;
|
|
|
|
while(!(RFSTATUS & TX_ACTIVE) && (counter++ < 3)) {
|
2012-04-30 14:30:34 +02:00
|
|
|
clock_delay_usec(6);
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
if(!(RFSTATUS & TX_ACTIVE)) {
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("cc2430_rf: TX never active.\n");
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISFLUSHTX);
|
2012-03-05 17:28:06 +01:00
|
|
|
ret = RADIO_TX_ERR;
|
2009-09-08 22:07:35 +02:00
|
|
|
} else {
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Wait for the transmission to finish */
|
|
|
|
while(RFSTATUS & TX_ACTIVE);
|
2009-09-08 22:07:35 +02:00
|
|
|
RF_RX_LED_OFF();
|
|
|
|
RF_TX_LED_ON();
|
2012-03-05 17:28:06 +01:00
|
|
|
ret = RADIO_TX_OK;
|
2009-09-08 22:07:35 +02:00
|
|
|
// rf_flags |= TX_ON_AIR;
|
|
|
|
}
|
2012-03-05 17:28:06 +01:00
|
|
|
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
|
|
|
|
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
|
|
|
|
|
|
|
if(rf_flags & WAS_OFF){
|
|
|
|
off();
|
|
|
|
}
|
|
|
|
|
|
|
|
RIMESTATS_ADD(lltx);
|
|
|
|
/* OK, sent. We are now ready to send more */
|
|
|
|
return ret;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
static int
|
|
|
|
send(void *payload, unsigned short payload_len)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
prepare(payload, payload_len);
|
|
|
|
return transmit(payload_len);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
|
|
read(void *buf, unsigned short bufsize)
|
|
|
|
{
|
|
|
|
uint8_t i;
|
|
|
|
uint8_t len;
|
|
|
|
uint8_t crc_corr;
|
|
|
|
int8_t rssi;
|
2009-09-08 22:07:35 +02:00
|
|
|
#if CC2420_CONF_CHECKSUM
|
|
|
|
uint16_t checksum;
|
|
|
|
#endif /* CC2420_CONF_CHECKSUM */
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Don't interrupt us while emptying the FIFO */
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2012-03-05 17:28:06 +01:00
|
|
|
IEN2 &= ~RFIE;
|
|
|
|
#endif
|
|
|
|
#if CC2430_RFERR_INTERRUPT
|
|
|
|
IEN0 &= ~RFERRIE;
|
|
|
|
#endif
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* RX interrupt polled the cc2430_rf_process, now read the RX FIFO */
|
2009-09-08 22:07:35 +02:00
|
|
|
/* Check the length */
|
|
|
|
len = RFD;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
/* Check for validity */
|
|
|
|
if(len > CC2430_MAX_PACKET_LEN) {
|
|
|
|
/* Oops, we must be out of sync. */
|
2012-03-05 17:28:06 +01:00
|
|
|
PRINTF("error: bad sync\n");
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
RIMESTATS_ADD(badsynch);
|
2012-03-05 17:28:06 +01:00
|
|
|
flush_rx();
|
2009-09-08 22:07:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
if(len <= CC2430_MIN_PACKET_LEN) {
|
2012-03-05 17:28:06 +01:00
|
|
|
PRINTF("error: too short\n");
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
RIMESTATS_ADD(tooshort);
|
2012-03-05 17:28:06 +01:00
|
|
|
flush_rx();
|
2009-09-08 22:07:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
if(len - CHECKSUM_LEN > bufsize) {
|
2012-03-05 17:28:06 +01:00
|
|
|
PRINTF("error: too long\n");
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
RIMESTATS_ADD(toolong);
|
2012-03-05 17:28:06 +01:00
|
|
|
flush_rx();
|
2009-09-08 22:07:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
#if CC2430_RF_CONF_HEXDUMP
|
|
|
|
/* If we reach here, chances are the FIFO is holding a valid frame */
|
|
|
|
uart1_writeb(magic[0]);
|
|
|
|
uart1_writeb(magic[1]);
|
|
|
|
uart1_writeb(magic[2]);
|
|
|
|
uart1_writeb(magic[3]);
|
|
|
|
uart1_writeb(len);
|
|
|
|
#endif
|
|
|
|
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("cc2430_rf: read = ");
|
2009-10-15 14:43:53 +02:00
|
|
|
PRINTF("(%d)", len);
|
2012-03-05 17:28:06 +01:00
|
|
|
len -= CHECKSUM_LEN;
|
|
|
|
for(i = 0; i < len; ++i) {
|
2009-09-08 22:07:35 +02:00
|
|
|
((unsigned char*)(buf))[i] = RFD;
|
2012-03-05 17:28:06 +01:00
|
|
|
#if CC2430_RF_CONF_HEXDUMP
|
|
|
|
uart1_writeb(((unsigned char*)(buf))[i]);
|
|
|
|
#endif
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("%02X", ((unsigned char*)(buf))[i]);
|
|
|
|
}
|
|
|
|
PRINTF("\n");
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
#if CC2430_CONF_CHECKSUM
|
|
|
|
/* Deal with the checksum */
|
2009-10-15 14:43:53 +02:00
|
|
|
checksum = RFD * 256;
|
|
|
|
checksum += RFD;
|
2009-09-08 22:07:35 +02:00
|
|
|
#endif /* CC2430_CONF_CHECKSUM */
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Read the RSSI and CRC/Corr bytes */
|
|
|
|
rssi = ((int8_t) RFD) - 45;
|
|
|
|
crc_corr = RFD;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
#if CC2430_RF_CONF_HEXDUMP
|
|
|
|
uart1_writeb(rssi);
|
|
|
|
uart1_writeb(crc_corr);
|
|
|
|
#endif
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
|
|
|
|
if(crc_corr & CRC_BIT_MASK) {
|
|
|
|
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
|
|
|
|
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
|
|
|
|
RIMESTATS_ADD(llrx);
|
2009-09-08 22:07:35 +02:00
|
|
|
} else {
|
2012-03-05 17:28:06 +01:00
|
|
|
RIMESTATS_ADD(badcrc);
|
|
|
|
flush_rx();
|
|
|
|
return 0;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2010-01-26 00:12:09 +01:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */
|
|
|
|
if((RFSTATUS & (FIFO | FIFOP)) == FIFOP) {
|
|
|
|
/*
|
|
|
|
* If we reach here means that there might be more intact packets in the
|
|
|
|
* FIFO despite the overflow. This can happen with bursts of small packets.
|
2009-09-08 22:07:35 +02:00
|
|
|
*
|
2012-03-05 17:28:06 +01:00
|
|
|
* Only flush if the FIFO is actually empty. If not, then next pass we will
|
|
|
|
* pick up one more packet or flush due to an error.
|
2009-09-08 22:07:35 +02:00
|
|
|
*/
|
2012-03-05 17:28:06 +01:00
|
|
|
if(!RXFIFOCNT) {
|
|
|
|
flush_rx();
|
|
|
|
}
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
RF_RX_LED_OFF();
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2012-03-05 17:28:06 +01:00
|
|
|
IEN2 |= RFIE;
|
|
|
|
#endif
|
|
|
|
#if CC2430_RFERR_INTERRUPT
|
|
|
|
IEN0 |= RFERRIE;
|
|
|
|
#endif
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
RFIF &= ~IRQ_FIFOP;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
return (len);
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
static int
|
|
|
|
channel_clear(void)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
if(!(RFSTATUS & CCA)) {
|
|
|
|
return CC2430_CCA_BUSY;
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2012-03-05 17:28:06 +01:00
|
|
|
return CC2430_CCA_CLEAR;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
|
|
receiving_packet(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* SFD high while transmitting and receiving.
|
|
|
|
* TX_ACTIVE high only when transmitting
|
|
|
|
*
|
|
|
|
* RFSTATUS & (TX_ACTIVE | SFD) == SFD <=> receiving
|
|
|
|
*/
|
|
|
|
return (RFSTATUS & (TX_ACTIVE | SFD) == SFD);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
|
|
pending_packet(void)
|
|
|
|
{
|
|
|
|
return (RFSTATUS & FIFOP);
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* Enable RF receiver.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* \return pdTRUE
|
2012-03-05 17:28:06 +01:00
|
|
|
* \return pdFALSE bus not free
|
2009-09-08 22:07:35 +02:00
|
|
|
*/
|
2012-03-05 17:28:06 +01:00
|
|
|
static int
|
|
|
|
on(void)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
rtimer_clock_t t0;
|
2009-09-11 10:07:12 +02:00
|
|
|
PRINTF("cc2430_rf_rx_enable called\n");
|
2009-09-08 22:07:35 +02:00
|
|
|
if(!(rf_flags & RX_ACTIVE)) {
|
2012-03-05 17:28:06 +01:00
|
|
|
t0 = RTIMER_NOW();
|
2009-09-08 22:07:35 +02:00
|
|
|
rf_flags |= RX_ACTIVE;
|
2012-03-05 17:28:06 +01:00
|
|
|
IOCFG0 = 0x7f; /* Set the FIFOP threshold 127 */
|
|
|
|
RSSIH = 0xd2; /* -84dbm = 0xd2 default, 0xe0 -70 dbm */
|
|
|
|
|
|
|
|
RFPWR &= ~RREG_RADIO_PD; /* make sure it's powered */
|
|
|
|
while ((RFIF & IRQ_RREG_ON) == 0); /* wait for power up */
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Make sure the RREG On Interrupt Flag is 0 next time we get called */
|
|
|
|
RFIF &= ~IRQ_RREG_ON;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISRXON);
|
|
|
|
cc2430_rf_command(ISFLUSHRX);
|
2012-03-05 17:28:06 +01:00
|
|
|
while (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
|
|
|
|
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2010-01-26 00:12:09 +01:00
|
|
|
PRINTF("cc2430_rf_rx_enable done\n");
|
2012-03-05 17:28:06 +01:00
|
|
|
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
2009-09-08 22:07:35 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* Disable RF receiver.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* \return pdTRUE
|
2012-03-05 17:28:06 +01:00
|
|
|
* \return pdFALSE bus not free
|
2009-09-08 22:07:35 +02:00
|
|
|
*/
|
2012-03-05 17:28:06 +01:00
|
|
|
|
|
|
|
static int
|
|
|
|
off(void)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
cc2430_rf_command(ISSTOP); /* make sure CSP is not running */
|
2009-09-08 22:07:35 +02:00
|
|
|
cc2430_rf_command(ISRFOFF);
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
RFPWR |= RREG_RADIO_PD; /* RF powerdown */
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
/* Clear the RREG On Interrupt Flag */
|
|
|
|
RFIF &= ~IRQ_RREG_ON;
|
2009-09-09 09:32:02 +02:00
|
|
|
|
2012-03-05 17:28:06 +01:00
|
|
|
rf_flags &= ~RX_ACTIVE;
|
|
|
|
rf_flags &= ~WAS_OFF;
|
|
|
|
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
2009-09-08 22:07:35 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
const struct radio_driver cc2430_rf_driver =
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
init,
|
|
|
|
prepare,
|
|
|
|
transmit,
|
|
|
|
send,
|
|
|
|
read,
|
|
|
|
channel_clear,
|
|
|
|
receiving_packet,
|
|
|
|
pending_packet,
|
|
|
|
on,
|
|
|
|
off,
|
|
|
|
};
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-04-01 22:43:22 +02:00
|
|
|
#if !NETSTACK_CONF_SHORTCUTS
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2012-03-05 17:28:06 +01:00
|
|
|
PROCESS_THREAD(cc2430_rf_process, ev, data)
|
2009-09-08 22:07:35 +02:00
|
|
|
{
|
2012-03-05 17:28:06 +01:00
|
|
|
int len;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
while(1) {
|
|
|
|
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
|
|
|
|
|
|
|
|
packetbuf_clear();
|
|
|
|
len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
|
|
|
|
if(len > 0) {
|
|
|
|
packetbuf_set_datalen(len);
|
|
|
|
NETSTACK_RDC.input();
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
|
|
|
}
|
2012-03-05 17:28:06 +01:00
|
|
|
|
|
|
|
PROCESS_END();
|
2009-09-08 22:07:35 +02:00
|
|
|
}
|
2012-03-05 17:28:06 +01:00
|
|
|
#endif
|
2009-09-08 22:07:35 +02:00
|
|
|
/*---------------------------------------------------------------------------*/
|