1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

Merge pull request #16232 from maribu/drivers/cc110x

drivers/cc110x: add power off (sleep) functions
This commit is contained in:
benpicco 2021-07-06 12:24:26 +02:00 committed by GitHub
commit 8f9233f329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 418 additions and 207 deletions

View File

@ -89,6 +89,13 @@ int cc110x_apply_config(cc110x_t *dev, const cc110x_config_t *conf,
return cc110x_full_calibration(dev); return cc110x_full_calibration(dev);
} }
static void _set_tx_power(cc110x_t *dev, cc110x_tx_power_t power)
{
uint8_t frend0 = 0x10 | (uint8_t)power;
cc110x_write(dev, CC110X_REG_FREND0, frend0);
dev->tx_power = power;
}
int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power) int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power)
{ {
DEBUG("[cc110x] Applying TX power setting at index %u\n", (unsigned)power); DEBUG("[cc110x] Applying TX power setting at index %u\n", (unsigned)power);
@ -114,9 +121,8 @@ int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power)
return -EAGAIN; return -EAGAIN;
} }
uint8_t frend0 = 0x10 | (uint8_t)power; _set_tx_power(dev, power);
cc110x_write(dev, CC110X_REG_FREND0, frend0);
dev->tx_power = power;
cc110x_release(dev); cc110x_release(dev);
return 0; return 0;
} }
@ -176,3 +182,47 @@ int cc110x_set_channel(cc110x_t *dev, uint8_t channel)
dev->netdev.event_callback(&dev->netdev, NETDEV_EVENT_FHSS_CHANGE_CHANNEL); dev->netdev.event_callback(&dev->netdev, NETDEV_EVENT_FHSS_CHANGE_CHANNEL);
return 0; return 0;
} }
int cc110x_wakeup(cc110x_t *dev)
{
int err = cc110x_power_on_and_acquire(dev);
if (err) {
return err;
}
/* PA_TABLE is lost on SLEEP, see 10.6 in the CC1101 data sheet */
cc110x_burst_write(dev, CC110X_MULTIREG_PATABLE,
dev->params.patable->data, CC110X_PATABLE_LEN);
_set_tx_power(dev, dev->tx_power);
cc110x_enter_rx_mode(dev);
cc110x_release(dev);
return 0;
}
void cc110x_sleep(cc110x_t *dev)
{
cc110x_acquire(dev);
if (dev->state == CC110X_STATE_OFF) {
cc110x_release(dev);
return;
}
/*
* Datasheet page 9 table 4.
*
* To achieve the lowest power consumption GDO's must
* be programmed to 0x2F
*/
cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_LOW);
cc110x_write(dev, CC110X_REG_IOCFG1, CC110X_GDO_CONSTANT_LOW);
cc110x_write(dev, CC110X_REG_IOCFG0, CC110X_GDO_CONSTANT_LOW);
/* transition to SLEEP only from state IDLE possible */
cc110x_cmd(dev, CC110X_STROBE_IDLE);
/* go to SLEEP */
cc110x_cmd(dev, CC110X_STROBE_OFF);
dev->state = CC110X_STATE_OFF;
cc110x_release(dev);
}

View File

@ -18,13 +18,16 @@
*/ */
#include <errno.h> #include <errno.h>
#include "cc110x.h"
#include "cc110x_communication.h"
#include "cc110x_constants.h"
#include "cc110x_internal.h"
#include "periph/gpio.h" #include "periph/gpio.h"
#include "periph/spi.h" #include "periph/spi.h"
#include "xtimer.h" #include "xtimer.h"
#include "cc110x.h"
#include "cc110x_constants.h"
int cc110x_power_on(cc110x_t *dev) int cc110x_power_on_and_acquire(cc110x_t *dev)
{ {
gpio_t cs = dev->params.cs; gpio_t cs = dev->params.cs;
@ -32,9 +35,19 @@ int cc110x_power_on(cc110x_t *dev)
return -EIO; return -EIO;
} }
gpio_clear(cs); gpio_clear(cs);
xtimer_usleep(150); xtimer_usleep(CC110X_WAKEUP_TIME_US);
gpio_set(cs); gpio_set(cs);
spi_init_cs(dev->params.spi, dev->params.cs); spi_init_cs(dev->params.spi, dev->params.cs);
if (cc110x_acquire(dev) != SPI_OK) {
return -EIO;
}
while (cc110x_state_from_status(cc110x_status(dev)) != CC110X_STATE_IDLE) {
cc110x_cmd(dev, CC110X_STROBE_IDLE);
xtimer_usleep(CC110X_WAKEUP_TIME_US);
}
return 0; return 0;
} }

View File

@ -120,36 +120,36 @@ static int identify_device(cc110x_t *dev)
} }
switch (version) { switch (version) {
case 3: case 3:
DEBUG("[cc110x] Detected CC1100 transceiver\n"); DEBUG("[cc110x] Detected CC1100 transceiver\n");
/* RSSI offset is 78dBm @ 868MHz & 250kBaud. /* RSSI offset is 78dBm @ 868MHz & 250kBaud.
* Depends on the symbol rate and base band and ranges from * Depends on the symbol rate and base band and ranges from
* 74dBm to 79dBm. * 74dBm to 79dBm.
*/ */
dev->rssi_offset = 78; dev->rssi_offset = 78;
return 0; return 0;
case 5: case 5:
DEBUG("[cc110x] Detected CC1100E transceiver\n"); DEBUG("[cc110x] Detected CC1100E transceiver\n");
/* RSSI offset is 79 dBm @ 250kbps & 250 kbps. /* RSSI offset is 79 dBm @ 250kbps & 250 kbps.
* Depends on base band and symbol rate and ranges from * Depends on base band and symbol rate and ranges from
* 75dBm to 79dBm * 75dBm to 79dBm
*/ */
dev->rssi_offset = 79; dev->rssi_offset = 79;
return 0; return 0;
case 4: case 4:
/* falls through */ /* falls through */
case 14: case 14:
/* falls through */ /* falls through */
case 20: case 20:
/* RSSI offset for the CC1101 is independent of symbol rate and /* RSSI offset for the CC1101 is independent of symbol rate and
* base 74 dBm * base 74 dBm
*/ */
dev->rssi_offset = 74; dev->rssi_offset = 74;
DEBUG("[cc110x] Detected CC1101 transceiver\n"); DEBUG("[cc110x] Detected CC1101 transceiver\n");
return 0; return 0;
default: default:
DEBUG("[cc110x] Device not a CC110x transceiver\n"); DEBUG("[cc110x] Device not a CC110x transceiver\n");
return -1; return -1;
} }
} }
@ -247,37 +247,25 @@ static int cc110x_init(netdev_t *netdev)
/* Make sure the crystal is stable and the chip ready. This is needed as /* Make sure the crystal is stable and the chip ready. This is needed as
* the reset is done via an SPI command, but the SPI interface must not be * the reset is done via an SPI command, but the SPI interface must not be
* used unless the chip is ready according to the data sheet. After the * used unless the chip is ready according to the data sheet. After the
* reset, a second call to cc110x_power_on() is needed to finally have * reset, a second call to cc110x_power_on_and_acquire() is needed to finally have
* the transceiver in a known state and ready for SPI communication. * the transceiver in a known state and ready for SPI communication.
*/ */
if (cc110x_power_on(dev)) { if (cc110x_power_on_and_acquire(dev)) {
DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low\n"); DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low\n");
return -EIO; return -EIO;
} }
if (cc110x_acquire(dev) != SPI_OK) {
DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup/acquire SPI "
"interface\n");
return -EIO;
}
/* Performing a reset of the transceiver to get it in a known state */ /* Performing a reset of the transceiver to get it in a known state */
cc110x_cmd(dev, CC110X_STROBE_RESET); cc110x_cmd(dev, CC110X_STROBE_RESET);
cc110x_release(dev); cc110x_release(dev);
/* Again, make sure the crystal is stable and the chip ready */ /* Again, make sure the crystal is stable and the chip ready */
if (cc110x_power_on(dev)) { if (cc110x_power_on_and_acquire(dev)) {
DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low " DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low "
"after reset\n"); "after reset\n");
return -EIO; return -EIO;
} }
if (cc110x_acquire(dev) != SPI_OK) {
DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup/acquire SPI "
"interface after reset\n");
return -EIO;
}
if (identify_device(dev)) { if (identify_device(dev)) {
DEBUG("[cc110x] netdev_driver_t::init(): Device identification failed\n"); DEBUG("[cc110x] netdev_driver_t::init(): Device identification failed\n");
cc110x_release(dev); cc110x_release(dev);
@ -414,20 +402,23 @@ static int cc110x_send(netdev_t *netdev, const iolist_t *iolist)
} }
switch (dev->state) { switch (dev->state) {
case CC110X_STATE_FSTXON: case CC110X_STATE_FSTXON:
/* falls through */ /* falls through */
case CC110X_STATE_RX_MODE: case CC110X_STATE_RX_MODE:
break; break;
case CC110X_STATE_RECEIVING: case CC110X_STATE_RECEIVING:
cc110x_release(dev); cc110x_release(dev);
DEBUG("[cc110x] netdev_driver_t::send(): Refusing to send while " DEBUG("[cc110x] netdev_driver_t::send(): Refusing to send while "
"receiving a frame\n"); "receiving a frame\n");
return -EBUSY; return -EBUSY;
default: case CC110X_STATE_OFF:
cc110x_release(dev); cc110x_release(dev);
DEBUG("[cc110x] netdev_driver_t::send(): Driver state %i prevents " return -ENOTSUP;
"sending\n", (int)dev->state); default:
return -1; cc110x_release(dev);
DEBUG("[cc110x] netdev_driver_t::send(): Driver state %i prevents "
"sending\n", (int)dev->state);
return -1;
} }
/* Copy data to send into frame buffer */ /* Copy data to send into frame buffer */
@ -530,42 +521,73 @@ static int cc110x_get(netdev_t *netdev, netopt_t opt,
(void)max_len; /* only used in assert() */ (void)max_len; /* only used in assert() */
switch (opt) { switch (opt) {
case NETOPT_DEVICE_TYPE: case NETOPT_DEVICE_TYPE:
assert(max_len == sizeof(uint16_t)); assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = NETDEV_TYPE_CC110X; *((uint16_t *)val) = NETDEV_TYPE_CC110X;
return sizeof(uint16_t); return sizeof(uint16_t);
case NETOPT_PROTO: case NETOPT_PROTO:
assert(max_len == sizeof(gnrc_nettype_t)); assert(max_len == sizeof(gnrc_nettype_t));
*((gnrc_nettype_t *)val) = CC110X_DEFAULT_PROTOCOL; *((gnrc_nettype_t *)val) = CC110X_DEFAULT_PROTOCOL;
return sizeof(gnrc_nettype_t); return sizeof(gnrc_nettype_t);
case NETOPT_MAX_PDU_SIZE: case NETOPT_MAX_PDU_SIZE:
assert(max_len == sizeof(uint16_t)); assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = CC110X_MAX_FRAME_SIZE - sizeof(cc1xxx_l2hdr_t); *((uint16_t *)val) = CC110X_MAX_FRAME_SIZE - sizeof(cc1xxx_l2hdr_t);
return sizeof(uint16_t); return sizeof(uint16_t);
case NETOPT_ADDR_LEN: case NETOPT_ADDR_LEN:
/* falls through */ /* falls through */
case NETOPT_SRC_LEN: case NETOPT_SRC_LEN:
assert(max_len == sizeof(uint16_t)); assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = CC1XXX_ADDR_SIZE; *((uint16_t *)val) = CC1XXX_ADDR_SIZE;
return sizeof(uint16_t); return sizeof(uint16_t);
case NETOPT_ADDRESS: case NETOPT_ADDRESS:
assert(max_len >= CC1XXX_ADDR_SIZE); assert(max_len >= CC1XXX_ADDR_SIZE);
*((uint8_t *)val) = dev->addr; *((uint8_t *)val) = dev->addr;
return CC1XXX_ADDR_SIZE; return CC1XXX_ADDR_SIZE;
case NETOPT_CHANNEL: case NETOPT_CHANNEL:
assert(max_len == sizeof(uint16_t)); assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = dev->channel; *((uint16_t *)val) = dev->channel;
return sizeof(uint16_t); return sizeof(uint16_t);
case NETOPT_TX_POWER: case NETOPT_TX_POWER:
assert(max_len == sizeof(uint16_t)); assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = dbm_from_tx_power[dev->tx_power]; *((uint16_t *)val) = dbm_from_tx_power[dev->tx_power];
return sizeof(uint16_t); return sizeof(uint16_t);
case NETOPT_PROMISCUOUSMODE: case NETOPT_PROMISCUOUSMODE:
assert(max_len == sizeof(netopt_enable_t)); assert(max_len == sizeof(netopt_enable_t));
return cc110x_get_promiscuous_mode(dev, val); return cc110x_get_promiscuous_mode(dev, val);
default: case NETOPT_STATE:
return -ENOTSUP; assert(max_len == sizeof(netopt_state_t));
{
netopt_state_t *state = val;
switch (dev->state) {
case CC110X_STATE_RECEIVING:
case CC110X_STATE_FRAME_READY:
case CC110X_STATE_RXFIFO_OVERFLOW:
*state = NETOPT_STATE_RX;
break;
case CC110X_STATE_IDLE:
*state = NETOPT_STATE_STANDBY;
break;
case CC110X_STATE_OFF:
*state = NETOPT_STATE_SLEEP;
break;
case CC110X_STATE_TX_MODE:
case CC110X_STATE_TX_COMPLETING:
case CC110X_STATE_TXFIFO_UNDERFLOW:
*state = NETOPT_STATE_TX;
break;
case CC110X_STATE_RX_MODE:
*state = NETOPT_STATE_IDLE;
break;
default:
*state = NETOPT_STATE_RESET;
break;
}
}
break;
default:
break;
} }
return -ENOTSUP;
} }
/** /**
@ -619,41 +641,56 @@ static int cc110x_set(netdev_t *netdev, netopt_t opt,
cc110x_t *dev = (cc110x_t *)netdev; cc110x_t *dev = (cc110x_t *)netdev;
switch (opt) { switch (opt) {
case NETOPT_ADDRESS: case NETOPT_ADDRESS:
assert(len == CC1XXX_ADDR_SIZE); assert(len == CC1XXX_ADDR_SIZE);
return cc110x_set_addr(dev, *((uint8_t *)val)); return cc110x_set_addr(dev, *((uint8_t *)val));
case NETOPT_CHANNEL: case NETOPT_CHANNEL:
{ {
assert(len == sizeof(uint16_t)); assert(len == sizeof(uint16_t));
int retval; int retval;
uint16_t channel = *((uint16_t *)val); uint16_t channel = *((uint16_t *)val);
if (channel >= CC110X_MAX_CHANNELS) { if (channel >= CC110X_MAX_CHANNELS) {
return -EINVAL; return -EINVAL;
} }
if ((retval = cc110x_set_channel(dev, (uint8_t)channel))) { if ((retval = cc110x_set_channel(dev, (uint8_t)channel))) {
return retval; return retval;
}
}
return sizeof(uint16_t);
case NETOPT_TX_POWER:
{
assert(len == sizeof(int16_t));
int16_t dbm = *((int16_t *)val);
cc110x_tx_power_t power = CC110X_TX_POWER_MINUS_30_DBM;
for ( ; power < CC110X_TX_POWER_PLUS_10_DBM; power++) {
if ((int16_t)tx_power_from_dbm[power] >= dbm) {
break;
} }
} }
return sizeof(uint16_t); if (cc110x_set_tx_power(dev, power)) {
case NETOPT_TX_POWER: return -EINVAL;
{
assert(len == sizeof(int16_t));
int16_t dbm = *((int16_t *)val);
cc110x_tx_power_t power = CC110X_TX_POWER_MINUS_30_DBM;
for ( ; power < CC110X_TX_POWER_PLUS_10_DBM; power++) {
if ((int16_t)tx_power_from_dbm[power] >= dbm) {
break;
}
}
if (cc110x_set_tx_power(dev, power)) {
return -EINVAL;
}
} }
return sizeof(uint16_t); }
case NETOPT_PROMISCUOUSMODE: return sizeof(uint16_t);
assert(len == sizeof(netopt_enable_t)); case NETOPT_PROMISCUOUSMODE:
return cc110x_set_promiscuous_mode(dev, *((const netopt_enable_t *)val)); assert(len == sizeof(netopt_enable_t));
return cc110x_set_promiscuous_mode(dev, *((const netopt_enable_t *)val));
case NETOPT_STATE:
assert(len == sizeof(netopt_state_t));
switch (*((netopt_state_t *)val)) {
case NETOPT_STATE_RESET:
case NETOPT_STATE_IDLE:
cc110x_wakeup(dev);
return sizeof(netopt_state_t);
case NETOPT_STATE_OFF:
case NETOPT_STATE_SLEEP:
cc110x_sleep(dev);
return sizeof(netopt_state_t);
default: default:
return -ENOTSUP; return -ENOTSUP;
}
break;
default:
return -ENOTSUP;
} }
} }

View File

@ -35,8 +35,9 @@ extern "C" {
* @retval SPI_NOMODE SPI mode 0 not supported by MCU * @retval SPI_NOMODE SPI mode 0 not supported by MCU
* @retval SPI_NOCLK SPI clock given in @ref cc110x_params_t is not supported * @retval SPI_NOCLK SPI clock given in @ref cc110x_params_t is not supported
* *
* @pre @ref cc110x_power_on has be called before calling this function. * @pre When first acquiring the device either after boot or after having put
* (Only needed *once* when the driver initializes.) * the device to sleep mode, use @ref cc110x_power_on_and_acquire
* instead. Subsequently, this function should be used (it is faster).
*/ */
static inline int cc110x_acquire(cc110x_t *dev) static inline int cc110x_acquire(cc110x_t *dev)
{ {
@ -200,11 +201,13 @@ uint8_t cc110x_status(cc110x_t *dev);
* of messing with the SPI interface, this driver simply waits for this upper * of messing with the SPI interface, this driver simply waits for this upper
* bound, as suggested in the note below Table 22 on page 30 in the data sheet. * bound, as suggested in the note below Table 22 on page 30 in the data sheet.
* *
* @pre The device was not acquired and in low power mode
* @post The device is in IDLE mode and acquired
*
* @retval 0 Success * @retval 0 Success
* @retval -EIO Couldn't pull the CS pin down (@ref cc110x_params_t::cs) * @retval -EIO Couldn't pull the CS pin down (@ref cc110x_params_t::cs)
*/ */
int cc110x_power_on(cc110x_t *dev); int cc110x_power_on_and_acquire(cc110x_t *dev);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -570,6 +570,11 @@ extern "C" {
#define CC110X_PKTCTRL1_GET_ADDR_MODE 0x03 #define CC110X_PKTCTRL1_GET_ADDR_MODE 0x03
/** @} */ /** @} */
/**
* @brief Time in micro seconds the CC110X takes to wake up from SLEEP state
*/
#define CC110X_WAKEUP_TIME_US 150
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -235,7 +235,8 @@ extern "C" {
#endif #endif
/** /**
* @defgroup drivers_cc110x_config CC1100/CC1100e/CC1101 Sub-GHz transceiver driver compile configuration * @defgroup drivers_cc110x_config CC1100/CC1100e/CC1101 Sub-GHz transceiver driver
* compile time configuration
* @ingroup config_drivers_netdev * @ingroup config_drivers_netdev
* @{ * @{
*/ */
@ -263,7 +264,7 @@ typedef enum {
*/ */
CC110X_STATE_FRAME_READY = 0x08, CC110X_STATE_FRAME_READY = 0x08,
/** /**
* @brief Frame received, waiting for upper layer to retrieve it * @brief Devices is powered down
* *
* Transceiver is in SLEEP state. There is no matching representation in the * Transceiver is in SLEEP state. There is no matching representation in the
* status byte, as reading the status byte will power up the transceiver in * status byte, as reading the status byte will power up the transceiver in
@ -324,7 +325,6 @@ typedef struct {
uint8_t data[8]; /**< Magic number to store in the configuration register */ uint8_t data[8]; /**< Magic number to store in the configuration register */
} cc110x_patable_t; } cc110x_patable_t;
/** /**
* @brief Configuration of the transceiver to use * @brief Configuration of the transceiver to use
* *
@ -633,6 +633,21 @@ int cc110x_set_channel(cc110x_t *dev, uint8_t channel);
*/ */
int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power); int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power);
/**
* @brief Wakes the transceiver from SLEEP mode and enters RX mode
*
* @retval 0 Success
* @retval -EIO Communication with the transceiver failed
*/
int cc110x_wakeup(cc110x_t *dev);
/**
* @brief Sets the transceiver into SLEEP mode.
*
* Only @ref cc110x_wakeup can awake the device again.
*/
void cc110x_sleep(cc110x_t *dev);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -31,10 +31,14 @@
static int sc_dump(int argc, char **argv); static int sc_dump(int argc, char **argv);
int sc_cc110x(int argc, char **argv); int sc_cc110x(int argc, char **argv);
int sc_cc110x_sleep(int argc, char **argv);
int sc_cc110x_wakeup(int argc, char **argv);
static const shell_command_t shell_commands[] = { static const shell_command_t shell_commands[] = {
{ "dump", "Enable/disable dumping of frames", sc_dump }, { "dump", "Enable/disable dumping of frames", sc_dump },
{ "cc110x", "Print the low level state of an CC110x device", sc_cc110x }, { "cc110x", "Print the low level state of an CC110x device", sc_cc110x },
{ "sleep", "Set CC110x onto sleep mode", sc_cc110x_sleep },
{ "wakeup", "Wake-up CC110x device", sc_cc110x_wakeup },
{ NULL, NULL, NULL } { NULL, NULL, NULL }
}; };
@ -126,7 +130,13 @@ int main(void)
"- Using \"cc110x\":\n" "- Using \"cc110x\":\n"
" - This tool will print low level details for all CC110x devices\n" " - This tool will print low level details for all CC110x devices\n"
" attached\n" " attached\n"
" - This will be mostly useful for debugging, not for testing\n"); " - This will be mostly useful for debugging, not for testing\n"
"- Using \"sleep\":\n"
" - Puts the given (or all, if no iface is given) transceiver into\n"
" deep sleep mode\n"
"- Using \"awake\":\n"
" - Wakes up the given (or all, if no iface is given) transceiver(s)"
" \n");
char line_buf[SHELL_DEFAULT_BUFSIZE]; char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);

View File

@ -32,30 +32,30 @@ static const char *pa_settings[] = {
static const char *state2s(cc110x_state_t state) static const char *state2s(cc110x_state_t state)
{ {
switch (state) { switch (state) {
case CC110X_STATE_IDLE: case CC110X_STATE_IDLE:
return "IDLE"; return "IDLE";
case CC110X_STATE_FRAME_READY: case CC110X_STATE_FRAME_READY:
return "Frame ready"; return "Frame ready";
case CC110X_STATE_OFF: case CC110X_STATE_OFF:
return "Off"; return "Off";
case CC110X_STATE_RX_MODE: case CC110X_STATE_RX_MODE:
return "RX mode"; return "RX mode";
case CC110X_STATE_RECEIVING: case CC110X_STATE_RECEIVING:
return "RX mode and currently receiving frame"; return "RX mode and currently receiving frame";
case CC110X_STATE_TX_MODE: case CC110X_STATE_TX_MODE:
return "TX"; return "TX";
case CC110X_STATE_TX_COMPLETING: case CC110X_STATE_TX_COMPLETING:
return "TX completing"; return "TX completing";
case CC110X_STATE_FSTXON: case CC110X_STATE_FSTXON:
return "Fast TX on"; return "Fast TX on";
case CC110X_STATE_CALIBRATE: case CC110X_STATE_CALIBRATE:
return "Calibrating"; return "Calibrating";
case CC110X_STATE_SETTLING: case CC110X_STATE_SETTLING:
return "Settling"; return "Settling";
case CC110X_STATE_RXFIFO_OVERFLOW: case CC110X_STATE_RXFIFO_OVERFLOW:
return "RX FIFO overflow"; return "RX FIFO overflow";
case CC110X_STATE_TXFIFO_UNDERFLOW: case CC110X_STATE_TXFIFO_UNDERFLOW:
return "TX FIFO underflow"; return "TX FIFO underflow";
} }
return "Unknown"; return "Unknown";
} }
@ -63,22 +63,22 @@ static const char *state2s(cc110x_state_t state)
static const char *gdoconf2s(uint8_t conf) static const char *gdoconf2s(uint8_t conf)
{ {
switch (conf) { switch (conf) {
case CC110X_GDO_ON_RX_DATA: case CC110X_GDO_ON_RX_DATA:
return "High when frame received or RX FIFO needs draining"; return "High when frame received or RX FIFO needs draining";
case CC110X_GDO_ON_TX_DATA: case CC110X_GDO_ON_TX_DATA:
return "Low when TX FIFO needs refilling"; return "Low when TX FIFO needs refilling";
case CC110X_GDO_ON_TRANSMISSION: case CC110X_GDO_ON_TRANSMISSION:
return "High while frame is incoming / outgoing"; return "High while frame is incoming / outgoing";
case CC110X_GDO_ON_CHANNEL_CLEAR: case CC110X_GDO_ON_CHANNEL_CLEAR:
return "High when channel is clear"; return "High when channel is clear";
case CC110X_GDO_ON_PLL_IN_LOCK: case CC110X_GDO_ON_PLL_IN_LOCK:
return "High when frequency generator is on and PLL is in lock"; return "High when frequency generator is on and PLL is in lock";
case CC110X_GDO_CONSTANT_LOW: case CC110X_GDO_CONSTANT_LOW:
return "Constant low"; return "Constant low";
case CC110X_GDO_CONSTANT_HIGH: case CC110X_GDO_CONSTANT_HIGH:
return "Constant high"; return "Constant high";
case CC110X_GDO0_ANALOG_TEMPERATURE: case CC110X_GDO0_ANALOG_TEMPERATURE:
return "Analog output of the temperature sensor (GDO0 only)"; return "Analog output of the temperature sensor (GDO0 only)";
} }
return "Unknown"; return "Unknown";
@ -109,6 +109,12 @@ static void print_state(cc110x_t *dev)
return; return;
} }
if (dev->state == CC110X_STATE_OFF) {
cc110x_release(dev);
puts("Device in SLEEP mode");
return;
}
/* Reading out the RSSI changes it, as SPI communication seems to generate /* Reading out the RSSI changes it, as SPI communication seems to generate
* some noise. Reading the RSSI out first yields up to 20 dBm lower * some noise. Reading the RSSI out first yields up to 20 dBm lower
* values... (E.g. about -100dBm instead of about -80dBm with no * values... (E.g. about -100dBm instead of about -80dBm with no
@ -174,34 +180,106 @@ static void print_state(cc110x_t *dev)
int sc_cc110x(int argc, char **argv) int sc_cc110x(int argc, char **argv)
{ {
switch (argc) { switch (argc) {
case 1: case 1:
for (unsigned i = 0; i < CC110X_NUM; i++){ for (unsigned i = 0; i < CC110X_NUM; i++){
printf("CC110x #%u:\n", i); printf("CC110x #%u:\n", i);
print_state(&_cc110x_devs[i]); print_state(&_cc110x_devs[i]);
}
break;
case 2:
if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
printf("Usage: %s [NUM]\n"
"\n"
"Prints the status of the CC1100/CC1101 transceiver "
"identified by NUM, or of\n"
"all available CC110x transceivers if no argument is "
"given\n", argv[0]);
}
else {
unsigned pos = atoi(argv[1]);
if (pos >= CC110X_NUM) {
puts("No such transceiver");
return EXIT_FAILURE;
} }
break; printf("CC110x #%u:\n", pos);
case 2: print_state(&_cc110x_devs[pos]);
if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) { }
printf("Usage: %s [NUM]\n" break;
"\n" default:
"Prints the status of the CC1100/CC1101 transceiver " printf("Usage: %s [NUM]\n", argv[0]);
"identified by NUM, or of\n" return EXIT_FAILURE;
"all available CC110x transceivers if no argument is " }
"given\n", argv[0]);
} return EXIT_SUCCESS;
else { }
unsigned pos = atoi(argv[1]);
if (pos >= CC110X_NUM) { int sc_cc110x_sleep(int argc, char **argv)
puts("No such transceiver"); {
return EXIT_FAILURE; switch (argc) {
} case 1:
printf("CC110x #%u:\n", pos); for (unsigned i = 0; i < CC110X_NUM; i++){
print_state(&_cc110x_devs[pos]); printf("Putting to sleep CC110x #%u:\n", i);
} cc110x_sleep(&_cc110x_devs[i]);
break; }
default: break;
printf("Usage: %s [NUM]\n", argv[0]); case 2:
return EXIT_FAILURE; if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
printf("Usage: %s [NUM]\n"
"\n"
"Sets into sleep mode the CC1100/CC1101 transceiver "
"identified by NUM, or of\n"
"all available CC110x transceivers if no argument is "
"given\n", argv[0]);
}
else {
unsigned pos = atoi(argv[1]);
if (pos >= CC110X_NUM) {
puts("No such transceiver");
return EXIT_FAILURE;
}
printf("Putting to sleep CC110x #%u:\n", pos);
cc110x_sleep(&_cc110x_devs[pos]);
}
break;
default:
printf("Usage: %s [NUM]\n", argv[0]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int sc_cc110x_wakeup(int argc, char **argv)
{
switch (argc) {
case 1:
for (unsigned i = 0; i < CC110X_NUM; i++){
printf("Waking up CC110x #%u:\n", i);
cc110x_wakeup(&_cc110x_devs[i]);
}
break;
case 2:
if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
printf("Usage: %s [NUM]\n"
"\n"
"Wakes up the CC1100/CC1101 transceiver "
"identified by NUM, or of\n"
"all available CC110x transceivers if no argument is "
"given\n", argv[0]);
}
else {
unsigned pos = atoi(argv[1]);
if (pos >= CC110X_NUM) {
puts("No such transceiver");
return EXIT_FAILURE;
}
printf("Waking up CC110x #%u:\n", pos);
cc110x_wakeup(&_cc110x_devs[pos]);
}
break;
default:
printf("Usage: %s [NUM]\n", argv[0]);
return EXIT_FAILURE;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;