mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
284 lines
8.5 KiB
C
284 lines
8.5 KiB
C
/*
|
|
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "cc110x.h"
|
|
#include "cc110x_internal.h"
|
|
#include "cc110x_params.h"
|
|
|
|
#define CC110X_NUM (sizeof(cc110x_params) / sizeof(cc110x_params[0]))
|
|
|
|
extern cc110x_t _cc110x_devs[CC110X_NUM];
|
|
|
|
static const char *pa_settings[] = {
|
|
"-30",
|
|
"-20",
|
|
"-15",
|
|
"-10",
|
|
"0",
|
|
"+5",
|
|
"+7",
|
|
"+10",
|
|
};
|
|
|
|
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";
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
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)";
|
|
}
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
static inline const char *b2s(int boolean)
|
|
{
|
|
return (boolean) ? "1" : "0";
|
|
}
|
|
|
|
static void print_state(cc110x_t *dev)
|
|
{
|
|
uint8_t status;
|
|
uint8_t pktstatus;
|
|
int8_t rssi_raw;
|
|
uint8_t iocfg2;
|
|
uint8_t iocfg0;
|
|
uint8_t txbytes;
|
|
uint8_t rxbytes;
|
|
uint8_t hwaddr;
|
|
uint8_t frend0;
|
|
uint8_t physical_channel;
|
|
uint8_t virtual_channel;
|
|
|
|
/* Get all required data and release device */
|
|
cc110x_acquire(dev);
|
|
|
|
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
|
|
* other sources of Sub-GHz RF)
|
|
*/
|
|
status = cc110x_read_reliable(dev, CC110X_REG_RSSI, (uint8_t *)&rssi_raw);
|
|
cc110x_read_reliable(dev, CC110X_REG_PKTSTATUS, &pktstatus);
|
|
cc110x_read(dev, CC110X_REG_IOCFG2, &iocfg2);
|
|
cc110x_read(dev, CC110X_REG_IOCFG0, &iocfg0);
|
|
cc110x_read(dev, CC110X_REG_ADDR, &hwaddr);
|
|
cc110x_read(dev, CC110X_REG_FREND0, &frend0);
|
|
cc110x_read(dev, CC110X_REG_CHANNR, &physical_channel);
|
|
virtual_channel = dev->channel;
|
|
cc110x_read_reliable(dev, CC110X_REG_TXBYTES, &txbytes);
|
|
cc110x_read_reliable(dev, CC110X_REG_RXBYTES, &rxbytes);
|
|
cc110x_state_t sw_state = dev->state;
|
|
cc110x_release(dev);
|
|
|
|
/* Parse obtained raw data */
|
|
cc110x_state_t hw_state = (status >> 4) & 0x03;
|
|
int ready = !(status & 0x80);
|
|
int rssi = ((int)rssi_raw / 2) - (int)dev->rssi_offset;
|
|
int gdo0 = pktstatus & CC110X_PKTSTATUS_GDO0;
|
|
int gdo2 = pktstatus & CC110X_PKTSTATUS_GDO2;
|
|
int recv = pktstatus & CC110X_PKTSTATUS_RECEIVING;
|
|
int cca = pktstatus & CC110X_PKTSTATUS_CCA;
|
|
int cs = pktstatus & CC110X_PKTSTATUS_CS;
|
|
const char *pa = pa_settings[frend0 & 0x07];
|
|
|
|
/* Print all information */
|
|
if (!ready) {
|
|
puts(" CRITICAL: Crystal has not stabilized yet!");
|
|
}
|
|
printf(" GDO0: %s (%s)\n", b2s(gdo0), gdoconf2s(iocfg0));
|
|
printf(" GDO2: %s (%s)\n", b2s(gdo2), gdoconf2s(iocfg2));
|
|
printf(" Receiving: %s, CCA: %s, CS: %s\n", b2s(recv), b2s(cca), b2s(cs));
|
|
printf(" RSSI: %i.%sdBm, TX power: %sdBm\n",
|
|
rssi, (rssi_raw & 1) ? "5" : "0", pa);
|
|
printf(" L2 addr: %02x, physical channel: %u, virtual channel: %u\n",
|
|
(int)hwaddr, (unsigned)physical_channel, (unsigned)virtual_channel);
|
|
if (dev->channels->map[virtual_channel] != physical_channel) {
|
|
puts(" WARNING: Physical channel does not match channel map");
|
|
}
|
|
printf(" Driver state: %s, transceiver state: %s\n",
|
|
state2s(sw_state), state2s(hw_state));
|
|
if (hw_state != (sw_state & 0x07)) {
|
|
puts(" WARNING: Transceiver and device state don't match!");
|
|
}
|
|
if (0x80 & txbytes) {
|
|
puts(" TX FIFO: Underflown!");
|
|
}
|
|
else {
|
|
printf(" TX FIFO: %iB\n", (int)txbytes);
|
|
}
|
|
if (0x80 & rxbytes) {
|
|
puts(" RX FIFO: Overflown!");
|
|
}
|
|
else {
|
|
printf(" RX FIFO: %iB\n", (int)rxbytes);
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|