1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

tests: Added test for the cc110x driver

The test application provides:
- RIOT's basic network utilities such as `ping6`
- A custom `cc110x` shell command that can be used print the low level device
  and driver state. This is mostly useful for debugging.
This commit is contained in:
Marian Buschsieweke 2019-06-19 17:27:06 +02:00
parent ccf713c5ad
commit f33b963ef4
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
3 changed files with 399 additions and 0 deletions

View File

@ -0,0 +1,57 @@
BOARD ?= msba2
include ../Makefile.tests_common
DEVICE ?= cc1100 # The MSB-A2 uses the CC1100. New boards use CC1101
BOARD_INSUFFICIENT_MEMORY += arduino-duemilanove
BOARD_INSUFFICIENT_MEMORY += arduino-leonardo
BOARD_INSUFFICIENT_MEMORY += arduino-mega2560
BOARD_INSUFFICIENT_MEMORY += arduino-nano
BOARD_INSUFFICIENT_MEMORY += arduino-uno
BOARD_INSUFFICIENT_MEMORY += blackpill
BOARD_INSUFFICIENT_MEMORY += bluepill
BOARD_INSUFFICIENT_MEMORY += i-nucleo-lrwan1
BOARD_INSUFFICIENT_MEMORY += mega-xplained
BOARD_INSUFFICIENT_MEMORY += nucleo-f031k6
BOARD_INSUFFICIENT_MEMORY += nucleo-f042k6
BOARD_INSUFFICIENT_MEMORY += nucleo-f072rb
BOARD_INSUFFICIENT_MEMORY += nucleo-f302r8
BOARD_INSUFFICIENT_MEMORY += nucleo-f303k8
BOARD_INSUFFICIENT_MEMORY += nucleo-f334r8
BOARD_INSUFFICIENT_MEMORY += nucleo-l031k6
BOARD_INSUFFICIENT_MEMORY += nucleo-l053r8
BOARD_INSUFFICIENT_MEMORY += saml10-xpro
BOARD_INSUFFICIENT_MEMORY += saml11-xpro
BOARD_INSUFFICIENT_MEMORY += stm32f0discovery
BOARD_INSUFFICIENT_MEMORY += stm32l0538-disco
BOARD_INSUFFICIENT_MEMORY += waspmote-pro
# stdlib.h for msp430 does not provide EXIT_FAILURE and EXIT_SUCCESS
BOARD_BLACKLIST += msb-430 msb-430h telosb wsn430-v1_3b wsn430-v1_4 z1
# This test will rely on a human interacting with the shell, so we better add
# the shell and some commands
USEMODULE += shell
USEMODULE += shell_commands
# Add the device driver
USEMODULE += $(DEVICE)
# Add a network stack and auto init of the network devices
USEMODULE += gnrc
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
# checking current state of network threads can be useful for testing/debuggig
USEMODULE += ps
# txtsnd can be useful to test lower layers
USEMODULE += gnrc_txtsnd
USEMODULE += auto_init_gnrc_netif
# Activate ICMPv6 error messages
USEMODULE += gnrc_icmpv6_error
# This application dumps received packets to STDIO using the pktdump module
USEMODULE += gnrc_pktdump
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
# Some statistics could also be helpful
USEMODULE += netstats_l2
USEMODULE += netstats_ipv6
include $(RIOTBASE)/Makefile.include

134
tests/driver_cc110x/main.c Normal file
View File

@ -0,0 +1,134 @@
/*
* 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.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the CC110x driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include "shell.h"
#include "shell_commands.h"
#include "net/gnrc/pktdump.h"
#include "net/gnrc.h"
#define MAIN_QUEUE_SIZE (8)
static int sc_dump(int argc, char **argv);
int sc_cc110x(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 },
{ NULL, NULL, NULL }
};
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
static gnrc_netreg_entry_t dump;
static int sc_dump(int argc, char **argv)
{
static int is_enabled = 0;
if (argc == 1) {
if (is_enabled) {
puts("Currently dumping packets");
}
else {
puts("Currently NOT dumping packets");
}
return 0;
}
else if (argc == 2) {
int new_state = 0;
if (!strcmp("y", argv[1])) {
new_state = 1;
}
else if (!strcmp("n", argv[1])) {
new_state = 0;
}
else {
printf("Usage: %s [y/n]\n", argv[0]);
return 0;
}
if (new_state == is_enabled) {
// Nothing to do;
return 0;
}
if (new_state) {
if (gnrc_netreg_register(GNRC_NETTYPE_SIXLOWPAN, &dump)) {
puts("Failed to register packet dumping");
}
}
else {
gnrc_netreg_unregister(GNRC_NETTYPE_SIXLOWPAN, &dump);
}
is_enabled = new_state;
return 0;
}
printf("Usage: %s [y/n]\n", argv[0]);
return 0;
}
int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
gnrc_netreg_entry_init_pid(&dump, GNRC_NETREG_DEMUX_CTX_ALL,
gnrc_pktdump_pid);
puts("cc110x driver test application\n"
"==============================\n"
"\n"
"Use the shell and two boards equipped with an CC1100/CC1101\n"
"transceiver to test the driver. Common testing tasks:\n"
"\n"
"- Using \"ifconfig\":\n"
" - Check the information stated for plausibility/correctness\n"
" - Try to get/set parameters like TX power, channel, address, ...\n"
" - BEWARE: With short communication distances (<=1m) for boards\n"
" with high gain antennas a high TX power may result in packet\n"
" loss: The incoming signal can only be demodulated when the\n"
" input signal is at most +10 dBm on the CC1101.\n"
" - Check the statistics for correctness/plausibility (after\n"
" sending frames using \"txtsnd\" or \"ping6\")\n"
"- Using \"ping6\":\n"
" - Does the other device respond to the ping?\n"
" - Does the measured RSSI increase when the nodes are closer\n"
" together?\n"
" - Try to increase the size of the pings, so that the TX/RX FIFO\n"
" needs to be filled/drain more than once per frame. The TX/RX\n"
" FIFO can hold 64 bytes\n"
" - Try to increase the size of the pings in order to trigger L2\n"
" fragmentation. The driver supports frames of up to 255 bytes\n"
"- Using \"txtsnd\":\n"
" - Turn on packet dumping using the command \"dump y\" on node A\n"
" - Send both unicast and broadcast frame from node B to A\n"
"- 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");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}

View File

@ -0,0 +1,208 @@
/*
* 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 */
if (cc110x_acquire(dev) != SPI_OK) {
puts("Failed to acquire CC1100/CC1101 transceiver");
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;
}