Merge branch 'develop' into bugfix/simplelink/board

This commit is contained in:
Simon Duquennoy 2018-10-12 14:16:23 +02:00 committed by GitHub
commit 5cecd5f9c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 2547 additions and 561 deletions

View File

@ -29,10 +29,17 @@ else
CFLAGS += -O2
endif
### Use CMSIS and the existing dbg-io from arch/cpu/arm/common
CONTIKI_ARM_DIRS += . common/dbg-io
### Use CMSIS from arch/cpu/arm/common
CONTIKI_ARM_DIRS += .
CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS))
### Default to use os/lib/dbg-io unless configured to do otherwise
MAKE_WITH_LIB_DBG_IO ?= 1
ifeq ($(MAKE_WITH_LIB_DBG_IO),1)
MODULES += os/lib/dbg-io
endif
### CPU-dependent cleanup files
CLEAN += *.elf *.bin *.lst *.hex *.i16hex

View File

@ -28,8 +28,6 @@ CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c
CONTIKI_CPU_SOURCEFILES += i2c.c cc2538-temp-sensor.c vdd3-sensor.c
CONTIKI_CPU_SOURCEFILES += cfs-coffee.c cfs-coffee-arch.c pwm.c
MODULES += os/lib/dbg-io
USB_SOURCEFILES += usb-core.c cdc-acm.c usb-arch.c usb-serial.c cdc-acm-descriptors.c
CPU_START_SOURCEFILES = startup-gcc.c

View File

@ -37,10 +37,13 @@
#define RTIMER_ARCH_SECOND 32768
/*---------------------------------------------------------------------------*/
/* 352us from calling transmit() until the SFD byte has been sent */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352))
#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352))
/* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */
#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250))
#define RADIO_DELAY_BEFORE_DETECT 0
#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250))
#define CC2538_DELAY_BEFORE_DETECT 0
/* Frame filtering done in software */
#define TSCH_CONF_HW_FRAME_FILTERING 0
#ifndef TSCH_CONF_BASE_DRIFT_PPM
/* The drift compared to "true" 10ms slots.
* Enable adaptive sync to enable compensation for this.
@ -54,9 +57,6 @@
#define TSCH_CONF_BASE_DRIFT_PPM -977
#endif
#if MAC_CONF_WITH_TSCH
#define TSCH_CONF_HW_FRAME_FILTERING 0
#endif /* MAC_CONF_WITH_TSCH */
/*---------------------------------------------------------------------------*/
#define SPI_CONF_CONTROLLER_COUNT 2
/*---------------------------------------------------------------------------*/

View File

@ -42,6 +42,7 @@
#include "net/packetbuf.h"
#include "net/linkaddr.h"
#include "net/netstack.h"
#include "net/mac/tsch/tsch.h"
#include "sys/energest.h"
#include "dev/cc2538-rf.h"
#include "dev/rfcore.h"
@ -68,13 +69,10 @@
*/
#define UDMA_RX_SIZE_THRESHOLD 3
/*---------------------------------------------------------------------------*/
#include <stdio.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "cc2538-rf"
#define LOG_LEVEL LOG_LEVEL_NONE
/*---------------------------------------------------------------------------*/
/* Local RF Flags */
#define RX_ACTIVE 0x80
@ -86,6 +84,7 @@
#define LQI_BIT_MASK 0x7F
/* RSSI Offset */
#define RSSI_OFFSET 73
#define RSSI_INVALID -128
/* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */
#define ONOFF_TIME RTIMER_ARCH_SECOND / 3125
@ -156,28 +155,19 @@ PROCESS(cc2538_rf_process, "cc2538 RF driver");
static uint8_t
get_channel()
{
uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ;
return (chan - CC2538_RF_CHANNEL_MIN) / CC2538_RF_CHANNEL_SPACING
+ CC2538_RF_CHANNEL_MIN;
return rf_channel;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set the current operating channel
* \param channel The desired channel as a value in [11,26]
* \return Returns a value in [11,26] representing the current channel
* or a negative value if \e channel was out of bounds
*/
static int8_t
static void
set_channel(uint8_t channel)
{
uint8_t was_on = 0;
PRINTF("RF: Set Channel\n");
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
return CC2538_RF_CHANNEL_SET_ERROR;
}
LOG_INFO("Set Channel\n");
/* Changes to FREQCTRL take effect after the next recalibration */
@ -195,8 +185,6 @@ set_channel(uint8_t channel)
}
rf_channel = channel;
return (int8_t)channel;
}
/*---------------------------------------------------------------------------*/
static radio_value_t
@ -244,10 +232,11 @@ get_rssi(void)
on();
}
/* Wait on RSSI_VALID */
while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0);
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
/* Wait for a valid RSSI reading */
do {
rssi = REG(RFCORE_XREG_RSSI);
} while(rssi == RSSI_INVALID);
rssi -= RSSI_OFFSET;
/* If we were off, turn back off */
if(was_off) {
@ -322,6 +311,16 @@ set_frame_filtering(uint8_t enable)
}
/*---------------------------------------------------------------------------*/
static void
set_shr_search(int enable)
{
if(enable) {
REG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_RX_MODE;
} else {
REG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_RX_MODE;
}
}
/*---------------------------------------------------------------------------*/
static void
mac_timer_init(void)
{
CLOCK_STABLE();
@ -403,7 +402,7 @@ channel_clear(void)
int cca;
uint8_t was_off = 0;
PRINTF("RF: CCA\n");
LOG_INFO("CCA\n");
/* If we are off, turn on first */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
@ -431,7 +430,7 @@ channel_clear(void)
static int
on(void)
{
PRINTF("RF: On\n");
LOG_INFO("On\n");
if(!(rf_flags & RX_ACTIVE)) {
CC2538_RF_CSP_ISFLUSHRX();
@ -447,7 +446,7 @@ on(void)
static int
off(void)
{
PRINTF("RF: Off\n");
LOG_INFO("Off\n");
/* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */
while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);
@ -470,7 +469,7 @@ off(void)
static int
init(void)
{
PRINTF("RF: Init\n");
LOG_INFO("Init\n");
if(rf_flags & RF_ON) {
return 0;
@ -490,6 +489,7 @@ init(void)
REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */
REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */
REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */
REG(RFCORE_XREG_FSCAL1) = 0x01; /** Tune frequency calibration */
/*
* Defaults:
@ -513,6 +513,9 @@ init(void)
set_channel(rf_channel);
/* Enable SHR search */
set_shr_search(1);
/* Acknowledge all RF Error interrupts */
REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM;
NVIC_EnableIRQ(RF_ERR_IRQn);
@ -545,8 +548,6 @@ init(void)
rf_flags |= RF_ON;
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
return 1;
}
/*---------------------------------------------------------------------------*/
@ -555,7 +556,7 @@ prepare(const void *payload, unsigned short payload_len)
{
uint8_t i;
PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN);
LOG_INFO("Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN);
/*
* When we transmit in very quick bursts, make sure previous transmission
@ -569,12 +570,12 @@ prepare(const void *payload, unsigned short payload_len)
CC2538_RF_CSP_ISFLUSHTX();
PRINTF("RF: data = ");
LOG_INFO("data = ");
/* Send the phy length byte first */
REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN;
if(CC2538_RF_CONF_TX_USE_DMA) {
PRINTF("<uDMA payload>");
LOG_INFO_("<uDMA payload>");
/* Set the transfer source's end address */
udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN,
@ -598,10 +599,10 @@ prepare(const void *payload, unsigned short payload_len)
} else {
for(i = 0; i < payload_len; i++) {
REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i];
PRINTF("%02x", ((unsigned char *)(payload))[i]);
LOG_INFO_("%02x", ((unsigned char *)(payload))[i]);
}
}
PRINTF("\n");
LOG_INFO_("\n");
return 0;
}
@ -614,7 +615,7 @@ transmit(unsigned short transmit_len)
rtimer_clock_t t0;
uint8_t was_off = 0;
PRINTF("RF: Transmit\n");
LOG_INFO("Transmit\n");
if(!(rf_flags & RX_ACTIVE)) {
t0 = RTIMER_NOW();
@ -649,7 +650,7 @@ transmit(unsigned short transmit_len)
}
if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) {
PRINTF("RF: TX never active.\n");
LOG_ERR("TX never active.\n");
CC2538_RF_CSP_ISFLUSHTX();
ret = RADIO_TX_ERR;
} else {
@ -679,7 +680,7 @@ read(void *buf, unsigned short bufsize)
uint8_t i;
uint8_t len;
PRINTF("RF: Read\n");
LOG_INFO("Read\n");
if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) {
return 0;
@ -691,33 +692,33 @@ read(void *buf, unsigned short bufsize)
/* Check for validity */
if(len > CC2538_RF_MAX_PACKET_LEN) {
/* Oops, we must be out of sync. */
PRINTF("RF: bad sync\n");
LOG_ERR("RF: bad sync\n");
CC2538_RF_CSP_ISFLUSHRX();
return 0;
}
if(len <= CC2538_RF_MIN_PACKET_LEN) {
PRINTF("RF: too short\n");
LOG_ERR("RF: too short\n");
CC2538_RF_CSP_ISFLUSHRX();
return 0;
}
if(len - CHECKSUM_LEN > bufsize) {
PRINTF("RF: too long\n");
LOG_ERR("RF: too long\n");
CC2538_RF_CSP_ISFLUSHRX();
return 0;
}
/* If we reach here, chances are the FIFO is holding a valid frame */
PRINTF("RF: read (0x%02x bytes) = ", len);
LOG_INFO("read (0x%02x bytes) = ", len);
len -= CHECKSUM_LEN;
/* Don't bother with uDMA for short frames (e.g. ACKs) */
if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) {
PRINTF("<uDMA payload>");
LOG_INFO_("<uDMA payload>");
/* Set the transfer destination's end address */
udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN,
@ -738,7 +739,7 @@ read(void *buf, unsigned short bufsize)
} else {
for(i = 0; i < len; ++i) {
((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA);
PRINTF("%02x", ((unsigned char *)(buf))[i]);
LOG_INFO_("%02x", ((unsigned char *)(buf))[i]);
}
}
@ -746,14 +747,14 @@ read(void *buf, unsigned short bufsize)
rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET;
crc_corr = REG(RFCORE_SFR_RFDATA);
PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr);
LOG_INFO_("%02x%02x\n", (uint8_t)rssi, crc_corr);
/* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
if(crc_corr & CRC_BIT_MASK) {
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
} else {
PRINTF("RF: Bad CRC\n");
LOG_ERR("Bad CRC\n");
CC2538_RF_CSP_ISFLUSHRX();
return 0;
}
@ -775,7 +776,7 @@ read(void *buf, unsigned short bufsize)
static int
receiving_packet(void)
{
PRINTF("RF: Receiving\n");
LOG_INFO("Receiving\n");
/*
* SFD high while transmitting and receiving.
@ -791,7 +792,7 @@ receiving_packet(void)
static int
pending_packet(void)
{
PRINTF("RF: Pending\n");
LOG_INFO("Pending\n");
return REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP;
}
@ -862,6 +863,21 @@ get_value(radio_param_t param, radio_value_t *value)
case RADIO_CONST_TXPOWER_MAX:
*value = OUTPUT_POWER_MAX;
return RADIO_RESULT_OK;
case RADIO_CONST_PHY_OVERHEAD:
*value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */
return RADIO_RESULT_OK;
case RADIO_CONST_BYTE_AIR_TIME:
*value = (radio_value_t)32; /* 250kbps data rate. One byte = 32us.*/
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_TX:
*value = (radio_value_t)CC2538_DELAY_BEFORE_TX;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_RX:
*value = (radio_value_t)CC2538_DELAY_BEFORE_RX;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_DETECT:
*value = (radio_value_t)CC2538_DELAY_BEFORE_DETECT;
return RADIO_RESULT_OK;
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
@ -886,9 +902,7 @@ set_value(radio_param_t param, radio_value_t value)
value > CC2538_RF_CHANNEL_MAX) {
return RADIO_RESULT_INVALID_VALUE;
}
if(set_channel(value) == CC2538_RF_CHANNEL_SET_ERROR) {
return RADIO_RESULT_ERROR;
}
set_channel(value);
return RADIO_RESULT_OK;
case RADIO_PARAM_PAN_ID:
set_pan_id(value & 0xffff);
@ -924,6 +938,9 @@ set_value(radio_param_t param, radio_value_t value)
case RADIO_PARAM_CCA_THRESHOLD:
set_cca_threshold(value);
return RADIO_RESULT_OK;
case RADIO_PARAM_SHR_SEARCH:
set_shr_search(value);
return RADIO_RESULT_OK;
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
@ -956,6 +973,16 @@ get_object(radio_param_t param, void *dest, size_t size)
return RADIO_RESULT_OK;
}
#if MAC_CONF_WITH_TSCH
if(param == RADIO_CONST_TSCH_TIMING) {
if(size != sizeof(uint16_t *) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(const uint16_t **)dest = tsch_timeslot_timing_us_10000;
return RADIO_RESULT_OK;
}
#endif /* MAC_CONF_WITH_TSCH */
return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
@ -1085,7 +1112,7 @@ cc2538_rf_rx_tx_isr(void)
void
cc2538_rf_err_isr(void)
{
PRINTF("RF Error: 0x%08lx\n", REG(RFCORE_SFR_RFERRF));
LOG_ERR("Error 0x%08lx occurred\n", REG(RFCORE_SFR_RFERRF));
/* If the error is not an RX FIFO overflow, set a flag */
if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) {
@ -1097,10 +1124,5 @@ cc2538_rf_err_isr(void)
process_poll(&cc2538_rf_process);
}
/*---------------------------------------------------------------------------*/
void
cc2538_rf_set_promiscous_mode(char p)
{
set_frame_filtering(p);
}
/*---------------------------------------------------------------------------*/
/** @} */

View File

@ -56,7 +56,6 @@
#define CC2538_RF_CHANNEL_MIN 11
#define CC2538_RF_CHANNEL_MAX 26
#define CC2538_RF_CHANNEL_SPACING 5
#define CC2538_RF_CHANNEL_SET_ERROR -1
#define CC2538_RF_MAX_PACKET_LEN 127
#define CC2538_RF_MIN_PACKET_LEN 4
#define CC2538_RF_CCA_CLEAR 1
@ -113,7 +112,6 @@
*/
#define CC2538_RF_CSP_ISFLUSHRX() do { \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
} while(0)
/**
@ -121,7 +119,6 @@
*/
#define CC2538_RF_CSP_ISFLUSHTX() do { \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
} while(0)
/*---------------------------------------------------------------------------*/
/** The NETSTACK data structure for the cc2538 RF driver */
@ -138,16 +135,6 @@ extern const struct radio_driver cc2538_rf_driver;
*/
void cc2538_rf_set_addr(uint16_t pan);
/**
* \brief Turn promiscous mode on or off
* \param p If promiscous mode should be on (1) or off (0)
*
* This function turns promiscous mode on or off. In promiscous mode,
* every received frame is returned from the RF core. In
* non-promiscous mode, only broadcast frames or frames with our
* address as the receive address are returned from the RF core.
*/
void cc2538_rf_set_promiscous_mode(char p);
/*---------------------------------------------------------------------------*/
#endif /* CC2538_RF_H__ */

View File

@ -107,7 +107,7 @@ static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = {
typedef struct spi_locks_s {
mutex_t lock;
spi_device_t *owner;
const spi_device_t *owner;
} spi_locks_t;
/* One lock per SPI controller */
@ -115,40 +115,40 @@ spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKE
/*---------------------------------------------------------------------------*/
static void
spix_wait_tx_ready(spi_device_t *dev)
spix_wait_tx_ready(const spi_device_t *dev)
{
/* Infinite loop until SR_TNF - Transmit FIFO Not Full */
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF));
}
/*---------------------------------------------------------------------------*/
static int
spix_read_buf(spi_device_t *dev)
spix_read_buf(const spi_device_t *dev)
{
return REG(spi_regs[dev->spi_controller].base + SSI_DR);
}
/*---------------------------------------------------------------------------*/
static void
spix_write_buf(spi_device_t *dev, int data)
spix_write_buf(const spi_device_t *dev, int data)
{
REG(spi_regs[dev->spi_controller].base + SSI_DR) = data;
}
/*---------------------------------------------------------------------------*/
static void
spix_wait_eotx(spi_device_t *dev)
spix_wait_eotx(const spi_device_t *dev)
{
/* wait until not busy */
while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY);
}
/*---------------------------------------------------------------------------*/
static void
spix_wait_eorx(spi_device_t *dev)
spix_wait_eorx(const spi_device_t *dev)
{
/* wait as long as receive is empty */
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE));
}
/*---------------------------------------------------------------------------*/
bool
spi_arch_has_lock(spi_device_t *dev)
spi_arch_has_lock(const spi_device_t *dev)
{
if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
return true;
@ -158,7 +158,7 @@ spi_arch_has_lock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
bool
spi_arch_is_bus_locked(spi_device_t *dev)
spi_arch_is_bus_locked(const spi_device_t *dev)
{
if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
return true;
@ -168,7 +168,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_lock_and_open(spi_device_t *dev)
spi_arch_lock_and_open(const spi_device_t *dev)
{
const spi_regs_t *regs;
uint32_t scr;
@ -265,7 +265,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_close_and_unlock(spi_device_t *dev)
spi_arch_close_and_unlock(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -282,7 +282,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_select(spi_device_t *dev)
spi_arch_select(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
@ -295,7 +295,7 @@ spi_arch_select(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_deselect(spi_device_t *dev)
spi_arch_deselect(const spi_device_t *dev)
{
SPIX_CS_SET(PIN_TO_PORT(dev->pin_spi_cs), PIN_TO_NUM(dev->pin_spi_cs));
@ -304,7 +304,7 @@ spi_arch_deselect(spi_device_t *dev)
/*---------------------------------------------------------------------------*/
/* Assumes that checking dev and bus is not NULL before calling this */
spi_status_t
spi_arch_transfer(spi_device_t *dev,
spi_arch_transfer(const spi_device_t *dev,
const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len)
{

View File

@ -45,8 +45,6 @@ CONTIKI_CPU_SOURCEFILES += ble-cc2650.c ble-hal-cc26xx.c ble-addr.c rf-ble-cmd.c
CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c
CONTIKI_CPU_SOURCEFILES += spi-arch.c
MODULES += os/lib/dbg-io
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES)
CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS)

View File

@ -36,6 +36,10 @@
/*---------------------------------------------------------------------------*/
/* TSCH related defines */
/* 1 len byte, 2 bytes CRC */
#define RADIO_PHY_OVERHEAD 3
/* 250kbps data rate. One byte = 32us */
#define RADIO_BYTE_AIR_TIME 32
/* Delay between GO signal and SFD */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
/* Delay between GO signal and start listening.

View File

@ -37,7 +37,7 @@
typedef struct spi_locks_s {
mutex_t lock;
spi_device_t *owner;
const spi_device_t *owner;
} spi_locks_t;
/* One lock per SPI controller */
@ -68,7 +68,7 @@ static const board_spi_controller_t spi_controller[SPI_CONTROLLER_COUNT] = {
};
/*---------------------------------------------------------------------------*/
bool
spi_arch_has_lock(spi_device_t *dev)
spi_arch_has_lock(const spi_device_t *dev)
{
if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
return true;
@ -78,7 +78,7 @@ spi_arch_has_lock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
bool
spi_arch_is_bus_locked(spi_device_t *dev)
spi_arch_is_bus_locked(const spi_device_t *dev)
{
if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
return true;
@ -88,7 +88,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
static uint32_t
get_mode(spi_device_t *dev)
get_mode(const spi_device_t *dev)
{
/* Select the correct SPI mode */
if(dev->spi_pha == 0 && dev->spi_pol == 0) {
@ -103,7 +103,7 @@ get_mode(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_lock_and_open(spi_device_t *dev)
spi_arch_lock_and_open(const spi_device_t *dev)
{
uint32_t c;
@ -152,7 +152,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_close_and_unlock(spi_device_t *dev)
spi_arch_close_and_unlock(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -181,7 +181,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_transfer(spi_device_t *dev,
spi_arch_transfer(const spi_device_t *dev,
const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len)
{
@ -231,7 +231,7 @@ spi_arch_transfer(spi_device_t *dev,
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_select(spi_device_t *dev)
spi_arch_select(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
@ -243,7 +243,7 @@ spi_arch_select(spi_device_t *dev)
return SPI_DEV_STATUS_OK;
}
spi_status_t
spi_arch_deselect(spi_device_t *dev)
spi_arch_deselect(const spi_device_t *dev)
{
ti_lib_gpio_set_dio(dev->pin_spi_cs);

View File

@ -91,9 +91,6 @@ SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME)
EXTERNALDIRS += $(SDK_SOURCE) $(SDK_NORTOS)
# CPU-dependent debug source files
MODULES += os/lib/dbg-io
# CPU-dependent directories
CONTIKI_CPU_DIRS += . dev $(SUBFAMILY)
CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC)

View File

@ -57,6 +57,10 @@
/*---------------------------------------------------------------------------*/
/* TSCH related defines */
/* 1 len byte, 2 bytes CRC */
#define RADIO_PHY_OVERHEAD 3
/* 250kbps data rate. One byte = 32us */
#define RADIO_BYTE_AIR_TIME 32
/* Delay between GO signal and SFD */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
/* Delay between GO signal and start listening.

View File

@ -54,7 +54,7 @@
/*---------------------------------------------------------------------------*/
typedef struct {
SPI_Handle handle;
spi_device_t *owner;
const spi_device_t *owner;
} spi_arch_t;
/*---------------------------------------------------------------------------*/
#if (SPI_CONTROLLER_COUNT > 0)
@ -96,7 +96,7 @@ convert_frame_format(uint8_t pol, uint8_t pha)
}
/*---------------------------------------------------------------------------*/
bool
spi_arch_has_lock(spi_device_t *dev)
spi_arch_has_lock(const spi_device_t *dev)
{
/*
* The SPI device is the owner if the SPI controller returns a valid
@ -107,7 +107,7 @@ spi_arch_has_lock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
bool
spi_arch_is_bus_locked(spi_device_t *dev)
spi_arch_is_bus_locked(const spi_device_t *dev)
{
/*
* The SPI controller is locked by any device if the SPI controller returns
@ -118,7 +118,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_lock_and_open(spi_device_t *dev)
spi_arch_lock_and_open(const spi_device_t *dev)
{
uint_least8_t spi_index;
spi_arch_t *spi_arch;
@ -167,7 +167,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_close_and_unlock(spi_device_t *dev)
spi_arch_close_and_unlock(const spi_device_t *dev)
{
spi_arch_t *spi_arch;
@ -196,7 +196,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_transfer(spi_device_t *dev,
spi_arch_transfer(const spi_device_t *dev,
const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len)
{
@ -236,7 +236,7 @@ spi_arch_transfer(spi_device_t *dev,
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_select(spi_device_t *dev)
spi_arch_select(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -248,7 +248,7 @@ spi_arch_select(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_arch_deselect(spi_device_t *dev)
spi_arch_deselect(const spi_device_t *dev)
{
if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED;

View File

@ -34,6 +34,7 @@
#include "cc1200-rf-cfg.h"
#include "cc1200-const.h"
#include "net/mac/tsch/tsch.h"
/*
* This is a setup for the following configuration:
@ -62,6 +63,52 @@
/*---------------------------------------------------------------------------*/
static const char rf_cfg_descriptor[] = "802.15.4g 863-870MHz MR-FSK mode #1";
/*---------------------------------------------------------------------------*/
/* 1 byte time: 160 usec */
#define CC1200_TSCH_PREAMBLE_LENGTH 800 /* 5 bytes */
#define CC1200_TSCH_CONF_RX_WAIT 2200
#define CC1200_TSCH_CONF_RX_ACK_WAIT 400
#define CC1200_TSCH_DEFAULT_TS_CCA_OFFSET 1800
#define CC1200_TSCH_DEFAULT_TS_CCA 128
#define CC1200_TSCH_DEFAULT_TS_TX_OFFSET 3800
#define CC1200_TSCH_DEFAULT_TS_RX_OFFSET (CC1200_TSCH_DEFAULT_TS_TX_OFFSET - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_WAIT / 2))
#define CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY (CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_ACK_WAIT / 2))
#define CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY 3000
#define CC1200_TSCH_DEFAULT_TS_RX_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_WAIT)
#define CC1200_TSCH_DEFAULT_TS_ACK_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_ACK_WAIT)
#define CC1200_TSCH_DEFAULT_TS_RX_TX 192
#define CC1200_TSCH_DEFAULT_TS_MAX_ACK 3360 /* 17+1+3 bytes at 50 kbps */
#define CC1200_TSCH_DEFAULT_TS_MAX_TX 20800 /* 126+1+3 bytes at 50 kbps */
#define CC1200_TSCH_DEFAULT_SLACK_TIME 500
/* Timeslot length: 31460 usec */
#define CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH \
( CC1200_TSCH_DEFAULT_TS_TX_OFFSET \
+ CC1200_TSCH_DEFAULT_TS_MAX_TX \
+ CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY \
+ CC1200_TSCH_DEFAULT_TS_MAX_ACK \
+ CC1200_TSCH_DEFAULT_SLACK_TIME \
)
/* TSCH timeslot timing (mircoseconds) */
static const uint16_t cc1200_50kbps_tsch_timing[tsch_ts_elements_count] = {
CC1200_TSCH_DEFAULT_TS_CCA_OFFSET,
CC1200_TSCH_DEFAULT_TS_CCA,
CC1200_TSCH_DEFAULT_TS_TX_OFFSET,
CC1200_TSCH_DEFAULT_TS_RX_OFFSET,
CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY,
CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY,
CC1200_TSCH_DEFAULT_TS_RX_WAIT,
CC1200_TSCH_DEFAULT_TS_ACK_WAIT,
CC1200_TSCH_DEFAULT_TS_RX_TX,
CC1200_TSCH_DEFAULT_TS_MAX_ACK,
CC1200_TSCH_DEFAULT_TS_MAX_TX,
CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
};
/*
* Register settings exported from SmartRF Studio using the standard template
* "trxEB RF Settings Performance Line".
@ -159,6 +206,11 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = {
.size_of_register_settings = sizeof(preferredSettings),
.tx_pkt_lifetime = (RTIMER_SECOND / 20),
.tx_rx_turnaround = (RTIMER_SECOND / 100),
/* Includes 3 Bytes preamble + 2 Bytes SFD, at 160usec per byte = 800 usec */
/* Includes time to completion of "Wait for TX to start" if cc1200.c: 397 usec */
.delay_before_tx = ((unsigned)US_TO_RTIMERTICKS(800 + 397 + 423)),
.delay_before_rx = (unsigned)US_TO_RTIMERTICKS(400),
.delay_before_detect = 0,
.chan_center_freq0 = RF_CFG_CHAN_CENTER_F0,
.chan_spacing = RF_CFG_CHAN_SPACING,
.min_channel = RF_CFG_MIN_CHANNEL,
@ -166,5 +218,7 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = {
.max_txpower = RF_CFG_MAX_TXPOWER,
.cca_threshold = RF_CFG_CCA_THRESHOLD,
.rssi_offset = RF_CFG_RSSI_OFFSET,
.bitrate = 50000,
.tsch_timing = cc1200_50kbps_tsch_timing,
};
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2015, Weptech elektronik GmbH Germany
* http://www.weptech.de
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
#include "cc1200-rf-cfg.h"
#include "cc1200-const.h"
#include "net/mac/tsch/tsch.h"
/*
* Register settings exported from SmartRF Studio using the standard 1000kpbs 868MHz template
*/
/* Base frequency in kHz */
#define RF_CFG_CHAN_CENTER_F0 863125
/* Channel spacing in Hz */
#define RF_CFG_CHAN_SPACING 1666667
/* The minimum channel */
#define RF_CFG_MIN_CHANNEL 0
/* The maximum channel */
#define RF_CFG_MAX_CHANNEL 3
/* The maximum output power in dBm */
#define RF_CFG_MAX_TXPOWER CC1200_CONST_TX_POWER_MAX
/* The carrier sense level used for CCA in dBm */
#define RF_CFG_CCA_THRESHOLD (-91)
/* The RSSI offset in dBm */
#define RF_CFG_RSSI_OFFSET (-81)
/*---------------------------------------------------------------------------*/
static const char rf_cfg_descriptor[] = "868MHz 2-GFSK 1000 kbps";
/*---------------------------------------------------------------------------*/
/* 1 byte time: 8 usec */
#define CC1200_TSCH_PREAMBLE_LENGTH 800 /* 5 bytes */
#define CC1200_TSCH_CONF_RX_WAIT 2200
#define CC1200_TSCH_CONF_RX_ACK_WAIT 400
#define CC1200_TSCH_DEFAULT_TS_CCA_OFFSET 1800
#define CC1200_TSCH_DEFAULT_TS_CCA 128
#define CC1200_TSCH_DEFAULT_TS_TX_OFFSET 2200
#define CC1200_TSCH_DEFAULT_TS_RX_OFFSET (CC1200_TSCH_DEFAULT_TS_TX_OFFSET - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_WAIT / 2))
#define CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY (CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_ACK_WAIT / 2))
#define CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY 1900
#define CC1200_TSCH_DEFAULT_TS_RX_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_WAIT)
#define CC1200_TSCH_DEFAULT_TS_ACK_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_ACK_WAIT)
#define CC1200_TSCH_DEFAULT_TS_RX_TX 192
#define CC1200_TSCH_DEFAULT_TS_MAX_ACK 168 /* 17+1+3 bytes at 1000 kbps */
#define CC1200_TSCH_DEFAULT_TS_MAX_TX 1040 /* 126+1+3 bytes at 1000 kbps */
#define CC1200_TSCH_DEFAULT_SLACK_TIME 500
/* Timeslot length: 5808 usec */
#define CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH \
( CC1200_TSCH_DEFAULT_TS_TX_OFFSET \
+ CC1200_TSCH_DEFAULT_TS_MAX_TX \
+ CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY \
+ CC1200_TSCH_DEFAULT_TS_MAX_ACK \
+ CC1200_TSCH_DEFAULT_SLACK_TIME \
)
/* TSCH timeslot timing (in rtimer ticks) */
static const uint16_t cc1200_1000kbps_tsch_timing[tsch_ts_elements_count] = {
CC1200_TSCH_DEFAULT_TS_CCA_OFFSET,
CC1200_TSCH_DEFAULT_TS_CCA,
CC1200_TSCH_DEFAULT_TS_TX_OFFSET,
CC1200_TSCH_DEFAULT_TS_RX_OFFSET,
CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY,
CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY,
CC1200_TSCH_DEFAULT_TS_RX_WAIT,
CC1200_TSCH_DEFAULT_TS_ACK_WAIT,
CC1200_TSCH_DEFAULT_TS_RX_TX,
CC1200_TSCH_DEFAULT_TS_MAX_ACK,
CC1200_TSCH_DEFAULT_TS_MAX_TX,
CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
};
static const registerSetting_t preferredSettings[]=
{
{CC1200_IOCFG2, 0x06},
{CC1200_SYNC_CFG1, 0xA8},
{CC1200_DEVIATION_M, 0x47},
{CC1200_MODCFG_DEV_E, 0x2F},
{CC1200_DCFILT_CFG, 0x1E},
{CC1200_PREAMBLE_CFG0, 0x8A},
{CC1200_IQIC, 0x00},
{CC1200_CHAN_BW, 0x01},
{CC1200_MDMCFG1, 0x42},
{CC1200_MDMCFG0, 0x05},
{CC1200_SYMBOL_RATE2, 0xC9},
{CC1200_SYMBOL_RATE1, 0x99},
{CC1200_SYMBOL_RATE0, 0x99},
{CC1200_AGC_REF, 0x2F},
{CC1200_AGC_CS_THR, 0xF8},
{CC1200_AGC_CFG2, 0x60},
{CC1200_AGC_CFG1, 0x12},
{CC1200_AGC_CFG0, 0x84},
{CC1200_FIFO_CFG, 0x00},
{CC1200_FS_CFG, 0x12},
{CC1200_PKT_CFG2, 0x00},
{CC1200_PKT_CFG0, 0x20},
{CC1200_PKT_LEN, 0xFF},
{CC1200_FREQOFF_CFG, 0x23},
{CC1200_MDMCFG2, 0x00},
{CC1200_FREQ2, 0x56},
{CC1200_FREQ1, 0xCC},
{CC1200_FREQ0, 0xCC},
{CC1200_IF_ADC1, 0xEE},
{CC1200_IF_ADC0, 0x10},
{CC1200_FS_DIG1, 0x04},
{CC1200_FS_DIG0, 0xA3},
{CC1200_FS_CAL1, 0x40},
{CC1200_FS_CAL0, 0x0E},
{CC1200_FS_DIVTWO, 0x03},
{CC1200_FS_DSM0, 0x33},
{CC1200_FS_DVC1, 0xF7},
{CC1200_FS_DVC0, 0x0F},
{CC1200_FS_PFD, 0x00},
{CC1200_FS_PRE, 0x6E},
{CC1200_FS_REG_DIV_CML, 0x1C},
{CC1200_FS_SPARE, 0xAC},
{CC1200_FS_VCO0, 0xB5},
{CC1200_IFAMP, 0x0D},
{CC1200_XOSC5, 0x0E},
{CC1200_XOSC1, 0x03},
};
/*---------------------------------------------------------------------------*/
/* Global linkage: symbol name must be different in each exported file! */
const cc1200_rf_cfg_t cc1200_868_4gfsk_1000kbps = {
.cfg_descriptor = rf_cfg_descriptor,
.register_settings = preferredSettings,
.size_of_register_settings = sizeof(preferredSettings),
.tx_pkt_lifetime = (RTIMER_SECOND),
.tx_rx_turnaround = (RTIMER_SECOND / 100),
/* Includes 3 Bytes preamble + 2 Bytes SFD, at 8usec per byte = 40 usec */
/* Includes time to completion of "Wait for TX to start" if cc1200.c: 397 usec */
.delay_before_tx = ((unsigned)US_TO_RTIMERTICKS(40 + 397 + 207)),
.delay_before_rx = (unsigned)US_TO_RTIMERTICKS(400),
.delay_before_detect = 0,
.chan_center_freq0 = RF_CFG_CHAN_CENTER_F0,
.chan_spacing = RF_CFG_CHAN_SPACING,
.min_channel = RF_CFG_MIN_CHANNEL,
.max_channel = RF_CFG_MAX_CHANNEL,
.max_txpower = RF_CFG_MAX_TXPOWER,
.cca_threshold = RF_CFG_CCA_THRESHOLD,
.rssi_offset = RF_CFG_RSSI_OFFSET,
.bitrate = 1000000,
.tsch_timing = cc1200_1000kbps_tsch_timing,
};
/*---------------------------------------------------------------------------*/

View File

@ -126,6 +126,9 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = {
.size_of_register_settings = sizeof(preferredSettings),
.tx_pkt_lifetime = (2 * RTIMER_SECOND),
.tx_rx_turnaround = (RTIMER_SECOND / 2),
.delay_before_tx = 0,
.delay_before_rx = 0,
.delay_before_detect = 0,
.chan_center_freq0 = RF_CFG_CHAN_CENTER_F0,
.chan_spacing = RF_CFG_CHAN_SPACING,
.min_channel = RF_CFG_MIN_CHANNEL,
@ -133,5 +136,7 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = {
.max_txpower = RF_CFG_MAX_TXPOWER,
.cca_threshold = RF_CFG_CCA_THRESHOLD,
.rssi_offset = RF_CFG_RSSI_OFFSET,
.bitrate = 1200,
.tsch_timing = NULL,
};
/*---------------------------------------------------------------------------*/

View File

@ -69,6 +69,13 @@ typedef struct cc1200_rf_cfg {
rtimer_clock_t tx_pkt_lifetime;
/* The maximum time it takes to switch from Tx to Rx */
rtimer_clock_t tx_rx_turnaround;
/* The delay between a call to transmit() and end of SFD */
rtimer_clock_t delay_before_tx;
/* Delay between GO signal and start listening
* Measured 104us: between GO signal and start listening */
rtimer_clock_t delay_before_rx;
/* Delay between the SFD finishes arriving and it is detected in software */
rtimer_clock_t delay_before_detect;
/* Base frequency in kHz */
uint32_t chan_center_freq0;
/* Channel spacing in Hz */
@ -87,6 +94,10 @@ typedef struct cc1200_rf_cfg {
/* The RSSI offset in dBm.
* -99 when MDMCFG1.DVGA_GAIN=00, -81 when MDMCFG1.DVGA_GAIN=01 */
int8_t rssi_offset;
/* The bitrate in bps */
uint32_t bitrate;
/* TSCH timeslot timing */
const uint16_t *tsch_timing;
} cc1200_rf_cfg_t;
/*---------------------------------------------------------------------------*/
#endif /* CC1200_RF_CFG_H */

View File

@ -47,6 +47,9 @@
#include <string.h>
#include <stdio.h>
static int16_t rssi;
static rtimer_clock_t sfd_timestamp = 0;
/*---------------------------------------------------------------------------*/
/* Various implementation specific defines */
/*---------------------------------------------------------------------------*/
@ -57,7 +60,7 @@
* - 2: Print errors + warnings (recoverable errors)
* - 3: Print errors + warnings + information (what's going on...)
*/
#define DEBUG_LEVEL 2
#define DEBUG_LEVEL 0
/*
* RF test mode. Blocks inside "configure()".
* - Set this parameter to 1 in order to produce an modulated carrier (PN9)
@ -79,6 +82,14 @@
#define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
#endif
#endif
/*
* When set, a software buffer is used to store outgoing packets before copying
* to Tx FIFO. This enabled sending packets larger than the FIFO. When unset,
* no buffer is used; instead, the payload is copied directly to the Tx FIFO.
* This is requried by TSCH, for shorter and more predictable delay in the Tx
* chain. This, however, restircts the payload length to the Tx FIFO size.
*/
#define CC1200_WITH_TX_BUF (!MAC_CONF_WITH_TSCH)
/*
* Set this parameter to 1 in order to use the MARC_STATE register when
* polling the chips's status. Else use the status byte returned when sending
@ -93,7 +104,11 @@
*
* TODO: Option to be removed upon approval of the driver
*/
#if MAC_CONF_WITH_TSCH
#define USE_SFSTXON 0
#else /* MAC_CONF_WITH_TSCH */
#define USE_SFSTXON 1
#endif /* MAC_CONF_WITH_TSCH */
/*---------------------------------------------------------------------------*/
/* Phy header length */
#if CC1200_802154G
@ -133,7 +148,15 @@
/* Use GPIO2 as RX / TX FIFO threshold indicator pin */
#define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR
/* This is the FIFO threshold we use */
#if MAC_CONF_WITH_TSCH
#if CC1200_802154G
#define FIFO_THRESHOLD 1
#else
#define FIFO_THRESHOLD 0
#endif
#else /* MAC_CONF_WITH_TSCH */
#define FIFO_THRESHOLD 32
#endif /* MAC_CONF_WITH_TSCH */
/* Turn on RX after packet reception */
#define RXOFF_MODE_RX 1
/* Let the CC1200 append RSSI + LQI */
@ -249,6 +272,8 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
#define RF_UPDATE_CHANNEL 0x10
/* SPI was locked when calling RX interrupt, let the pollhandler do the job */
#define RF_POLL_RX_INTERRUPT 0x20
/* Ongoing reception */
#define RF_RX_ONGOING 0x40
/* Force calibration in case we don't use CC1200 AUTOCAL + timeout */
#if !CC1200_AUTOCAL
#if CC1200_CAL_TIMEOUT_SECONDS
@ -285,15 +310,7 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
#define LOCK_SPI() do { spi_locked++; } while(0)
#define SPI_IS_LOCKED() (spi_locked != 0)
#define RELEASE_SPI() do { spi_locked--; } while(0)
/*---------------------------------------------------------------------------*/
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \
watchdog_periodic(); \
} \
} while(0)
/*---------------------------------------------------------------------------*/
#if CC1200_USE_GPIO2
/* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */
@ -353,38 +370,22 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
#define INFO(...)
#endif
#if DEBUG_LEVEL > 0
/*
* As BUSYWAIT_UNTIL was mainly used to test for a state transition,
* we define a separate macro for this adding the possibility to
* throw an error message when the timeout exceeds
*/
#define BUSYWAIT_UNTIL_STATE(s, t) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t)))) { \
printf("RF: Timeout exceeded in line %d!\n", __LINE__); \
} \
} while(0)
#else
#define BUSYWAIT_UNTIL_STATE(s, t) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \
} while(0)
#endif
/* Busy-wait (time-bounded) until the radio reaches a given state */
#define RTIMER_BUSYWAIT_UNTIL_STATE(s, t) RTIMER_BUSYWAIT_UNTIL(state() == (s), t)
/*---------------------------------------------------------------------------*/
/* Variables */
/*---------------------------------------------------------------------------*/
/* Flag indicating whether non-interrupt routines are using SPI */
static volatile uint8_t spi_locked = 0;
#if CC1200_WITH_TX_BUF
/* Packet buffer for transmission, filled within prepare() */
static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN];
#endif /* CC1200_WITH_TX_BUF */
/* The number of bytes waiting in tx_pkt */
static uint16_t tx_pkt_len;
/* Number of bytes from tx_pkt left to write to FIFO */
uint16_t bytes_left_to_write;
/* Packet buffer for reception */
static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
/* The number of bytes placed in rx_pkt */
@ -422,6 +423,9 @@ static struct etimer et;
/* Init the radio. */
static int
init(void);
/* Prepare and copy PHY header to Tx FIFO */
static int
copy_header_to_tx_fifo(unsigned short payload_len);
/* Prepare the radio with a packet to be sent. */
static int
prepare(const void *payload, unsigned short payload_len);
@ -530,7 +534,7 @@ idle_calibrate_rx(void);
/* Restart RX from within RX interrupt. */
static void
rx_rx(void);
/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len);
/* Update TX power */
@ -572,7 +576,7 @@ PROCESS_THREAD(cc1200_process, ev, data)
/*
* We are on and not in TX. As every function of this driver
* assures that we are in RX mode
* (using BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in
* (using RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in
* either rx_rx(), idle_calibrate_rx() or transmit(),
* something probably went wrong in the rx interrupt handler
* if we are not in RX at this point.
@ -624,7 +628,7 @@ pollhandler(void)
set_channel(new_rf_channel);
}
if(rx_pkt_len > 0) {
if((rx_mode_value & RADIO_RX_MODE_POLL_MODE) == 0 && rx_pkt_len > 0) {
int len;
@ -722,10 +726,67 @@ prepare(const void *payload, unsigned short payload_len)
}
tx_pkt_len = payload_len;
#if CC1200_WITH_TX_BUF
/* Copy payload to buffer, will be sent later */
memcpy(tx_pkt, payload, tx_pkt_len);
#else /* CC1200_WITH_TX_BUF */
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
#error CC1200 max payload too large
#else
/* Copy header and payload directly to Radio Tx FIFO (127 bytes max) */
copy_header_to_tx_fifo(payload_len);
burst_write(CC1200_TXFIFO, payload, payload_len);
#endif
#endif /* CC1200_WITH_TX_BUF */
return RADIO_TX_OK;
}
/*---------------------------------------------------------------------------*/
/* Prepare the radio with a packet to be sent. */
static int
copy_header_to_tx_fifo(unsigned short payload_len)
{
#if CC1200_802154G
/* Prepare PHR for 802.15.4g frames */
struct {
uint8_t phra;
uint8_t phrb;
} phr;
#if CC1200_802154G_CRC16
payload_len += 2;
#else
payload_len += 4;
#endif
/* Frame length */
phr.phrb = (uint8_t)(payload_len & 0x00FF);
phr.phra = (uint8_t)((payload_len >> 8) & 0x0007);
#if CC1200_802154G_WHITENING
/* Enable Whitening */
phr.phra |= (1 << 3);
#endif /* #if CC1200_802154G_WHITENING */
#if CC1200_802154G_CRC16
/* FCS type 1, 2 Byte CRC */
phr.phra |= (1 << 4);
#endif /* #if CC1200_802154G_CRC16 */
#endif /* #if CC1200_802154G */
idle();
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
/* Flush TX FIFO */
strobe(CC1200_SFTX);
#if CC1200_802154G
/* Write PHR */
burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN);
#else
/* Write length byte */
burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN);
#endif /* #if CC1200_802154G */
return 0;
}
/*---------------------------------------------------------------------------*/
/* Send the packet that has previously been prepared. */
@ -735,6 +796,7 @@ transmit(unsigned short transmit_len)
uint8_t was_off = 0;
int ret = RADIO_TX_OK;
int txret;
INFO("RF: Transmit (%d)\n", transmit_len);
@ -790,7 +852,12 @@ transmit(unsigned short transmit_len)
#endif
/* Send data using TX FIFO */
if(idle_tx_rx((const uint8_t *)tx_pkt, tx_pkt_len) == RADIO_TX_OK) {
#if CC1200_WITH_TX_BUF
txret = idle_tx_rx(tx_pkt, tx_pkt_len);
#else /* CC1200_WITH_TX_BUF */
txret = idle_tx_rx(NULL, tx_pkt_len);
#endif /* CC1200_WITH_TX_BUF */
if(txret == RADIO_TX_OK) {
/*
* TXOFF_MODE is set to RX,
@ -798,7 +865,7 @@ transmit(unsigned short transmit_len)
* again as they were turned off in idle()
*/
BUSYWAIT_UNTIL_STATE(STATE_RX,
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX,
CC1200_RF_CFG.tx_rx_turnaround);
ENABLE_GPIO_INTERRUPTS();
@ -861,7 +928,7 @@ read(void *buf, unsigned short buf_len)
if(rx_pkt_len > 0) {
int8_t rssi = rx_pkt[rx_pkt_len - 2];
rssi = (int8_t)rx_pkt[rx_pkt_len - 2] + (int)CC1200_RF_CFG.rssi_offset;
/* CRC is already checked */
uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1];
@ -938,7 +1005,7 @@ channel_clear(void)
}
/* Wait for CARRIER_SENSE_VALID signal */
BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
& CC1200_CARRIER_SENSE_VALID),
RTIMER_SECOND / 100);
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
@ -1009,9 +1076,16 @@ receiving_packet(void)
static int
pending_packet(void)
{
int ret;
ret = ((rx_pkt_len != 0) ? 1 : 0);
if(ret == 0 && !SPI_IS_LOCKED()) {
LOCK_SPI();
ret = (single_read(CC1200_NUM_RXBYTES) > 0);
RELEASE_SPI();
}
INFO("RF: Pending (%d)\n", ((rx_pkt_len != 0) ? 1 : 0));
return (rx_pkt_len != 0) ? 1 : 0;
INFO("RF: Pending (%d)\n", ret);
return ret;
}
/*---------------------------------------------------------------------------*/
@ -1033,11 +1107,12 @@ on(void)
/* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */
cc1200_arch_spi_select();
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_SECOND / 100);
RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0));
cc1200_arch_spi_deselect();
rf_flags = RF_INITIALIZED;
rf_flags |= RF_ON;
/* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */
@ -1080,6 +1155,16 @@ off(void)
idle();
if(single_read(CC1200_NUM_RXBYTES) > 0) {
RELEASE_SPI();
/* In case there is something in the Rx FIFO, read it */
cc1200_rx_interrupt();
if(SPI_IS_LOCKED()) {
return 0;
}
LOCK_SPI();
}
/*
* As we use GPIO as CHIP_RDYn signal on wake-up / on(),
* we re-configure it for CHIP_RDYn.
@ -1106,6 +1191,40 @@ off(void)
}
/*---------------------------------------------------------------------------*/
/**
* \brief Reads the current signal strength (RSSI)
* \return The current RSSI in dBm
*
* This function reads the current RSSI on the currently configured
* channel.
*/
static int16_t
get_rssi(void)
{
int16_t rssi0, rssi1;
uint8_t was_off = 0;
/* If we are off, turn on first */
if(!(rf_flags & RF_ON)) {
was_off = 1;
on();
}
/* Wait for CARRIER_SENSE_VALID signal */
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
& CC1200_CARRIER_SENSE_VALID),
RTIMER_SECOND / 100);
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
rssi1 = (int8_t)single_read(CC1200_RSSI1) + (int)CC1200_RF_CFG.rssi_offset;
/* If we were off, turn back off */
if(was_off) {
off();
}
return rssi1;
}
/*---------------------------------------------------------------------------*/
/* Get a radio parameter value. */
static radio_result_t
get_value(radio_param_t param, radio_value_t *value)
@ -1156,6 +1275,13 @@ get_value(radio_param_t param, radio_value_t *value)
return RADIO_RESULT_OK;
case RADIO_PARAM_RSSI:
*value = get_rssi();
return RADIO_RESULT_OK;
case RADIO_PARAM_LAST_RSSI:
*value = (radio_value_t)rssi;
return RADIO_RESULT_OK;
case RADIO_PARAM_64BIT_ADDR:
return RADIO_RESULT_NOT_SUPPORTED;
@ -1180,6 +1306,34 @@ get_value(radio_param_t param, radio_value_t *value)
*value = (radio_value_t)CC1200_RF_CFG.max_txpower;
return RADIO_RESULT_OK;
case RADIO_CONST_PHY_OVERHEAD:
#if CC1200_802154G
#if CC1200_802154G_CRC16
*value = (radio_value_t)4; /* 2 bytes PHR, 2 bytes CRC */
#else
*value = (radio_value_t)6; /* 2 bytes PHR, 4 bytes CRC */
#endif
#else
*value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */
#endif
return RADIO_RESULT_OK;
case RADIO_CONST_BYTE_AIR_TIME:
*value = (radio_value_t)8*1000*1000 / CC1200_RF_CFG.bitrate;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_TX:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_tx;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_RX:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_rx;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_DETECT:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_detect;
return RADIO_RESULT_OK;
default:
return RADIO_RESULT_NOT_SUPPORTED;
@ -1282,6 +1436,23 @@ set_value(radio_param_t param, radio_value_t value)
static radio_result_t
get_object(radio_param_t param, void *dest, size_t size)
{
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
if(size != sizeof(rtimer_clock_t) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(rtimer_clock_t *)dest = sfd_timestamp;
return RADIO_RESULT_OK;
}
#if MAC_CONF_WITH_TSCH
if(param == RADIO_CONST_TSCH_TIMING) {
if(size != sizeof(uint16_t *) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(const uint16_t **)dest = CC1200_RF_CFG.tsch_timing;
return RADIO_RESULT_OK;
}
#endif /* MAC_CONF_WITH_TSCH */
return RADIO_RESULT_NOT_SUPPORTED;
@ -1507,20 +1678,20 @@ configure(void)
while(1) {
#if (CC1200_RF_TESTMODE == 1)
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW);
leds_on(LEDS_RED);
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED);
leds_on(LEDS_YELLOW);
#else
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN);
leds_on(LEDS_RED);
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED);
leds_on(LEDS_GREEN);
#endif
@ -1542,11 +1713,11 @@ configure(void)
while(1) {
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN);
leds_on(LEDS_YELLOW);
watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW);
leds_on(LEDS_GREEN);
clock_delay_usec(1000);
@ -1667,8 +1838,8 @@ calibrate(void)
INFO("RF: Calibrate\n");
strobe(CC1200_SCAL);
BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
#if CC1200_CAL_TIMEOUT_SECONDS
cal_timer = clock_seconds();
@ -1705,7 +1876,7 @@ idle(void)
}
strobe(CC1200_SIDLE);
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
} /* idle(), 21.05.2015 */
/*---------------------------------------------------------------------------*/
@ -1723,7 +1894,7 @@ idle_calibrate_rx(void)
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
strobe(CC1200_SRX);
BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
ENABLE_GPIO_INTERRUPTS();
@ -1748,7 +1919,7 @@ rx_rx(void)
strobe(CC1200_SFTX);
} else {
strobe(CC1200_SIDLE);
BUSYWAIT_UNTIL_STATE(STATE_IDLE,
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE,
RTIMER_SECOND / 100);
}
@ -1760,79 +1931,29 @@ rx_rx(void)
strobe(CC1200_SFRX);
strobe(CC1200_SRX);
BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
}
/*---------------------------------------------------------------------------*/
/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
{
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
uint16_t bytes_left_to_write;
uint8_t to_write;
const uint8_t *p;
#endif
#if CC1200_802154G
/* Prepare PHR for 802.15.4g frames */
struct {
uint8_t phra;
uint8_t phrb;
} phr;
#if CC1200_802154G_CRC16
payload_len += 2;
#else
payload_len += 4;
#endif
/* Frame length */
phr.phrb = (uint8_t)(payload_len & 0x00FF);
phr.phra = (uint8_t)((payload_len >> 8) & 0x0007);
#if CC1200_802154G_WHITENING
/* Enable Whitening */
phr.phra |= (1 << 3);
#endif /* #if CC1200_802154G_WHITENING */
#if CC1200_802154G_CRC16
/* FCS type 1, 2 Byte CRC */
phr.phra |= (1 << 4);
#endif /* #if CC1200_802154G_CRC16 */
#endif /* #if CC1200_802154G */
/* Prepare for RX */
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
/* Flush TX FIFO */
strobe(CC1200_SFTX);
#if USE_SFSTXON
/*
* Enable synthesizer. Saves us a few µs especially if it takes
* long enough to fill the FIFO. This strobe must not be
* send before SFTX!
*/
strobe(CC1200_SFSTXON);
#endif
/* Configure GPIO0 to detect TX state */
single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0);
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
/*
* We already checked that GPIO2 is used if
* CC1200_MAX_PAYLOAD_LEN > 127 / 126 in the header of this file
*/
single_write(CC1200_IOCFG2, CC1200_IOCFG_TXFIFO_THR);
#endif
#if CC1200_802154G
/* Write PHR */
burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN);
#else
/* Write length byte */
burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN);
#endif /* #if CC1200_802154G */
#if CC1200_WITH_TX_BUF
/* Prepare and write header */
copy_header_to_tx_fifo(payload_len);
/*
* Fill FIFO with data. If SPI is slow it might make sense
@ -1849,17 +1970,18 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
#else
burst_write(CC1200_TXFIFO, payload, payload_len);
#endif
#endif /* CC1200_WITH_TX_BUF */
#if USE_SFSTXON
/* Wait for synthesizer to be ready */
BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
#endif
/* Start TX */
strobe(CC1200_STX);
/* Wait for TX to start. */
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100);
/* Turned off at the latest in idle() */
TX_LEDS_ON();
@ -1888,7 +2010,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
}
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) && CC1200_WITH_TX_BUF
if(bytes_left_to_write != 0) {
rtimer_clock_t t0;
uint8_t s;
@ -1922,7 +2044,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
*/
INFO("RF: TX failure!\n");
BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100);
/* Re-configure GPIO2 */
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
idle();
@ -1936,12 +2058,12 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
} else {
/* Wait for TX to complete */
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
CC1200_RF_CFG.tx_pkt_lifetime);
}
#else
/* Wait for TX to complete */
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
CC1200_RF_CFG.tx_pkt_lifetime);
#endif
@ -2026,6 +2148,9 @@ set_channel(uint8_t channel)
uint8_t was_off = 0;
uint32_t freq;
channel %= (CC1200_RF_CFG.max_channel - CC1200_RF_CFG.min_channel + 1);
channel += CC1200_RF_CFG.min_channel;
#if 0
/*
* We explicitly allow a channel update even if the channel does not change.
@ -2156,6 +2281,7 @@ addr_check_auto_ack(uint8_t *frame, uint16_t frame_len)
idle();
#endif
prepare((const uint8_t *)ack, ACK_LEN);
idle_tx_rx((const uint8_t *)ack, ACK_LEN);
/* rx_rx() will follow */
@ -2204,6 +2330,23 @@ cc1200_rx_interrupt(void)
*/
static uint8_t buf[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
/*
* If CC1200_USE_GPIO2 is enabled, we come here either once RX FIFO
* threshold is reached (GPIO2 rising edge)
* or at the end of the packet (GPIO0 falling edge).
*/
#if CC1200_USE_GPIO2
int gpio2 = cc1200_arch_gpio2_read_pin();
int gpio0 = cc1200_arch_gpio0_read_pin();
if((rf_flags & RF_RX_ONGOING) == 0 && gpio2 > 0) {
rf_flags |= RF_RX_ONGOING;
sfd_timestamp = RTIMER_NOW();
}
if(gpio0 == 0) {
rf_flags &= ~RF_RX_ONGOING;
}
#endif
if(SPI_IS_LOCKED()) {
/*

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2018, RISE SICS.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* IEEE 802.15.4 TSCH timeslot timings for 15ms slots
* \author
* Simon Duquennoy <simon.duquennoy@ri.se>
*
*/
#include "contiki.h"
#include "net/mac/tsch/tsch.h"
/**
* \brief 15ms TSCH timeslot timings, required for cc2420 platforms as
* they are unable to keep up with the defulat 10ms timeslots.
*/
const uint16_t tsch_timeslot_timing_us_15000[tsch_ts_elements_count] = {
1800, /* CCAOffset */
128, /* CCA */
4000, /* TxOffset */
(4000 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */
3600, /* RxAckDelay */
4000, /* TxAckDelay */
TSCH_CONF_RX_WAIT, /* RxWait */
800, /* AckWait */
2072, /* RxTx */
2400, /* MaxAck */
4256, /* MaxTx */
15000, /* TimeslotLength */
};

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, RISE SICS.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
#include "contiki.h"
extern const uint16_t tsch_timeslot_timing_us_15000[];

View File

@ -96,9 +96,6 @@ static const struct output_config output_power[] = {
void cc2420_arch_init(void);
/* XXX hack: these will be made as Chameleon packet attributes */
rtimer_clock_t cc2420_time_of_arrival, cc2420_time_of_departure;
int cc2420_authority_level_of_sender;
volatile uint8_t cc2420_sfd_counter;

View File

@ -102,9 +102,6 @@ int cc2420_get_txpower(void);
*/
int cc2420_interrupt(void);
/* XXX hack: these will be made as Chameleon packet attributes */
extern rtimer_clock_t cc2420_time_of_arrival,
cc2420_time_of_departure;
extern int cc2420_authority_level_of_sender;
int cc2420_on(void);

View File

@ -99,7 +99,7 @@
#define VERIFY_PART_POWERED_DOWN 0
#define VERIFY_PART_OK 1
/*---------------------------------------------------------------------------*/
static spi_device_t flash_spi_configuration_default = {
static const spi_device_t flash_spi_configuration_default = {
.spi_controller = EXT_FLASH_SPI_CONTROLLER,
.pin_spi_sck = EXT_FLASH_SPI_PIN_SCK,
.pin_spi_miso = EXT_FLASH_SPI_PIN_MISO,
@ -113,8 +113,8 @@ static spi_device_t flash_spi_configuration_default = {
/**
* Get spi configuration, return default configuration if NULL
*/
static spi_device_t *
get_spi_conf(spi_device_t *conf)
static const spi_device_t *
get_spi_conf(const spi_device_t *conf)
{
if(conf == NULL) {
return &flash_spi_configuration_default;
@ -126,7 +126,7 @@ get_spi_conf(spi_device_t *conf)
* Clear external flash CSN line
*/
static bool
select_on_bus(spi_device_t *flash_spi_configuration)
select_on_bus(const spi_device_t *flash_spi_configuration)
{
if(spi_select(flash_spi_configuration) == SPI_DEV_STATUS_OK) {
return true;
@ -138,7 +138,7 @@ select_on_bus(spi_device_t *flash_spi_configuration)
* Set external flash CSN line
*/
static void
deselect(spi_device_t *flash_spi_configuration)
deselect(const spi_device_t *flash_spi_configuration)
{
spi_deselect(flash_spi_configuration);
}
@ -148,7 +148,7 @@ deselect(spi_device_t *flash_spi_configuration)
* \return True when successful.
*/
static bool
wait_ready(spi_device_t *flash_spi_configuration)
wait_ready(const spi_device_t *flash_spi_configuration)
{
bool ret;
const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
@ -196,7 +196,7 @@ wait_ready(spi_device_t *flash_spi_configuration)
* was powered down
*/
static uint8_t
verify_part(spi_device_t *flash_spi_configuration)
verify_part(const spi_device_t *flash_spi_configuration)
{
const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
uint8_t rbuf[2] = { 0, 0 };
@ -230,7 +230,7 @@ verify_part(spi_device_t *flash_spi_configuration)
* the status register is accessible.
*/
static bool
power_down(spi_device_t *flash_spi_configuration)
power_down(const spi_device_t *flash_spi_configuration)
{
uint8_t cmd;
uint8_t i;
@ -271,7 +271,7 @@ power_down(spi_device_t *flash_spi_configuration)
* \return True if the command was written successfully
*/
static bool
power_standby(spi_device_t *flash_spi_configuration)
power_standby(const spi_device_t *flash_spi_configuration)
{
uint8_t cmd;
bool success;
@ -297,7 +297,7 @@ power_standby(spi_device_t *flash_spi_configuration)
* \return True when successful.
*/
static bool
write_enable(spi_device_t *flash_spi_configuration)
write_enable(const spi_device_t *flash_spi_configuration)
{
bool ret;
const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
@ -316,9 +316,9 @@ write_enable(spi_device_t *flash_spi_configuration)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_open(spi_device_t *conf)
ext_flash_open(const spi_device_t *conf)
{
spi_device_t *flash_spi_configuration;
const spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
@ -346,10 +346,10 @@ ext_flash_open(spi_device_t *conf)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_close(spi_device_t *conf)
ext_flash_close(const spi_device_t *conf)
{
bool ret;
spi_device_t *flash_spi_configuration;
const spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
@ -365,12 +365,12 @@ ext_flash_close(spi_device_t *conf)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
{
uint8_t wbuf[4];
bool ret;
spi_device_t *flash_spi_configuration;
const spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
@ -406,12 +406,12 @@ ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *bu
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
{
uint8_t wbuf[4];
uint32_t ilen; /* interim length per instruction */
spi_device_t *flash_spi_configuration;
const spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
@ -466,7 +466,7 @@ ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length)
{
/*
* Note that Block erase might be more efficient when the floor map
@ -477,7 +477,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
uint32_t i, numsectors;
uint32_t endoffset = offset + length - 1;
spi_device_t *flash_spi_configuration;
const spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
@ -518,7 +518,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_init(spi_device_t *conf)
ext_flash_init(const spi_device_t *conf)
{
if(ext_flash_open(conf) == false) {
return false;

View File

@ -61,7 +61,7 @@
* \param conf SPI bus configuration struct. NULL for default.
* \return True when successful.
*/
bool ext_flash_open(spi_device_t *conf);
bool ext_flash_open(const spi_device_t *conf);
/**
* \brief Close the storage driver
@ -70,7 +70,7 @@ bool ext_flash_open(spi_device_t *conf);
*
* This call will put the device in its lower power mode (power down).
*/
bool ext_flash_close(spi_device_t *conf);
bool ext_flash_close(const spi_device_t *conf);
/**
* \brief Read storage content
@ -82,7 +82,7 @@ bool ext_flash_close(spi_device_t *conf);
*
* buf must be allocated by the caller
*/
bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf);
bool ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf);
/**
* \brief Erase storage sectors corresponding to the range.
@ -94,7 +94,7 @@ bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_
* The erase operation will be sector-wise, therefore a call to this function
* will generally start the erase procedure at an address lower than offset
*/
bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length);
bool ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length);
/**
* \brief Write to storage sectors.
@ -105,7 +105,7 @@ bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length);
*
* \return True when successful.
*/
bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf);
bool ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf);
/**
* \brief Initialise the external flash
@ -117,7 +117,7 @@ bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const
* In order to perform any operation, the caller must first wake the device
* up by calling ext_flash_open()
*/
bool ext_flash_init(spi_device_t *conf);
bool ext_flash_init(const spi_device_t *conf);
/*---------------------------------------------------------------------------*/
#endif /* EXT_FLASH_H_ */
/*---------------------------------------------------------------------------*/

View File

@ -122,6 +122,10 @@ typedef unsigned long clock_time_t;
/* Use 64-bit rtimer (default in Contiki-NG is 32) */
#define RTIMER_CONF_CLOCK_SIZE 8
/* 1 len byte, 2 bytes CRC */
#define RADIO_PHY_OVERHEAD 3
/* 250kbps data rate. One byte = 32us */
#define RADIO_BYTE_AIR_TIME 32
#define RADIO_DELAY_BEFORE_TX 0
#define RADIO_DELAY_BEFORE_RX 0
#define RADIO_DELAY_BEFORE_DETECT 0

View File

@ -330,6 +330,10 @@ get_value(radio_param_t param, radio_value_t *value)
case RADIO_PARAM_LAST_LINK_QUALITY:
*value = simLQI;
return RADIO_RESULT_OK;
case RADIO_PARAM_RSSI:
/* return a fixed value depending on the channel */
*value = -90 + simRadioChannel - 11;
return RADIO_RESULT_OK;
default:
return RADIO_RESULT_NOT_SUPPORTED;
}

View File

@ -30,8 +30,10 @@
*
*/
/* Dummy watchdog routines for the Raven 1284p */
/* Dummy watchdog routines for Cooja motes */
#include "dev/watchdog.h"
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
/*---------------------------------------------------------------------------*/
void
@ -47,6 +49,9 @@ watchdog_start(void)
void
watchdog_periodic(void)
{
/* Yield and give control back to the simulator scheduler */
simProcessRunValue = 1;
cooja_mt_yield();
}
/*---------------------------------------------------------------------------*/
void

View File

@ -103,8 +103,6 @@ endif
CONTIKI_TARGET_DIRS = . dev
CONTIKI_TARGET_MAIN = platform.c
MODULES += os/lib/dbg-io
ifeq ($(JN516x_WITH_DR1175),1)
JN516x_WITH_DR1174 = 1
CFLAGS += -DSENSOR_BOARD_DR1175

View File

@ -130,13 +130,6 @@
#define MICROMAC_CONF_ALWAYS_ON 1
#endif /* MICROMAC_CONF_ALWAYS_ON */
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
} while(0)
/* Local variables */
static volatile signed char radio_last_rssi;
static volatile uint8_t radio_last_correlation; /* LQI */
@ -377,14 +370,14 @@ transmit(unsigned short payload_len)
(send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA));
#endif
if(poll_mode) {
BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
RTIMER_BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
} else {
if(in_ack_transmission) {
/* as nested interupts are not possible, the tx flag will never be cleared */
BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION);
RTIMER_BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION);
} else {
/* wait until the tx flag is cleared */
BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
RTIMER_BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
}
}

View File

@ -66,14 +66,6 @@ extern volatile unsigned char xonxoff_state;
#endif /* UART_XONXOFF_FLOW_CTRL */
/*** Macro Definitions ***/
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
} while(0)
#define DEBUG_UART_BUFFERED FALSE
#define CHAR_DEADLINE (uart_char_delay * 100)
@ -276,7 +268,7 @@ uart_driver_write_with_deadline(uint8_t uart_dev, uint8_t ch)
volatile int16_t write = 0;
watchdog_periodic();
/* wait until there is space in tx fifo */
BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0),
RTIMER_BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0),
CHAR_DEADLINE);
/* write only if there is space so we do not get stuck */
if(write) {

View File

@ -38,6 +38,10 @@
#undef putchar
/* 1 len byte, 2 bytes CRC */
#define RADIO_PHY_OVERHEAD 3
/* 250kbps data rate. One byte = 32us */
#define RADIO_BYTE_AIR_TIME 32
/* Delay between GO signal and SFD
* Measured 153us between GO and preamble. Add 5 bytes (preamble + SFD) air time: 153+5*32 = 313 */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(313))

View File

@ -9,12 +9,12 @@ CONTIKI_TARGET_DIRS += . dev config
CONTIKI_SOURCEFILES += platform.c leds-arch.c nrf52dk-sensors.c button-sensor.c temperature-sensor.c
ifeq ($(NRF52_USE_RTT),1)
### Use the existing debug I/O in arch/cpu/arm/common
### Suppress the existing debug I/O in os/lib
MAKE_WITH_LIB_DBG_IO = 0
CONTIKI_TARGET_DIRS += rtt
CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c
else
CONTIKI_SOURCEFILES += dbg.c
MODULES += os/lib/dbg-io
endif
### Unless the example dictates otherwise, build with code size optimisations switched off

View File

@ -17,11 +17,14 @@
#define NETSTACK_CONF_RADIO cc2420_driver
#endif /* NETSTACK_CONF_RADIO */
/* Symbol for the TSCH 15ms timeslot timing template */
#define TSCH_CONF_ARCH_HDR_PATH "dev/cc2420/cc2420-tsch-15ms.h"
/* The TSCH default slot length of 10ms is a bit too short for this platform,
* use 15ms instead. */
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_15000
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */
/* Save RAM through a smaller uIP buffer */
#ifndef UIP_CONF_BUFFER_SIZE

View File

@ -43,6 +43,7 @@
#include "lib/random.h"
#include "net/netstack.h"
#include "net/mac/framer/frame802154.h"
#include "net/mac/tsch/tsch.h"
#if NETSTACK_CONF_WITH_IPV6
#include "net/ipv6/uip-ds6.h"

View File

@ -43,6 +43,11 @@
* Definitions below are dictated by the hardware and not really
* changeable!
*/
/* 1 len byte, 2 bytes CRC */
#define RADIO_PHY_OVERHEAD 3
/* 250kbps data rate. One byte = 32us */
#define RADIO_BYTE_AIR_TIME 32
/* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us
* ~327us + 129preample = 456 us */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456))

View File

@ -55,6 +55,25 @@
#endif /* PROJECT_CONF_PATH */
/*---------------------------------------------------------------------------*/
#include "cc2538-def.h"
unsigned radio_phy_overhead(void);
unsigned radio_byte_air_time(void);
unsigned radio_delay_before_tx(void);
unsigned radio_delay_before_rx(void);
unsigned radio_delay_before_detect(void);
uint16_t *radio_tsch_timeslot_timing(void);
/** @} */
/*---------------------------------------------------------------------------*/
#define RADIO_PHY_OVERHEAD radio_phy_overhead()
#define RADIO_BYTE_AIR_TIME radio_byte_air_time()
#define RADIO_DELAY_BEFORE_TX radio_delay_before_tx()
#define RADIO_DELAY_BEFORE_RX radio_delay_before_rx()
#define RADIO_DELAY_BEFORE_DETECT radio_delay_before_detect()
#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING radio_tsch_timeslot_timing()
/*---------------------------------------------------------------------------*/
/**
* \name Serial Boot Loader Backdoor configuration

View File

@ -76,18 +76,8 @@
/*---------------------------------------------------------------------------*/
#if DEBUG_CC1200_ARCH > 0
#define PRINTF(...) printf(__VA_ARGS__)
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) {} \
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)))) { \
printf("ARCH: Timeout exceeded in line %d!\n", __LINE__); \
} \
} while(0)
#else
#define PRINTF(...)
#define BUSYWAIT_UNTIL(cond, max_time) while(!cond)
#endif
/*---------------------------------------------------------------------------*/
extern int cc1200_rx_interrupt(void);
@ -105,7 +95,7 @@ cc1200_arch_spi_select(void)
/* Set CSn to low (0) */
GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
/* The MISO pin should go low before chip is fully enabled. */
BUSYWAIT_UNTIL(
RTIMER_BUSYWAIT_UNTIL(
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0,
RTIMER_SECOND / 100);
}
@ -288,7 +278,7 @@ cc1200_arch_init(void)
cc1200_arch_spi_deselect();
/* Ensure MISO is high */
BUSYWAIT_UNTIL(
RTIMER_BUSYWAIT_UNTIL(
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK),
RTIMER_SECOND / 10);
}
@ -297,4 +287,3 @@ cc1200_arch_init(void)
* @}
* @}
*/

View File

@ -51,15 +51,6 @@
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
#define BUSYWAIT_UNTIL(max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \
watchdog_periodic(); \
} \
} while(0)
/*---------------------------------------------------------------------------*/
#define DHT22_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT)
#define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN)
/*---------------------------------------------------------------------------*/
@ -80,12 +71,12 @@ dht22_read(void)
/* Exit low power mode and initialize variables */
GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
BUSYWAIT_UNTIL(DHT22_AWAKE_TIME);
RTIMER_BUSYWAIT(DHT22_AWAKE_TIME);
memset(dht22_data, 0, DHT22_BUFFER);
/* Initialization sequence */
GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
BUSYWAIT_UNTIL(DHT22_START_TIME);
RTIMER_BUSYWAIT(DHT22_START_TIME);
GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
clock_delay_usec(DHT22_READY_TIME);

View File

@ -257,6 +257,48 @@ platform_idle()
lpm_enter();
}
/*---------------------------------------------------------------------------*/
unsigned
radio_phy_overhead(void) {
radio_value_t ret;
NETSTACK_RADIO.get_value(RADIO_CONST_PHY_OVERHEAD, &ret);
return (unsigned)ret;
}
/*---------------------------------------------------------------------------*/
unsigned
radio_byte_air_time(void) {
radio_value_t ret;
NETSTACK_RADIO.get_value(RADIO_CONST_BYTE_AIR_TIME, &ret);
return (unsigned)ret;
}
/*---------------------------------------------------------------------------*/
unsigned
radio_delay_before_tx(void) {
radio_value_t ret;
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_TX, &ret);
return (unsigned)ret;
}
/*---------------------------------------------------------------------------*/
unsigned
radio_delay_before_rx(void) {
radio_value_t ret;
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_RX, &ret);
return (unsigned)ret;
}
/*---------------------------------------------------------------------------*/
unsigned
radio_delay_before_detect(void) {
radio_value_t ret;
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_DETECT, &ret);
return (unsigned)ret;
}
/*---------------------------------------------------------------------------*/
uint16_t *
radio_tsch_timeslot_timing(void) {
uint16_t *ret;
NETSTACK_RADIO.get_object(RADIO_CONST_TSCH_TIMING, &ret, sizeof(ret));
return ret;
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}

View File

@ -0,0 +1,34 @@
CONTIKI_PROJECT = node
all: $(CONTIKI_PROJECT)
CONTIKI=../../..
PLATFORMS_EXCLUDE = sky nrf52dk native
BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350
# The channel selection library
MODULES += os/services/tsch-cs
# force Orchestra from command line
MAKE_WITH_ORCHESTRA ?= 0
# force Security from command line
MAKE_WITH_SECURITY ?= 0
# print #routes periodically, used for regression tests
MAKE_WITH_PERIODIC_ROUTES_PRINT ?= 0
MAKE_MAC = MAKE_MAC_TSCH
MODULES += os/services/shell
ifeq ($(MAKE_WITH_ORCHESTRA),1)
MODULES += os/services/orchestra
endif
ifeq ($(MAKE_WITH_SECURITY),1)
CFLAGS += -DWITH_SECURITY=1
endif
ifeq ($(MAKE_WITH_PERIODIC_ROUTES_PRINT),1)
CFLAGS += -DWITH_PERIODIC_ROUTES_PRINT=1
endif
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,8 @@
Demonstration of TSCH adaptive channel selection based on background noise RSSI metric.
TSCH stats must be enabled for the adaptive selection functionality to compile and work.
This code relies on the `os/services/channel-selection` library that implements
the "RSSI upstream" adaptative channel selection strategy, described in the following paper:
A. Elsts, X. Fafoutis, G. Oikonomou and R. Piechocki. Adaptive Channel Selection in IEEE 802.15.4 TSCH Networks, 1st Global Internet of Things Summit, 2017.
http://ieeexplore.ieee.org/document/8016246/

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2015, SICS Swedish ICT.
* Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* A RPL+TSCH node.
*
* \author Simon Duquennoy <simonduq@sics.se>
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#include "contiki.h"
#include "sys/node-id.h"
#include "sys/log.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/ipv6/uip-sr.h"
#include "net/mac/tsch/tsch.h"
#include "net/routing/routing.h"
#include "tsch-cs.h"
#define DEBUG DEBUG_PRINT
#include "net/ipv6/uip-debug.h"
/*---------------------------------------------------------------------------*/
PROCESS(node_process, "RPL Node");
AUTOSTART_PROCESSES(&node_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(node_process, ev, data)
{
int is_coordinator;
PROCESS_BEGIN();
is_coordinator = 0;
#if CONTIKI_TARGET_COOJA
is_coordinator = (node_id == 1);
#endif
if(is_coordinator) {
NETSTACK_ROUTING.root_start();
}
NETSTACK_MAC.on();
#if WITH_PERIODIC_ROUTES_PRINT
{
static struct etimer et;
/* Print out routing tables every minute */
etimer_set(&et, CLOCK_SECOND * 60);
while(1) {
/* Used for non-regression testing */
#if (UIP_MAX_ROUTES != 0)
PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes());
#endif
#if (UIP_SR_LINK_NUM != 0)
PRINTF("Routing links: %u\n", uip_sr_num_nodes());
#endif
PROCESS_YIELD_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
}
#endif /* WITH_PERIODIC_ROUTES_PRINT */
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2015, SICS Swedish ICT.
* Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \author Simon Duquennoy <simonduq@sics.se>
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#ifndef __PROJECT_CONF_H__
#define __PROJECT_CONF_H__
#include <stdint.h>
#include <stdbool.h>
/* Set to enable TSCH security */
#ifndef WITH_SECURITY
#define WITH_SECURITY 0
#endif /* WITH_SECURITY */
/* USB serial takes space, free more space elsewhere */
#define SICSLOWPAN_CONF_FRAG 0
#define UIP_CONF_BUFFER_SIZE 160
/*******************************************************/
/******************* Configure TSCH ********************/
/*******************************************************/
/* IEEE802.15.4 PANID */
#define IEEE802154_CONF_PANID 0x81a5
/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */
#define TSCH_CONF_AUTOSTART 0
/* 6TiSCH minimal schedule length.
* Larger values result in less frequent active slots: reduces capacity and saves energy. */
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 3
#if WITH_SECURITY
/* Enable security */
#define LLSEC802154_CONF_ENABLED 1
#endif /* WITH_SECURITY */
/* Enable TSCH statistics: must be on for channel selection to work */
#define TSCH_STATS_CONF_ON 1
/* Enable periodic RSSI sampling for TSCH statistics */
#define TSCH_STATS_CONF_SAMPLE_NOISE_RSSI 1
/* Reduce the TSCH stat "decay to normal" period to get printouts more often */
#define TSCH_STATS_CONF_DECAY_INTERVAL (60 * CLOCK_SECOND)
/* For adaptive channel selection */
extern void tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric);
extern bool tsch_cs_process(void);
/* These will be called from the core TSCH code */
#define TSCH_CALLBACK_CHANNEL_STATS_UPDATED tsch_cs_channel_stats_updated
#define TSCH_CALLBACK_SELECT_CHANNELS tsch_cs_process
/* The coordinator will update the network nodes with new hopping sequences */
#define TSCH_PACKET_CONF_EB_WITH_HOPPING_SEQUENCE 1
/* Reduce the EB period in order to update the network nodes with more agility */
#define TSCH_CONF_EB_PERIOD (4 * CLOCK_SECOND)
#define TSCH_CONF_MAX_EB_PERIOD (4 * CLOCK_SECOND)
/*******************************************************/
/************* Other system configuration **************/
/*******************************************************/
/* Logging */
#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO
#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_MAC LOG_LEVEL_DBG
#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_INFO
#define TSCH_LOG_CONF_PER_SLOT 1
#endif /* __PROJECT_CONF_H__ */

View File

@ -74,33 +74,4 @@
#endif /* WITH_SECURITY */
/*******************************************************/
/************* Other system configuration **************/
/*******************************************************/
#if CONTIKI_TARGET_Z1
/* Save some space to fit the limited RAM of the z1 */
#define UIP_CONF_TCP 0
#define QUEUEBUF_CONF_NUM 2
#define NETSTACK_MAX_ROUTE_ENTRIES 2
#define NBR_TABLE_CONF_MAX_NEIGHBORS 2
#define UIP_CONF_ND6_SEND_NA 0
#define SICSLOWPAN_CONF_FRAG 0
#if WITH_SECURITY
/* Note: on sky or z1 in cooja, crypto operations are done in S/W and
* cannot be accommodated in normal slots. Use 65ms slots instead, and
* a very short 6TiSCH minimal schedule length */
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 65000
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 2
#endif /* WITH_SECURITY */
#endif /* CONTIKI_TARGET_Z1 */
#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL || \
CONTIKI_TARGET_OPENMOTE_CC2538
#define TSCH_CONF_HW_FRAME_FILTERING 0
#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \
|| CONTIKI_TARGET_OPENMOTE_CC2538 */
#endif /* PROJECT_CONF_H_ */

View File

@ -0,0 +1,31 @@
CONTIKI_PROJECT = node
all: $(CONTIKI_PROJECT)
CONTIKI=../../..
PLATFORMS_EXCLUDE = sky nrf52dk native
BOARDS_EXCLUDE = srf06/cc13xx launchpad/cc1310 launchpad/cc1350 sensortag/cc2650 sensortag/cc1350
# force Orchestra from command line
MAKE_WITH_ORCHESTRA ?= 0
# force Security from command line
MAKE_WITH_SECURITY ?= 0
# print #routes periodically, used for regression tests
MAKE_WITH_PERIODIC_ROUTES_PRINT ?= 0
MAKE_MAC = MAKE_MAC_TSCH
MODULES += os/services/shell
ifeq ($(MAKE_WITH_ORCHESTRA),1)
MODULES += os/services/orchestra
endif
ifeq ($(MAKE_WITH_SECURITY),1)
CFLAGS += -DWITH_SECURITY=1
endif
ifeq ($(MAKE_WITH_PERIODIC_ROUTES_PRINT),1)
CFLAGS += -DWITH_PERIODIC_ROUTES_PRINT=1
endif
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1 @@
Demonstration of TSCH stats.

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, SICS Swedish ICT.
* Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* A RPL+TSCH node.
*
* \author Simon Duquennoy <simonduq@sics.se>
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#include "contiki.h"
#include "sys/node-id.h"
#include "sys/log.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/ipv6/uip-sr.h"
#include "net/mac/tsch/tsch.h"
#include "net/routing/routing.h"
#define DEBUG DEBUG_PRINT
#include "net/ipv6/uip-debug.h"
/*---------------------------------------------------------------------------*/
PROCESS(node_process, "RPL Node");
AUTOSTART_PROCESSES(&node_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(node_process, ev, data)
{
int is_coordinator;
PROCESS_BEGIN();
is_coordinator = 0;
#if CONTIKI_TARGET_COOJA
is_coordinator = (node_id == 1);
#endif
if(is_coordinator) {
NETSTACK_ROUTING.root_start();
}
NETSTACK_MAC.on();
#if WITH_PERIODIC_ROUTES_PRINT
{
static struct etimer et;
/* Print out routing tables every minute */
etimer_set(&et, CLOCK_SECOND * 60);
while(1) {
/* Used for non-regression testing */
#if (UIP_MAX_ROUTES != 0)
PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes());
#endif
#if (UIP_SR_LINK_NUM != 0)
PRINTF("Routing links: %u\n", uip_sr_num_nodes());
#endif
PROCESS_YIELD_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
}
#endif /* WITH_PERIODIC_ROUTES_PRINT */
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015, SICS Swedish ICT.
* Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \author Simon Duquennoy <simonduq@sics.se>
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#ifndef __PROJECT_CONF_H__
#define __PROJECT_CONF_H__
/* Set to enable TSCH security */
#ifndef WITH_SECURITY
#define WITH_SECURITY 0
#endif /* WITH_SECURITY */
/* USB serial takes space, free more space elsewhere */
#define SICSLOWPAN_CONF_FRAG 0
#define UIP_CONF_BUFFER_SIZE 160
/*******************************************************/
/******************* Configure TSCH ********************/
/*******************************************************/
/* IEEE802.15.4 PANID */
#define IEEE802154_CONF_PANID 0x81a5
/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */
#define TSCH_CONF_AUTOSTART 0
/* 6TiSCH minimal schedule length.
* Larger values result in less frequent active slots: reduces capacity and saves energy. */
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 3
#if WITH_SECURITY
/* Enable security */
#define LLSEC802154_CONF_ENABLED 1
#endif /* WITH_SECURITY */
/* Enable TSCH statistics */
#define TSCH_STATS_CONF_ON 1
/* Enable periodic RSSI sampling for TSCH statistics */
#define TSCH_STATS_CONF_SAMPLE_NOISE_RSSI 1
/* Reduce the TSCH stat "decay to normal" period to get printouts more often */
#define TSCH_STATS_CONF_DECAY_INTERVAL (60 * CLOCK_SECOND)
/*******************************************************/
/************* Other system configuration **************/
/*******************************************************/
/* Logging */
#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO
#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN
#define LOG_CONF_LEVEL_MAC LOG_LEVEL_DBG
#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_INFO
#define TSCH_LOG_CONF_PER_SLOT 1
#endif /* __PROJECT_CONF_H__ */

View File

@ -194,7 +194,7 @@ PROCESS_THREAD(node_process, ev, data)
if (host_found) {
/* Make sample count dependent on asn. After a disconnect, waveforms remain
synchronous. Use node_mac to create phase offset between waveforms in different nodes */
sample_count = ((tsch_current_asn.ls4b/((1000/(TSCH_CONF_DEFAULT_TIMESLOT_LENGTH/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1);
sample_count = ((tsch_current_asn.ls4b/((1000/(tsch_timing_us[tsch_ts_timeslot_length]/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1);
printf("%d sec. waveform=%s. cnt=%d. value=%d\n", total_time, waveform_table[selected_waveform].str, sample_count, waveform_table[selected_waveform].table[sample_count]);
my_sprintf(udp_buf, waveform_table[selected_waveform].table[sample_count]);
uip_udp_packet_send(udp_conn_tx, udp_buf, strlen(udp_buf));

View File

@ -53,6 +53,7 @@
#include "services/orchestra/orchestra.h"
#include "services/shell/serial-shell.h"
#include "services/simple-energest/simple-energest.h"
#include "services/tsch-cs/tsch-cs.h"
#include <stdio.h>
#include <stdint.h>
@ -146,6 +147,11 @@ main(void)
simple_energest_init();
#endif /* BUILD_WITH_SIMPLE_ENERGEST */
#if BUILD_WITH_TSCH_CS
/* Initialize the channel selection module */
tsch_cs_adaptations_init();
#endif /* BUILD_WITH_TSCH_CS */
autostart_start(autostart_processes);
watchdog_start();

View File

@ -170,6 +170,9 @@ enum {
* it needs to be used with radio.get_object()/set_object(). */
RADIO_PARAM_LAST_PACKET_TIMESTAMP,
/* For enabling and disabling the SHR search */
RADIO_PARAM_SHR_SEARCH,
/* Constants (read only) */
/* The lowest radio channel. */
@ -180,7 +183,14 @@ enum {
/* The minimum transmission power in dBm. */
RADIO_CONST_TXPOWER_MIN,
/* The maximum transmission power in dBm. */
RADIO_CONST_TXPOWER_MAX
RADIO_CONST_TXPOWER_MAX,
RADIO_CONST_TSCH_TIMING,
RADIO_CONST_PHY_OVERHEAD,
RADIO_CONST_BYTE_AIR_TIME,
RADIO_CONST_DELAY_BEFORE_TX,
RADIO_CONST_DELAY_BEFORE_RX,
RADIO_CONST_DELAY_BEFORE_DETECT,
};
/* Radio power modes */

View File

@ -43,7 +43,7 @@
#include <stdbool.h>
/*---------------------------------------------------------------------------*/
spi_status_t
spi_acquire(spi_device_t *dev)
spi_acquire(const spi_device_t *dev)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -54,7 +54,7 @@ spi_acquire(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_release(spi_device_t *dev)
spi_release(const spi_device_t *dev)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -65,19 +65,19 @@ spi_release(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_select(spi_device_t *dev)
spi_select(const spi_device_t *dev)
{
return spi_arch_select(dev);
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_deselect(spi_device_t *dev)
spi_deselect(const spi_device_t *dev)
{
return spi_arch_deselect(dev);
}
/*---------------------------------------------------------------------------*/
bool
spi_has_bus(spi_device_t *dev)
spi_has_bus(const spi_device_t *dev)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return false;
@ -87,7 +87,7 @@ spi_has_bus(spi_device_t *dev)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_write_byte(spi_device_t *dev, uint8_t data)
spi_write_byte(const spi_device_t *dev, uint8_t data)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -101,7 +101,7 @@ spi_write_byte(spi_device_t *dev, uint8_t data)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_write(spi_device_t *dev, const uint8_t *data, int size)
spi_write(const spi_device_t *dev, const uint8_t *data, int size)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -115,7 +115,7 @@ spi_write(spi_device_t *dev, const uint8_t *data, int size)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_read_byte(spi_device_t *dev, uint8_t *buf)
spi_read_byte(const spi_device_t *dev, uint8_t *buf)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -129,7 +129,7 @@ spi_read_byte(spi_device_t *dev, uint8_t *buf)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_read(spi_device_t *dev, uint8_t *buf, int size)
spi_read(const spi_device_t *dev, uint8_t *buf, int size)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -143,7 +143,7 @@ spi_read(spi_device_t *dev, uint8_t *buf, int size)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_read_skip(spi_device_t *dev, int size)
spi_read_skip(const spi_device_t *dev, int size)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;
@ -157,7 +157,7 @@ spi_read_skip(spi_device_t *dev, int size)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_transfer(spi_device_t *dev,
spi_transfer(const spi_device_t *dev,
const uint8_t *wdata, int wsize,
uint8_t *rbuf, int rsize, int ignore)
{
@ -181,7 +181,7 @@ spi_transfer(spi_device_t *dev,
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
spi_read_register(const spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
{
spi_status_t status;
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
@ -204,7 +204,7 @@ spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
}
/*---------------------------------------------------------------------------*/
spi_status_t
spi_strobe(spi_device_t *dev, uint8_t strobe, uint8_t *result)
spi_strobe(const spi_device_t *dev, uint8_t strobe, uint8_t *result)
{
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
return SPI_DEV_STATUS_EINVAL;

View File

@ -115,7 +115,7 @@ typedef struct spi_device {
* to be locked and the opening configuration.
* \return SPI return code
*/
spi_status_t spi_acquire(spi_device_t *dev);
spi_status_t spi_acquire(const spi_device_t *dev);
/**
* \brief Closes and then unlocks an SPI controller
@ -127,7 +127,7 @@ spi_status_t spi_acquire(spi_device_t *dev);
* This should work only if the device has already locked the SPI
* controller.
*/
spi_status_t spi_release(spi_device_t *dev);
spi_status_t spi_release(const spi_device_t *dev);
/**
* \brief Selects the SPI peripheral
@ -137,7 +137,7 @@ spi_status_t spi_release(spi_device_t *dev);
* Clears the CS pin. This should work only if the device has
* already locked the SPI controller.
*/
spi_status_t spi_select(spi_device_t *dev);
spi_status_t spi_select(const spi_device_t *dev);
/**
* \brief Deselects the SPI peripheral
@ -146,14 +146,14 @@ spi_status_t spi_select(spi_device_t *dev);
*
* Sets the CS pin. Lock is not required.
*/
spi_status_t spi_deselect(spi_device_t *dev);
spi_status_t spi_deselect(const spi_device_t *dev);
/**
* \brief Checks if a device has locked an SPI controller
* \param dev An SPI device configuration which defines the controller.
* \return true if the device has the lock, false otherwise.
*/
bool spi_has_bus(spi_device_t *dev);
bool spi_has_bus(const spi_device_t *dev);
/**
* \brief Writes a single byte to an SPI device
@ -163,7 +163,7 @@ bool spi_has_bus(spi_device_t *dev);
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data);
spi_status_t spi_write_byte(const spi_device_t *dev, uint8_t data);
/**
* \brief Reads a single byte from an SPI device
@ -173,7 +173,7 @@ spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data);
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data);
spi_status_t spi_read_byte(const spi_device_t *dev, uint8_t *data);
/**
* \brief Writes a buffer to an SPI device
@ -184,7 +184,7 @@ spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data);
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_write(spi_device_t *dev,
spi_status_t spi_write(const spi_device_t *dev,
const uint8_t *data, int size);
/**
@ -196,7 +196,7 @@ spi_status_t spi_write(spi_device_t *dev,
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size);
spi_status_t spi_read(const spi_device_t *dev, uint8_t *data, int size);
/**
* \brief Reads and ignores data from an SPI device
@ -207,7 +207,7 @@ spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size);
* Reads size bytes from the SPI and throws them away.
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_skip(spi_device_t *dev, int size);
spi_status_t spi_read_skip(const spi_device_t *dev, int size);
/**
* \brief Performs a generic SPI transfer
@ -226,7 +226,7 @@ spi_status_t spi_read_skip(spi_device_t *dev, int size);
* be copied to buf. The remaining ignore_len bytes won't be copied to the
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
*/
spi_status_t spi_transfer(spi_device_t *dev,
spi_status_t spi_transfer(const spi_device_t *dev,
const uint8_t *data, int wsize,
uint8_t *buf, int rsize, int ignore);
@ -239,7 +239,7 @@ spi_status_t spi_transfer(spi_device_t *dev,
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe,
spi_status_t spi_strobe(const spi_device_t *dev, uint8_t strobe,
uint8_t *status);
/**
@ -252,7 +252,7 @@ spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe,
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg,
spi_status_t spi_read_register(const spi_device_t *dev, uint8_t reg,
uint8_t *data, int size);
/*---------------------------------------------------------------------------*/
@ -266,7 +266,7 @@ spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg,
* \return 1 if the device has the lock, 0 otherwise.
*
*/
bool spi_arch_has_lock(spi_device_t *dev);
bool spi_arch_has_lock(const spi_device_t *dev);
/**
* \brief Checks if an SPI controller is locked by any device
@ -275,7 +275,7 @@ bool spi_arch_has_lock(spi_device_t *dev);
* \return 1 if the controller is locked, 0 otherwise.
*
*/
bool spi_arch_is_bus_locked(spi_device_t *dev);
bool spi_arch_is_bus_locked(const spi_device_t *dev);
/**
* \brief Locks and opens an SPI controller to the configuration specified.
@ -286,7 +286,7 @@ bool spi_arch_is_bus_locked(spi_device_t *dev);
* controller.
*
*/
spi_status_t spi_arch_lock_and_open(spi_device_t *dev);
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev);
/**
* \brief Closes and unlocks an SPI controller
@ -299,7 +299,7 @@ spi_status_t spi_arch_lock_and_open(spi_device_t *dev);
* controller.
*
*/
spi_status_t spi_arch_close_and_unlock(spi_device_t *dev);
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev);
/**
* \brief Performs an SPI transfer
@ -318,7 +318,7 @@ spi_status_t spi_arch_close_and_unlock(spi_device_t *dev);
* be copied to buf. The remaining ignore_len bytes won't be copied to the
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
*/
spi_status_t spi_arch_transfer(spi_device_t *dev,
spi_status_t spi_arch_transfer(const spi_device_t *dev,
const uint8_t *data, int wlen,
uint8_t *buf, int rlen,
int ignore_len);
@ -331,7 +331,7 @@ spi_status_t spi_arch_transfer(spi_device_t *dev,
* Clears the CS pin. It should work only if the device has already
* locked the SPI controller.
*/
spi_status_t spi_arch_select(spi_device_t *dev);
spi_status_t spi_arch_select(const spi_device_t *dev);
/**
* \brief Deselects an SPI device
@ -340,7 +340,7 @@ spi_status_t spi_arch_select(spi_device_t *dev);
*
* Set the CS pin. Locking the SPI controller is not needed.
*/
spi_status_t spi_arch_deselect(spi_device_t *dev);
spi_status_t spi_arch_deselect(const spi_device_t *dev);
#endif /* SPI_H_ */
/*---------------------------------------------------------------------------*/

View File

@ -37,12 +37,10 @@
#include "net/link-stats.h"
#include <stdio.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "Link Stats"
#define LOG_LEVEL LOG_LEVEL_MAC
/* Maximum value for the Tx count counter */
#define TX_COUNT_MAX 32
@ -82,6 +80,13 @@ link_stats_from_lladdr(const linkaddr_t *lladdr)
return nbr_table_get_from_lladdr(link_stats, lladdr);
}
/*---------------------------------------------------------------------------*/
/* Returns the neighbor's address given a link stats item */
const linkaddr_t *
link_stats_get_lladdr(const struct link_stats *stat)
{
return nbr_table_get_lladdr(link_stats, stat);
}
/*---------------------------------------------------------------------------*/
/* Are the statistics fresh? */
int
link_stats_is_fresh(const struct link_stats *stats)
@ -156,6 +161,14 @@ link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx)
stats->last_tx_time = clock_time();
stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX);
#if LINK_STATS_PACKET_COUNTERS
/* Update paket counters */
stats->cnt_current.num_packets_tx += numtx;
if(status == MAC_TX_OK) {
stats->cnt_current.num_packets_acked++;
}
#endif
/* Add penalty in case of no-ACK */
if(status == MAC_TX_NOACK) {
numtx += ETX_NOACK_PENALTY;
@ -219,8 +232,38 @@ link_stats_input_callback(const linkaddr_t *lladdr)
/* Update RSSI EWMA */
stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) +
(int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE;
#if LINK_STATS_PACKET_COUNTERS
stats->cnt_current.num_packets_rx++;
#endif
}
/*---------------------------------------------------------------------------*/
#if LINK_STATS_PACKET_COUNTERS
/*---------------------------------------------------------------------------*/
static void
print_and_update_counters(void)
{
struct link_stats *stats;
for(stats = nbr_table_head(link_stats); stats != NULL;
stats = nbr_table_next(link_stats, stats)) {
struct link_packet_counter *c = &stats->cnt_current;
LOG_INFO("num packets: tx=%u ack=%u rx=%u to=",
c->num_packets_tx, c->num_packets_acked, c->num_packets_rx);
LOG_INFO_LLADDR(link_stats_get_lladdr(stats));
LOG_INFO_("\n");
stats->cnt_total.num_packets_tx += stats->cnt_current.num_packets_tx;
stats->cnt_total.num_packets_acked += stats->cnt_current.num_packets_acked;
stats->cnt_total.num_packets_rx += stats->cnt_current.num_packets_rx;
memset(&stats->cnt_current, 0, sizeof(stats->cnt_current));
}
}
/*---------------------------------------------------------------------------*/
#endif /* LINK_STATS_PACKET_COUNTERS */
/*---------------------------------------------------------------------------*/
/* Periodic timer called at a period of FRESHNESS_HALF_LIFE */
static void
periodic(void *ptr)
@ -231,6 +274,10 @@ periodic(void *ptr)
for(stats = nbr_table_head(link_stats); stats != NULL; stats = nbr_table_next(link_stats, stats)) {
stats->freshness >>= 1;
}
#if LINK_STATS_PACKET_COUNTERS
print_and_update_counters();
#endif
}
/*---------------------------------------------------------------------------*/
/* Resets link-stats module */

View File

@ -56,6 +56,25 @@
#define LINK_STATS_ETX_FROM_PACKET_COUNT 0
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */
/* Store and periodically print packet counters? */
#ifdef LINK_STATS_CONF_PACKET_COUNTERS
#define LINK_STATS_PACKET_COUNTERS LINK_STATS_CONF_PACKET_COUNTERS
#else /* LINK_STATS_CONF_PACKET_COUNTERS */
#define LINK_STATS_PACKET_COUNTERS 0
#endif /* LINK_STATS_PACKET_COUNTERS */
typedef uint16_t link_packet_stat_t;
struct link_packet_counter {
/* total attempts to transmit unicast packets */
link_packet_stat_t num_packets_tx;
/* total ACKs for unicast packets */
link_packet_stat_t num_packets_acked;
/* total number of unicast and broadcast packets received */
link_packet_stat_t num_packets_rx;
};
/* All statistics of a given link */
struct link_stats {
clock_time_t last_tx_time; /* Last Tx timestamp */
@ -66,10 +85,17 @@ struct link_stats {
uint8_t tx_count; /* Tx count, used for ETX calculation */
uint8_t ack_count; /* ACK count, used for ETX calculation */
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */
#if LINK_STATS_PACKET_COUNTERS
struct link_packet_counter cnt_current; /* packets in the current period */
struct link_packet_counter cnt_total; /* packets in total */
#endif
};
/* Returns the neighbor's link statistics */
const struct link_stats *link_stats_from_lladdr(const linkaddr_t *lladdr);
/* Returns the address of the neighbor */
const linkaddr_t *link_stats_get_lladdr(const struct link_stats *);
/* Are the statistics fresh? */
int link_stats_is_fresh(const struct link_stats *stats);
/* Resets link-stats module */

View File

@ -50,11 +50,6 @@
#include "lib/list.h"
#include "lib/memb.h"
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
#endif /* CONTIKI_TARGET_COOJA */
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "CSMA"
@ -201,17 +196,10 @@ send_one_packet(void *ptr)
if(is_broadcast) {
ret = MAC_TX_OK;
} else {
rtimer_clock_t wt;
/* Check for ack */
wt = RTIMER_NOW();
watchdog_periodic();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_ACK_WAIT_TIME)) {
#if CONTIKI_TARGET_COOJA
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA */
}
/* Wait for max CSMA_ACK_WAIT_TIME */
RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_ACK_WAIT_TIME);
ret = MAC_TX_NOACK;
if(NETSTACK_RADIO.receiving_packet() ||
@ -220,17 +208,8 @@ send_one_packet(void *ptr)
int len;
uint8_t ackbuf[CSMA_ACK_LEN];
if(CSMA_AFTER_ACK_DETECTED_WAIT_TIME > 0) {
wt = RTIMER_NOW();
watchdog_periodic();
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) {
#if CONTIKI_TARGET_COOJA
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA */
}
}
/* Wait an additional CSMA_AFTER_ACK_DETECTED_WAIT_TIME to complete reception */
RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_AFTER_ACK_DETECTED_WAIT_TIME);
if(NETSTACK_RADIO.pending_packet()) {
len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);

View File

@ -151,7 +151,7 @@
#ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
#define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
#else
#define TSCH_HOPPING_SEQUENCE_MAX_LEN 16
#define TSCH_HOPPING_SEQUENCE_MAX_LEN sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)
#endif
/******** Configuration: association *******/
@ -365,18 +365,21 @@
/******** Configuration: CSMA *******/
/* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */
/* Min backoff exponent */
#ifdef TSCH_CONF_MAC_MIN_BE
#define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE
#else
#define TSCH_MAC_MIN_BE 1
#endif
/* Max backoff exponent */
#ifdef TSCH_CONF_MAC_MAX_BE
#define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE
#else
#define TSCH_MAC_MAX_BE 5
#endif
/* Max number of re-transmissions */
#ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES
#define TSCH_MAC_MAX_FRAME_RETRIES TSCH_CONF_MAC_MAX_FRAME_RETRIES
@ -391,6 +394,13 @@
#define TSCH_PACKET_EACK_WITH_SRC_ADDR 0
#endif
/* Perform CCA before sending? */
#ifdef TSCH_CONF_CCA_ENABLED
#define TSCH_CCA_ENABLED TSCH_CONF_CCA_ENABLED
#else
#define TSCH_CCA_ENABLED 0
#endif
/* Include destination address in ACK? */
#ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
#define TSCH_PACKET_EACK_WITH_DEST_ADDR TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
@ -415,12 +425,12 @@ by default, useful in case of duplicate seqno */
#define TSCH_RADIO_ON_DURING_TIMESLOT 0
#endif
/* Timeslot timing */
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 10000
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */
/* TSCH timeslot timing template */
#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#define TSCH_DEFAULT_TIMESLOT_TIMING TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#else
#define TSCH_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_10000
#endif
/* Configurable Rx guard time is micro-seconds */
#ifndef TSCH_CONF_RX_WAIT

View File

@ -75,87 +75,16 @@
#define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32)
/* The approximate number of slots per second */
#define TSCH_SLOTS_PER_SECOND (1000000 / TSCH_DEFAULT_TS_TIMESLOT_LENGTH)
#define TSCH_SLOTS_PER_SECOND (1000000 / tsch_timing_us[tsch_ts_timeslot_length])
/* Calculate packet tx/rx duration in rtimer ticks based on sent
* packet len in bytes with 802.15.4 250kbps data rate.
* One byte = 32us. Add two bytes for CRC and one for len field */
#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(32 * ((len) + 3))
#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * ((len) + RADIO_PHY_OVERHEAD))
/* Convert rtimer ticks to clock and vice versa */
#define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND)
#define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length)
/* The default timeslot timing in the standard is a guard time of
* 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us.
* As a result, the listening device has a guard time not centered
* on the expected Tx time. This is to be fixed in the next iteration
* of the standard. This can be enabled with:
* #define TSCH_DEFAULT_TS_TX_OFFSET 2120
* #define TSCH_DEFAULT_TS_RX_OFFSET 1120
* #define TSCH_DEFAULT_TS_RX_WAIT 2200
*
* Instead, we align the Rx guard time on expected Tx time. The Rx
* guard time is user-configurable with TSCH_CONF_RX_WAIT.
* (TS_TX_OFFSET - (TS_RX_WAIT / 2)) instead */
#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 10000
/* Default timeslot timing as per IEEE 802.15.4e */
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
#define TSCH_DEFAULT_TS_CCA 128
#define TSCH_DEFAULT_TS_TX_OFFSET 2120
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 800
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 1000
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
#define TSCH_DEFAULT_TS_ACK_WAIT 400
#define TSCH_DEFAULT_TS_RX_TX 192
#define TSCH_DEFAULT_TS_MAX_ACK 2400
#define TSCH_DEFAULT_TS_MAX_TX 4256
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 10000
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 15000
/* Default timeslot timing for platforms requiring 15ms slots */
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
#define TSCH_DEFAULT_TS_CCA 128
#define TSCH_DEFAULT_TS_TX_OFFSET 4000
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 3600
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 4000
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
#define TSCH_DEFAULT_TS_ACK_WAIT 800
#define TSCH_DEFAULT_TS_RX_TX 2072
#define TSCH_DEFAULT_TS_MAX_ACK 2400
#define TSCH_DEFAULT_TS_MAX_TX 4256
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 15000
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 65000U
/* 65ms timeslot, i.e. nearly the max length allowed by standard (16-bit unsigned in micro-seconds).
* Useful for running link-layer security on sky in Cooja, where only S/W security is supported.
* Note: this slot timing would require a total of 120ms. If a slot overlaps with the next active slot,
* the latter will be skipped.
* This configuration is mostly a work-around to test link-layer security in Cooja, it is recommended
* to use it with a 6TiSCH minimal schedule of length >= 2. */
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
#define TSCH_DEFAULT_TS_CCA 128
#define TSCH_DEFAULT_TS_TX_OFFSET 52000
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 58600
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 59000
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
#define TSCH_DEFAULT_TS_ACK_WAIT 800
#define TSCH_DEFAULT_TS_RX_TX 2072
#define TSCH_DEFAULT_TS_MAX_ACK 2400
#define TSCH_DEFAULT_TS_MAX_TX 4256
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 65000
#else
#error "TSCH: Unsupported default timeslot length"
#endif
#endif /* __TSCH_CONST_H__ */
/** @} */

View File

@ -173,6 +173,8 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr)
old_time_src->is_time_source = 0;
}
tsch_stats_reset_neighbor_stats();
#ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src);
#endif

View File

@ -52,10 +52,6 @@
#include "net/queuebuf.h"
#include "net/mac/framer/framer-802154.h"
#include "net/mac/tsch/tsch.h"
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
#endif /* CONTIKI_TARGET_COOJA */
#include "sys/log.h"
/* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH
@ -94,7 +90,7 @@
/* Truncate received drift correction information to maximum half
* of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */
#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(TSCH_DEFAULT_TS_RX_WAIT / 4))
#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(tsch_timing_us[tsch_ts_rx_wait] / 4))
/* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */
#if RTIMER_SECOND < (32 * 1024)
@ -206,10 +202,7 @@ tsch_get_lock(void)
busy_wait = 1;
busy_wait_time = RTIMER_NOW();
while(tsch_in_slot_operation) {
#if CONTIKI_TARGET_COOJA
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA */
watchdog_periodic();
}
busy_wait_time = RTIMER_NOW() - busy_wait_time;
}
@ -303,7 +296,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_
}
/* block until the time to schedule comes */
BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
return 0;
}
/*---------------------------------------------------------------------------*/
@ -314,7 +307,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_
do { \
if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
PT_YIELD(pt); \
BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
} \
} while(0);
/*---------------------------------------------------------------------------*/
@ -464,9 +457,9 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
/* Did we set the frame pending bit to request an extra burst link? */
static int burst_link_requested;
#if CCA_ENABLED
#if TSCH_CCA_ENABLED
static uint8_t cca_status;
#endif
#endif /* TSCH_CCA_ENABLED */
/* get payload */
packet = queuebuf_dataptr(current_packet->qb);
@ -507,22 +500,22 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */
static rtimer_clock_t tx_duration;
#if CCA_ENABLED
#if TSCH_CCA_ENABLED
cca_status = 1;
/* delay before CCA */
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca");
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_cca_offset], "cca");
TSCH_DEBUG_TX_EVENT();
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
/* CCA */
BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()),
current_slot_start, TS_CCA_OFFSET + TS_CCA);
RTIMER_BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()),
current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]);
TSCH_DEBUG_TX_EVENT();
/* there is not enough time to turn radio off */
/* NETSTACK_RADIO.off(); */
if(cca_status == 0) {
mac_tx_status = MAC_TX_COLLISION;
} else
#endif /* CCA_ENABLED */
#endif /* TSCH_CCA_ENABLED */
{
/* delay before TX */
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx");
@ -561,14 +554,14 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
TSCH_DEBUG_TX_EVENT();
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
/* Wait for ACK to come */
BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
RTIMER_BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait] + RADIO_DELAY_BEFORE_DETECT);
TSCH_DEBUG_TX_EVENT();
ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
/* Wait for ACK to finish */
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
ack_start_time, tsch_timing[tsch_ts_max_ack]);
TSCH_DEBUG_TX_EVENT();
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
@ -625,6 +618,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
"!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction);
);
}
tsch_stats_on_time_synchronization(eack_time_correction);
is_drift_correction_used = 1;
tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction);
/* Keep track of sync time */
@ -666,6 +660,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
ringbufindex_put(&dequeued_ringbuf);
}
/* If this is an unicast packet to timesource, update stats */
if(current_neighbor != NULL && current_neighbor->is_time_source) {
tsch_stats_tx_packet(current_neighbor, mac_tx_status, tsch_current_channel);
}
/* Log every tx attempt */
TSCH_LOG_ADD(tsch_log_tx,
log->tx.mac_tx_status = mac_tx_status;
@ -742,7 +741,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet();
if(!packet_seen) {
/* Check if receiving within guard time */
BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
RTIMER_BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT);
}
if(!packet_seen) {
@ -754,7 +753,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
/* Wait until packet is received, turn radio off */
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]);
TSCH_DEBUG_RX_EVENT();
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
@ -764,6 +763,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
static int header_len;
static frame802154_t frame;
radio_value_t radio_last_rssi;
radio_value_t radio_last_lqi;
/* Read packet */
current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN);
@ -782,6 +782,8 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
#endif
packet_duration = TSCH_PACKET_DURATION(current_input->len);
/* limit packet_duration to its max value */
packet_duration = MIN(packet_duration, tsch_timing[tsch_ts_max_tx]);
if(!frame_valid) {
TSCH_LOG_ADD(tsch_log_message,
@ -821,6 +823,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
int do_nack = 0;
rx_count++;
estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
tsch_stats_on_time_synchronization(estimated_drift);
#if TSCH_TIMESYNC_REMOVE_JITTER
/* remove jitter due to measurement errors */
@ -889,6 +892,12 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
/* Add current input to ringbuf */
ringbufindex_put(&input_ringbuf);
/* If the neighbor is known, update its stats */
if(n != NULL) {
NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_LINK_QUALITY, &radio_last_lqi);
tsch_stats_rx_packet(n, current_input->rssi, radio_last_lqi, tsch_current_channel);
}
/* Log every reception */
TSCH_LOG_ADD(tsch_log_rx,
linkaddr_copy(&log->rx.src, (linkaddr_t *)&frame.src_addr);
@ -951,6 +960,8 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr))
int is_active_slot;
TSCH_DEBUG_SLOT_START();
tsch_in_slot_operation = 1;
/* Measure on-air noise level while TSCH is idle */
tsch_stats_sample_rssi();
/* Reset drift correction */
drift_correction = 0;
is_drift_correction_used = 0;

View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2016-2017, University of Bristol - http://www.bristol.ac.uk
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Source file for TSCH statistics
* \author
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#include "contiki.h"
#include "net/mac/tsch/tsch.h"
#include "net/netstack.h"
#include "dev/radio.h"
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "TSCH Stats"
#define LOG_LEVEL LOG_LEVEL_MAC
/*---------------------------------------------------------------------------*/
#if TSCH_STATS_ON
/*---------------------------------------------------------------------------*/
struct tsch_global_stats tsch_stats;
struct tsch_neighbor_stats tsch_neighbor_stats;
/* Called every TSCH_STATS_DECAY_INTERVAL ticks */
static struct ctimer periodic_timer;
static void periodic(void *);
/*---------------------------------------------------------------------------*/
void
tsch_stats_init(void)
{
#if TSCH_STATS_SAMPLE_NOISE_RSSI
int i;
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
tsch_stats.noise_rssi[i] = TSCH_STATS_DEFAULT_RSSI;
tsch_stats.channel_free_ewma[i] = TSCH_STATS_DEFAULT_CHANNEL_FREE;
}
#endif
tsch_stats_reset_neighbor_stats();
/* Start the periodic processing soonish */
ctimer_set(&periodic_timer, TSCH_STATS_DECAY_INTERVAL / 10, periodic, NULL);
}
/*---------------------------------------------------------------------------*/
void
tsch_stats_reset_neighbor_stats(void)
{
int i;
struct tsch_channel_stats *ch_stats;
ch_stats = tsch_neighbor_stats.channel_stats;
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
ch_stats[i].rssi = TSCH_STATS_DEFAULT_RSSI;
ch_stats[i].lqi = TSCH_STATS_DEFAULT_LQI;
ch_stats[i].p_tx_success = TSCH_STATS_DEFAULT_P_TX;
}
}
/*---------------------------------------------------------------------------*/
struct tsch_neighbor_stats *
tsch_stats_get_from_neighbor(struct tsch_neighbor *n)
{
/* Due to RAM limitations, this module only collects neighbor stats about the time source */
if(n != NULL && n->is_time_source) {
return &tsch_neighbor_stats;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void
tsch_stats_tx_packet(struct tsch_neighbor *n, uint8_t mac_status, uint8_t channel)
{
struct tsch_neighbor_stats *stats;
stats = tsch_stats_get_from_neighbor(n);
if(stats != NULL) {
uint8_t index = tsch_stats_channel_to_index(channel);
uint16_t new_tx_value = (mac_status == MAC_TX_OK ? 1 : 0);
new_tx_value *= TSCH_STATS_BINARY_SCALING_FACTOR;
TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].p_tx_success, new_tx_value);
}
}
/*---------------------------------------------------------------------------*/
void
tsch_stats_rx_packet(struct tsch_neighbor *n, int8_t rssi, uint8_t lqi, uint8_t channel)
{
struct tsch_neighbor_stats *stats;
stats = tsch_stats_get_from_neighbor(n);
if(stats != NULL) {
uint8_t index = tsch_stats_channel_to_index(channel);
TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].rssi,
TSCH_STATS_TRANSFORM(rssi, TSCH_STATS_RSSI_SCALING_FACTOR));
TSCH_STATS_EWMA_UPDATE(stats->channel_stats[index].lqi,
TSCH_STATS_TRANSFORM(lqi, TSCH_STATS_LQI_SCALING_FACTOR));
}
}
/*---------------------------------------------------------------------------*/
void
tsch_stats_on_time_synchronization(int32_t sync_error)
{
/* Update the maximal error so far if the absolute value of the new one is larger */
tsch_stats.max_sync_error = MAX(tsch_stats.max_sync_error, ABS(sync_error));
}
/*---------------------------------------------------------------------------*/
void
tsch_stats_sample_rssi(void)
{
#if TSCH_STATS_SAMPLE_NOISE_RSSI
uint8_t index;
radio_value_t value;
radio_result_t rv;
static uint8_t measurement_channel = TSCH_STATS_FIRST_CHANNEL;
index = tsch_stats_channel_to_index(measurement_channel);
/* Select the measurement channel */
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, measurement_channel);
/* Need to explicitly turn on for Coojamotes */
NETSTACK_RADIO.on();
/* Measure the background noise RSSI and act on it */
rv = NETSTACK_RADIO.get_value(RADIO_PARAM_RSSI, &value);
if(rv == RADIO_RESULT_OK) {
tsch_stat_t prev_busyness_metric;
uint16_t is_free;
is_free = (((int)value <= TSCH_STATS_BUSY_CHANNEL_RSSI) ? 1 : 0) * TSCH_STATS_BINARY_SCALING_FACTOR;
/* LOG_DBG("noise RSSI on %u: %d\n", measurement_channel, (int)value); */
TSCH_STATS_EWMA_UPDATE(tsch_stats.noise_rssi[index],
TSCH_STATS_TRANSFORM((int)value, TSCH_STATS_RSSI_SCALING_FACTOR));
prev_busyness_metric = tsch_stats.channel_free_ewma[index];
(void)prev_busyness_metric;
TSCH_STATS_EWMA_UPDATE(tsch_stats.channel_free_ewma[index], is_free);
/* potentially select a new TSCH hopping sequence */
#ifdef TSCH_CALLBACK_CHANNEL_STATS_UPDATED
TSCH_CALLBACK_CHANNEL_STATS_UPDATED(measurement_channel, prev_busyness_metric);
#endif
} else {
LOG_ERR("! sampling RSSI failed: %d\n", (int)rv);
}
/* Increment the channel index for the next time */
measurement_channel++;
if(measurement_channel >= TSCH_STATS_FIRST_CHANNEL + TSCH_STATS_NUM_CHANNELS) {
measurement_channel = TSCH_STATS_FIRST_CHANNEL;
}
#endif /* TSCH_STATS_SAMPLE_NOISE_RSSI */
}
/*---------------------------------------------------------------------------*/
/* Periodic timer called every TSCH_STATS_DECAY_INTERVAL ticks */
static void
periodic(void *ptr)
{
int i;
struct tsch_neighbor *timesource;
struct tsch_channel_stats *stats = tsch_neighbor_stats.channel_stats;
#if TSCH_STATS_SAMPLE_NOISE_RSSI
LOG_DBG("Noise RSSI:\n");
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
LOG_DBG(" channel %u: %d rssi, %u/%u free\n",
TSCH_STATS_FIRST_CHANNEL + i,
tsch_stats.noise_rssi[i] / TSCH_STATS_RSSI_SCALING_FACTOR,
tsch_stats.channel_free_ewma[i],
TSCH_STATS_BINARY_SCALING_FACTOR);
}
#endif
timesource = tsch_queue_get_time_source();
if(timesource != NULL) {
LOG_DBG("Time source neighbor:\n");
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
LOG_DBG(" channel %u: %d rssi, %u lqi, %u/%u P(tx)\n",
TSCH_STATS_FIRST_CHANNEL + i,
stats[i].rssi / TSCH_STATS_RSSI_SCALING_FACTOR,
stats[i].lqi / TSCH_STATS_LQI_SCALING_FACTOR,
stats[i].p_tx_success,
TSCH_STATS_BINARY_SCALING_FACTOR);
}
}
/* Do not decay the periodic global stats, as they are updated independely of packet rate */
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
/* decay Rx stats */
TSCH_STATS_EWMA_UPDATE(stats[i].rssi, TSCH_STATS_DEFAULT_RSSI);
TSCH_STATS_EWMA_UPDATE(stats[i].lqi, TSCH_STATS_DEFAULT_LQI);
/* decay Tx stats */
TSCH_STATS_EWMA_UPDATE(stats[i].p_tx_success, TSCH_STATS_DEFAULT_P_TX);
}
ctimer_set(&periodic_timer, TSCH_STATS_DECAY_INTERVAL, periodic, NULL);
}
/*---------------------------------------------------------------------------*/
#endif /* TSCH_STATS_ON */
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,223 @@
/*
* Copyright (c) 2016-2017, University of Bristol - http://www.bristol.ac.uk
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Header file for TSCH statistics
* \author
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
/**
* \addtogroup tsch
* @{
*/
#ifndef __TSCH_STATS_H__
#define __TSCH_STATS_H__
/********** Includes **********/
#include "contiki.h"
#include "net/linkaddr.h"
#include "net/mac/tsch/tsch-conf.h"
#include "net/mac/tsch/tsch-queue.h"
/************ Constants ***********/
/* Enable the collection of TSCH statistics? */
#ifdef TSCH_STATS_CONF_ON
#define TSCH_STATS_ON TSCH_STATS_CONF_ON
#else
#define TSCH_STATS_ON 0
#endif
/* Enable the collection background noise RSSI? */
#ifdef TSCH_STATS_CONF_SAMPLE_NOISE_RSSI
#define TSCH_STATS_SAMPLE_NOISE_RSSI TSCH_STATS_CONF_SAMPLE_NOISE_RSSI
#else
#define TSCH_STATS_SAMPLE_NOISE_RSSI 0
#endif
/*
* How to update a TSCH statistic.
* Uses a hardcoded EWMA alpha value equal to 0.125 by default.
*/
#ifdef TSCH_STATS_CONF_EWMA_UPDATE
#define TSCH_STATS_EWMA_UPDATE TSCH_STATS_CONF_EWMA_UPDATE
#else
#define TSCH_STATS_EWMA_UPDATE(x, v) (x) = (((x) * 7 / 8) + (v) / 8)
#endif
/*
* A channel is considered busy if at the sampling instant
* it has RSSI higher or equal to this limit.
*/
#ifdef TSCH_STATS_CONF_BUSY_CHANNEL_RSSI
#define TSCH_STATS_BUSY_CHANNEL_RSSI TSCH_STATS_CONF_BUSY_CHANNEL_RSSI
#else
#define TSCH_STATS_BUSY_CHANNEL_RSSI -85
#endif
/* The period after which stat values are decayed towards the default values */
#ifdef TSCH_STATS_CONF_DECAY_INTERVAL
#define TSCH_STATS_DECAY_INTERVAL TSCH_STATS_CONF_DECAY_INTERVAL
#else
#define TSCH_STATS_DECAY_INTERVAL (20ul * 60 * CLOCK_SECOND)
#endif
/*
* The total number of MAC-layer channels.
* Sixteen for the IEEE802.15.4 2.4 GHz band.
*/
#ifdef TSCH_STATS_CONF_NUM_CHANNELS
#define TSCH_STATS_NUM_CHANNELS TSCH_STATS_CONF_NUM_CHANNELS
#else
#define TSCH_STATS_NUM_CHANNELS 16
#endif
/* The number of the first MAC-layer channel. */
#ifdef TSCH_STATS_CONF_FIRST_CHANNEL
#define TSCH_STATS_FIRST_CHANNEL TSCH_STATS_CONF_FIRST_CHANNEL
#else
#define TSCH_STATS_FIRST_CHANNEL 11
#endif
/* Internal: the scaling of the various stats */
#define TSCH_STATS_RSSI_SCALING_FACTOR -16
#define TSCH_STATS_LQI_SCALING_FACTOR 16
#define TSCH_STATS_BINARY_SCALING_FACTOR 4096
/*
* Transform a statistic from external form to the internal representation.
* To transform back, simply divide by the factor.
*/
#define TSCH_STATS_TRANSFORM(x, factor) ((int16_t)(x) * factor)
/* The default value for RSSI statistics: -90 dBm */
#define TSCH_STATS_DEFAULT_RSSI TSCH_STATS_TRANSFORM(-90, TSCH_STATS_RSSI_SCALING_FACTOR)
/* The default value for LQI statistics: 100 */
#define TSCH_STATS_DEFAULT_LQI TSCH_STATS_TRANSFORM(100, TSCH_STATS_LQI_SCALING_FACTOR)
/* The default value for P_tx (packet transmission probability) statistics: 50% */
#define TSCH_STATS_DEFAULT_P_TX (TSCH_STATS_BINARY_SCALING_FACTOR / 2)
/* The default value for channel free status: 100% */
#define TSCH_STATS_DEFAULT_CHANNEL_FREE TSCH_STATS_BINARY_SCALING_FACTOR
/* #define these callbacks to do the adaptive channel selection based on RSSI */
/* TSCH_CALLBACK_CHANNEL_STATS_UPDATED(channel, previous_metric); */
/* TSCH_CALLBACK_SELECT_CHANNELS(); */
/************ Types ***********/
typedef uint16_t tsch_stat_t;
struct tsch_global_stats {
/* the maximum synchronization error */
uint32_t max_sync_error;
/* number of disassociations */
uint16_t num_disassociations;
#if TSCH_STATS_SAMPLE_NOISE_RSSI
/* per-channel noise estimates */
tsch_stat_t noise_rssi[TSCH_STATS_NUM_CHANNELS];
/* derived from `noise_rssi` and BUSY_CHANNEL_RSSI */
tsch_stat_t channel_free_ewma[TSCH_STATS_NUM_CHANNELS];
#endif /* TSCH_STATS_SAMPLE_NOISE_RSSI */
};
struct tsch_channel_stats {
/* EWMA, from receptions */
tsch_stat_t rssi;
/* EWMA, from receptions */
tsch_stat_t lqi;
/* EWMA of probability, for unicast transmissions only */
tsch_stat_t p_tx_success;
};
struct tsch_neighbor_stats {
struct tsch_channel_stats channel_stats[TSCH_STATS_NUM_CHANNELS];
};
struct tsch_neighbor; /* Forward declaration */
/************ External variables ***********/
#if TSCH_STATS_ON
/* Statistics for the local node */
extern struct tsch_global_stats tsch_stats;
/* For the timesource neighbor */
extern struct tsch_neighbor_stats tsch_neighbor_stats;
/************ Functions ***********/
void tsch_stats_init(void);
void tsch_stats_tx_packet(struct tsch_neighbor *, uint8_t mac_status, uint8_t channel);
void tsch_stats_rx_packet(struct tsch_neighbor *, int8_t rssi, uint8_t lqi, uint8_t channel);
void tsch_stats_on_time_synchronization(int32_t sync_error);
void tsch_stats_sample_rssi(void);
struct tsch_neighbor_stats *tsch_stats_get_from_neighbor(struct tsch_neighbor *);
void tsch_stats_reset_neighbor_stats(void);
#else /* TSCH_STATS_ON */
#define tsch_stats_init()
#define tsch_stats_tx_packet(n, mac_status, channel)
#define tsch_stats_rx_packet(n, rssi, lqi, channel)
#define tsch_stats_on_time_synchronization(sync_error)
#define tsch_stats_sample_rssi()
#define tsch_stats_get_from_neighbor(neighbor) NULL
#define tsch_stats_reset_neighbor_stats()
#endif /* TSCH_STATS_ON */
static inline uint8_t
tsch_stats_channel_to_index(uint8_t channel)
{
return channel - TSCH_STATS_FIRST_CHANNEL;
}
static inline uint8_t
tsch_stats_index_to_channel(uint8_t channel_index)
{
return channel_index + TSCH_STATS_FIRST_CHANNEL;
}
#endif /* __TSCH_STATS_H__ */
/** @} */

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2018, RISE SICS.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* IEEE 802.15.4 TSCH timeslot timings
* \author
* Simon Duquennoy <simon.duquennoy@ri.se>
*
*/
/**
* \addtogroup tsch
* @{
*/
#include "contiki.h"
#include "net/mac/tsch/tsch.h"
/**
* \brief The default timeslot timing in the standard is a guard time of
* 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us.
* As a result, the listening device has a guard time not centered
* on the expected Tx time. This is to be fixed in the next iteration
* of the standard. This can be enabled with:
* TxOffset: 2120
* RxOffset: 1120
* RxWait: 2200
*
* Instead, we align the Rx guard time on expected Tx time. The Rx
* guard time is user-configurable with TSCH_CONF_RX_WAIT.
* (TxOffset - (RxWait / 2)) instead
*/
const uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count] = {
1800, /* CCAOffset */
128, /* CCA */
2120, /* TxOffset */
(2120 - (TSCH_CONF_RX_WAIT / 2)), /* RxOffset */
800, /* RxAckDelay */
1000, /* TxAckDelay */
TSCH_CONF_RX_WAIT, /* RxWait */
400, /* AckWait */
192, /* RxTx */
2400, /* MaxAck */
4256, /* MaxTx */
10000, /* TimeslotLength */
};
/** @} */

View File

@ -102,20 +102,9 @@ uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
struct tsch_asn_divisor_t tsch_hopping_sequence_length;
/* Default TSCH timeslot timing (in micro-second) */
static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = {
TSCH_DEFAULT_TS_CCA_OFFSET,
TSCH_DEFAULT_TS_CCA,
TSCH_DEFAULT_TS_TX_OFFSET,
TSCH_DEFAULT_TS_RX_OFFSET,
TSCH_DEFAULT_TS_RX_ACK_DELAY,
TSCH_DEFAULT_TS_TX_ACK_DELAY,
TSCH_DEFAULT_TS_RX_WAIT,
TSCH_DEFAULT_TS_ACK_WAIT,
TSCH_DEFAULT_TS_RX_TX,
TSCH_DEFAULT_TS_MAX_ACK,
TSCH_DEFAULT_TS_MAX_TX,
TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
};
static const uint16_t *tsch_default_timing_us;
/* TSCH timeslot timing (in micro-second) */
uint16_t tsch_timing_us[tsch_ts_elements_count];
/* TSCH timeslot timing (in rtimer ticks) */
rtimer_clock_t tsch_timing[tsch_ts_elements_count];
@ -231,8 +220,10 @@ tsch_reset(void)
TSCH_ASN_INIT(tsch_current_asn, 0, 0);
current_link = NULL;
/* Reset timeslot timing to defaults */
tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING;
for(i = 0; i < tsch_ts_elements_count; i++) {
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
tsch_timing_us[i] = tsch_default_timing_us[i];
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
}
#ifdef TSCH_CALLBACK_LEAVING_NETWORK
TSCH_CALLBACK_LEAVING_NETWORK();
@ -412,6 +403,22 @@ eb_input(struct input_packet *current_input)
}
#endif /* TSCH_AUTOSELECT_TIME_SOURCE */
}
/* TSCH hopping sequence */
if(eb_ies.ie_channel_hopping_sequence_id != 0) {
if(eb_ies.ie_hopping_sequence_len != tsch_hopping_sequence_length.val
|| memcmp((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, tsch_hopping_sequence_length.val)) {
if(eb_ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
memcpy((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list,
eb_ies.ie_hopping_sequence_len);
TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, eb_ies.ie_hopping_sequence_len);
LOG_WARN("Updating TSCH hopping sequence from EB\n");
} else {
LOG_WARN("TSCH:! parse_eb: hopping sequence too long (%u)\n", eb_ies.ie_hopping_sequence_len);
}
}
}
}
}
}
@ -565,10 +572,11 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
/* TSCH timeslot timing */
for(i = 0; i < tsch_ts_elements_count; i++) {
if(ies.ie_tsch_timeslot_id == 0) {
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
tsch_timing_us[i] = tsch_default_timing_us[i];
} else {
tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]);
tsch_timing_us[i] = ies.ie_tsch_timeslot[i];
}
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
}
/* TSCH hopping sequence */
@ -714,11 +722,11 @@ PT_THREAD(tsch_scan(struct pt *pt))
/* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
if(current_channel != scan_channel) {
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
current_channel = scan_channel;
LOG_INFO("scanning on channel %u\n", scan_channel);
}
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
current_channel = scan_channel;
LOG_INFO("scanning on channel %u\n", scan_channel);
current_channel_since = now_time;
}
@ -729,20 +737,30 @@ PT_THREAD(tsch_scan(struct pt *pt))
if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
/* If we are currently receiving a packet, wait until end of reception */
t0 = RTIMER_NOW();
BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
}
if(is_packet_pending) {
rtimer_clock_t t1;
/* Read packet */
input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
/* Save packet timestamp */
NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
t1 = RTIMER_NOW();
/* Parse EB and attempt to associate */
LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
tsch_associate(&input_eb, t0);
/* Sanity-check the timestamp */
if(ABS(RTIMER_CLOCK_DIFF(t0, t1)) < tsch_timing[tsch_ts_timeslot_length]) {
tsch_associate(&input_eb, t0);
} else {
LOG_WARN("scan: dropping packet, timestamp too far from current time %u %u\n",
(unsigned)t0,
(unsigned)t1
);
}
}
if(tsch_is_associated) {
@ -864,6 +882,9 @@ PROCESS_THREAD(tsch_pending_events_process, ev, data)
tsch_rx_process_pending();
tsch_tx_process_pending();
tsch_log_process_pending();
#ifdef TSCH_CALLBACK_SELECT_CHANNELS
TSCH_CALLBACK_SELECT_CHANNELS();
#endif
}
PROCESS_END();
}
@ -878,6 +899,12 @@ tsch_init(void)
radio_value_t radio_tx_mode;
rtimer_clock_t t;
/* Check that the platform provides a TSCH timeslot timing template */
if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) {
LOG_ERR("! platform does not provide a timeslot timing template.\n");
return;
}
/* Radio Rx mode */
if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) {
LOG_ERR("! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
@ -918,6 +945,7 @@ tsch_init(void)
/* Check max hopping sequence length vs default sequence length */
if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
return;
}
/* Init the queuebuf and TSCH sub-modules */
@ -944,6 +972,8 @@ tsch_init(void)
#if TSCH_WITH_SIXTOP
sixtop_init();
#endif
tsch_stats_init();
}
/*---------------------------------------------------------------------------*/
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */

View File

@ -60,28 +60,16 @@ frequency hopping for enhanced reliability.
#include "net/mac/tsch/tsch-packet.h"
#include "net/mac/tsch/tsch-security.h"
#include "net/mac/tsch/tsch-schedule.h"
#include "net/mac/tsch/tsch-stats.h"
#if UIP_CONF_IPV6_RPL
#include "net/mac/tsch/tsch-rpl.h"
#endif /* UIP_CONF_IPV6_RPL */
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
#endif /* CONTIKI_TARGET_COOJA */
/*********** Macros *********/
/* Wait for a condition with timeout t0+offset. */
#if CONTIKI_TARGET_COOJA
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) { \
simProcessRunValue = 1; \
cooja_mt_yield(); \
};
#else
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ;
#endif /* CONTIKI_TARGET_COOJA */
/* Include Arch-Specific conf */
#ifdef TSCH_CONF_ARCH_HDR_PATH
#include TSCH_CONF_ARCH_HDR_PATH
#endif /* TSCH_CONF_ARCH_HDR_PATH */
/*********** Callbacks *********/
@ -169,6 +157,8 @@ extern uint8_t tsch_current_channel;
/* TSCH channel hopping sequence */
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
extern struct tsch_asn_divisor_t tsch_hopping_sequence_length;
/* TSCH timeslot timing (in micro-second) */
uint16_t tsch_timing_us[tsch_ts_elements_count];
/* TSCH timeslot timing (in rtimer ticks) */
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
/* Statistics on the current session */
@ -177,6 +167,8 @@ extern unsigned long rx_count;
extern unsigned long sync_count;
extern int32_t min_drift_seen;
extern int32_t max_drift_seen;
/* The TSCH standard 10ms timeslot timing */
extern const uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count];
/* TSCH processes */
PROCESS_NAME(tsch_process);

View File

@ -272,7 +272,7 @@
#ifdef RPL_CONF_DAG_LIFETIME
#define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME
#else
#define RPL_DAG_LIFETIME (60 * 60) /* one hour */
#define RPL_DAG_LIFETIME (8 * 60) /* 8 hours */
#endif /* RPL_CONF_DAG_LIFETIME */
/*

View File

@ -0,0 +1 @@
CFLAGS += -DBUILD_WITH_TSCH_CS=1

View File

@ -0,0 +1,328 @@
/*
* Copyright (c) 2016-2018, University of Bristol - http://www.bristol.ac.uk
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Source file for TSCH adaptive channel selection
* \author
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#include "tsch.h"
#include "tsch-stats.h"
#include "tsch-cs.h"
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "TSCH CS"
#define LOG_LEVEL LOG_LEVEL_MAC
/*---------------------------------------------------------------------------*/
/* Allow to change only 1 channel at once */
#define TSCH_CS_MAX_CHANNELS_CHANGED 1
/* Do not up change channels more frequently than this */
#define TSCH_CS_MIN_UPDATE_INTERVAL_SEC 60
/* Do not change channels if the difference in qualities is below this */
#define TSCH_CS_HYSTERESIS (TSCH_STATS_BINARY_SCALING_FACTOR / 10)
/* After removing a channel from the sequence, do not add it back at least this time */
#define TSCH_CS_BLACKLIST_DURATION_SEC (5 * 60)
/* A potential for change detected? */
static bool recaculation_requested;
/* Time (in seconds) when channels were marked as busy; 0 if they are not busy */
static uint32_t tsch_cs_busy_since[TSCH_STATS_NUM_CHANNELS];
/*
* The following variables are kept in order to avoid completely migrating away
* from the initial hopping sequence (as then new nodes would not be able to join).
* The invariant is: tsch_cs_initial_bitmap & tsch_cs_current_bitmap != 0
*/
/* The bitmap with the initial channels */
static tsch_cs_bitmap_t tsch_cs_initial_bitmap;
/* The bitmap with the current channels */
static tsch_cs_bitmap_t tsch_cs_current_bitmap;
/* structure for sorting */
struct tsch_cs_quality {
/* channel number */
uint8_t channel;
/* the higher, the better */
tsch_stat_t metric;
};
/*---------------------------------------------------------------------------*/
static inline bool
tsch_cs_bitmap_contains(tsch_cs_bitmap_t bitmap, uint8_t channel)
{
return (1 << (channel - TSCH_STATS_FIRST_CHANNEL)) & bitmap;
}
/*---------------------------------------------------------------------------*/
static inline tsch_cs_bitmap_t
tsch_cs_bitmap_set(tsch_cs_bitmap_t bitmap, uint8_t channel)
{
return (1 << (channel - TSCH_STATS_FIRST_CHANNEL)) | bitmap;
}
/*---------------------------------------------------------------------------*/
static tsch_cs_bitmap_t
tsch_cs_bitmap_calc(void)
{
tsch_cs_bitmap_t result = 0;
int i;
for(i = 0; i < tsch_hopping_sequence_length.val; ++i) {
result = tsch_cs_bitmap_set(result, tsch_hopping_sequence[i]);
}
return result;
}
/*---------------------------------------------------------------------------*/
void
tsch_cs_adaptations_init(void)
{
tsch_cs_initial_bitmap = tsch_cs_bitmap_calc();
tsch_cs_current_bitmap = tsch_cs_initial_bitmap;
}
/*---------------------------------------------------------------------------*/
/* Sort the elements to that the channels with the best metrics are in the front */
static void
tsch_cs_bubble_sort(struct tsch_cs_quality *qualities)
{
int i, j;
struct tsch_cs_quality tmp;
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
for(j = 0; j + 1 < TSCH_STATS_NUM_CHANNELS; ++j) {
if(qualities[j].metric < qualities[j+1].metric){
tmp = qualities[j];
qualities[j] = qualities[j+1];
qualities[j+1] = tmp;
}
}
}
}
/*---------------------------------------------------------------------------*/
/* Select a single, currently unused, good enough channel. Returns 0xff on failure. */
static uint8_t
tsch_cs_select_replacement(uint8_t old_channel, tsch_stat_t old_ewma,
struct tsch_cs_quality *qualities, uint8_t is_in_sequence[])
{
int i;
uint32_t now = clock_seconds();
tsch_cs_bitmap_t bitmap = tsch_cs_bitmap_set(0, old_channel);
/* Don't want to replace a channel if the improvement is miniscule (< 10%) */
old_ewma += TSCH_CS_HYSTERESIS;
/* iterate up to -1 because we know that at least one of the channels is bad */
for(i = 0; i < TSCH_STATS_NUM_CHANNELS - 1; ++i) {
/* select a replacement candidate */
uint8_t candidate = qualities[i].channel;
if(qualities[i].metric < TSCH_CS_FREE_THRESHOLD) {
/* This channel is not good enough.
* since we know that the other channels in the sorted list are even worse,
* it makes sense to return immediately rather than to continue t
*/
LOG_DBG("ch %u: busy\n", candidate);
return 0xff;
}
if(qualities[i].metric < old_ewma) {
/* not good enough to replace */
LOG_DBG("ch %u: hysteresis check failed\n", candidate);
return 0xff;
}
/* already in the current TSCH hopping sequence? */
if(is_in_sequence[candidate - TSCH_STATS_FIRST_CHANNEL] != 0xff) {
LOG_DBG("ch %u: in seq\n", candidate);
continue;
}
/* ignore this candidate if too recently blacklisted */
if(tsch_cs_busy_since[candidate - TSCH_STATS_FIRST_CHANNEL] != 0
&& tsch_cs_busy_since[candidate - TSCH_STATS_FIRST_CHANNEL] + TSCH_CS_BLACKLIST_DURATION_SEC > now) {
LOG_DBG("ch %u: recent bl\n", candidate);
continue;
}
/* check if removing the old channel would break our hopping sequence invariant */
if(bitmap == (tsch_cs_initial_bitmap & tsch_cs_current_bitmap)) {
/* the channel is the only one that belongs to both */
if(!tsch_cs_bitmap_contains(tsch_cs_initial_bitmap, candidate)) {
/* the candidate is not in the initial sequence; not acceptable */
continue;
}
}
return candidate;
}
return 0xff;
}
/*---------------------------------------------------------------------------*/
bool
tsch_cs_process(void)
{
int i;
bool try_replace;
bool has_replaced;
struct tsch_cs_quality qualities[TSCH_STATS_NUM_CHANNELS];
uint8_t is_channel_busy[TSCH_STATS_NUM_CHANNELS];
uint8_t is_in_sequence[TSCH_STATS_NUM_CHANNELS];
static uint32_t last_time_changed;
if(!recaculation_requested) {
/* nothing to do */
return false;
}
if(last_time_changed != 0 && last_time_changed + TSCH_CS_MIN_UPDATE_INTERVAL_SEC > clock_seconds()) {
/* too soon */
return false;
}
/* reset the flag */
recaculation_requested = false;
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
qualities[i].channel = i + TSCH_STATS_FIRST_CHANNEL;
qualities[i].metric = tsch_stats.channel_free_ewma[i];
}
/* bubble sort the channels */
tsch_cs_bubble_sort(qualities);
/* start with the threshold values */
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
is_channel_busy[i] = (tsch_stats.channel_free_ewma[i] < TSCH_CS_FREE_THRESHOLD);
}
memset(is_in_sequence, 0xff, sizeof(is_in_sequence));
for(i = 0; i < tsch_hopping_sequence_length.val; ++i) {
uint8_t channel = tsch_hopping_sequence[i];
is_in_sequence[channel - TSCH_STATS_FIRST_CHANNEL] = i;
}
/* mark the first N channels as "good" - there is nothing better to select */
for(i = 0; i < tsch_hopping_sequence_length.val; ++i) {
is_channel_busy[qualities[i].channel - TSCH_STATS_FIRST_CHANNEL] = 0;
}
for(i = 0; i < TSCH_STATS_NUM_CHANNELS; ++i) {
uint8_t ci = qualities[i].channel - TSCH_STATS_FIRST_CHANNEL;
(void)ci;
LOG_DBG("ch %u q %u busy %u in seq %u\n",
qualities[i].channel,
qualities[i].metric,
is_channel_busy[ci],
is_in_sequence[ci] == 0xff ? 0 : 1);
}
try_replace = false;
for(i = 0; i < tsch_hopping_sequence_length.val; ++i) {
uint8_t channel = tsch_hopping_sequence[i];
if(is_channel_busy[channel - TSCH_STATS_FIRST_CHANNEL]) {
try_replace = true;
}
}
if(!try_replace) {
LOG_DBG("cs: not replacing\n");
return false;
}
has_replaced = false;
for(i = TSCH_STATS_NUM_CHANNELS - 1; i >= tsch_hopping_sequence_length.val; --i) {
if(is_in_sequence[qualities[i].channel - TSCH_STATS_FIRST_CHANNEL] != 0xff) {
/* found the worst channel; it must be busy */
uint8_t channel = qualities[i].channel;
tsch_stat_t ewma_metric = qualities[i].metric;
uint8_t replacement = tsch_cs_select_replacement(channel, ewma_metric,
qualities, is_in_sequence);
uint8_t position = is_in_sequence[channel - TSCH_STATS_FIRST_CHANNEL];
if(replacement != 0xff) {
printf("\ncs: replacing channel %u %u (%u) with %u\n",
channel, tsch_hopping_sequence[position], position, replacement);
/* mark the old channel as busy */
tsch_cs_busy_since[channel - TSCH_STATS_FIRST_CHANNEL] = clock_seconds();
/* do the actual replacement in the global TSCH HS variable */
tsch_hopping_sequence[position] = replacement;
has_replaced = true;
/* recalculate the hopping sequence bitmap */
tsch_cs_current_bitmap = tsch_cs_bitmap_calc();
}
break; /* replace just one at once */
}
}
if(has_replaced) {
last_time_changed = clock_seconds();
return true;
}
LOG_DBG("cs: no changes\n");
return false;
}
/*---------------------------------------------------------------------------*/
void
tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric)
{
uint8_t index;
bool old_is_busy;
bool new_is_busy;
/* Enable this only on the coordinator node */
if(!tsch_is_coordinator) {
return;
}
/* Do not try to adapt before enough information has been learned */
if(clock_seconds() < TSCH_CS_LEARNING_PERIOD_SEC) {
return;
}
index = tsch_stats_channel_to_index(updated_channel);
old_is_busy = (old_busyness_metric < TSCH_CS_FREE_THRESHOLD);
new_is_busy = (tsch_stats.channel_free_ewma[index] < TSCH_CS_FREE_THRESHOLD);
if(old_is_busy != new_is_busy) {
/* the status of the channel has changed*/
recaculation_requested = true;
} else if(new_is_busy) {
/* run the reselection algorithm iff the channel is both (1) bad and (2) in use */
if(tsch_cs_bitmap_contains(tsch_cs_current_bitmap, updated_channel)) {
/* the channel is in use and is busy */
recaculation_requested = true;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016-2018, University of Bristol - http://www.bristol.ac.uk
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Header file for TSCH adaptive channel selection
* \author
* Atis Elsts <atis.elsts@bristol.ac.uk>
*/
#ifndef __TSCH_CS_H__
#define __TSCH_CS_H__
#include "contiki.h"
#include <stdbool.h>
/* If `channel_free_ewma` value is less than this, the channel is considered busy */
#ifdef TSCH_CS_CONF_FREE_THRESHOLD
#define TSCH_CS_FREE_THRESHOLD TSCH_CS_CONF_FREE_THRESHOLD
#else
/* < 85% free */
#define TSCH_CS_FREE_THRESHOLD ((tsch_stat_t)(85ul * TSCH_STATS_BINARY_SCALING_FACTOR / 100))
#endif
#define TSCH_CS_LEARNING_PERIOD_SEC 30
/**
* \brief Initializes the TSCH hopping sequence selection module.
*/
void tsch_cs_adaptations_init(void);
/**
* \brief Signal the need to potentially update the TSCH hopping sequence.
* \param updated_channel The channel with the updated RSSI measurement
* \param old_busyness_metric The EWMA value of the "channel busy" status before the last RSSI measurement
*/
void tsch_cs_channel_stats_updated(uint8_t updated_channel, uint16_t old_busyness_metric);
/**
* \brief Potentially update the TSCH hopping sequence
* \return true if the hopping sequence was updated, false otherwise
*/
bool tsch_cs_process(void);
/* A bit corresponds to a channel; `uint16_t` value is OK for up to 16 channels. */
typedef uint16_t tsch_cs_bitmap_t;
#endif /* __TSCH_CS_H__ */

View File

@ -54,6 +54,8 @@
#define RTIMER_H_
#include "contiki.h"
#include "dev/watchdog.h"
#include <stdbool.h>
/** \brief The rtimer size (in bytes) */
#ifdef RTIMER_CONF_CLOCK_SIZE
@ -186,6 +188,26 @@ void rtimer_arch_schedule(rtimer_clock_t t);
#define RTIMER_GUARD_TIME (RTIMER_ARCH_SECOND >> 14)
#endif /* RTIMER_CONF_GUARD_TIME */
/** \brief Busy-wait until a condition. Start time is t0, max wait time is max_time */
#define RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time) \
({ \
bool c; \
while(!(c = cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (max_time))) { \
watchdog_periodic(); \
} \
c; \
})
/** \brief Busy-wait until a condition for at most max_time */
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time) \
({ \
rtimer_clock_t t0 = RTIMER_NOW(); \
RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time); \
})
/** \brief Busy-wait for a fixed duration */
#define RTIMER_BUSYWAIT(duration) RTIMER_BUSYWAIT_UNTIL(0, duration)
#endif /* RTIMER_H_ */
/** @} */

View File

@ -54,10 +54,10 @@
##### "TSCH_CONF_MAX_EB_PERIOD": _______________ -> TSCH_MAX_EB_PERIOD
#endif
#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ == TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ == TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#else
##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ -> TSCH_DEFAULT_TIMESLOT_LENGTH
##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ -> TSCH_DEFAULT_TIMESLOT_TIMING
#endif
#ifdef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH