diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c index 8c96111877..a175845831 100644 --- a/drivers/cc110x/cc110x.c +++ b/drivers/cc110x/cc110x.c @@ -89,6 +89,13 @@ int cc110x_apply_config(cc110x_t *dev, const cc110x_config_t *conf, 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) { 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; } - uint8_t frend0 = 0x10 | (uint8_t)power; - cc110x_write(dev, CC110X_REG_FREND0, frend0); - dev->tx_power = power; + _set_tx_power(dev, power); + cc110x_release(dev); 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); 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); +} diff --git a/drivers/cc110x/cc110x_communication.c b/drivers/cc110x/cc110x_communication.c index 7afac9c9e9..86ae38d1d6 100644 --- a/drivers/cc110x/cc110x_communication.c +++ b/drivers/cc110x/cc110x_communication.c @@ -18,13 +18,16 @@ */ #include + +#include "cc110x.h" +#include "cc110x_communication.h" +#include "cc110x_constants.h" +#include "cc110x_internal.h" #include "periph/gpio.h" #include "periph/spi.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; @@ -32,9 +35,19 @@ int cc110x_power_on(cc110x_t *dev) return -EIO; } gpio_clear(cs); - xtimer_usleep(150); + xtimer_usleep(CC110X_WAKEUP_TIME_US); gpio_set(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; } diff --git a/drivers/cc110x/cc110x_netdev.c b/drivers/cc110x/cc110x_netdev.c index c896efbb18..ae9949516e 100644 --- a/drivers/cc110x/cc110x_netdev.c +++ b/drivers/cc110x/cc110x_netdev.c @@ -120,36 +120,36 @@ static int identify_device(cc110x_t *dev) } switch (version) { - case 3: - DEBUG("[cc110x] Detected CC1100 transceiver\n"); - /* RSSI offset is 78dBm @ 868MHz & 250kBaud. - * Depends on the symbol rate and base band and ranges from - * 74dBm to 79dBm. - */ - dev->rssi_offset = 78; - return 0; - case 5: - DEBUG("[cc110x] Detected CC1100E transceiver\n"); - /* RSSI offset is 79 dBm @ 250kbps & 250 kbps. - * Depends on base band and symbol rate and ranges from - * 75dBm to 79dBm - */ - dev->rssi_offset = 79; - return 0; - case 4: - /* falls through */ - case 14: - /* falls through */ - case 20: - /* RSSI offset for the CC1101 is independent of symbol rate and - * base 74 dBm - */ - dev->rssi_offset = 74; - DEBUG("[cc110x] Detected CC1101 transceiver\n"); - return 0; - default: - DEBUG("[cc110x] Device not a CC110x transceiver\n"); - return -1; + case 3: + DEBUG("[cc110x] Detected CC1100 transceiver\n"); + /* RSSI offset is 78dBm @ 868MHz & 250kBaud. + * Depends on the symbol rate and base band and ranges from + * 74dBm to 79dBm. + */ + dev->rssi_offset = 78; + return 0; + case 5: + DEBUG("[cc110x] Detected CC1100E transceiver\n"); + /* RSSI offset is 79 dBm @ 250kbps & 250 kbps. + * Depends on base band and symbol rate and ranges from + * 75dBm to 79dBm + */ + dev->rssi_offset = 79; + return 0; + case 4: + /* falls through */ + case 14: + /* falls through */ + case 20: + /* RSSI offset for the CC1101 is independent of symbol rate and + * base 74 dBm + */ + dev->rssi_offset = 74; + DEBUG("[cc110x] Detected CC1101 transceiver\n"); + return 0; + default: + DEBUG("[cc110x] Device not a CC110x transceiver\n"); + 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 * 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 - * 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. */ - 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"); 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 */ cc110x_cmd(dev, CC110X_STROBE_RESET); cc110x_release(dev); /* 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 " "after reset\n"); 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)) { DEBUG("[cc110x] netdev_driver_t::init(): Device identification failed\n"); cc110x_release(dev); @@ -414,20 +402,23 @@ static int cc110x_send(netdev_t *netdev, const iolist_t *iolist) } switch (dev->state) { - case CC110X_STATE_FSTXON: - /* falls through */ - case CC110X_STATE_RX_MODE: - break; - case CC110X_STATE_RECEIVING: - cc110x_release(dev); - DEBUG("[cc110x] netdev_driver_t::send(): Refusing to send while " - "receiving a frame\n"); - return -EBUSY; - default: - cc110x_release(dev); - DEBUG("[cc110x] netdev_driver_t::send(): Driver state %i prevents " - "sending\n", (int)dev->state); - return -1; + case CC110X_STATE_FSTXON: + /* falls through */ + case CC110X_STATE_RX_MODE: + break; + case CC110X_STATE_RECEIVING: + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::send(): Refusing to send while " + "receiving a frame\n"); + return -EBUSY; + case CC110X_STATE_OFF: + cc110x_release(dev); + return -ENOTSUP; + default: + 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 */ @@ -530,42 +521,73 @@ static int cc110x_get(netdev_t *netdev, netopt_t opt, (void)max_len; /* only used in assert() */ switch (opt) { - case NETOPT_DEVICE_TYPE: - assert(max_len == sizeof(uint16_t)); - *((uint16_t *)val) = NETDEV_TYPE_CC110X; - return sizeof(uint16_t); - case NETOPT_PROTO: - assert(max_len == sizeof(gnrc_nettype_t)); - *((gnrc_nettype_t *)val) = CC110X_DEFAULT_PROTOCOL; - return sizeof(gnrc_nettype_t); - case NETOPT_MAX_PDU_SIZE: - assert(max_len == sizeof(uint16_t)); - *((uint16_t *)val) = CC110X_MAX_FRAME_SIZE - sizeof(cc1xxx_l2hdr_t); - return sizeof(uint16_t); - case NETOPT_ADDR_LEN: - /* falls through */ - case NETOPT_SRC_LEN: - assert(max_len == sizeof(uint16_t)); - *((uint16_t *)val) = CC1XXX_ADDR_SIZE; - return sizeof(uint16_t); - case NETOPT_ADDRESS: - assert(max_len >= CC1XXX_ADDR_SIZE); - *((uint8_t *)val) = dev->addr; - return CC1XXX_ADDR_SIZE; - case NETOPT_CHANNEL: - assert(max_len == sizeof(uint16_t)); - *((uint16_t *)val) = dev->channel; - return sizeof(uint16_t); - case NETOPT_TX_POWER: - assert(max_len == sizeof(uint16_t)); - *((uint16_t *)val) = dbm_from_tx_power[dev->tx_power]; - return sizeof(uint16_t); - case NETOPT_PROMISCUOUSMODE: - assert(max_len == sizeof(netopt_enable_t)); - return cc110x_get_promiscuous_mode(dev, val); - default: - return -ENOTSUP; + case NETOPT_DEVICE_TYPE: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = NETDEV_TYPE_CC110X; + return sizeof(uint16_t); + case NETOPT_PROTO: + assert(max_len == sizeof(gnrc_nettype_t)); + *((gnrc_nettype_t *)val) = CC110X_DEFAULT_PROTOCOL; + return sizeof(gnrc_nettype_t); + case NETOPT_MAX_PDU_SIZE: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = CC110X_MAX_FRAME_SIZE - sizeof(cc1xxx_l2hdr_t); + return sizeof(uint16_t); + case NETOPT_ADDR_LEN: + /* falls through */ + case NETOPT_SRC_LEN: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = CC1XXX_ADDR_SIZE; + return sizeof(uint16_t); + case NETOPT_ADDRESS: + assert(max_len >= CC1XXX_ADDR_SIZE); + *((uint8_t *)val) = dev->addr; + return CC1XXX_ADDR_SIZE; + case NETOPT_CHANNEL: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = dev->channel; + return sizeof(uint16_t); + case NETOPT_TX_POWER: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = dbm_from_tx_power[dev->tx_power]; + return sizeof(uint16_t); + case NETOPT_PROMISCUOUSMODE: + assert(max_len == sizeof(netopt_enable_t)); + return cc110x_get_promiscuous_mode(dev, val); + case NETOPT_STATE: + 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; switch (opt) { - case NETOPT_ADDRESS: - assert(len == CC1XXX_ADDR_SIZE); - return cc110x_set_addr(dev, *((uint8_t *)val)); - case NETOPT_CHANNEL: - { - assert(len == sizeof(uint16_t)); - int retval; - uint16_t channel = *((uint16_t *)val); - if (channel >= CC110X_MAX_CHANNELS) { - return -EINVAL; - } - if ((retval = cc110x_set_channel(dev, (uint8_t)channel))) { - return retval; + case NETOPT_ADDRESS: + assert(len == CC1XXX_ADDR_SIZE); + return cc110x_set_addr(dev, *((uint8_t *)val)); + case NETOPT_CHANNEL: + { + assert(len == sizeof(uint16_t)); + int retval; + uint16_t channel = *((uint16_t *)val); + if (channel >= CC110X_MAX_CHANNELS) { + return -EINVAL; + } + if ((retval = cc110x_set_channel(dev, (uint8_t)channel))) { + 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); - 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; - } - } - if (cc110x_set_tx_power(dev, power)) { - return -EINVAL; - } + if (cc110x_set_tx_power(dev, power)) { + return -EINVAL; } - return sizeof(uint16_t); - case NETOPT_PROMISCUOUSMODE: - assert(len == sizeof(netopt_enable_t)); - return cc110x_set_promiscuous_mode(dev, *((const netopt_enable_t *)val)); + } + return sizeof(uint16_t); + case NETOPT_PROMISCUOUSMODE: + 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: return -ENOTSUP; + } + break; + default: + return -ENOTSUP; } } diff --git a/drivers/cc110x/include/cc110x_communication.h b/drivers/cc110x/include/cc110x_communication.h index 02e254bd7b..2f26636318 100644 --- a/drivers/cc110x/include/cc110x_communication.h +++ b/drivers/cc110x/include/cc110x_communication.h @@ -35,8 +35,9 @@ extern "C" { * @retval SPI_NOMODE SPI mode 0 not supported by MCU * @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. - * (Only needed *once* when the driver initializes.) + * @pre When first acquiring the device either after boot or after having put + * 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) { @@ -200,11 +201,13 @@ uint8_t cc110x_status(cc110x_t *dev); * 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. * + * @pre The device was not acquired and in low power mode + * @post The device is in IDLE mode and acquired + * * @retval 0 Success * @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 } diff --git a/drivers/cc110x/include/cc110x_constants.h b/drivers/cc110x/include/cc110x_constants.h index 45e5280183..ce4a49062c 100644 --- a/drivers/cc110x/include/cc110x_constants.h +++ b/drivers/cc110x/include/cc110x_constants.h @@ -570,6 +570,11 @@ extern "C" { #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 } #endif diff --git a/drivers/include/cc110x.h b/drivers/include/cc110x.h index 0405739ad9..710cb4d5a3 100644 --- a/drivers/include/cc110x.h +++ b/drivers/include/cc110x.h @@ -235,7 +235,8 @@ extern "C" { #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 * @{ */ @@ -263,7 +264,7 @@ typedef enum { */ 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 * 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 */ } cc110x_patable_t; - /** * @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); +/** + * @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 } #endif diff --git a/tests/driver_cc110x/main.c b/tests/driver_cc110x/main.c index 5e3ff85d62..b13f49da2c 100644 --- a/tests/driver_cc110x/main.c +++ b/tests/driver_cc110x/main.c @@ -31,10 +31,14 @@ static int sc_dump(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[] = { { "dump", "Enable/disable dumping of frames", sc_dump }, { "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 } }; @@ -126,7 +130,13 @@ int main(void) "- Using \"cc110x\":\n" " - This tool will print low level details for all CC110x devices\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]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); diff --git a/tests/driver_cc110x/sc_cc110x.c b/tests/driver_cc110x/sc_cc110x.c index 5cf55d652f..c42a14a7ea 100644 --- a/tests/driver_cc110x/sc_cc110x.c +++ b/tests/driver_cc110x/sc_cc110x.c @@ -32,30 +32,30 @@ static const char *pa_settings[] = { static const char *state2s(cc110x_state_t state) { switch (state) { - case CC110X_STATE_IDLE: - return "IDLE"; - case CC110X_STATE_FRAME_READY: - return "Frame ready"; - case CC110X_STATE_OFF: - return "Off"; - case CC110X_STATE_RX_MODE: - return "RX mode"; - case CC110X_STATE_RECEIVING: - return "RX mode and currently receiving frame"; - case CC110X_STATE_TX_MODE: - return "TX"; - case CC110X_STATE_TX_COMPLETING: - return "TX completing"; - case CC110X_STATE_FSTXON: - return "Fast TX on"; - case CC110X_STATE_CALIBRATE: - return "Calibrating"; - case CC110X_STATE_SETTLING: - return "Settling"; - case CC110X_STATE_RXFIFO_OVERFLOW: - return "RX FIFO overflow"; - case CC110X_STATE_TXFIFO_UNDERFLOW: - return "TX FIFO underflow"; + case CC110X_STATE_IDLE: + return "IDLE"; + case CC110X_STATE_FRAME_READY: + return "Frame ready"; + case CC110X_STATE_OFF: + return "Off"; + case CC110X_STATE_RX_MODE: + return "RX mode"; + case CC110X_STATE_RECEIVING: + return "RX mode and currently receiving frame"; + case CC110X_STATE_TX_MODE: + return "TX"; + case CC110X_STATE_TX_COMPLETING: + return "TX completing"; + case CC110X_STATE_FSTXON: + return "Fast TX on"; + case CC110X_STATE_CALIBRATE: + return "Calibrating"; + case CC110X_STATE_SETTLING: + return "Settling"; + case CC110X_STATE_RXFIFO_OVERFLOW: + return "RX FIFO overflow"; + case CC110X_STATE_TXFIFO_UNDERFLOW: + return "TX FIFO underflow"; } return "Unknown"; } @@ -63,22 +63,22 @@ static const char *state2s(cc110x_state_t state) static const char *gdoconf2s(uint8_t conf) { switch (conf) { - case CC110X_GDO_ON_RX_DATA: - return "High when frame received or RX FIFO needs draining"; - case CC110X_GDO_ON_TX_DATA: - return "Low when TX FIFO needs refilling"; - case CC110X_GDO_ON_TRANSMISSION: - return "High while frame is incoming / outgoing"; - case CC110X_GDO_ON_CHANNEL_CLEAR: - return "High when channel is clear"; - case CC110X_GDO_ON_PLL_IN_LOCK: - return "High when frequency generator is on and PLL is in lock"; - case CC110X_GDO_CONSTANT_LOW: - return "Constant low"; - case CC110X_GDO_CONSTANT_HIGH: - return "Constant high"; - case CC110X_GDO0_ANALOG_TEMPERATURE: - return "Analog output of the temperature sensor (GDO0 only)"; + case CC110X_GDO_ON_RX_DATA: + return "High when frame received or RX FIFO needs draining"; + case CC110X_GDO_ON_TX_DATA: + return "Low when TX FIFO needs refilling"; + case CC110X_GDO_ON_TRANSMISSION: + return "High while frame is incoming / outgoing"; + case CC110X_GDO_ON_CHANNEL_CLEAR: + return "High when channel is clear"; + case CC110X_GDO_ON_PLL_IN_LOCK: + return "High when frequency generator is on and PLL is in lock"; + case CC110X_GDO_CONSTANT_LOW: + return "Constant low"; + case CC110X_GDO_CONSTANT_HIGH: + return "Constant high"; + case CC110X_GDO0_ANALOG_TEMPERATURE: + return "Analog output of the temperature sensor (GDO0 only)"; } return "Unknown"; @@ -109,6 +109,12 @@ static void print_state(cc110x_t *dev) 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 * some noise. Reading the RSSI out first yields up to 20 dBm lower * 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) { switch (argc) { - case 1: - for (unsigned i = 0; i < CC110X_NUM; i++){ - printf("CC110x #%u:\n", i); - print_state(&_cc110x_devs[i]); + case 1: + for (unsigned i = 0; i < CC110X_NUM; i++){ + printf("CC110x #%u:\n", 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; - 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; - } - printf("CC110x #%u:\n", pos); - print_state(&_cc110x_devs[pos]); - } - break; - default: - printf("Usage: %s [NUM]\n", argv[0]); - return EXIT_FAILURE; + printf("CC110x #%u:\n", pos); + print_state(&_cc110x_devs[pos]); + } + break; + default: + printf("Usage: %s [NUM]\n", argv[0]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int sc_cc110x_sleep(int argc, char **argv) +{ + switch (argc) { + case 1: + for (unsigned i = 0; i < CC110X_NUM; i++){ + printf("Putting to sleep CC110x #%u:\n", i); + cc110x_sleep(&_cc110x_devs[i]); + } + break; + case 2: + 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;