mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
6be1cf2a76
sys/transceiver] * renamed all occurrences of cc1100 to cc110x as in fact all driver parts should work for cc1100 and cc110x as well [driver/cc110x_ng] * added some documentation * introduced a new register function to access rxfifo (fixing the of-by-one problem on chronos platform
337 lines
8.1 KiB
C
337 lines
8.1 KiB
C
#include <cc110x_ng.h>
|
|
#include <cc110x-arch.h>
|
|
#include <cc110x-config.h>
|
|
#include <cc110x-defaultSettings.h>
|
|
#include <cc110x-internal.h>
|
|
#include <cc110x_spi.h>
|
|
#include <cc110x-reg.h>
|
|
|
|
#include <hwtimer.h>
|
|
#include <config.h>
|
|
|
|
//#define ENABLE_DEBUG (1)
|
|
#include <debug.h>
|
|
|
|
/* some externals */
|
|
extern uint8_t pa_table[]; ///< PATABLE with available output powers
|
|
extern uint8_t pa_table_index; ///< Current PATABLE Index
|
|
|
|
/* global variables */
|
|
|
|
cc110x_statistic_t cc110x_statistic;
|
|
|
|
volatile cc110x_flags rflags; ///< Radio control flags
|
|
volatile uint8_t radio_state = RADIO_UNKNOWN; ///< Radio state
|
|
|
|
static radio_address_t radio_address; ///< Radio address
|
|
static uint8_t radio_channel; ///< Radio channel
|
|
|
|
int transceiver_pid; ///< the transceiver thread pid
|
|
|
|
/* internal function prototypes */
|
|
static int rd_set_mode(int mode);
|
|
static void reset(void);
|
|
static void power_up_reset(void);
|
|
static void write_register(uint8_t r, uint8_t value);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
// Radio Driver API
|
|
/*---------------------------------------------------------------------------*/
|
|
void cc110x_init(int tpid) {
|
|
transceiver_pid = tpid;
|
|
DEBUG("Transceiver PID: %i\n", transceiver_pid);
|
|
|
|
rx_buffer_next = 0;
|
|
|
|
#ifdef MODULE_CC110X_SPI
|
|
/* Initialize SPI */
|
|
cc110x_spi_init();
|
|
#endif
|
|
|
|
/* Load driver & reset */
|
|
power_up_reset();
|
|
|
|
/* Write configuration to configuration registers */
|
|
cc110x_writeburst_reg(0x00, cc110x_conf, CC1100_CONF_SIZE);
|
|
|
|
/* Write PATABLE (power settings) */
|
|
cc110x_write_reg(CC1100_PATABLE, pa_table[pa_table_index]);
|
|
|
|
/* Initialize Radio Flags */
|
|
rflags._RSSI = 0x00;
|
|
rflags.LL_ACK = 0;
|
|
rflags.CAA = 0;
|
|
rflags.CRC = 0;
|
|
rflags.SEQ = 0;
|
|
rflags.MAN_WOR = 0;
|
|
rflags.KT_RES_ERR = 0;
|
|
rflags.TX = 0;
|
|
rflags.WOR_RST = 0;
|
|
|
|
/* Set default channel number */
|
|
#ifdef MODULE_CONFIG
|
|
cc110x_set_config_channel(sysconfig.radio_channel);
|
|
#else
|
|
cc110x_set_channel(CC1100_DEFAULT_CHANNR);
|
|
#endif
|
|
DEBUG("CC1100 initialized and set to channel %i\n", radio_channel);
|
|
|
|
// Switch to desired mode (WOR or RX)
|
|
rd_set_mode(RADIO_MODE_ON);
|
|
}
|
|
|
|
void cc110x_disable_interrupts(void) {
|
|
cc110x_gdo2_disable();
|
|
cc110x_gdo0_disable();
|
|
}
|
|
|
|
void cc110x_gdo0_irq(void) {
|
|
// Air was not free -> Clear CCA flag
|
|
rflags.CAA = false;
|
|
// Disable carrier sense detection (GDO0 interrupt)
|
|
cc110x_gdo0_disable();
|
|
}
|
|
|
|
void cc110x_gdo2_irq(void) {
|
|
cc110x_rx_handler();
|
|
}
|
|
|
|
uint8_t cc110x_get_buffer_pos(void) {
|
|
return (rx_buffer_next-1);
|
|
}
|
|
|
|
radio_address_t cc110x_get_address() {
|
|
return radio_address;
|
|
}
|
|
|
|
radio_address_t cc110x_set_address(radio_address_t address) {
|
|
if ((address < MIN_UID) || (address > MAX_UID)) {
|
|
return 0;
|
|
}
|
|
|
|
uint8_t id = (uint8_t) address;
|
|
if (radio_state != RADIO_UNKNOWN) {
|
|
write_register(CC1100_ADDR, id);
|
|
}
|
|
|
|
radio_address = id;
|
|
return radio_address;
|
|
}
|
|
|
|
#ifdef MODULE_CONFIG
|
|
radio_address_t cc110x_set_config_address(radio_address_t address) {
|
|
radio_address_t a = cc110x_set_address(address);
|
|
if (a) {
|
|
sysconfig.radio_address = a;
|
|
}
|
|
config_save();
|
|
return a;
|
|
}
|
|
#endif
|
|
|
|
void cc110x_set_monitor(uint8_t mode) {
|
|
if (mode) {
|
|
write_register(CC1100_PKTCTRL1, (0x04));
|
|
}
|
|
else {
|
|
write_register(CC1100_PKTCTRL1, (0x06));
|
|
}
|
|
}
|
|
|
|
void cc110x_setup_rx_mode(void) {
|
|
// Stay in RX mode until end of packet
|
|
cc110x_write_reg(CC1100_MCSM2, 0x07);
|
|
cc110x_switch_to_rx();
|
|
}
|
|
|
|
void cc110x_switch_to_rx(void) {
|
|
radio_state = RADIO_RX;
|
|
cc110x_strobe(CC1100_SRX);
|
|
}
|
|
|
|
void cc110x_wakeup_from_rx(void) {
|
|
if (radio_state != RADIO_RX) {
|
|
return;
|
|
}
|
|
DEBUG("CC1100 going to idle\n");
|
|
cc110x_strobe(CC1100_SIDLE);
|
|
radio_state = RADIO_IDLE;
|
|
}
|
|
|
|
char* cc110x_get_marc_state(void) {
|
|
uint8_t state;
|
|
|
|
// Save old radio state
|
|
uint8_t old_state = radio_state;
|
|
|
|
// Read content of status register
|
|
state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
|
|
|
|
// Make sure in IDLE state.
|
|
// Only goes to IDLE if state was RX/WOR
|
|
cc110x_wakeup_from_rx();
|
|
|
|
// Have to put radio back to WOR/RX if old radio state
|
|
// was WOR/RX, otherwise no action is necessary
|
|
if (old_state == RADIO_WOR || old_state == RADIO_RX) {
|
|
cc110x_switch_to_rx();
|
|
}
|
|
|
|
switch (state)
|
|
{
|
|
// Note: it is not possible to read back the SLEEP or XOFF state numbers
|
|
// because setting CSn low will make the chip enter the IDLE mode from the
|
|
// SLEEP (0) or XOFF (2) states.
|
|
case 1: return "IDLE";
|
|
case 3: case 4: case 5: return "MANCAL";
|
|
case 6: case 7: return "FS_WAKEUP";
|
|
case 8: case 12: return "CALIBRATE";
|
|
case 9: case 10: case 11: return "SETTLING";
|
|
case 13: case 14: case 15: return "RX";
|
|
case 16: return "TXRX_SETTLING";
|
|
case 17: return "RXFIFO_OVERFLOW";
|
|
case 18: return "FSTXON";
|
|
case 19: case 20: return "TX";
|
|
case 21: return "RXTX_SETTLING";
|
|
case 22: return "TXFIFO_UNDERFLOW";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
char* cc110x_state_to_text(uint8_t state) {
|
|
switch (state)
|
|
{
|
|
case RADIO_UNKNOWN:
|
|
return "Unknown";
|
|
case RADIO_AIR_FREE_WAITING:
|
|
return "CS";
|
|
case RADIO_WOR:
|
|
return "WOR";
|
|
case RADIO_IDLE:
|
|
return "IDLE";
|
|
case RADIO_SEND_BURST:
|
|
return "TX BURST";
|
|
case RADIO_RX:
|
|
return "RX";
|
|
case RADIO_SEND_ACK:
|
|
return "TX ACK";
|
|
case RADIO_PWD:
|
|
return "PWD";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
void cc110x_print_config(void) {
|
|
printf("Current radio state: %s\r\n", cc110x_state_to_text(radio_state));
|
|
printf("Current MARC state: %s\r\n", cc110x_get_marc_state());
|
|
printf("Current channel number: %u\r\n", radio_channel);
|
|
}
|
|
|
|
void cc110x_switch_to_pwd(void) {
|
|
DEBUG("[cc110x_ng] switching to powerdown\n");
|
|
cc110x_wakeup_from_rx();
|
|
cc110x_strobe(CC1100_SPWD);
|
|
radio_state = RADIO_PWD;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int16_t cc110x_set_channel(uint8_t channr) {
|
|
uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
|
|
if ((state != 1) && (channr > MAX_CHANNR)) {
|
|
return -1;
|
|
}
|
|
write_register(CC1100_CHANNR, channr*10);
|
|
radio_channel = channr;
|
|
return radio_channel;
|
|
}
|
|
|
|
#ifdef MODULE_CONFIG
|
|
int16_t cc110x_set_config_channel(uint8_t channr) {
|
|
int16_t c = cc110x_set_channel(channr);
|
|
if (c) {
|
|
sysconfig.radio_channel = c;
|
|
}
|
|
config_save();
|
|
return c;
|
|
}
|
|
#endif
|
|
|
|
int16_t cc110x_get_channel(void) {
|
|
return radio_channel;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
// CC1100 reset functionality
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void reset(void) {
|
|
cc110x_wakeup_from_rx();
|
|
#ifdef MODULE_CC110x_SPI
|
|
cc110x_spi_select();
|
|
#endif
|
|
cc110x_strobe(CC1100_SRES);
|
|
hwtimer_wait(RTIMER_TICKS(100));
|
|
}
|
|
|
|
static void power_up_reset(void) {
|
|
#ifdef MODULE_CC110x_SPI
|
|
cc110x_spi_unselect();
|
|
cc110x_spi_cs();
|
|
cc110x_spi_unselect();
|
|
#endif
|
|
hwtimer_wait(RESET_WAIT_TIME);
|
|
reset();
|
|
radio_state = RADIO_IDLE;
|
|
}
|
|
|
|
static void write_register(uint8_t r, uint8_t value) {
|
|
// Save old radio state
|
|
uint8_t old_state = radio_state;
|
|
|
|
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */
|
|
cc110x_wakeup_from_rx();
|
|
cc110x_write_reg(r, value);
|
|
|
|
// Have to put radio back to WOR/RX if old radio state
|
|
// was WOR/RX, otherwise no action is necessary
|
|
if ((old_state == RADIO_WOR) || (old_state == RADIO_RX)) {
|
|
cc110x_switch_to_rx();
|
|
}
|
|
}
|
|
|
|
static int rd_set_mode(int mode) {
|
|
int result;
|
|
|
|
// Get current radio mode
|
|
if ((radio_state == RADIO_UNKNOWN) || (radio_state == RADIO_PWD)) {
|
|
result = RADIO_MODE_OFF;
|
|
}
|
|
else {
|
|
result = RADIO_MODE_ON;
|
|
}
|
|
|
|
switch (mode) {
|
|
case RADIO_MODE_ON:
|
|
DEBUG("Enabling rx mode\n");
|
|
cc110x_init_interrupts(); // Enable interrupts
|
|
cc110x_setup_rx_mode(); // Set chip to desired mode
|
|
break;
|
|
case RADIO_MODE_OFF:
|
|
cc110x_disable_interrupts(); // Disable interrupts
|
|
cc110x_switch_to_pwd(); // Set chip to power down mode
|
|
break;
|
|
case RADIO_MODE_GET:
|
|
// do nothing, just return current mode
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
|
|
// Return previous mode
|
|
return result;
|
|
}
|
|
|
|
|