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 CFLAGS += -O2
endif endif
### Use CMSIS and the existing dbg-io from arch/cpu/arm/common ### Use CMSIS from arch/cpu/arm/common
CONTIKI_ARM_DIRS += . common/dbg-io CONTIKI_ARM_DIRS += .
CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(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 ### CPU-dependent cleanup files
CLEAN += *.elf *.bin *.lst *.hex *.i16hex 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 += i2c.c cc2538-temp-sensor.c vdd3-sensor.c
CONTIKI_CPU_SOURCEFILES += cfs-coffee.c cfs-coffee-arch.c pwm.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 USB_SOURCEFILES += usb-core.c cdc-acm.c usb-arch.c usb-serial.c cdc-acm-descriptors.c
CPU_START_SOURCEFILES = startup-gcc.c CPU_START_SOURCEFILES = startup-gcc.c

View File

@ -37,10 +37,13 @@
#define RTIMER_ARCH_SECOND 32768 #define RTIMER_ARCH_SECOND 32768
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* 352us from calling transmit() until the SFD byte has been sent */ /* 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 */ /* 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 CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250))
#define RADIO_DELAY_BEFORE_DETECT 0 #define CC2538_DELAY_BEFORE_DETECT 0
/* Frame filtering done in software */
#define TSCH_CONF_HW_FRAME_FILTERING 0
#ifndef TSCH_CONF_BASE_DRIFT_PPM #ifndef TSCH_CONF_BASE_DRIFT_PPM
/* The drift compared to "true" 10ms slots. /* The drift compared to "true" 10ms slots.
* Enable adaptive sync to enable compensation for this. * Enable adaptive sync to enable compensation for this.
@ -54,9 +57,6 @@
#define TSCH_CONF_BASE_DRIFT_PPM -977 #define TSCH_CONF_BASE_DRIFT_PPM -977
#endif #endif
#if MAC_CONF_WITH_TSCH
#define TSCH_CONF_HW_FRAME_FILTERING 0
#endif /* MAC_CONF_WITH_TSCH */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#define SPI_CONF_CONTROLLER_COUNT 2 #define SPI_CONF_CONTROLLER_COUNT 2
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -42,6 +42,7 @@
#include "net/packetbuf.h" #include "net/packetbuf.h"
#include "net/linkaddr.h" #include "net/linkaddr.h"
#include "net/netstack.h" #include "net/netstack.h"
#include "net/mac/tsch/tsch.h"
#include "sys/energest.h" #include "sys/energest.h"
#include "dev/cc2538-rf.h" #include "dev/cc2538-rf.h"
#include "dev/rfcore.h" #include "dev/rfcore.h"
@ -68,13 +69,10 @@
*/ */
#define UDMA_RX_SIZE_THRESHOLD 3 #define UDMA_RX_SIZE_THRESHOLD 3
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#include <stdio.h> /* Log configuration */
#define DEBUG 0 #include "sys/log.h"
#if DEBUG #define LOG_MODULE "cc2538-rf"
#define PRINTF(...) printf(__VA_ARGS__) #define LOG_LEVEL LOG_LEVEL_NONE
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Local RF Flags */ /* Local RF Flags */
#define RX_ACTIVE 0x80 #define RX_ACTIVE 0x80
@ -86,6 +84,7 @@
#define LQI_BIT_MASK 0x7F #define LQI_BIT_MASK 0x7F
/* RSSI Offset */ /* RSSI Offset */
#define RSSI_OFFSET 73 #define RSSI_OFFSET 73
#define RSSI_INVALID -128
/* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */ /* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */
#define ONOFF_TIME RTIMER_ARCH_SECOND / 3125 #define ONOFF_TIME RTIMER_ARCH_SECOND / 3125
@ -156,28 +155,19 @@ PROCESS(cc2538_rf_process, "cc2538 RF driver");
static uint8_t static uint8_t
get_channel() get_channel()
{ {
uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ; return rf_channel;
return (chan - CC2538_RF_CHANNEL_MIN) / CC2538_RF_CHANNEL_SPACING
+ CC2538_RF_CHANNEL_MIN;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** /**
* \brief Set the current operating channel * \brief Set the current operating channel
* \param channel The desired channel as a value in [11,26] * \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) set_channel(uint8_t channel)
{ {
uint8_t was_on = 0; uint8_t was_on = 0;
PRINTF("RF: Set Channel\n"); LOG_INFO("Set Channel\n");
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
return CC2538_RF_CHANNEL_SET_ERROR;
}
/* Changes to FREQCTRL take effect after the next recalibration */ /* Changes to FREQCTRL take effect after the next recalibration */
@ -195,8 +185,6 @@ set_channel(uint8_t channel)
} }
rf_channel = channel; rf_channel = channel;
return (int8_t)channel;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static radio_value_t static radio_value_t
@ -244,10 +232,11 @@ get_rssi(void)
on(); on();
} }
/* Wait on RSSI_VALID */ /* Wait for a valid RSSI reading */
while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0); do {
rssi = REG(RFCORE_XREG_RSSI);
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET; } while(rssi == RSSI_INVALID);
rssi -= RSSI_OFFSET;
/* If we were off, turn back off */ /* If we were off, turn back off */
if(was_off) { if(was_off) {
@ -322,6 +311,16 @@ set_frame_filtering(uint8_t enable)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void 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) mac_timer_init(void)
{ {
CLOCK_STABLE(); CLOCK_STABLE();
@ -403,7 +402,7 @@ channel_clear(void)
int cca; int cca;
uint8_t was_off = 0; uint8_t was_off = 0;
PRINTF("RF: CCA\n"); LOG_INFO("CCA\n");
/* If we are off, turn on first */ /* If we are off, turn on first */
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) { if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
@ -431,7 +430,7 @@ channel_clear(void)
static int static int
on(void) on(void)
{ {
PRINTF("RF: On\n"); LOG_INFO("On\n");
if(!(rf_flags & RX_ACTIVE)) { if(!(rf_flags & RX_ACTIVE)) {
CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISFLUSHRX();
@ -447,7 +446,7 @@ on(void)
static int static int
off(void) off(void)
{ {
PRINTF("RF: Off\n"); LOG_INFO("Off\n");
/* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */ /* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */
while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);
@ -470,7 +469,7 @@ off(void)
static int static int
init(void) init(void)
{ {
PRINTF("RF: Init\n"); LOG_INFO("Init\n");
if(rf_flags & RF_ON) { if(rf_flags & RF_ON) {
return 0; return 0;
@ -490,6 +489,7 @@ init(void)
REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */ REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */
REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */ REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */
REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */ REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */
REG(RFCORE_XREG_FSCAL1) = 0x01; /** Tune frequency calibration */
/* /*
* Defaults: * Defaults:
@ -513,6 +513,9 @@ init(void)
set_channel(rf_channel); set_channel(rf_channel);
/* Enable SHR search */
set_shr_search(1);
/* Acknowledge all RF Error interrupts */ /* Acknowledge all RF Error interrupts */
REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM; REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM;
NVIC_EnableIRQ(RF_ERR_IRQn); NVIC_EnableIRQ(RF_ERR_IRQn);
@ -545,8 +548,6 @@ init(void)
rf_flags |= RF_ON; rf_flags |= RF_ON;
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
return 1; return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -555,7 +556,7 @@ prepare(const void *payload, unsigned short payload_len)
{ {
uint8_t i; 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 * 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(); CC2538_RF_CSP_ISFLUSHTX();
PRINTF("RF: data = "); LOG_INFO("data = ");
/* Send the phy length byte first */ /* Send the phy length byte first */
REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN; REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN;
if(CC2538_RF_CONF_TX_USE_DMA) { if(CC2538_RF_CONF_TX_USE_DMA) {
PRINTF("<uDMA payload>"); LOG_INFO_("<uDMA payload>");
/* Set the transfer source's end address */ /* Set the transfer source's end address */
udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN, udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN,
@ -598,10 +599,10 @@ prepare(const void *payload, unsigned short payload_len)
} else { } else {
for(i = 0; i < payload_len; i++) { for(i = 0; i < payload_len; i++) {
REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[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; return 0;
} }
@ -614,7 +615,7 @@ transmit(unsigned short transmit_len)
rtimer_clock_t t0; rtimer_clock_t t0;
uint8_t was_off = 0; uint8_t was_off = 0;
PRINTF("RF: Transmit\n"); LOG_INFO("Transmit\n");
if(!(rf_flags & RX_ACTIVE)) { if(!(rf_flags & RX_ACTIVE)) {
t0 = RTIMER_NOW(); t0 = RTIMER_NOW();
@ -649,7 +650,7 @@ transmit(unsigned short transmit_len)
} }
if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) { 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(); CC2538_RF_CSP_ISFLUSHTX();
ret = RADIO_TX_ERR; ret = RADIO_TX_ERR;
} else { } else {
@ -679,7 +680,7 @@ read(void *buf, unsigned short bufsize)
uint8_t i; uint8_t i;
uint8_t len; uint8_t len;
PRINTF("RF: Read\n"); LOG_INFO("Read\n");
if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) { if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) {
return 0; return 0;
@ -691,33 +692,33 @@ read(void *buf, unsigned short bufsize)
/* Check for validity */ /* Check for validity */
if(len > CC2538_RF_MAX_PACKET_LEN) { if(len > CC2538_RF_MAX_PACKET_LEN) {
/* Oops, we must be out of sync. */ /* Oops, we must be out of sync. */
PRINTF("RF: bad sync\n"); LOG_ERR("RF: bad sync\n");
CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISFLUSHRX();
return 0; return 0;
} }
if(len <= CC2538_RF_MIN_PACKET_LEN) { if(len <= CC2538_RF_MIN_PACKET_LEN) {
PRINTF("RF: too short\n"); LOG_ERR("RF: too short\n");
CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISFLUSHRX();
return 0; return 0;
} }
if(len - CHECKSUM_LEN > bufsize) { if(len - CHECKSUM_LEN > bufsize) {
PRINTF("RF: too long\n"); LOG_ERR("RF: too long\n");
CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISFLUSHRX();
return 0; return 0;
} }
/* If we reach here, chances are the FIFO is holding a valid frame */ /* 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; len -= CHECKSUM_LEN;
/* Don't bother with uDMA for short frames (e.g. ACKs) */ /* Don't bother with uDMA for short frames (e.g. ACKs) */
if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) { 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 */ /* Set the transfer destination's end address */
udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN, udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN,
@ -738,7 +739,7 @@ read(void *buf, unsigned short bufsize)
} else { } else {
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA); ((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; rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET;
crc_corr = REG(RFCORE_SFR_RFDATA); 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 */ /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
if(crc_corr & CRC_BIT_MASK) { if(crc_corr & CRC_BIT_MASK) {
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
} else { } else {
PRINTF("RF: Bad CRC\n"); LOG_ERR("Bad CRC\n");
CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISFLUSHRX();
return 0; return 0;
} }
@ -775,7 +776,7 @@ read(void *buf, unsigned short bufsize)
static int static int
receiving_packet(void) receiving_packet(void)
{ {
PRINTF("RF: Receiving\n"); LOG_INFO("Receiving\n");
/* /*
* SFD high while transmitting and receiving. * SFD high while transmitting and receiving.
@ -791,7 +792,7 @@ receiving_packet(void)
static int static int
pending_packet(void) pending_packet(void)
{ {
PRINTF("RF: Pending\n"); LOG_INFO("Pending\n");
return REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP; 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: case RADIO_CONST_TXPOWER_MAX:
*value = OUTPUT_POWER_MAX; *value = OUTPUT_POWER_MAX;
return RADIO_RESULT_OK; 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: default:
return RADIO_RESULT_NOT_SUPPORTED; return RADIO_RESULT_NOT_SUPPORTED;
} }
@ -886,9 +902,7 @@ set_value(radio_param_t param, radio_value_t value)
value > CC2538_RF_CHANNEL_MAX) { value > CC2538_RF_CHANNEL_MAX) {
return RADIO_RESULT_INVALID_VALUE; return RADIO_RESULT_INVALID_VALUE;
} }
if(set_channel(value) == CC2538_RF_CHANNEL_SET_ERROR) { set_channel(value);
return RADIO_RESULT_ERROR;
}
return RADIO_RESULT_OK; return RADIO_RESULT_OK;
case RADIO_PARAM_PAN_ID: case RADIO_PARAM_PAN_ID:
set_pan_id(value & 0xffff); set_pan_id(value & 0xffff);
@ -924,6 +938,9 @@ set_value(radio_param_t param, radio_value_t value)
case RADIO_PARAM_CCA_THRESHOLD: case RADIO_PARAM_CCA_THRESHOLD:
set_cca_threshold(value); set_cca_threshold(value);
return RADIO_RESULT_OK; return RADIO_RESULT_OK;
case RADIO_PARAM_SHR_SEARCH:
set_shr_search(value);
return RADIO_RESULT_OK;
default: default:
return RADIO_RESULT_NOT_SUPPORTED; return RADIO_RESULT_NOT_SUPPORTED;
} }
@ -956,6 +973,16 @@ get_object(radio_param_t param, void *dest, size_t size)
return RADIO_RESULT_OK; 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; return RADIO_RESULT_NOT_SUPPORTED;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -1085,7 +1112,7 @@ cc2538_rf_rx_tx_isr(void)
void void
cc2538_rf_err_isr(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 the error is not an RX FIFO overflow, set a flag */
if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) { if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) {
@ -1097,10 +1124,5 @@ cc2538_rf_err_isr(void)
process_poll(&cc2538_rf_process); 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_MIN 11
#define CC2538_RF_CHANNEL_MAX 26 #define CC2538_RF_CHANNEL_MAX 26
#define CC2538_RF_CHANNEL_SPACING 5 #define CC2538_RF_CHANNEL_SPACING 5
#define CC2538_RF_CHANNEL_SET_ERROR -1
#define CC2538_RF_MAX_PACKET_LEN 127 #define CC2538_RF_MAX_PACKET_LEN 127
#define CC2538_RF_MIN_PACKET_LEN 4 #define CC2538_RF_MIN_PACKET_LEN 4
#define CC2538_RF_CCA_CLEAR 1 #define CC2538_RF_CCA_CLEAR 1
@ -113,7 +112,6 @@
*/ */
#define CC2538_RF_CSP_ISFLUSHRX() do { \ #define CC2538_RF_CSP_ISFLUSHRX() do { \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \ REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
} while(0) } while(0)
/** /**
@ -121,7 +119,6 @@
*/ */
#define CC2538_RF_CSP_ISFLUSHTX() do { \ #define CC2538_RF_CSP_ISFLUSHTX() do { \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \ REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
} while(0) } while(0)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** The NETSTACK data structure for the cc2538 RF driver */ /** 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); 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__ */ #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 { typedef struct spi_locks_s {
mutex_t lock; mutex_t lock;
spi_device_t *owner; const spi_device_t *owner;
} spi_locks_t; } spi_locks_t;
/* One lock per SPI controller */ /* One lock per SPI controller */
@ -115,40 +115,40 @@ spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKE
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void 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 */ /* Infinite loop until SR_TNF - Transmit FIFO Not Full */
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF)); while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF));
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int 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); return REG(spi_regs[dev->spi_controller].base + SSI_DR);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void 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; REG(spi_regs[dev->spi_controller].base + SSI_DR) = data;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
spix_wait_eotx(spi_device_t *dev) spix_wait_eotx(const spi_device_t *dev)
{ {
/* wait until not busy */ /* wait until not busy */
while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY); while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
spix_wait_eorx(spi_device_t *dev) spix_wait_eorx(const spi_device_t *dev)
{ {
/* wait as long as receive is empty */ /* wait as long as receive is empty */
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE)); while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE));
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
bool 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) { if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
return true; return true;
@ -158,7 +158,7 @@ spi_arch_has_lock(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
bool 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) { if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
return true; return true;
@ -168,7 +168,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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; const spi_regs_t *regs;
uint32_t scr; uint32_t scr;
@ -265,7 +265,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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)) { if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED; return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -282,7 +282,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t spi_status_t
spi_arch_select(spi_device_t *dev) spi_arch_select(const spi_device_t *dev)
{ {
if(!spi_arch_has_lock(dev)) { if(!spi_arch_has_lock(dev)) {
@ -295,7 +295,7 @@ spi_arch_select(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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)); 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 */ /* Assumes that checking dev and bus is not NULL before calling this */
spi_status_t 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, const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len) 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 += random.c soc-trng.c int-master.c
CONTIKI_CPU_SOURCEFILES += spi-arch.c CONTIKI_CPU_SOURCEFILES += spi-arch.c
MODULES += os/lib/dbg-io
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES)
CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS) CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS)

View File

@ -36,6 +36,10 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* TSCH related defines */ /* 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 */ /* Delay between GO signal and SFD */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
/* Delay between GO signal and start listening. /* Delay between GO signal and start listening.

View File

@ -37,7 +37,7 @@
typedef struct spi_locks_s { typedef struct spi_locks_s {
mutex_t lock; mutex_t lock;
spi_device_t *owner; const spi_device_t *owner;
} spi_locks_t; } spi_locks_t;
/* One lock per SPI controller */ /* One lock per SPI controller */
@ -68,7 +68,7 @@ static const board_spi_controller_t spi_controller[SPI_CONTROLLER_COUNT] = {
}; };
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
bool 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) { if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
return true; return true;
@ -78,7 +78,7 @@ spi_arch_has_lock(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
bool 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) { if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
return true; return true;
@ -88,7 +88,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint32_t static uint32_t
get_mode(spi_device_t *dev) get_mode(const spi_device_t *dev)
{ {
/* Select the correct SPI mode */ /* Select the correct SPI mode */
if(dev->spi_pha == 0 && dev->spi_pol == 0) { if(dev->spi_pha == 0 && dev->spi_pol == 0) {
@ -103,7 +103,7 @@ get_mode(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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; uint32_t c;
@ -152,7 +152,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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)) { if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED; return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -181,7 +181,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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, const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len) uint8_t *inbuf, int rlen, int ignore_len)
{ {
@ -231,7 +231,7 @@ spi_arch_transfer(spi_device_t *dev,
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t spi_status_t
spi_arch_select(spi_device_t *dev) spi_arch_select(const spi_device_t *dev)
{ {
if(!spi_arch_has_lock(dev)) { if(!spi_arch_has_lock(dev)) {
@ -243,7 +243,7 @@ spi_arch_select(spi_device_t *dev)
return SPI_DEV_STATUS_OK; return SPI_DEV_STATUS_OK;
} }
spi_status_t 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); 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) EXTERNALDIRS += $(SDK_SOURCE) $(SDK_NORTOS)
# CPU-dependent debug source files
MODULES += os/lib/dbg-io
# CPU-dependent directories # CPU-dependent directories
CONTIKI_CPU_DIRS += . dev $(SUBFAMILY) CONTIKI_CPU_DIRS += . dev $(SUBFAMILY)
CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC) CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC)

View File

@ -57,6 +57,10 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* TSCH related defines */ /* 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 */ /* Delay between GO signal and SFD */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
/* Delay between GO signal and start listening. /* Delay between GO signal and start listening.

View File

@ -54,7 +54,7 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
typedef struct { typedef struct {
SPI_Handle handle; SPI_Handle handle;
spi_device_t *owner; const spi_device_t *owner;
} spi_arch_t; } spi_arch_t;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if (SPI_CONTROLLER_COUNT > 0) #if (SPI_CONTROLLER_COUNT > 0)
@ -96,7 +96,7 @@ convert_frame_format(uint8_t pol, uint8_t pha)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
bool 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 * 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 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 * 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_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; uint_least8_t spi_index;
spi_arch_t *spi_arch; spi_arch_t *spi_arch;
@ -167,7 +167,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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; spi_arch_t *spi_arch;
@ -196,7 +196,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t 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, const uint8_t *write_buf, int wlen,
uint8_t *inbuf, int rlen, int ignore_len) uint8_t *inbuf, int rlen, int ignore_len)
{ {
@ -236,7 +236,7 @@ spi_arch_transfer(spi_device_t *dev,
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t spi_status_t
spi_arch_select(spi_device_t *dev) spi_arch_select(const spi_device_t *dev)
{ {
if(!spi_arch_has_lock(dev)) { if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED; return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -248,7 +248,7 @@ spi_arch_select(spi_device_t *dev)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
spi_status_t spi_status_t
spi_arch_deselect(spi_device_t *dev) spi_arch_deselect(const spi_device_t *dev)
{ {
if(!spi_arch_has_lock(dev)) { if(!spi_arch_has_lock(dev)) {
return SPI_DEV_STATUS_BUS_NOT_OWNED; return SPI_DEV_STATUS_BUS_NOT_OWNED;
@ -262,4 +262,4 @@ spi_arch_deselect(spi_device_t *dev)
/** /**
* @} * @}
* @} * @}
*/ */

View File

@ -34,6 +34,7 @@
#include "cc1200-rf-cfg.h" #include "cc1200-rf-cfg.h"
#include "cc1200-const.h" #include "cc1200-const.h"
#include "net/mac/tsch/tsch.h"
/* /*
* This is a setup for the following configuration: * This is a setup for the following configuration:
@ -62,7 +63,53 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static const char rf_cfg_descriptor[] = "802.15.4g 863-870MHz MR-FSK mode #1"; 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 * Register settings exported from SmartRF Studio using the standard template
* "trxEB RF Settings Performance Line". * "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), .size_of_register_settings = sizeof(preferredSettings),
.tx_pkt_lifetime = (RTIMER_SECOND / 20), .tx_pkt_lifetime = (RTIMER_SECOND / 20),
.tx_rx_turnaround = (RTIMER_SECOND / 100), .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_center_freq0 = RF_CFG_CHAN_CENTER_F0,
.chan_spacing = RF_CFG_CHAN_SPACING, .chan_spacing = RF_CFG_CHAN_SPACING,
.min_channel = RF_CFG_MIN_CHANNEL, .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, .max_txpower = RF_CFG_MAX_TXPOWER,
.cca_threshold = RF_CFG_CCA_THRESHOLD, .cca_threshold = RF_CFG_CCA_THRESHOLD,
.rssi_offset = RF_CFG_RSSI_OFFSET, .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), .size_of_register_settings = sizeof(preferredSettings),
.tx_pkt_lifetime = (2 * RTIMER_SECOND), .tx_pkt_lifetime = (2 * RTIMER_SECOND),
.tx_rx_turnaround = (RTIMER_SECOND / 2), .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_center_freq0 = RF_CFG_CHAN_CENTER_F0,
.chan_spacing = RF_CFG_CHAN_SPACING, .chan_spacing = RF_CFG_CHAN_SPACING,
.min_channel = RF_CFG_MIN_CHANNEL, .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, .max_txpower = RF_CFG_MAX_TXPOWER,
.cca_threshold = RF_CFG_CCA_THRESHOLD, .cca_threshold = RF_CFG_CCA_THRESHOLD,
.rssi_offset = RF_CFG_RSSI_OFFSET, .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; rtimer_clock_t tx_pkt_lifetime;
/* The maximum time it takes to switch from Tx to Rx */ /* The maximum time it takes to switch from Tx to Rx */
rtimer_clock_t tx_rx_turnaround; 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 */ /* Base frequency in kHz */
uint32_t chan_center_freq0; uint32_t chan_center_freq0;
/* Channel spacing in Hz */ /* Channel spacing in Hz */
@ -87,6 +94,10 @@ typedef struct cc1200_rf_cfg {
/* The RSSI offset in dBm. /* The RSSI offset in dBm.
* -99 when MDMCFG1.DVGA_GAIN=00, -81 when MDMCFG1.DVGA_GAIN=01 */ * -99 when MDMCFG1.DVGA_GAIN=00, -81 when MDMCFG1.DVGA_GAIN=01 */
int8_t rssi_offset; int8_t rssi_offset;
/* The bitrate in bps */
uint32_t bitrate;
/* TSCH timeslot timing */
const uint16_t *tsch_timing;
} cc1200_rf_cfg_t; } cc1200_rf_cfg_t;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#endif /* CC1200_RF_CFG_H */ #endif /* CC1200_RF_CFG_H */

View File

@ -47,6 +47,9 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
static int16_t rssi;
static rtimer_clock_t sfd_timestamp = 0;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Various implementation specific defines */ /* Various implementation specific defines */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -57,7 +60,7 @@
* - 2: Print errors + warnings (recoverable errors) * - 2: Print errors + warnings (recoverable errors)
* - 3: Print errors + warnings + information (what's going on...) * - 3: Print errors + warnings + information (what's going on...)
*/ */
#define DEBUG_LEVEL 2 #define DEBUG_LEVEL 0
/* /*
* RF test mode. Blocks inside "configure()". * RF test mode. Blocks inside "configure()".
* - Set this parameter to 1 in order to produce an modulated carrier (PN9) * - 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 #define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
#endif #endif
#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 * 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 * 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 * 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 #define USE_SFSTXON 1
#endif /* MAC_CONF_WITH_TSCH */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Phy header length */ /* Phy header length */
#if CC1200_802154G #if CC1200_802154G
@ -133,7 +148,15 @@
/* Use GPIO2 as RX / TX FIFO threshold indicator pin */ /* Use GPIO2 as RX / TX FIFO threshold indicator pin */
#define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR #define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR
/* This is the FIFO threshold we use */ /* 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 #define FIFO_THRESHOLD 32
#endif /* MAC_CONF_WITH_TSCH */
/* Turn on RX after packet reception */ /* Turn on RX after packet reception */
#define RXOFF_MODE_RX 1 #define RXOFF_MODE_RX 1
/* Let the CC1200 append RSSI + LQI */ /* Let the CC1200 append RSSI + LQI */
@ -249,6 +272,8 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
#define RF_UPDATE_CHANNEL 0x10 #define RF_UPDATE_CHANNEL 0x10
/* SPI was locked when calling RX interrupt, let the pollhandler do the job */ /* SPI was locked when calling RX interrupt, let the pollhandler do the job */
#define RF_POLL_RX_INTERRUPT 0x20 #define RF_POLL_RX_INTERRUPT 0x20
/* Ongoing reception */
#define RF_RX_ONGOING 0x40
/* Force calibration in case we don't use CC1200 AUTOCAL + timeout */ /* Force calibration in case we don't use CC1200 AUTOCAL + timeout */
#if !CC1200_AUTOCAL #if !CC1200_AUTOCAL
#if CC1200_CAL_TIMEOUT_SECONDS #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 LOCK_SPI() do { spi_locked++; } while(0)
#define SPI_IS_LOCKED() (spi_locked != 0) #define SPI_IS_LOCKED() (spi_locked != 0)
#define RELEASE_SPI() do { spi_locked--; } while(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 #if CC1200_USE_GPIO2
/* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */ /* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */
@ -353,38 +370,22 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
#define INFO(...) #define INFO(...)
#endif #endif
#if DEBUG_LEVEL > 0 /* Busy-wait (time-bounded) until the radio reaches a given state */
/* #define RTIMER_BUSYWAIT_UNTIL_STATE(s, t) RTIMER_BUSYWAIT_UNTIL(state() == (s), t)
* 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
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Variables */ /* Variables */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Flag indicating whether non-interrupt routines are using SPI */ /* Flag indicating whether non-interrupt routines are using SPI */
static volatile uint8_t spi_locked = 0; static volatile uint8_t spi_locked = 0;
#if CC1200_WITH_TX_BUF
/* Packet buffer for transmission, filled within prepare() */ /* Packet buffer for transmission, filled within prepare() */
static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN]; static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN];
#endif /* CC1200_WITH_TX_BUF */
/* The number of bytes waiting in tx_pkt */ /* The number of bytes waiting in tx_pkt */
static uint16_t tx_pkt_len; 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 */ /* Packet buffer for reception */
static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN]; static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
/* The number of bytes placed in rx_pkt */ /* The number of bytes placed in rx_pkt */
@ -422,6 +423,9 @@ static struct etimer et;
/* Init the radio. */ /* Init the radio. */
static int static int
init(void); 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. */ /* Prepare the radio with a packet to be sent. */
static int static int
prepare(const void *payload, unsigned short payload_len); prepare(const void *payload, unsigned short payload_len);
@ -530,7 +534,7 @@ idle_calibrate_rx(void);
/* Restart RX from within RX interrupt. */ /* Restart RX from within RX interrupt. */
static void static void
rx_rx(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 static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len); idle_tx_rx(const uint8_t *payload, uint16_t payload_len);
/* Update TX power */ /* 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 * We are on and not in TX. As every function of this driver
* assures that we are in RX mode * 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(), * either rx_rx(), idle_calibrate_rx() or transmit(),
* something probably went wrong in the rx interrupt handler * something probably went wrong in the rx interrupt handler
* if we are not in RX at this point. * if we are not in RX at this point.
@ -624,7 +628,7 @@ pollhandler(void)
set_channel(new_rf_channel); 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; int len;
@ -722,10 +726,67 @@ prepare(const void *payload, unsigned short payload_len)
} }
tx_pkt_len = 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); 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; 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. */ /* Send the packet that has previously been prepared. */
@ -735,6 +796,7 @@ transmit(unsigned short transmit_len)
uint8_t was_off = 0; uint8_t was_off = 0;
int ret = RADIO_TX_OK; int ret = RADIO_TX_OK;
int txret;
INFO("RF: Transmit (%d)\n", transmit_len); INFO("RF: Transmit (%d)\n", transmit_len);
@ -790,7 +852,12 @@ transmit(unsigned short transmit_len)
#endif #endif
/* Send data using TX FIFO */ /* 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, * TXOFF_MODE is set to RX,
@ -798,7 +865,7 @@ transmit(unsigned short transmit_len)
* again as they were turned off in idle() * 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); CC1200_RF_CFG.tx_rx_turnaround);
ENABLE_GPIO_INTERRUPTS(); ENABLE_GPIO_INTERRUPTS();
@ -861,7 +928,7 @@ read(void *buf, unsigned short buf_len)
if(rx_pkt_len > 0) { 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 */ /* CRC is already checked */
uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1]; uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1];
@ -938,7 +1005,7 @@ channel_clear(void)
} }
/* Wait for CARRIER_SENSE_VALID signal */ /* 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), & CC1200_CARRIER_SENSE_VALID),
RTIMER_SECOND / 100); RTIMER_SECOND / 100);
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID); RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
@ -1009,9 +1076,16 @@ receiving_packet(void)
static int static int
pending_packet(void) 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)); INFO("RF: Pending (%d)\n", ret);
return (rx_pkt_len != 0) ? 1 : 0; return ret;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -1033,11 +1107,12 @@ on(void)
/* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */ /* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */
cc1200_arch_spi_select(); cc1200_arch_spi_select();
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0), RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_SECOND / 100); RTIMER_SECOND / 100);
RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0)); RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0));
cc1200_arch_spi_deselect(); cc1200_arch_spi_deselect();
rf_flags = RF_INITIALIZED;
rf_flags |= RF_ON; rf_flags |= RF_ON;
/* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */ /* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */
@ -1080,6 +1155,16 @@ off(void)
idle(); 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(), * As we use GPIO as CHIP_RDYn signal on wake-up / on(),
* we re-configure it for CHIP_RDYn. * 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. */ /* Get a radio parameter value. */
static radio_result_t static radio_result_t
get_value(radio_param_t param, radio_value_t *value) 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; return RADIO_RESULT_OK;
case RADIO_PARAM_RSSI: 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: case RADIO_PARAM_64BIT_ADDR:
return RADIO_RESULT_NOT_SUPPORTED; 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; *value = (radio_value_t)CC1200_RF_CFG.max_txpower;
return RADIO_RESULT_OK; 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: default:
return RADIO_RESULT_NOT_SUPPORTED; return RADIO_RESULT_NOT_SUPPORTED;
@ -1282,6 +1436,23 @@ set_value(radio_param_t param, radio_value_t value)
static radio_result_t static radio_result_t
get_object(radio_param_t param, void *dest, size_t size) 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; return RADIO_RESULT_NOT_SUPPORTED;
@ -1507,20 +1678,20 @@ configure(void)
while(1) { while(1) {
#if (CC1200_RF_TESTMODE == 1) #if (CC1200_RF_TESTMODE == 1)
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW); leds_off(LEDS_YELLOW);
leds_on(LEDS_RED); leds_on(LEDS_RED);
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED); leds_off(LEDS_RED);
leds_on(LEDS_YELLOW); leds_on(LEDS_YELLOW);
#else #else
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN); leds_off(LEDS_GREEN);
leds_on(LEDS_RED); leds_on(LEDS_RED);
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED); leds_off(LEDS_RED);
leds_on(LEDS_GREEN); leds_on(LEDS_GREEN);
#endif #endif
@ -1542,11 +1713,11 @@ configure(void)
while(1) { while(1) {
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN); leds_off(LEDS_GREEN);
leds_on(LEDS_YELLOW); leds_on(LEDS_YELLOW);
watchdog_periodic(); watchdog_periodic();
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10); RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW); leds_off(LEDS_YELLOW);
leds_on(LEDS_GREEN); leds_on(LEDS_GREEN);
clock_delay_usec(1000); clock_delay_usec(1000);
@ -1667,8 +1838,8 @@ calibrate(void)
INFO("RF: Calibrate\n"); INFO("RF: Calibrate\n");
strobe(CC1200_SCAL); strobe(CC1200_SCAL);
BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100); RTIMER_BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
#if CC1200_CAL_TIMEOUT_SECONDS #if CC1200_CAL_TIMEOUT_SECONDS
cal_timer = clock_seconds(); cal_timer = clock_seconds();
@ -1705,7 +1876,7 @@ idle(void)
} }
strobe(CC1200_SIDLE); strobe(CC1200_SIDLE);
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100); RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
} /* idle(), 21.05.2015 */ } /* idle(), 21.05.2015 */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -1723,7 +1894,7 @@ idle_calibrate_rx(void)
rf_flags &= ~RF_RX_PROCESSING_PKT; rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX); strobe(CC1200_SFRX);
strobe(CC1200_SRX); strobe(CC1200_SRX);
BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100); RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
ENABLE_GPIO_INTERRUPTS(); ENABLE_GPIO_INTERRUPTS();
@ -1748,7 +1919,7 @@ rx_rx(void)
strobe(CC1200_SFTX); strobe(CC1200_SFTX);
} else { } else {
strobe(CC1200_SIDLE); strobe(CC1200_SIDLE);
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE,
RTIMER_SECOND / 100); RTIMER_SECOND / 100);
} }
@ -1760,79 +1931,29 @@ rx_rx(void)
strobe(CC1200_SFRX); strobe(CC1200_SFRX);
strobe(CC1200_SRX); 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 static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len) 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))
uint16_t bytes_left_to_write;
uint8_t to_write; uint8_t to_write;
const uint8_t *p; const uint8_t *p;
#endif #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 */ /* Prepare for RX */
rf_flags &= ~RF_RX_PROCESSING_PKT; rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX); 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 */ /* Configure GPIO0 to detect TX state */
single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0); single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0);
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) #if CC1200_WITH_TX_BUF
/* /* Prepare and write header */
* We already checked that GPIO2 is used if copy_header_to_tx_fifo(payload_len);
* 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 */
/* /*
* Fill FIFO with data. If SPI is slow it might make sense * 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 #else
burst_write(CC1200_TXFIFO, payload, payload_len); burst_write(CC1200_TXFIFO, payload, payload_len);
#endif #endif
#endif /* CC1200_WITH_TX_BUF */
#if USE_SFSTXON #if USE_SFSTXON
/* Wait for synthesizer to be ready */ /* Wait for synthesizer to be ready */
BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100); RTIMER_BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
#endif #endif
/* Start TX */ /* Start TX */
strobe(CC1200_STX); strobe(CC1200_STX);
/* Wait for TX to start. */ /* 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() */ /* Turned off at the latest in idle() */
TX_LEDS_ON(); 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) { if(bytes_left_to_write != 0) {
rtimer_clock_t t0; rtimer_clock_t t0;
uint8_t s; uint8_t s;
@ -1922,7 +2044,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
*/ */
INFO("RF: TX failure!\n"); 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 */ /* Re-configure GPIO2 */
single_write(CC1200_IOCFG2, GPIO2_IOCFG); single_write(CC1200_IOCFG2, GPIO2_IOCFG);
idle(); idle();
@ -1936,12 +2058,12 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
} else { } else {
/* Wait for TX to complete */ /* 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); CC1200_RF_CFG.tx_pkt_lifetime);
} }
#else #else
/* Wait for TX to complete */ /* 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); CC1200_RF_CFG.tx_pkt_lifetime);
#endif #endif
@ -2026,6 +2148,9 @@ set_channel(uint8_t channel)
uint8_t was_off = 0; uint8_t was_off = 0;
uint32_t freq; uint32_t freq;
channel %= (CC1200_RF_CFG.max_channel - CC1200_RF_CFG.min_channel + 1);
channel += CC1200_RF_CFG.min_channel;
#if 0 #if 0
/* /*
* We explicitly allow a channel update even if the channel does not change. * 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(); idle();
#endif #endif
prepare((const uint8_t *)ack, ACK_LEN);
idle_tx_rx((const uint8_t *)ack, ACK_LEN); idle_tx_rx((const uint8_t *)ack, ACK_LEN);
/* rx_rx() will follow */ /* rx_rx() will follow */
@ -2204,6 +2330,23 @@ cc1200_rx_interrupt(void)
*/ */
static uint8_t buf[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN]; 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()) { 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); 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; int cc2420_authority_level_of_sender;
volatile uint8_t cc2420_sfd_counter; volatile uint8_t cc2420_sfd_counter;

View File

@ -102,9 +102,6 @@ int cc2420_get_txpower(void);
*/ */
int cc2420_interrupt(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; extern int cc2420_authority_level_of_sender;
int cc2420_on(void); int cc2420_on(void);

View File

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

View File

@ -61,7 +61,7 @@
* \param conf SPI bus configuration struct. NULL for default. * \param conf SPI bus configuration struct. NULL for default.
* \return True when successful. * \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 * \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). * 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 * \brief Read storage content
@ -82,7 +82,7 @@ bool ext_flash_close(spi_device_t *conf);
* *
* buf must be allocated by the caller * 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. * \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 * 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 * 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. * \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. * \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 * \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 * In order to perform any operation, the caller must first wake the device
* up by calling ext_flash_open() * 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_ */ #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) */ /* Use 64-bit rtimer (default in Contiki-NG is 32) */
#define RTIMER_CONF_CLOCK_SIZE 8 #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_TX 0
#define RADIO_DELAY_BEFORE_RX 0 #define RADIO_DELAY_BEFORE_RX 0
#define RADIO_DELAY_BEFORE_DETECT 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: case RADIO_PARAM_LAST_LINK_QUALITY:
*value = simLQI; *value = simLQI;
return RADIO_RESULT_OK; 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: default:
return RADIO_RESULT_NOT_SUPPORTED; 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 "dev/watchdog.h"
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
@ -47,6 +49,9 @@ watchdog_start(void)
void void
watchdog_periodic(void) watchdog_periodic(void)
{ {
/* Yield and give control back to the simulator scheduler */
simProcessRunValue = 1;
cooja_mt_yield();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void

View File

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

View File

@ -130,13 +130,6 @@
#define MICROMAC_CONF_ALWAYS_ON 1 #define MICROMAC_CONF_ALWAYS_ON 1
#endif /* MICROMAC_CONF_ALWAYS_ON */ #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 */ /* Local variables */
static volatile signed char radio_last_rssi; static volatile signed char radio_last_rssi;
static volatile uint8_t radio_last_correlation; /* LQI */ 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)); (send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA));
#endif #endif
if(poll_mode) { 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 { } else {
if(in_ack_transmission) { if(in_ack_transmission) {
/* as nested interupts are not possible, the tx flag will never be cleared */ /* 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 { } else {
/* wait until the tx flag is cleared */ /* 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 */ #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 DEBUG_UART_BUFFERED FALSE
#define CHAR_DEADLINE (uart_char_delay * 100) #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; volatile int16_t write = 0;
watchdog_periodic(); watchdog_periodic();
/* wait until there is space in tx fifo */ /* 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); CHAR_DEADLINE);
/* write only if there is space so we do not get stuck */ /* write only if there is space so we do not get stuck */
if(write) { if(write) {

View File

@ -38,6 +38,10 @@
#undef putchar #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 /* Delay between GO signal and SFD
* Measured 153us between GO and preamble. Add 5 bytes (preamble + SFD) air time: 153+5*32 = 313 */ * 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)) #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 CONTIKI_SOURCEFILES += platform.c leds-arch.c nrf52dk-sensors.c button-sensor.c temperature-sensor.c
ifeq ($(NRF52_USE_RTT),1) 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_TARGET_DIRS += rtt
CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c
else else
CONTIKI_SOURCEFILES += dbg.c CONTIKI_SOURCEFILES += dbg.c
MODULES += os/lib/dbg-io
endif endif
### Unless the example dictates otherwise, build with code size optimisations switched off ### Unless the example dictates otherwise, build with code size optimisations switched off

View File

@ -17,11 +17,14 @@
#define NETSTACK_CONF_RADIO cc2420_driver #define NETSTACK_CONF_RADIO cc2420_driver
#endif /* NETSTACK_CONF_RADIO */ #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, /* The TSCH default slot length of 10ms is a bit too short for this platform,
* use 15ms instead. */ * use 15ms instead. */
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH #ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000 #define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_15000
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */ #endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */
/* Save RAM through a smaller uIP buffer */ /* Save RAM through a smaller uIP buffer */
#ifndef UIP_CONF_BUFFER_SIZE #ifndef UIP_CONF_BUFFER_SIZE

View File

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

View File

@ -43,6 +43,11 @@
* Definitions below are dictated by the hardware and not really * Definitions below are dictated by the hardware and not really
* changeable! * 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 /* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us
* ~327us + 129preample = 456 us */ * ~327us + 129preample = 456 us */
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456)) #define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456))

View File

@ -55,6 +55,25 @@
#endif /* PROJECT_CONF_PATH */ #endif /* PROJECT_CONF_PATH */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#include "cc2538-def.h" #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 * \name Serial Boot Loader Backdoor configuration

View File

@ -76,18 +76,8 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if DEBUG_CC1200_ARCH > 0 #if DEBUG_CC1200_ARCH > 0
#define PRINTF(...) printf(__VA_ARGS__) #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 #else
#define PRINTF(...) #define PRINTF(...)
#define BUSYWAIT_UNTIL(cond, max_time) while(!cond)
#endif #endif
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
extern int cc1200_rx_interrupt(void); extern int cc1200_rx_interrupt(void);
@ -105,7 +95,7 @@ cc1200_arch_spi_select(void)
/* Set CSn to low (0) */ /* Set CSn to low (0) */
GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK); GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
/* The MISO pin should go low before chip is fully enabled. */ /* 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, GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0,
RTIMER_SECOND / 100); RTIMER_SECOND / 100);
} }
@ -288,7 +278,7 @@ cc1200_arch_init(void)
cc1200_arch_spi_deselect(); cc1200_arch_spi_deselect();
/* Ensure MISO is high */ /* Ensure MISO is high */
BUSYWAIT_UNTIL( RTIMER_BUSYWAIT_UNTIL(
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK), GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK),
RTIMER_SECOND / 10); RTIMER_SECOND / 10);
} }
@ -297,4 +287,3 @@ cc1200_arch_init(void)
* @} * @}
* @} * @}
*/ */

View File

@ -51,15 +51,6 @@
#define PRINTF(...) #define PRINTF(...)
#endif #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_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT)
#define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN) #define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -80,12 +71,12 @@ dht22_read(void)
/* Exit low power mode and initialize variables */ /* Exit low power mode and initialize variables */
GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK); GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
GPIO_SET_PIN(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); memset(dht22_data, 0, DHT22_BUFFER);
/* Initialization sequence */ /* Initialization sequence */
GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); 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); GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
clock_delay_usec(DHT22_READY_TIME); clock_delay_usec(DHT22_READY_TIME);

View File

@ -257,6 +257,48 @@ platform_idle()
lpm_enter(); 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 */ #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_ */ #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) { if (host_found) {
/* Make sample count dependent on asn. After a disconnect, waveforms remain /* Make sample count dependent on asn. After a disconnect, waveforms remain
synchronous. Use node_mac to create phase offset between waveforms in different nodes */ 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]); 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]); my_sprintf(udp_buf, waveform_table[selected_waveform].table[sample_count]);
uip_udp_packet_send(udp_conn_tx, udp_buf, strlen(udp_buf)); 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/orchestra/orchestra.h"
#include "services/shell/serial-shell.h" #include "services/shell/serial-shell.h"
#include "services/simple-energest/simple-energest.h" #include "services/simple-energest/simple-energest.h"
#include "services/tsch-cs/tsch-cs.h"
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -146,6 +147,11 @@ main(void)
simple_energest_init(); simple_energest_init();
#endif /* BUILD_WITH_SIMPLE_ENERGEST */ #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); autostart_start(autostart_processes);
watchdog_start(); watchdog_start();

View File

@ -170,6 +170,9 @@ enum {
* it needs to be used with radio.get_object()/set_object(). */ * it needs to be used with radio.get_object()/set_object(). */
RADIO_PARAM_LAST_PACKET_TIMESTAMP, RADIO_PARAM_LAST_PACKET_TIMESTAMP,
/* For enabling and disabling the SHR search */
RADIO_PARAM_SHR_SEARCH,
/* Constants (read only) */ /* Constants (read only) */
/* The lowest radio channel. */ /* The lowest radio channel. */
@ -180,7 +183,14 @@ enum {
/* The minimum transmission power in dBm. */ /* The minimum transmission power in dBm. */
RADIO_CONST_TXPOWER_MIN, RADIO_CONST_TXPOWER_MIN,
/* The maximum transmission power in dBm. */ /* 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 */ /* Radio power modes */

View File

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

View File

@ -115,7 +115,7 @@ typedef struct spi_device {
* to be locked and the opening configuration. * to be locked and the opening configuration.
* \return SPI return code * \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 * \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 * This should work only if the device has already locked the SPI
* controller. * 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 * \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 * Clears the CS pin. This should work only if the device has
* already locked the SPI controller. * 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 * \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. * 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 * \brief Checks if a device has locked an SPI controller
* \param dev An SPI device configuration which defines the controller. * \param dev An SPI device configuration which defines the controller.
* \return true if the device has the lock, false otherwise. * \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 * \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. * 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 * \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. * 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 * \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. * 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); 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. * 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 * \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. * Reads size bytes from the SPI and throws them away.
* It should work only if the device has already locked the SPI controller. * 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 * \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 * 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. * 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, const uint8_t *data, int wsize,
uint8_t *buf, int rsize, int ignore); 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. * 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); 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. * 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); 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. * \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 * \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. * \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. * \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. * 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 * \brief Closes and unlocks an SPI controller
@ -299,7 +299,7 @@ spi_status_t spi_arch_lock_and_open(spi_device_t *dev);
* controller. * 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 * \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 * 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. * 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, const uint8_t *data, int wlen,
uint8_t *buf, int rlen, uint8_t *buf, int rlen,
int ignore_len); 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 * Clears the CS pin. It should work only if the device has already
* locked the SPI controller. * 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 * \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. * 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_ */ #endif /* SPI_H_ */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -37,12 +37,10 @@
#include "net/link-stats.h" #include "net/link-stats.h"
#include <stdio.h> #include <stdio.h>
#define DEBUG 0 /* Log configuration */
#if DEBUG #include "sys/log.h"
#define PRINTF(...) printf(__VA_ARGS__) #define LOG_MODULE "Link Stats"
#else #define LOG_LEVEL LOG_LEVEL_MAC
#define PRINTF(...)
#endif
/* Maximum value for the Tx count counter */ /* Maximum value for the Tx count counter */
#define TX_COUNT_MAX 32 #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); 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? */ /* Are the statistics fresh? */
int int
link_stats_is_fresh(const struct link_stats *stats) 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->last_tx_time = clock_time();
stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX); 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 */ /* Add penalty in case of no-ACK */
if(status == MAC_TX_NOACK) { if(status == MAC_TX_NOACK) {
numtx += ETX_NOACK_PENALTY; numtx += ETX_NOACK_PENALTY;
@ -219,8 +232,38 @@ link_stats_input_callback(const linkaddr_t *lladdr)
/* Update RSSI EWMA */ /* Update RSSI EWMA */
stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) + stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) +
(int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE; (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 */ /* Periodic timer called at a period of FRESHNESS_HALF_LIFE */
static void static void
periodic(void *ptr) 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)) { for(stats = nbr_table_head(link_stats); stats != NULL; stats = nbr_table_next(link_stats, stats)) {
stats->freshness >>= 1; stats->freshness >>= 1;
} }
#if LINK_STATS_PACKET_COUNTERS
print_and_update_counters();
#endif
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Resets link-stats module */ /* Resets link-stats module */

View File

@ -56,6 +56,25 @@
#define LINK_STATS_ETX_FROM_PACKET_COUNT 0 #define LINK_STATS_ETX_FROM_PACKET_COUNT 0
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */ #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 */ /* All statistics of a given link */
struct link_stats { struct link_stats {
clock_time_t last_tx_time; /* Last Tx timestamp */ 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 tx_count; /* Tx count, used for ETX calculation */
uint8_t ack_count; /* ACK count, used for ETX calculation */ uint8_t ack_count; /* ACK count, used for ETX calculation */
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */ #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 */ /* Returns the neighbor's link statistics */
const struct link_stats *link_stats_from_lladdr(const linkaddr_t *lladdr); 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? */ /* Are the statistics fresh? */
int link_stats_is_fresh(const struct link_stats *stats); int link_stats_is_fresh(const struct link_stats *stats);
/* Resets link-stats module */ /* Resets link-stats module */

View File

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

View File

@ -151,7 +151,7 @@
#ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN #ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
#define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN #define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
#else #else
#define TSCH_HOPPING_SEQUENCE_MAX_LEN 16 #define TSCH_HOPPING_SEQUENCE_MAX_LEN sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)
#endif #endif
/******** Configuration: association *******/ /******** Configuration: association *******/
@ -365,18 +365,21 @@
/******** Configuration: CSMA *******/ /******** Configuration: CSMA *******/
/* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */ /* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */
/* Min backoff exponent */ /* Min backoff exponent */
#ifdef TSCH_CONF_MAC_MIN_BE #ifdef TSCH_CONF_MAC_MIN_BE
#define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE #define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE
#else #else
#define TSCH_MAC_MIN_BE 1 #define TSCH_MAC_MIN_BE 1
#endif #endif
/* Max backoff exponent */ /* Max backoff exponent */
#ifdef TSCH_CONF_MAC_MAX_BE #ifdef TSCH_CONF_MAC_MAX_BE
#define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE #define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE
#else #else
#define TSCH_MAC_MAX_BE 5 #define TSCH_MAC_MAX_BE 5
#endif #endif
/* Max number of re-transmissions */ /* Max number of re-transmissions */
#ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES #ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES
#define TSCH_MAC_MAX_FRAME_RETRIES 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 #define TSCH_PACKET_EACK_WITH_SRC_ADDR 0
#endif #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? */ /* Include destination address in ACK? */
#ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR #ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
#define TSCH_PACKET_EACK_WITH_DEST_ADDR 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 #define TSCH_RADIO_ON_DURING_TIMESLOT 0
#endif #endif
/* TSCH timeslot timing template */
#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
/* Timeslot timing */ #define TSCH_DEFAULT_TIMESLOT_TIMING TSCH_CONF_DEFAULT_TIMESLOT_TIMING
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH #else
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 10000 #define TSCH_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_10000
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */ #endif
/* Configurable Rx guard time is micro-seconds */ /* Configurable Rx guard time is micro-seconds */
#ifndef TSCH_CONF_RX_WAIT #ifndef TSCH_CONF_RX_WAIT

View File

@ -75,87 +75,16 @@
#define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32) #define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32)
/* The approximate number of slots per second */ /* 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 /* Calculate packet tx/rx duration in rtimer ticks based on sent
* packet len in bytes with 802.15.4 250kbps data rate. * packet len in bytes with 802.15.4 250kbps data rate.
* One byte = 32us. Add two bytes for CRC and one for len field */ * 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 */ /* Convert rtimer ticks to clock and vice versa */
#define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND) #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) #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__ */ #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; old_time_src->is_time_source = 0;
} }
tsch_stats_reset_neighbor_stats();
#ifdef TSCH_CALLBACK_NEW_TIME_SOURCE #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src); TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src);
#endif #endif

View File

@ -52,10 +52,6 @@
#include "net/queuebuf.h" #include "net/queuebuf.h"
#include "net/mac/framer/framer-802154.h" #include "net/mac/framer/framer-802154.h"
#include "net/mac/tsch/tsch.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" #include "sys/log.h"
/* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH /* 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 /* Truncate received drift correction information to maximum half
* of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */ * 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 */ /* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */
#if RTIMER_SECOND < (32 * 1024) #if RTIMER_SECOND < (32 * 1024)
@ -206,10 +202,7 @@ tsch_get_lock(void)
busy_wait = 1; busy_wait = 1;
busy_wait_time = RTIMER_NOW(); busy_wait_time = RTIMER_NOW();
while(tsch_in_slot_operation) { while(tsch_in_slot_operation) {
#if CONTIKI_TARGET_COOJA watchdog_periodic();
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA */
} }
busy_wait_time = RTIMER_NOW() - busy_wait_time; 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 */ /* block until the time to schedule comes */
BUSYWAIT_UNTIL_ABS(0, ref_time, offset); RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
return 0; return 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -314,7 +307,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_
do { \ do { \
if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \ if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
PT_YIELD(pt); \ PT_YIELD(pt); \
BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \ RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
} \ } \
} while(0); } 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? */ /* Did we set the frame pending bit to request an extra burst link? */
static int burst_link_requested; static int burst_link_requested;
#if CCA_ENABLED #if TSCH_CCA_ENABLED
static uint8_t cca_status; static uint8_t cca_status;
#endif #endif /* TSCH_CCA_ENABLED */
/* get payload */ /* get payload */
packet = queuebuf_dataptr(current_packet->qb); 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 */ if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */
static rtimer_clock_t tx_duration; static rtimer_clock_t tx_duration;
#if CCA_ENABLED #if TSCH_CCA_ENABLED
cca_status = 1; cca_status = 1;
/* delay before CCA */ /* 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_DEBUG_TX_EVENT();
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
/* CCA */ /* CCA */
BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()), RTIMER_BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()),
current_slot_start, TS_CCA_OFFSET + TS_CCA); current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]);
TSCH_DEBUG_TX_EVENT(); TSCH_DEBUG_TX_EVENT();
/* there is not enough time to turn radio off */ /* there is not enough time to turn radio off */
/* NETSTACK_RADIO.off(); */ /* NETSTACK_RADIO.off(); */
if(cca_status == 0) { if(cca_status == 0) {
mac_tx_status = MAC_TX_COLLISION; mac_tx_status = MAC_TX_COLLISION;
} else } else
#endif /* CCA_ENABLED */ #endif /* TSCH_CCA_ENABLED */
{ {
/* delay before TX */ /* delay before TX */
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx"); 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_DEBUG_TX_EVENT();
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT); tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
/* Wait for ACK to come */ /* 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); 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(); TSCH_DEBUG_TX_EVENT();
ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT; ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
/* Wait for ACK to finish */ /* 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]); ack_start_time, tsch_timing[tsch_ts_max_ack]);
TSCH_DEBUG_TX_EVENT(); TSCH_DEBUG_TX_EVENT();
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT); 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); "!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction);
); );
} }
tsch_stats_on_time_synchronization(eack_time_correction);
is_drift_correction_used = 1; is_drift_correction_used = 1;
tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction); tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction);
/* Keep track of sync time */ /* Keep track of sync time */
@ -666,6 +660,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
ringbufindex_put(&dequeued_ringbuf); 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 */ /* Log every tx attempt */
TSCH_LOG_ADD(tsch_log_tx, TSCH_LOG_ADD(tsch_log_tx,
log->tx.mac_tx_status = mac_tx_status; 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(); packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet();
if(!packet_seen) { if(!packet_seen) {
/* Check if receiving within guard time */ /* 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); current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT);
} }
if(!packet_seen) { 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; rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
/* Wait until packet is received, turn radio off */ /* 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]); 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_DEBUG_RX_EVENT();
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT); 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 int header_len;
static frame802154_t frame; static frame802154_t frame;
radio_value_t radio_last_rssi; radio_value_t radio_last_rssi;
radio_value_t radio_last_lqi;
/* Read packet */ /* Read packet */
current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN); 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 #endif
packet_duration = TSCH_PACKET_DURATION(current_input->len); 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) { if(!frame_valid) {
TSCH_LOG_ADD(tsch_log_message, 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; int do_nack = 0;
rx_count++; rx_count++;
estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time); estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
tsch_stats_on_time_synchronization(estimated_drift);
#if TSCH_TIMESYNC_REMOVE_JITTER #if TSCH_TIMESYNC_REMOVE_JITTER
/* remove jitter due to measurement errors */ /* 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 */ /* Add current input to ringbuf */
ringbufindex_put(&input_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 */ /* Log every reception */
TSCH_LOG_ADD(tsch_log_rx, TSCH_LOG_ADD(tsch_log_rx,
linkaddr_copy(&log->rx.src, (linkaddr_t *)&frame.src_addr); 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; int is_active_slot;
TSCH_DEBUG_SLOT_START(); TSCH_DEBUG_SLOT_START();
tsch_in_slot_operation = 1; tsch_in_slot_operation = 1;
/* Measure on-air noise level while TSCH is idle */
tsch_stats_sample_rssi();
/* Reset drift correction */ /* Reset drift correction */
drift_correction = 0; drift_correction = 0;
is_drift_correction_used = 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; struct tsch_asn_divisor_t tsch_hopping_sequence_length;
/* Default TSCH timeslot timing (in micro-second) */ /* Default TSCH timeslot timing (in micro-second) */
static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = { static const uint16_t *tsch_default_timing_us;
TSCH_DEFAULT_TS_CCA_OFFSET, /* TSCH timeslot timing (in micro-second) */
TSCH_DEFAULT_TS_CCA, uint16_t tsch_timing_us[tsch_ts_elements_count];
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,
};
/* TSCH timeslot timing (in rtimer ticks) */ /* TSCH timeslot timing (in rtimer ticks) */
rtimer_clock_t tsch_timing[tsch_ts_elements_count]; rtimer_clock_t tsch_timing[tsch_ts_elements_count];
@ -231,8 +220,10 @@ tsch_reset(void)
TSCH_ASN_INIT(tsch_current_asn, 0, 0); TSCH_ASN_INIT(tsch_current_asn, 0, 0);
current_link = NULL; current_link = NULL;
/* Reset timeslot timing to defaults */ /* Reset timeslot timing to defaults */
tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING;
for(i = 0; i < tsch_ts_elements_count; i++) { 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 #ifdef TSCH_CALLBACK_LEAVING_NETWORK
TSCH_CALLBACK_LEAVING_NETWORK(); TSCH_CALLBACK_LEAVING_NETWORK();
@ -412,6 +403,22 @@ eb_input(struct input_packet *current_input)
} }
#endif /* TSCH_AUTOSELECT_TIME_SOURCE */ #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 */ /* TSCH timeslot timing */
for(i = 0; i < tsch_ts_elements_count; i++) { for(i = 0; i < tsch_ts_elements_count; i++) {
if(ies.ie_tsch_timeslot_id == 0) { 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 { } 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 */ /* TSCH hopping sequence */
@ -714,11 +722,11 @@ PT_THREAD(tsch_scan(struct pt *pt))
/* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */ /* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[ uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
random_rand() % sizeof(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); NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
current_channel = scan_channel; current_channel = scan_channel;
LOG_INFO("scanning on channel %u\n", scan_channel); LOG_INFO("scanning on channel %u\n", scan_channel);
}
current_channel_since = now_time; 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(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
/* If we are currently receiving a packet, wait until end of reception */ /* If we are currently receiving a packet, wait until end of reception */
t0 = RTIMER_NOW(); 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) { if(is_packet_pending) {
rtimer_clock_t t1;
/* Read packet */ /* Read packet */
input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN); input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
/* Save packet timestamp */ /* Save packet timestamp */
NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t)); NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
t1 = RTIMER_NOW();
/* Parse EB and attempt to associate */ /* Parse EB and attempt to associate */
LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel); 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) { if(tsch_is_associated) {
@ -864,6 +882,9 @@ PROCESS_THREAD(tsch_pending_events_process, ev, data)
tsch_rx_process_pending(); tsch_rx_process_pending();
tsch_tx_process_pending(); tsch_tx_process_pending();
tsch_log_process_pending(); tsch_log_process_pending();
#ifdef TSCH_CALLBACK_SELECT_CHANNELS
TSCH_CALLBACK_SELECT_CHANNELS();
#endif
} }
PROCESS_END(); PROCESS_END();
} }
@ -878,6 +899,12 @@ tsch_init(void)
radio_value_t radio_tx_mode; radio_value_t radio_tx_mode;
rtimer_clock_t t; 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 */ /* Radio Rx mode */
if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) { 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"); 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 */ /* Check max hopping sequence length vs default sequence length */
if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) { 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"); LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
return;
} }
/* Init the queuebuf and TSCH sub-modules */ /* Init the queuebuf and TSCH sub-modules */
@ -944,6 +972,8 @@ tsch_init(void)
#if TSCH_WITH_SIXTOP #if TSCH_WITH_SIXTOP
sixtop_init(); sixtop_init();
#endif #endif
tsch_stats_init();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ /* 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-packet.h"
#include "net/mac/tsch/tsch-security.h" #include "net/mac/tsch/tsch-security.h"
#include "net/mac/tsch/tsch-schedule.h" #include "net/mac/tsch/tsch-schedule.h"
#include "net/mac/tsch/tsch-stats.h"
#if UIP_CONF_IPV6_RPL #if UIP_CONF_IPV6_RPL
#include "net/mac/tsch/tsch-rpl.h" #include "net/mac/tsch/tsch-rpl.h"
#endif /* UIP_CONF_IPV6_RPL */ #endif /* UIP_CONF_IPV6_RPL */
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
#endif /* CONTIKI_TARGET_COOJA */
/*********** Macros *********/ /* Include Arch-Specific conf */
#ifdef TSCH_CONF_ARCH_HDR_PATH
/* Wait for a condition with timeout t0+offset. */ #include TSCH_CONF_ARCH_HDR_PATH
#if CONTIKI_TARGET_COOJA #endif /* TSCH_CONF_ARCH_HDR_PATH */
#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 */
/*********** Callbacks *********/ /*********** Callbacks *********/
@ -169,6 +157,8 @@ extern uint8_t tsch_current_channel;
/* TSCH channel hopping sequence */ /* TSCH channel hopping sequence */
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN]; extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
extern struct tsch_asn_divisor_t tsch_hopping_sequence_length; 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) */ /* TSCH timeslot timing (in rtimer ticks) */
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count]; extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
/* Statistics on the current session */ /* Statistics on the current session */
@ -177,6 +167,8 @@ extern unsigned long rx_count;
extern unsigned long sync_count; extern unsigned long sync_count;
extern int32_t min_drift_seen; extern int32_t min_drift_seen;
extern int32_t max_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 */ /* TSCH processes */
PROCESS_NAME(tsch_process); PROCESS_NAME(tsch_process);

View File

@ -272,7 +272,7 @@
#ifdef RPL_CONF_DAG_LIFETIME #ifdef RPL_CONF_DAG_LIFETIME
#define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME #define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME
#else #else
#define RPL_DAG_LIFETIME (60 * 60) /* one hour */ #define RPL_DAG_LIFETIME (8 * 60) /* 8 hours */
#endif /* RPL_CONF_DAG_LIFETIME */ #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_ #define RTIMER_H_
#include "contiki.h" #include "contiki.h"
#include "dev/watchdog.h"
#include <stdbool.h>
/** \brief The rtimer size (in bytes) */ /** \brief The rtimer size (in bytes) */
#ifdef RTIMER_CONF_CLOCK_SIZE #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) #define RTIMER_GUARD_TIME (RTIMER_ARCH_SECOND >> 14)
#endif /* RTIMER_CONF_GUARD_TIME */ #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_ */ #endif /* RTIMER_H_ */
/** @} */ /** @} */

View File

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