You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
6.6 KiB
271 lines
6.6 KiB
/* |
|
* Copyright (C) 2014 Freie Universität Berlin |
|
* Copyright (C) 2013 INRIA |
|
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de> |
|
* |
|
* This file is subject to the terms and conditions of the GNU Lesser |
|
* General Public License v2.1. See the file LICENSE in the top level |
|
* directory for more details. |
|
*/ |
|
|
|
/** |
|
* @ingroup drivers_cc110x |
|
* @{ |
|
* @file |
|
* @brief Basic functionality of cc110x driver |
|
* |
|
* @author Oliver Hahm <oliver.hahm@inria.fr> |
|
* @author Fabian Nack <nack@inf.fu-berlin.de> |
|
* @author Kaspar Schleiser <kaspar@schleiser.de> |
|
* @} |
|
*/ |
|
|
|
#include "luid.h" |
|
#include "board.h" |
|
#include "periph/gpio.h" |
|
#include "periph/spi.h" |
|
#include "xtimer.h" |
|
#include "cpu.h" |
|
#include "log.h" |
|
|
|
#include "cc110x.h" |
|
#include "cc110x-defaultsettings.h" |
|
#include "cc110x-defines.h" |
|
#include "cc110x-interface.h" |
|
#include "cc110x-internal.h" |
|
#include "cc110x-spi.h" |
|
|
|
#define ENABLE_DEBUG (0) |
|
#include "debug.h" |
|
|
|
/* Internal function prototypes */ |
|
#ifndef CC110X_DONT_RESET |
|
static void _reset(cc110x_t *dev); |
|
static void _power_up_reset(cc110x_t *dev); |
|
#endif |
|
|
|
int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
#ifdef MODULE_CC110X_HOOKS |
|
cc110x_hooks_init(); |
|
#endif |
|
|
|
dev->params = *params; |
|
|
|
/* Configure chip-select */ |
|
spi_init_cs(dev->params.spi, dev->params.cs); |
|
|
|
/* Configure GDO1 */ |
|
gpio_init(dev->params.gdo1, GPIO_IN); |
|
|
|
#ifndef CC110X_DONT_RESET |
|
/* reset device*/ |
|
_power_up_reset(dev); |
|
#endif |
|
|
|
/* set default state */ |
|
dev->radio_state = RADIO_IDLE; |
|
|
|
/* Write configuration to configuration registers */ |
|
cc110x_writeburst_reg(dev, 0x00, cc110x_default_conf, cc110x_default_conf_size); |
|
|
|
/* Write PATABLE (power settings) */ |
|
cc110x_writeburst_reg(dev, CC110X_PATABLE, CC110X_DEFAULT_PATABLE, 8); |
|
|
|
/* set base frequency */ |
|
cc110x_set_base_freq_raw(dev, CC110X_DEFAULT_FREQ); |
|
|
|
/* Set default channel number */ |
|
cc110x_set_channel(dev, CC110X_DEFAULT_CHANNEL); |
|
|
|
/* set default node id */ |
|
uint8_t addr; |
|
luid_get(&addr, 1); |
|
cc110x_set_address(dev, addr); |
|
|
|
LOG_INFO("cc110x: initialized with address=%u and channel=%i\n", |
|
(unsigned)dev->radio_address, |
|
dev->radio_channel); |
|
|
|
return 0; |
|
} |
|
|
|
uint8_t cc110x_set_address(cc110x_t *dev, uint8_t address) |
|
{ |
|
DEBUG("%s:%s:%u setting address %u\n", RIOT_FILE_RELATIVE, __func__, |
|
__LINE__, (unsigned)address); |
|
if (!(address < MIN_UID) || (address > MAX_UID)) { |
|
if (dev->radio_state != RADIO_UNKNOWN) { |
|
cc110x_write_register(dev, CC110X_ADDR, address); |
|
dev->radio_address = address; |
|
return address; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
void cc110x_set_base_freq_raw(cc110x_t *dev, const char* freq_array) |
|
{ |
|
#if ENABLE_DEBUG == 1 |
|
uint8_t _tmp[] = { freq_array[2], freq_array[1], freq_array[0], 0x00}; |
|
uint32_t *FREQ = (uint32_t*) _tmp; |
|
|
|
DEBUG("cc110x_set_base_freq_raw(): setting base frequency to %uHz\n", |
|
(26000000>>16) * (unsigned)(*FREQ)); |
|
#endif |
|
cc110x_writeburst_reg(dev, CC110X_FREQ2, freq_array, 3); |
|
} |
|
|
|
void cc110x_set_monitor(cc110x_t *dev, uint8_t mode) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
cc110x_write_register(dev, CC110X_PKTCTRL1, mode ? 0x04 : 0x06); |
|
} |
|
|
|
void cc110x_setup_rx_mode(cc110x_t *dev) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
/* Stay in RX mode until end of packet */ |
|
cc110x_write_reg(dev, CC110X_MCSM2, 0x07); |
|
cc110x_switch_to_rx(dev); |
|
} |
|
|
|
void cc110x_switch_to_rx(cc110x_t *dev) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
#ifdef MODULE_CC110X_HOOKS |
|
cc110x_hook_rx(); |
|
#endif |
|
|
|
gpio_irq_disable(dev->params.gdo2); |
|
|
|
/* flush RX fifo */ |
|
cc110x_strobe(dev, CC110X_SIDLE); |
|
cc110x_strobe(dev, CC110X_SFRX); |
|
|
|
dev->radio_state = RADIO_RX; |
|
|
|
cc110x_write_reg(dev, CC110X_IOCFG2, 0x6); |
|
cc110x_strobe(dev, CC110X_SRX); |
|
|
|
gpio_irq_enable(dev->params.gdo2); |
|
} |
|
|
|
void cc110x_wakeup_from_rx(cc110x_t *dev) |
|
{ |
|
if (dev->radio_state != RADIO_RX) { |
|
return; |
|
} |
|
|
|
LOG_DEBUG("cc110x: switching to idle mode\n"); |
|
|
|
cc110x_strobe(dev, CC110X_SIDLE); |
|
dev->radio_state = RADIO_IDLE; |
|
} |
|
|
|
void cc110x_switch_to_pwd(cc110x_t *dev) |
|
{ |
|
LOG_DEBUG("cc110x: switching to powerdown mode\n"); |
|
cc110x_wakeup_from_rx(dev); |
|
cc110x_strobe(dev, CC110X_SPWD); |
|
dev->radio_state = RADIO_PWD; |
|
|
|
#ifdef MODULE_CC110X_HOOKS |
|
cc110x_hook_off(); |
|
#endif |
|
} |
|
|
|
#ifndef MODULE_CC110X_HOOKS |
|
int16_t cc110x_set_channel(cc110x_t *dev, uint8_t channr) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
if (channr > MAX_CHANNR) { |
|
return -1; |
|
} |
|
|
|
cc110x_write_register(dev, CC110X_CHANNR, channr * 10); |
|
dev->radio_channel = channr; |
|
|
|
return channr; |
|
} |
|
#endif |
|
|
|
#ifndef CC110X_DONT_RESET |
|
static void _reset(cc110x_t *dev) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
cc110x_wakeup_from_rx(dev); |
|
cc110x_cs(dev); |
|
cc110x_strobe(dev, CC110X_SRES); |
|
xtimer_usleep(100); |
|
} |
|
|
|
static void _power_up_reset(cc110x_t *dev) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
gpio_set(dev->params.cs); |
|
gpio_clear(dev->params.cs); |
|
gpio_set(dev->params.cs); |
|
xtimer_usleep(RESET_WAIT_TIME); |
|
_reset(dev); |
|
} |
|
#endif |
|
|
|
void cc110x_write_register(cc110x_t *dev, uint8_t r, uint8_t value) |
|
{ |
|
/* Save old radio state */ |
|
uint8_t old_state = dev->radio_state; |
|
|
|
/* Wake up from RX (no effect if in other mode) */ |
|
cc110x_wakeup_from_rx(dev); |
|
cc110x_write_reg(dev, r, value); |
|
|
|
/* Have to put radio back to RX if old radio state |
|
* was RX, otherwise no action is necessary */ |
|
if (old_state == RADIO_RX) { |
|
cc110x_switch_to_rx(dev); |
|
} |
|
} |
|
|
|
int cc110x_rd_set_mode(cc110x_t *dev, int mode) |
|
{ |
|
DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); |
|
|
|
int result; |
|
|
|
/* Get current radio mode */ |
|
if ((dev->radio_state == RADIO_UNKNOWN) || (dev->radio_state == RADIO_PWD)) { |
|
result = RADIO_MODE_OFF; |
|
} |
|
else { |
|
result = RADIO_MODE_ON; |
|
} |
|
|
|
switch(mode) { |
|
case RADIO_MODE_ON: |
|
LOG_DEBUG("cc110x: switching to RX mode\n"); |
|
cc110x_setup_rx_mode(dev); /* Set chip to desired mode */ |
|
break; |
|
|
|
case RADIO_MODE_OFF: |
|
gpio_irq_disable(dev->params.gdo2); /* Disable interrupts */ |
|
cc110x_switch_to_pwd(dev); /* 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; |
|
}
|
|
|