Merge branch 'develop' into bugfix/simplelink/board
This commit is contained in:
commit
5cecd5f9c4
@ -29,10 +29,17 @@ else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
### Use CMSIS and the existing dbg-io from arch/cpu/arm/common
|
||||
CONTIKI_ARM_DIRS += . common/dbg-io
|
||||
### Use CMSIS from arch/cpu/arm/common
|
||||
CONTIKI_ARM_DIRS += .
|
||||
CONTIKI_CPU_DIRS += $(addprefix ../arm/, $(CONTIKI_ARM_DIRS))
|
||||
|
||||
### Default to use os/lib/dbg-io unless configured to do otherwise
|
||||
MAKE_WITH_LIB_DBG_IO ?= 1
|
||||
|
||||
ifeq ($(MAKE_WITH_LIB_DBG_IO),1)
|
||||
MODULES += os/lib/dbg-io
|
||||
endif
|
||||
|
||||
### CPU-dependent cleanup files
|
||||
CLEAN += *.elf *.bin *.lst *.hex *.i16hex
|
||||
|
||||
|
@ -28,8 +28,6 @@ CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c
|
||||
CONTIKI_CPU_SOURCEFILES += i2c.c cc2538-temp-sensor.c vdd3-sensor.c
|
||||
CONTIKI_CPU_SOURCEFILES += cfs-coffee.c cfs-coffee-arch.c pwm.c
|
||||
|
||||
MODULES += os/lib/dbg-io
|
||||
|
||||
USB_SOURCEFILES += usb-core.c cdc-acm.c usb-arch.c usb-serial.c cdc-acm-descriptors.c
|
||||
|
||||
CPU_START_SOURCEFILES = startup-gcc.c
|
||||
|
@ -37,10 +37,13 @@
|
||||
#define RTIMER_ARCH_SECOND 32768
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* 352us from calling transmit() until the SFD byte has been sent */
|
||||
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352))
|
||||
#define CC2538_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(352))
|
||||
/* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */
|
||||
#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250))
|
||||
#define RADIO_DELAY_BEFORE_DETECT 0
|
||||
#define CC2538_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250))
|
||||
#define CC2538_DELAY_BEFORE_DETECT 0
|
||||
/* Frame filtering done in software */
|
||||
#define TSCH_CONF_HW_FRAME_FILTERING 0
|
||||
|
||||
#ifndef TSCH_CONF_BASE_DRIFT_PPM
|
||||
/* The drift compared to "true" 10ms slots.
|
||||
* Enable adaptive sync to enable compensation for this.
|
||||
@ -54,9 +57,6 @@
|
||||
#define TSCH_CONF_BASE_DRIFT_PPM -977
|
||||
#endif
|
||||
|
||||
#if MAC_CONF_WITH_TSCH
|
||||
#define TSCH_CONF_HW_FRAME_FILTERING 0
|
||||
#endif /* MAC_CONF_WITH_TSCH */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define SPI_CONF_CONTROLLER_COUNT 2
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "net/packetbuf.h"
|
||||
#include "net/linkaddr.h"
|
||||
#include "net/netstack.h"
|
||||
#include "net/mac/tsch/tsch.h"
|
||||
#include "sys/energest.h"
|
||||
#include "dev/cc2538-rf.h"
|
||||
#include "dev/rfcore.h"
|
||||
@ -68,13 +69,10 @@
|
||||
*/
|
||||
#define UDMA_RX_SIZE_THRESHOLD 3
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
/* Log configuration */
|
||||
#include "sys/log.h"
|
||||
#define LOG_MODULE "cc2538-rf"
|
||||
#define LOG_LEVEL LOG_LEVEL_NONE
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Local RF Flags */
|
||||
#define RX_ACTIVE 0x80
|
||||
@ -86,6 +84,7 @@
|
||||
#define LQI_BIT_MASK 0x7F
|
||||
/* RSSI Offset */
|
||||
#define RSSI_OFFSET 73
|
||||
#define RSSI_INVALID -128
|
||||
|
||||
/* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */
|
||||
#define ONOFF_TIME RTIMER_ARCH_SECOND / 3125
|
||||
@ -156,28 +155,19 @@ PROCESS(cc2538_rf_process, "cc2538 RF driver");
|
||||
static uint8_t
|
||||
get_channel()
|
||||
{
|
||||
uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ;
|
||||
|
||||
return (chan - CC2538_RF_CHANNEL_MIN) / CC2538_RF_CHANNEL_SPACING
|
||||
+ CC2538_RF_CHANNEL_MIN;
|
||||
return rf_channel;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Set the current operating channel
|
||||
* \param channel The desired channel as a value in [11,26]
|
||||
* \return Returns a value in [11,26] representing the current channel
|
||||
* or a negative value if \e channel was out of bounds
|
||||
*/
|
||||
static int8_t
|
||||
static void
|
||||
set_channel(uint8_t channel)
|
||||
{
|
||||
uint8_t was_on = 0;
|
||||
|
||||
PRINTF("RF: Set Channel\n");
|
||||
|
||||
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
|
||||
return CC2538_RF_CHANNEL_SET_ERROR;
|
||||
}
|
||||
LOG_INFO("Set Channel\n");
|
||||
|
||||
/* Changes to FREQCTRL take effect after the next recalibration */
|
||||
|
||||
@ -195,8 +185,6 @@ set_channel(uint8_t channel)
|
||||
}
|
||||
|
||||
rf_channel = channel;
|
||||
|
||||
return (int8_t)channel;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static radio_value_t
|
||||
@ -244,10 +232,11 @@ get_rssi(void)
|
||||
on();
|
||||
}
|
||||
|
||||
/* Wait on RSSI_VALID */
|
||||
while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0);
|
||||
|
||||
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
|
||||
/* Wait for a valid RSSI reading */
|
||||
do {
|
||||
rssi = REG(RFCORE_XREG_RSSI);
|
||||
} while(rssi == RSSI_INVALID);
|
||||
rssi -= RSSI_OFFSET;
|
||||
|
||||
/* If we were off, turn back off */
|
||||
if(was_off) {
|
||||
@ -322,6 +311,16 @@ set_frame_filtering(uint8_t enable)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_shr_search(int enable)
|
||||
{
|
||||
if(enable) {
|
||||
REG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_RX_MODE;
|
||||
} else {
|
||||
REG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_RX_MODE;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
mac_timer_init(void)
|
||||
{
|
||||
CLOCK_STABLE();
|
||||
@ -403,7 +402,7 @@ channel_clear(void)
|
||||
int cca;
|
||||
uint8_t was_off = 0;
|
||||
|
||||
PRINTF("RF: CCA\n");
|
||||
LOG_INFO("CCA\n");
|
||||
|
||||
/* If we are off, turn on first */
|
||||
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
||||
@ -431,7 +430,7 @@ channel_clear(void)
|
||||
static int
|
||||
on(void)
|
||||
{
|
||||
PRINTF("RF: On\n");
|
||||
LOG_INFO("On\n");
|
||||
|
||||
if(!(rf_flags & RX_ACTIVE)) {
|
||||
CC2538_RF_CSP_ISFLUSHRX();
|
||||
@ -447,7 +446,7 @@ on(void)
|
||||
static int
|
||||
off(void)
|
||||
{
|
||||
PRINTF("RF: Off\n");
|
||||
LOG_INFO("Off\n");
|
||||
|
||||
/* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */
|
||||
while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);
|
||||
@ -470,7 +469,7 @@ off(void)
|
||||
static int
|
||||
init(void)
|
||||
{
|
||||
PRINTF("RF: Init\n");
|
||||
LOG_INFO("Init\n");
|
||||
|
||||
if(rf_flags & RF_ON) {
|
||||
return 0;
|
||||
@ -490,6 +489,7 @@ init(void)
|
||||
REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */
|
||||
REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */
|
||||
REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */
|
||||
REG(RFCORE_XREG_FSCAL1) = 0x01; /** Tune frequency calibration */
|
||||
|
||||
/*
|
||||
* Defaults:
|
||||
@ -513,6 +513,9 @@ init(void)
|
||||
|
||||
set_channel(rf_channel);
|
||||
|
||||
/* Enable SHR search */
|
||||
set_shr_search(1);
|
||||
|
||||
/* Acknowledge all RF Error interrupts */
|
||||
REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM;
|
||||
NVIC_EnableIRQ(RF_ERR_IRQn);
|
||||
@ -545,8 +548,6 @@ init(void)
|
||||
|
||||
rf_flags |= RF_ON;
|
||||
|
||||
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -555,7 +556,7 @@ prepare(const void *payload, unsigned short payload_len)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN);
|
||||
LOG_INFO("Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN);
|
||||
|
||||
/*
|
||||
* When we transmit in very quick bursts, make sure previous transmission
|
||||
@ -569,12 +570,12 @@ prepare(const void *payload, unsigned short payload_len)
|
||||
|
||||
CC2538_RF_CSP_ISFLUSHTX();
|
||||
|
||||
PRINTF("RF: data = ");
|
||||
LOG_INFO("data = ");
|
||||
/* Send the phy length byte first */
|
||||
REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN;
|
||||
|
||||
if(CC2538_RF_CONF_TX_USE_DMA) {
|
||||
PRINTF("<uDMA payload>");
|
||||
LOG_INFO_("<uDMA payload>");
|
||||
|
||||
/* Set the transfer source's end address */
|
||||
udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN,
|
||||
@ -598,10 +599,10 @@ prepare(const void *payload, unsigned short payload_len)
|
||||
} else {
|
||||
for(i = 0; i < payload_len; i++) {
|
||||
REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i];
|
||||
PRINTF("%02x", ((unsigned char *)(payload))[i]);
|
||||
LOG_INFO_("%02x", ((unsigned char *)(payload))[i]);
|
||||
}
|
||||
}
|
||||
PRINTF("\n");
|
||||
LOG_INFO_("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -614,7 +615,7 @@ transmit(unsigned short transmit_len)
|
||||
rtimer_clock_t t0;
|
||||
uint8_t was_off = 0;
|
||||
|
||||
PRINTF("RF: Transmit\n");
|
||||
LOG_INFO("Transmit\n");
|
||||
|
||||
if(!(rf_flags & RX_ACTIVE)) {
|
||||
t0 = RTIMER_NOW();
|
||||
@ -649,7 +650,7 @@ transmit(unsigned short transmit_len)
|
||||
}
|
||||
|
||||
if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) {
|
||||
PRINTF("RF: TX never active.\n");
|
||||
LOG_ERR("TX never active.\n");
|
||||
CC2538_RF_CSP_ISFLUSHTX();
|
||||
ret = RADIO_TX_ERR;
|
||||
} else {
|
||||
@ -679,7 +680,7 @@ read(void *buf, unsigned short bufsize)
|
||||
uint8_t i;
|
||||
uint8_t len;
|
||||
|
||||
PRINTF("RF: Read\n");
|
||||
LOG_INFO("Read\n");
|
||||
|
||||
if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) {
|
||||
return 0;
|
||||
@ -691,33 +692,33 @@ read(void *buf, unsigned short bufsize)
|
||||
/* Check for validity */
|
||||
if(len > CC2538_RF_MAX_PACKET_LEN) {
|
||||
/* Oops, we must be out of sync. */
|
||||
PRINTF("RF: bad sync\n");
|
||||
LOG_ERR("RF: bad sync\n");
|
||||
|
||||
CC2538_RF_CSP_ISFLUSHRX();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len <= CC2538_RF_MIN_PACKET_LEN) {
|
||||
PRINTF("RF: too short\n");
|
||||
LOG_ERR("RF: too short\n");
|
||||
|
||||
CC2538_RF_CSP_ISFLUSHRX();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len - CHECKSUM_LEN > bufsize) {
|
||||
PRINTF("RF: too long\n");
|
||||
LOG_ERR("RF: too long\n");
|
||||
|
||||
CC2538_RF_CSP_ISFLUSHRX();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we reach here, chances are the FIFO is holding a valid frame */
|
||||
PRINTF("RF: read (0x%02x bytes) = ", len);
|
||||
LOG_INFO("read (0x%02x bytes) = ", len);
|
||||
len -= CHECKSUM_LEN;
|
||||
|
||||
/* Don't bother with uDMA for short frames (e.g. ACKs) */
|
||||
if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) {
|
||||
PRINTF("<uDMA payload>");
|
||||
LOG_INFO_("<uDMA payload>");
|
||||
|
||||
/* Set the transfer destination's end address */
|
||||
udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN,
|
||||
@ -738,7 +739,7 @@ read(void *buf, unsigned short bufsize)
|
||||
} else {
|
||||
for(i = 0; i < len; ++i) {
|
||||
((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA);
|
||||
PRINTF("%02x", ((unsigned char *)(buf))[i]);
|
||||
LOG_INFO_("%02x", ((unsigned char *)(buf))[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,14 +747,14 @@ read(void *buf, unsigned short bufsize)
|
||||
rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET;
|
||||
crc_corr = REG(RFCORE_SFR_RFDATA);
|
||||
|
||||
PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr);
|
||||
LOG_INFO_("%02x%02x\n", (uint8_t)rssi, crc_corr);
|
||||
|
||||
/* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
|
||||
if(crc_corr & CRC_BIT_MASK) {
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
|
||||
} else {
|
||||
PRINTF("RF: Bad CRC\n");
|
||||
LOG_ERR("Bad CRC\n");
|
||||
CC2538_RF_CSP_ISFLUSHRX();
|
||||
return 0;
|
||||
}
|
||||
@ -775,7 +776,7 @@ read(void *buf, unsigned short bufsize)
|
||||
static int
|
||||
receiving_packet(void)
|
||||
{
|
||||
PRINTF("RF: Receiving\n");
|
||||
LOG_INFO("Receiving\n");
|
||||
|
||||
/*
|
||||
* SFD high while transmitting and receiving.
|
||||
@ -791,7 +792,7 @@ receiving_packet(void)
|
||||
static int
|
||||
pending_packet(void)
|
||||
{
|
||||
PRINTF("RF: Pending\n");
|
||||
LOG_INFO("Pending\n");
|
||||
|
||||
return REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP;
|
||||
}
|
||||
@ -862,6 +863,21 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||
case RADIO_CONST_TXPOWER_MAX:
|
||||
*value = OUTPUT_POWER_MAX;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_PHY_OVERHEAD:
|
||||
*value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_BYTE_AIR_TIME:
|
||||
*value = (radio_value_t)32; /* 250kbps data rate. One byte = 32us.*/
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_DELAY_BEFORE_TX:
|
||||
*value = (radio_value_t)CC2538_DELAY_BEFORE_TX;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_DELAY_BEFORE_RX:
|
||||
*value = (radio_value_t)CC2538_DELAY_BEFORE_RX;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_DELAY_BEFORE_DETECT:
|
||||
*value = (radio_value_t)CC2538_DELAY_BEFORE_DETECT;
|
||||
return RADIO_RESULT_OK;
|
||||
default:
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
@ -886,9 +902,7 @@ set_value(radio_param_t param, radio_value_t value)
|
||||
value > CC2538_RF_CHANNEL_MAX) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
if(set_channel(value) == CC2538_RF_CHANNEL_SET_ERROR) {
|
||||
return RADIO_RESULT_ERROR;
|
||||
}
|
||||
set_channel(value);
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_PAN_ID:
|
||||
set_pan_id(value & 0xffff);
|
||||
@ -924,6 +938,9 @@ set_value(radio_param_t param, radio_value_t value)
|
||||
case RADIO_PARAM_CCA_THRESHOLD:
|
||||
set_cca_threshold(value);
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_SHR_SEARCH:
|
||||
set_shr_search(value);
|
||||
return RADIO_RESULT_OK;
|
||||
default:
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
@ -956,6 +973,16 @@ get_object(radio_param_t param, void *dest, size_t size)
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
|
||||
#if MAC_CONF_WITH_TSCH
|
||||
if(param == RADIO_CONST_TSCH_TIMING) {
|
||||
if(size != sizeof(uint16_t *) || !dest) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
*(const uint16_t **)dest = tsch_timeslot_timing_us_10000;
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
#endif /* MAC_CONF_WITH_TSCH */
|
||||
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -1085,7 +1112,7 @@ cc2538_rf_rx_tx_isr(void)
|
||||
void
|
||||
cc2538_rf_err_isr(void)
|
||||
{
|
||||
PRINTF("RF Error: 0x%08lx\n", REG(RFCORE_SFR_RFERRF));
|
||||
LOG_ERR("Error 0x%08lx occurred\n", REG(RFCORE_SFR_RFERRF));
|
||||
|
||||
/* If the error is not an RX FIFO overflow, set a flag */
|
||||
if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) {
|
||||
@ -1097,10 +1124,5 @@ cc2538_rf_err_isr(void)
|
||||
process_poll(&cc2538_rf_process);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
cc2538_rf_set_promiscous_mode(char p)
|
||||
{
|
||||
set_frame_filtering(p);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/** @} */
|
||||
|
@ -56,7 +56,6 @@
|
||||
#define CC2538_RF_CHANNEL_MIN 11
|
||||
#define CC2538_RF_CHANNEL_MAX 26
|
||||
#define CC2538_RF_CHANNEL_SPACING 5
|
||||
#define CC2538_RF_CHANNEL_SET_ERROR -1
|
||||
#define CC2538_RF_MAX_PACKET_LEN 127
|
||||
#define CC2538_RF_MIN_PACKET_LEN 4
|
||||
#define CC2538_RF_CCA_CLEAR 1
|
||||
@ -113,7 +112,6 @@
|
||||
*/
|
||||
#define CC2538_RF_CSP_ISFLUSHRX() do { \
|
||||
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
|
||||
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHRX; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
@ -121,7 +119,6 @@
|
||||
*/
|
||||
#define CC2538_RF_CSP_ISFLUSHTX() do { \
|
||||
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
|
||||
REG(RFCORE_SFR_RFST) = CC2538_RF_CSP_OP_ISFLUSHTX; \
|
||||
} while(0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** The NETSTACK data structure for the cc2538 RF driver */
|
||||
@ -138,16 +135,6 @@ extern const struct radio_driver cc2538_rf_driver;
|
||||
*/
|
||||
void cc2538_rf_set_addr(uint16_t pan);
|
||||
|
||||
/**
|
||||
* \brief Turn promiscous mode on or off
|
||||
* \param p If promiscous mode should be on (1) or off (0)
|
||||
*
|
||||
* This function turns promiscous mode on or off. In promiscous mode,
|
||||
* every received frame is returned from the RF core. In
|
||||
* non-promiscous mode, only broadcast frames or frames with our
|
||||
* address as the receive address are returned from the RF core.
|
||||
*/
|
||||
void cc2538_rf_set_promiscous_mode(char p);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* CC2538_RF_H__ */
|
||||
|
||||
|
@ -107,7 +107,7 @@ static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = {
|
||||
|
||||
typedef struct spi_locks_s {
|
||||
mutex_t lock;
|
||||
spi_device_t *owner;
|
||||
const spi_device_t *owner;
|
||||
} spi_locks_t;
|
||||
|
||||
/* One lock per SPI controller */
|
||||
@ -115,40 +115,40 @@ spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKE
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
spix_wait_tx_ready(spi_device_t *dev)
|
||||
spix_wait_tx_ready(const spi_device_t *dev)
|
||||
{
|
||||
/* Infinite loop until SR_TNF - Transmit FIFO Not Full */
|
||||
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
spix_read_buf(spi_device_t *dev)
|
||||
spix_read_buf(const spi_device_t *dev)
|
||||
{
|
||||
return REG(spi_regs[dev->spi_controller].base + SSI_DR);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
spix_write_buf(spi_device_t *dev, int data)
|
||||
spix_write_buf(const spi_device_t *dev, int data)
|
||||
{
|
||||
REG(spi_regs[dev->spi_controller].base + SSI_DR) = data;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
spix_wait_eotx(spi_device_t *dev)
|
||||
spix_wait_eotx(const spi_device_t *dev)
|
||||
{
|
||||
/* wait until not busy */
|
||||
while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
spix_wait_eorx(spi_device_t *dev)
|
||||
spix_wait_eorx(const spi_device_t *dev)
|
||||
{
|
||||
/* wait as long as receive is empty */
|
||||
while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_has_lock(spi_device_t *dev)
|
||||
spi_arch_has_lock(const spi_device_t *dev)
|
||||
{
|
||||
if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
|
||||
return true;
|
||||
@ -158,7 +158,7 @@ spi_arch_has_lock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
spi_arch_is_bus_locked(const spi_device_t *dev)
|
||||
{
|
||||
if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
|
||||
return true;
|
||||
@ -168,7 +168,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_lock_and_open(spi_device_t *dev)
|
||||
spi_arch_lock_and_open(const spi_device_t *dev)
|
||||
{
|
||||
const spi_regs_t *regs;
|
||||
uint32_t scr;
|
||||
@ -265,7 +265,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
spi_arch_close_and_unlock(const spi_device_t *dev)
|
||||
{
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
return SPI_DEV_STATUS_BUS_NOT_OWNED;
|
||||
@ -282,7 +282,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_select(spi_device_t *dev)
|
||||
spi_arch_select(const spi_device_t *dev)
|
||||
{
|
||||
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
@ -295,7 +295,7 @@ spi_arch_select(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_deselect(spi_device_t *dev)
|
||||
spi_arch_deselect(const spi_device_t *dev)
|
||||
{
|
||||
SPIX_CS_SET(PIN_TO_PORT(dev->pin_spi_cs), PIN_TO_NUM(dev->pin_spi_cs));
|
||||
|
||||
@ -304,7 +304,7 @@ spi_arch_deselect(spi_device_t *dev)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Assumes that checking dev and bus is not NULL before calling this */
|
||||
spi_status_t
|
||||
spi_arch_transfer(spi_device_t *dev,
|
||||
spi_arch_transfer(const spi_device_t *dev,
|
||||
const uint8_t *write_buf, int wlen,
|
||||
uint8_t *inbuf, int rlen, int ignore_len)
|
||||
{
|
||||
|
@ -45,8 +45,6 @@ CONTIKI_CPU_SOURCEFILES += ble-cc2650.c ble-hal-cc26xx.c ble-addr.c rf-ble-cmd.c
|
||||
CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c
|
||||
CONTIKI_CPU_SOURCEFILES += spi-arch.c
|
||||
|
||||
MODULES += os/lib/dbg-io
|
||||
|
||||
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES)
|
||||
|
||||
CPU_START_SOURCEFILES += fault-handlers.c $(TI_XXWARE_STARTUP_SRCS)
|
||||
|
@ -36,6 +36,10 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* TSCH related defines */
|
||||
|
||||
/* 1 len byte, 2 bytes CRC */
|
||||
#define RADIO_PHY_OVERHEAD 3
|
||||
/* 250kbps data rate. One byte = 32us */
|
||||
#define RADIO_BYTE_AIR_TIME 32
|
||||
/* Delay between GO signal and SFD */
|
||||
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
|
||||
/* Delay between GO signal and start listening.
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
typedef struct spi_locks_s {
|
||||
mutex_t lock;
|
||||
spi_device_t *owner;
|
||||
const spi_device_t *owner;
|
||||
} spi_locks_t;
|
||||
|
||||
/* One lock per SPI controller */
|
||||
@ -68,7 +68,7 @@ static const board_spi_controller_t spi_controller[SPI_CONTROLLER_COUNT] = {
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_has_lock(spi_device_t *dev)
|
||||
spi_arch_has_lock(const spi_device_t *dev)
|
||||
{
|
||||
if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
|
||||
return true;
|
||||
@ -78,7 +78,7 @@ spi_arch_has_lock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
spi_arch_is_bus_locked(const spi_device_t *dev)
|
||||
{
|
||||
if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
|
||||
return true;
|
||||
@ -88,7 +88,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint32_t
|
||||
get_mode(spi_device_t *dev)
|
||||
get_mode(const spi_device_t *dev)
|
||||
{
|
||||
/* Select the correct SPI mode */
|
||||
if(dev->spi_pha == 0 && dev->spi_pol == 0) {
|
||||
@ -103,7 +103,7 @@ get_mode(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_lock_and_open(spi_device_t *dev)
|
||||
spi_arch_lock_and_open(const spi_device_t *dev)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
@ -152,7 +152,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
spi_arch_close_and_unlock(const spi_device_t *dev)
|
||||
{
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
return SPI_DEV_STATUS_BUS_NOT_OWNED;
|
||||
@ -181,7 +181,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_transfer(spi_device_t *dev,
|
||||
spi_arch_transfer(const spi_device_t *dev,
|
||||
const uint8_t *write_buf, int wlen,
|
||||
uint8_t *inbuf, int rlen, int ignore_len)
|
||||
{
|
||||
@ -231,7 +231,7 @@ spi_arch_transfer(spi_device_t *dev,
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_select(spi_device_t *dev)
|
||||
spi_arch_select(const spi_device_t *dev)
|
||||
{
|
||||
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
@ -243,7 +243,7 @@ spi_arch_select(spi_device_t *dev)
|
||||
return SPI_DEV_STATUS_OK;
|
||||
}
|
||||
spi_status_t
|
||||
spi_arch_deselect(spi_device_t *dev)
|
||||
spi_arch_deselect(const spi_device_t *dev)
|
||||
{
|
||||
ti_lib_gpio_set_dio(dev->pin_spi_cs);
|
||||
|
||||
|
@ -91,9 +91,6 @@ SDK_DEVICES := $(CORE_SDK)/source/ti/devices/$(SDK_DEVICES_NAME)
|
||||
|
||||
EXTERNALDIRS += $(SDK_SOURCE) $(SDK_NORTOS)
|
||||
|
||||
# CPU-dependent debug source files
|
||||
MODULES += os/lib/dbg-io
|
||||
|
||||
# CPU-dependent directories
|
||||
CONTIKI_CPU_DIRS += . dev $(SUBFAMILY)
|
||||
CONTIKI_CPU_DIRS += rf rf-settings rf-settings/$(DEVICE_FAMILY_LC)
|
||||
|
@ -57,6 +57,10 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* TSCH related defines */
|
||||
|
||||
/* 1 len byte, 2 bytes CRC */
|
||||
#define RADIO_PHY_OVERHEAD 3
|
||||
/* 250kbps data rate. One byte = 32us */
|
||||
#define RADIO_BYTE_AIR_TIME 32
|
||||
/* Delay between GO signal and SFD */
|
||||
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
|
||||
/* Delay between GO signal and start listening.
|
||||
|
@ -54,7 +54,7 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
SPI_Handle handle;
|
||||
spi_device_t *owner;
|
||||
const spi_device_t *owner;
|
||||
} spi_arch_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if (SPI_CONTROLLER_COUNT > 0)
|
||||
@ -96,7 +96,7 @@ convert_frame_format(uint8_t pol, uint8_t pha)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_has_lock(spi_device_t *dev)
|
||||
spi_arch_has_lock(const spi_device_t *dev)
|
||||
{
|
||||
/*
|
||||
* The SPI device is the owner if the SPI controller returns a valid
|
||||
@ -107,7 +107,7 @@ spi_arch_has_lock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
spi_arch_is_bus_locked(const spi_device_t *dev)
|
||||
{
|
||||
/*
|
||||
* The SPI controller is locked by any device if the SPI controller returns
|
||||
@ -118,7 +118,7 @@ spi_arch_is_bus_locked(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_lock_and_open(spi_device_t *dev)
|
||||
spi_arch_lock_and_open(const spi_device_t *dev)
|
||||
{
|
||||
uint_least8_t spi_index;
|
||||
spi_arch_t *spi_arch;
|
||||
@ -167,7 +167,7 @@ spi_arch_lock_and_open(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
spi_arch_close_and_unlock(const spi_device_t *dev)
|
||||
{
|
||||
spi_arch_t *spi_arch;
|
||||
|
||||
@ -196,7 +196,7 @@ spi_arch_close_and_unlock(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_transfer(spi_device_t *dev,
|
||||
spi_arch_transfer(const spi_device_t *dev,
|
||||
const uint8_t *write_buf, int wlen,
|
||||
uint8_t *inbuf, int rlen, int ignore_len)
|
||||
{
|
||||
@ -236,7 +236,7 @@ spi_arch_transfer(spi_device_t *dev,
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_select(spi_device_t *dev)
|
||||
spi_arch_select(const spi_device_t *dev)
|
||||
{
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
return SPI_DEV_STATUS_BUS_NOT_OWNED;
|
||||
@ -248,7 +248,7 @@ spi_arch_select(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_arch_deselect(spi_device_t *dev)
|
||||
spi_arch_deselect(const spi_device_t *dev)
|
||||
{
|
||||
if(!spi_arch_has_lock(dev)) {
|
||||
return SPI_DEV_STATUS_BUS_NOT_OWNED;
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "cc1200-rf-cfg.h"
|
||||
#include "cc1200-const.h"
|
||||
#include "net/mac/tsch/tsch.h"
|
||||
|
||||
/*
|
||||
* This is a setup for the following configuration:
|
||||
@ -62,6 +63,52 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const char rf_cfg_descriptor[] = "802.15.4g 863-870MHz MR-FSK mode #1";
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* 1 byte time: 160 usec */
|
||||
#define CC1200_TSCH_PREAMBLE_LENGTH 800 /* 5 bytes */
|
||||
#define CC1200_TSCH_CONF_RX_WAIT 2200
|
||||
#define CC1200_TSCH_CONF_RX_ACK_WAIT 400
|
||||
|
||||
#define CC1200_TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||
#define CC1200_TSCH_DEFAULT_TS_CCA 128
|
||||
|
||||
#define CC1200_TSCH_DEFAULT_TS_TX_OFFSET 3800
|
||||
#define CC1200_TSCH_DEFAULT_TS_RX_OFFSET (CC1200_TSCH_DEFAULT_TS_TX_OFFSET - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_WAIT / 2))
|
||||
#define CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY (CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY - CC1200_TSCH_PREAMBLE_LENGTH - (CC1200_TSCH_CONF_RX_ACK_WAIT / 2))
|
||||
#define CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY 3000
|
||||
|
||||
#define CC1200_TSCH_DEFAULT_TS_RX_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_WAIT)
|
||||
#define CC1200_TSCH_DEFAULT_TS_ACK_WAIT (CC1200_TSCH_PREAMBLE_LENGTH + CC1200_TSCH_CONF_RX_ACK_WAIT)
|
||||
#define CC1200_TSCH_DEFAULT_TS_RX_TX 192
|
||||
#define CC1200_TSCH_DEFAULT_TS_MAX_ACK 3360 /* 17+1+3 bytes at 50 kbps */
|
||||
#define CC1200_TSCH_DEFAULT_TS_MAX_TX 20800 /* 126+1+3 bytes at 50 kbps */
|
||||
|
||||
#define CC1200_TSCH_DEFAULT_SLACK_TIME 500
|
||||
/* Timeslot length: 31460 usec */
|
||||
#define CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH \
|
||||
( CC1200_TSCH_DEFAULT_TS_TX_OFFSET \
|
||||
+ CC1200_TSCH_DEFAULT_TS_MAX_TX \
|
||||
+ CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY \
|
||||
+ CC1200_TSCH_DEFAULT_TS_MAX_ACK \
|
||||
+ CC1200_TSCH_DEFAULT_SLACK_TIME \
|
||||
)
|
||||
|
||||
/* TSCH timeslot timing (mircoseconds) */
|
||||
static const uint16_t cc1200_50kbps_tsch_timing[tsch_ts_elements_count] = {
|
||||
CC1200_TSCH_DEFAULT_TS_CCA_OFFSET,
|
||||
CC1200_TSCH_DEFAULT_TS_CCA,
|
||||
CC1200_TSCH_DEFAULT_TS_TX_OFFSET,
|
||||
CC1200_TSCH_DEFAULT_TS_RX_OFFSET,
|
||||
CC1200_TSCH_DEFAULT_TS_RX_ACK_DELAY,
|
||||
CC1200_TSCH_DEFAULT_TS_TX_ACK_DELAY,
|
||||
CC1200_TSCH_DEFAULT_TS_RX_WAIT,
|
||||
CC1200_TSCH_DEFAULT_TS_ACK_WAIT,
|
||||
CC1200_TSCH_DEFAULT_TS_RX_TX,
|
||||
CC1200_TSCH_DEFAULT_TS_MAX_ACK,
|
||||
CC1200_TSCH_DEFAULT_TS_MAX_TX,
|
||||
CC1200_TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
|
||||
};
|
||||
|
||||
/*
|
||||
* Register settings exported from SmartRF Studio using the standard template
|
||||
* "trxEB RF Settings Performance Line".
|
||||
@ -159,6 +206,11 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = {
|
||||
.size_of_register_settings = sizeof(preferredSettings),
|
||||
.tx_pkt_lifetime = (RTIMER_SECOND / 20),
|
||||
.tx_rx_turnaround = (RTIMER_SECOND / 100),
|
||||
/* Includes 3 Bytes preamble + 2 Bytes SFD, at 160usec per byte = 800 usec */
|
||||
/* Includes time to completion of "Wait for TX to start" if cc1200.c: 397 usec */
|
||||
.delay_before_tx = ((unsigned)US_TO_RTIMERTICKS(800 + 397 + 423)),
|
||||
.delay_before_rx = (unsigned)US_TO_RTIMERTICKS(400),
|
||||
.delay_before_detect = 0,
|
||||
.chan_center_freq0 = RF_CFG_CHAN_CENTER_F0,
|
||||
.chan_spacing = RF_CFG_CHAN_SPACING,
|
||||
.min_channel = RF_CFG_MIN_CHANNEL,
|
||||
@ -166,5 +218,7 @@ const cc1200_rf_cfg_t cc1200_802154g_863_870_fsk_50kbps = {
|
||||
.max_txpower = RF_CFG_MAX_TXPOWER,
|
||||
.cca_threshold = RF_CFG_CCA_THRESHOLD,
|
||||
.rssi_offset = RF_CFG_RSSI_OFFSET,
|
||||
.bitrate = 50000,
|
||||
.tsch_timing = cc1200_50kbps_tsch_timing,
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
176
arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c
Normal file
176
arch/dev/cc1200/cc1200-868-4gfsk-1000kbps.c
Normal 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,
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
@ -126,6 +126,9 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = {
|
||||
.size_of_register_settings = sizeof(preferredSettings),
|
||||
.tx_pkt_lifetime = (2 * RTIMER_SECOND),
|
||||
.tx_rx_turnaround = (RTIMER_SECOND / 2),
|
||||
.delay_before_tx = 0,
|
||||
.delay_before_rx = 0,
|
||||
.delay_before_detect = 0,
|
||||
.chan_center_freq0 = RF_CFG_CHAN_CENTER_F0,
|
||||
.chan_spacing = RF_CFG_CHAN_SPACING,
|
||||
.min_channel = RF_CFG_MIN_CHANNEL,
|
||||
@ -133,5 +136,7 @@ const cc1200_rf_cfg_t cc1200_868_fsk_1_2kbps = {
|
||||
.max_txpower = RF_CFG_MAX_TXPOWER,
|
||||
.cca_threshold = RF_CFG_CCA_THRESHOLD,
|
||||
.rssi_offset = RF_CFG_RSSI_OFFSET,
|
||||
.bitrate = 1200,
|
||||
.tsch_timing = NULL,
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -69,6 +69,13 @@ typedef struct cc1200_rf_cfg {
|
||||
rtimer_clock_t tx_pkt_lifetime;
|
||||
/* The maximum time it takes to switch from Tx to Rx */
|
||||
rtimer_clock_t tx_rx_turnaround;
|
||||
/* The delay between a call to transmit() and end of SFD */
|
||||
rtimer_clock_t delay_before_tx;
|
||||
/* Delay between GO signal and start listening
|
||||
* Measured 104us: between GO signal and start listening */
|
||||
rtimer_clock_t delay_before_rx;
|
||||
/* Delay between the SFD finishes arriving and it is detected in software */
|
||||
rtimer_clock_t delay_before_detect;
|
||||
/* Base frequency in kHz */
|
||||
uint32_t chan_center_freq0;
|
||||
/* Channel spacing in Hz */
|
||||
@ -87,6 +94,10 @@ typedef struct cc1200_rf_cfg {
|
||||
/* The RSSI offset in dBm.
|
||||
* -99 when MDMCFG1.DVGA_GAIN=00, -81 when MDMCFG1.DVGA_GAIN=01 */
|
||||
int8_t rssi_offset;
|
||||
/* The bitrate in bps */
|
||||
uint32_t bitrate;
|
||||
/* TSCH timeslot timing */
|
||||
const uint16_t *tsch_timing;
|
||||
} cc1200_rf_cfg_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* CC1200_RF_CFG_H */
|
||||
|
@ -47,6 +47,9 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int16_t rssi;
|
||||
static rtimer_clock_t sfd_timestamp = 0;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Various implementation specific defines */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -57,7 +60,7 @@
|
||||
* - 2: Print errors + warnings (recoverable errors)
|
||||
* - 3: Print errors + warnings + information (what's going on...)
|
||||
*/
|
||||
#define DEBUG_LEVEL 2
|
||||
#define DEBUG_LEVEL 0
|
||||
/*
|
||||
* RF test mode. Blocks inside "configure()".
|
||||
* - Set this parameter to 1 in order to produce an modulated carrier (PN9)
|
||||
@ -79,6 +82,14 @@
|
||||
#define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* When set, a software buffer is used to store outgoing packets before copying
|
||||
* to Tx FIFO. This enabled sending packets larger than the FIFO. When unset,
|
||||
* no buffer is used; instead, the payload is copied directly to the Tx FIFO.
|
||||
* This is requried by TSCH, for shorter and more predictable delay in the Tx
|
||||
* chain. This, however, restircts the payload length to the Tx FIFO size.
|
||||
*/
|
||||
#define CC1200_WITH_TX_BUF (!MAC_CONF_WITH_TSCH)
|
||||
/*
|
||||
* Set this parameter to 1 in order to use the MARC_STATE register when
|
||||
* polling the chips's status. Else use the status byte returned when sending
|
||||
@ -93,7 +104,11 @@
|
||||
*
|
||||
* TODO: Option to be removed upon approval of the driver
|
||||
*/
|
||||
#if MAC_CONF_WITH_TSCH
|
||||
#define USE_SFSTXON 0
|
||||
#else /* MAC_CONF_WITH_TSCH */
|
||||
#define USE_SFSTXON 1
|
||||
#endif /* MAC_CONF_WITH_TSCH */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Phy header length */
|
||||
#if CC1200_802154G
|
||||
@ -133,7 +148,15 @@
|
||||
/* Use GPIO2 as RX / TX FIFO threshold indicator pin */
|
||||
#define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR
|
||||
/* This is the FIFO threshold we use */
|
||||
#if MAC_CONF_WITH_TSCH
|
||||
#if CC1200_802154G
|
||||
#define FIFO_THRESHOLD 1
|
||||
#else
|
||||
#define FIFO_THRESHOLD 0
|
||||
#endif
|
||||
#else /* MAC_CONF_WITH_TSCH */
|
||||
#define FIFO_THRESHOLD 32
|
||||
#endif /* MAC_CONF_WITH_TSCH */
|
||||
/* Turn on RX after packet reception */
|
||||
#define RXOFF_MODE_RX 1
|
||||
/* Let the CC1200 append RSSI + LQI */
|
||||
@ -249,6 +272,8 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
|
||||
#define RF_UPDATE_CHANNEL 0x10
|
||||
/* SPI was locked when calling RX interrupt, let the pollhandler do the job */
|
||||
#define RF_POLL_RX_INTERRUPT 0x20
|
||||
/* Ongoing reception */
|
||||
#define RF_RX_ONGOING 0x40
|
||||
/* Force calibration in case we don't use CC1200 AUTOCAL + timeout */
|
||||
#if !CC1200_AUTOCAL
|
||||
#if CC1200_CAL_TIMEOUT_SECONDS
|
||||
@ -285,15 +310,7 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
|
||||
#define LOCK_SPI() do { spi_locked++; } while(0)
|
||||
#define SPI_IS_LOCKED() (spi_locked != 0)
|
||||
#define RELEASE_SPI() do { spi_locked--; } while(0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define BUSYWAIT_UNTIL(cond, max_time) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \
|
||||
watchdog_periodic(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if CC1200_USE_GPIO2
|
||||
/* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */
|
||||
@ -353,38 +370,22 @@ extern const cc1200_rf_cfg_t CC1200_RF_CFG;
|
||||
#define INFO(...)
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
/*
|
||||
* As BUSYWAIT_UNTIL was mainly used to test for a state transition,
|
||||
* we define a separate macro for this adding the possibility to
|
||||
* throw an error message when the timeout exceeds
|
||||
*/
|
||||
#define BUSYWAIT_UNTIL_STATE(s, t) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \
|
||||
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t)))) { \
|
||||
printf("RF: Timeout exceeded in line %d!\n", __LINE__); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define BUSYWAIT_UNTIL_STATE(s, t) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while((state() != s) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (t))) {} \
|
||||
} while(0)
|
||||
#endif
|
||||
/* Busy-wait (time-bounded) until the radio reaches a given state */
|
||||
#define RTIMER_BUSYWAIT_UNTIL_STATE(s, t) RTIMER_BUSYWAIT_UNTIL(state() == (s), t)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Variables */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Flag indicating whether non-interrupt routines are using SPI */
|
||||
static volatile uint8_t spi_locked = 0;
|
||||
#if CC1200_WITH_TX_BUF
|
||||
/* Packet buffer for transmission, filled within prepare() */
|
||||
static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN];
|
||||
#endif /* CC1200_WITH_TX_BUF */
|
||||
/* The number of bytes waiting in tx_pkt */
|
||||
static uint16_t tx_pkt_len;
|
||||
/* Number of bytes from tx_pkt left to write to FIFO */
|
||||
uint16_t bytes_left_to_write;
|
||||
/* Packet buffer for reception */
|
||||
static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
|
||||
/* The number of bytes placed in rx_pkt */
|
||||
@ -422,6 +423,9 @@ static struct etimer et;
|
||||
/* Init the radio. */
|
||||
static int
|
||||
init(void);
|
||||
/* Prepare and copy PHY header to Tx FIFO */
|
||||
static int
|
||||
copy_header_to_tx_fifo(unsigned short payload_len);
|
||||
/* Prepare the radio with a packet to be sent. */
|
||||
static int
|
||||
prepare(const void *payload, unsigned short payload_len);
|
||||
@ -530,7 +534,7 @@ idle_calibrate_rx(void);
|
||||
/* Restart RX from within RX interrupt. */
|
||||
static void
|
||||
rx_rx(void);
|
||||
/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */
|
||||
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
|
||||
static int
|
||||
idle_tx_rx(const uint8_t *payload, uint16_t payload_len);
|
||||
/* Update TX power */
|
||||
@ -572,7 +576,7 @@ PROCESS_THREAD(cc1200_process, ev, data)
|
||||
/*
|
||||
* We are on and not in TX. As every function of this driver
|
||||
* assures that we are in RX mode
|
||||
* (using BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in
|
||||
* (using RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in
|
||||
* either rx_rx(), idle_calibrate_rx() or transmit(),
|
||||
* something probably went wrong in the rx interrupt handler
|
||||
* if we are not in RX at this point.
|
||||
@ -624,7 +628,7 @@ pollhandler(void)
|
||||
set_channel(new_rf_channel);
|
||||
}
|
||||
|
||||
if(rx_pkt_len > 0) {
|
||||
if((rx_mode_value & RADIO_RX_MODE_POLL_MODE) == 0 && rx_pkt_len > 0) {
|
||||
|
||||
int len;
|
||||
|
||||
@ -722,10 +726,67 @@ prepare(const void *payload, unsigned short payload_len)
|
||||
}
|
||||
|
||||
tx_pkt_len = payload_len;
|
||||
|
||||
#if CC1200_WITH_TX_BUF
|
||||
/* Copy payload to buffer, will be sent later */
|
||||
memcpy(tx_pkt, payload, tx_pkt_len);
|
||||
#else /* CC1200_WITH_TX_BUF */
|
||||
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
|
||||
#error CC1200 max payload too large
|
||||
#else
|
||||
/* Copy header and payload directly to Radio Tx FIFO (127 bytes max) */
|
||||
copy_header_to_tx_fifo(payload_len);
|
||||
burst_write(CC1200_TXFIFO, payload, payload_len);
|
||||
#endif
|
||||
#endif /* CC1200_WITH_TX_BUF */
|
||||
|
||||
return RADIO_TX_OK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Prepare the radio with a packet to be sent. */
|
||||
static int
|
||||
copy_header_to_tx_fifo(unsigned short payload_len)
|
||||
{
|
||||
#if CC1200_802154G
|
||||
/* Prepare PHR for 802.15.4g frames */
|
||||
struct {
|
||||
uint8_t phra;
|
||||
uint8_t phrb;
|
||||
} phr;
|
||||
#if CC1200_802154G_CRC16
|
||||
payload_len += 2;
|
||||
#else
|
||||
payload_len += 4;
|
||||
#endif
|
||||
/* Frame length */
|
||||
phr.phrb = (uint8_t)(payload_len & 0x00FF);
|
||||
phr.phra = (uint8_t)((payload_len >> 8) & 0x0007);
|
||||
#if CC1200_802154G_WHITENING
|
||||
/* Enable Whitening */
|
||||
phr.phra |= (1 << 3);
|
||||
#endif /* #if CC1200_802154G_WHITENING */
|
||||
#if CC1200_802154G_CRC16
|
||||
/* FCS type 1, 2 Byte CRC */
|
||||
phr.phra |= (1 << 4);
|
||||
#endif /* #if CC1200_802154G_CRC16 */
|
||||
#endif /* #if CC1200_802154G */
|
||||
|
||||
idle();
|
||||
|
||||
rf_flags &= ~RF_RX_PROCESSING_PKT;
|
||||
strobe(CC1200_SFRX);
|
||||
/* Flush TX FIFO */
|
||||
strobe(CC1200_SFTX);
|
||||
|
||||
#if CC1200_802154G
|
||||
/* Write PHR */
|
||||
burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN);
|
||||
#else
|
||||
/* Write length byte */
|
||||
burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN);
|
||||
#endif /* #if CC1200_802154G */
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Send the packet that has previously been prepared. */
|
||||
@ -735,6 +796,7 @@ transmit(unsigned short transmit_len)
|
||||
|
||||
uint8_t was_off = 0;
|
||||
int ret = RADIO_TX_OK;
|
||||
int txret;
|
||||
|
||||
INFO("RF: Transmit (%d)\n", transmit_len);
|
||||
|
||||
@ -790,7 +852,12 @@ transmit(unsigned short transmit_len)
|
||||
#endif
|
||||
|
||||
/* Send data using TX FIFO */
|
||||
if(idle_tx_rx((const uint8_t *)tx_pkt, tx_pkt_len) == RADIO_TX_OK) {
|
||||
#if CC1200_WITH_TX_BUF
|
||||
txret = idle_tx_rx(tx_pkt, tx_pkt_len);
|
||||
#else /* CC1200_WITH_TX_BUF */
|
||||
txret = idle_tx_rx(NULL, tx_pkt_len);
|
||||
#endif /* CC1200_WITH_TX_BUF */
|
||||
if(txret == RADIO_TX_OK) {
|
||||
|
||||
/*
|
||||
* TXOFF_MODE is set to RX,
|
||||
@ -798,7 +865,7 @@ transmit(unsigned short transmit_len)
|
||||
* again as they were turned off in idle()
|
||||
*/
|
||||
|
||||
BUSYWAIT_UNTIL_STATE(STATE_RX,
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX,
|
||||
CC1200_RF_CFG.tx_rx_turnaround);
|
||||
|
||||
ENABLE_GPIO_INTERRUPTS();
|
||||
@ -861,7 +928,7 @@ read(void *buf, unsigned short buf_len)
|
||||
|
||||
if(rx_pkt_len > 0) {
|
||||
|
||||
int8_t rssi = rx_pkt[rx_pkt_len - 2];
|
||||
rssi = (int8_t)rx_pkt[rx_pkt_len - 2] + (int)CC1200_RF_CFG.rssi_offset;
|
||||
/* CRC is already checked */
|
||||
uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1];
|
||||
|
||||
@ -938,7 +1005,7 @@ channel_clear(void)
|
||||
}
|
||||
|
||||
/* Wait for CARRIER_SENSE_VALID signal */
|
||||
BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
|
||||
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
|
||||
& CC1200_CARRIER_SENSE_VALID),
|
||||
RTIMER_SECOND / 100);
|
||||
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
|
||||
@ -1009,9 +1076,16 @@ receiving_packet(void)
|
||||
static int
|
||||
pending_packet(void)
|
||||
{
|
||||
int ret;
|
||||
ret = ((rx_pkt_len != 0) ? 1 : 0);
|
||||
if(ret == 0 && !SPI_IS_LOCKED()) {
|
||||
LOCK_SPI();
|
||||
ret = (single_read(CC1200_NUM_RXBYTES) > 0);
|
||||
RELEASE_SPI();
|
||||
}
|
||||
|
||||
INFO("RF: Pending (%d)\n", ((rx_pkt_len != 0) ? 1 : 0));
|
||||
return (rx_pkt_len != 0) ? 1 : 0;
|
||||
INFO("RF: Pending (%d)\n", ret);
|
||||
return ret;
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -1033,11 +1107,12 @@ on(void)
|
||||
|
||||
/* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */
|
||||
cc1200_arch_spi_select();
|
||||
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
RTIMER_SECOND / 100);
|
||||
RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0));
|
||||
cc1200_arch_spi_deselect();
|
||||
|
||||
rf_flags = RF_INITIALIZED;
|
||||
rf_flags |= RF_ON;
|
||||
|
||||
/* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */
|
||||
@ -1080,6 +1155,16 @@ off(void)
|
||||
|
||||
idle();
|
||||
|
||||
if(single_read(CC1200_NUM_RXBYTES) > 0) {
|
||||
RELEASE_SPI();
|
||||
/* In case there is something in the Rx FIFO, read it */
|
||||
cc1200_rx_interrupt();
|
||||
if(SPI_IS_LOCKED()) {
|
||||
return 0;
|
||||
}
|
||||
LOCK_SPI();
|
||||
}
|
||||
|
||||
/*
|
||||
* As we use GPIO as CHIP_RDYn signal on wake-up / on(),
|
||||
* we re-configure it for CHIP_RDYn.
|
||||
@ -1106,6 +1191,40 @@ off(void)
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Reads the current signal strength (RSSI)
|
||||
* \return The current RSSI in dBm
|
||||
*
|
||||
* This function reads the current RSSI on the currently configured
|
||||
* channel.
|
||||
*/
|
||||
static int16_t
|
||||
get_rssi(void)
|
||||
{
|
||||
int16_t rssi0, rssi1;
|
||||
uint8_t was_off = 0;
|
||||
|
||||
/* If we are off, turn on first */
|
||||
if(!(rf_flags & RF_ON)) {
|
||||
was_off = 1;
|
||||
on();
|
||||
}
|
||||
|
||||
/* Wait for CARRIER_SENSE_VALID signal */
|
||||
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
|
||||
& CC1200_CARRIER_SENSE_VALID),
|
||||
RTIMER_SECOND / 100);
|
||||
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
|
||||
rssi1 = (int8_t)single_read(CC1200_RSSI1) + (int)CC1200_RF_CFG.rssi_offset;
|
||||
|
||||
/* If we were off, turn back off */
|
||||
if(was_off) {
|
||||
off();
|
||||
}
|
||||
|
||||
return rssi1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Get a radio parameter value. */
|
||||
static radio_result_t
|
||||
get_value(radio_param_t param, radio_value_t *value)
|
||||
@ -1156,6 +1275,13 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_PARAM_RSSI:
|
||||
*value = get_rssi();
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_PARAM_LAST_RSSI:
|
||||
*value = (radio_value_t)rssi;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_PARAM_64BIT_ADDR:
|
||||
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
@ -1180,6 +1306,34 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||
*value = (radio_value_t)CC1200_RF_CFG.max_txpower;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_CONST_PHY_OVERHEAD:
|
||||
#if CC1200_802154G
|
||||
#if CC1200_802154G_CRC16
|
||||
*value = (radio_value_t)4; /* 2 bytes PHR, 2 bytes CRC */
|
||||
#else
|
||||
*value = (radio_value_t)6; /* 2 bytes PHR, 4 bytes CRC */
|
||||
#endif
|
||||
#else
|
||||
*value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */
|
||||
#endif
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_CONST_BYTE_AIR_TIME:
|
||||
*value = (radio_value_t)8*1000*1000 / CC1200_RF_CFG.bitrate;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_CONST_DELAY_BEFORE_TX:
|
||||
*value = (radio_value_t)CC1200_RF_CFG.delay_before_tx;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_CONST_DELAY_BEFORE_RX:
|
||||
*value = (radio_value_t)CC1200_RF_CFG.delay_before_rx;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
case RADIO_CONST_DELAY_BEFORE_DETECT:
|
||||
*value = (radio_value_t)CC1200_RF_CFG.delay_before_detect;
|
||||
return RADIO_RESULT_OK;
|
||||
|
||||
default:
|
||||
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
@ -1282,6 +1436,23 @@ set_value(radio_param_t param, radio_value_t value)
|
||||
static radio_result_t
|
||||
get_object(radio_param_t param, void *dest, size_t size)
|
||||
{
|
||||
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
|
||||
if(size != sizeof(rtimer_clock_t) || !dest) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
*(rtimer_clock_t *)dest = sfd_timestamp;
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
|
||||
#if MAC_CONF_WITH_TSCH
|
||||
if(param == RADIO_CONST_TSCH_TIMING) {
|
||||
if(size != sizeof(uint16_t *) || !dest) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
*(const uint16_t **)dest = CC1200_RF_CFG.tsch_timing;
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
#endif /* MAC_CONF_WITH_TSCH */
|
||||
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
|
||||
@ -1507,20 +1678,20 @@ configure(void)
|
||||
while(1) {
|
||||
#if (CC1200_RF_TESTMODE == 1)
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_YELLOW);
|
||||
leds_on(LEDS_RED);
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_RED);
|
||||
leds_on(LEDS_YELLOW);
|
||||
#else
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_GREEN);
|
||||
leds_on(LEDS_RED);
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_RED);
|
||||
leds_on(LEDS_GREEN);
|
||||
#endif
|
||||
@ -1542,11 +1713,11 @@ configure(void)
|
||||
while(1) {
|
||||
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_GREEN);
|
||||
leds_on(LEDS_YELLOW);
|
||||
watchdog_periodic();
|
||||
BUSYWAIT_UNTIL(0, RTIMER_SECOND / 10);
|
||||
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
|
||||
leds_off(LEDS_YELLOW);
|
||||
leds_on(LEDS_GREEN);
|
||||
clock_delay_usec(1000);
|
||||
@ -1667,8 +1838,8 @@ calibrate(void)
|
||||
INFO("RF: Calibrate\n");
|
||||
|
||||
strobe(CC1200_SCAL);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
|
||||
|
||||
#if CC1200_CAL_TIMEOUT_SECONDS
|
||||
cal_timer = clock_seconds();
|
||||
@ -1705,7 +1876,7 @@ idle(void)
|
||||
}
|
||||
|
||||
strobe(CC1200_SIDLE);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
|
||||
|
||||
} /* idle(), 21.05.2015 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -1723,7 +1894,7 @@ idle_calibrate_rx(void)
|
||||
rf_flags &= ~RF_RX_PROCESSING_PKT;
|
||||
strobe(CC1200_SFRX);
|
||||
strobe(CC1200_SRX);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
|
||||
|
||||
ENABLE_GPIO_INTERRUPTS();
|
||||
|
||||
@ -1748,7 +1919,7 @@ rx_rx(void)
|
||||
strobe(CC1200_SFTX);
|
||||
} else {
|
||||
strobe(CC1200_SIDLE);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_IDLE,
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE,
|
||||
RTIMER_SECOND / 100);
|
||||
}
|
||||
|
||||
@ -1760,79 +1931,29 @@ rx_rx(void)
|
||||
|
||||
strobe(CC1200_SFRX);
|
||||
strobe(CC1200_SRX);
|
||||
BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Fill TX FIFO, start TX and wait for TX to complete (blocking!). */
|
||||
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
|
||||
static int
|
||||
idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
|
||||
{
|
||||
|
||||
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
|
||||
uint16_t bytes_left_to_write;
|
||||
uint8_t to_write;
|
||||
const uint8_t *p;
|
||||
#endif
|
||||
|
||||
#if CC1200_802154G
|
||||
/* Prepare PHR for 802.15.4g frames */
|
||||
struct {
|
||||
uint8_t phra;
|
||||
uint8_t phrb;
|
||||
} phr;
|
||||
#if CC1200_802154G_CRC16
|
||||
payload_len += 2;
|
||||
#else
|
||||
payload_len += 4;
|
||||
#endif
|
||||
/* Frame length */
|
||||
phr.phrb = (uint8_t)(payload_len & 0x00FF);
|
||||
phr.phra = (uint8_t)((payload_len >> 8) & 0x0007);
|
||||
#if CC1200_802154G_WHITENING
|
||||
/* Enable Whitening */
|
||||
phr.phra |= (1 << 3);
|
||||
#endif /* #if CC1200_802154G_WHITENING */
|
||||
#if CC1200_802154G_CRC16
|
||||
/* FCS type 1, 2 Byte CRC */
|
||||
phr.phra |= (1 << 4);
|
||||
#endif /* #if CC1200_802154G_CRC16 */
|
||||
#endif /* #if CC1200_802154G */
|
||||
|
||||
/* Prepare for RX */
|
||||
rf_flags &= ~RF_RX_PROCESSING_PKT;
|
||||
strobe(CC1200_SFRX);
|
||||
|
||||
/* Flush TX FIFO */
|
||||
strobe(CC1200_SFTX);
|
||||
|
||||
#if USE_SFSTXON
|
||||
/*
|
||||
* Enable synthesizer. Saves us a few µs especially if it takes
|
||||
* long enough to fill the FIFO. This strobe must not be
|
||||
* send before SFTX!
|
||||
*/
|
||||
strobe(CC1200_SFSTXON);
|
||||
#endif
|
||||
|
||||
/* Configure GPIO0 to detect TX state */
|
||||
single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0);
|
||||
|
||||
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
|
||||
/*
|
||||
* We already checked that GPIO2 is used if
|
||||
* CC1200_MAX_PAYLOAD_LEN > 127 / 126 in the header of this file
|
||||
*/
|
||||
single_write(CC1200_IOCFG2, CC1200_IOCFG_TXFIFO_THR);
|
||||
#endif
|
||||
|
||||
#if CC1200_802154G
|
||||
/* Write PHR */
|
||||
burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN);
|
||||
#else
|
||||
/* Write length byte */
|
||||
burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN);
|
||||
#endif /* #if CC1200_802154G */
|
||||
#if CC1200_WITH_TX_BUF
|
||||
/* Prepare and write header */
|
||||
copy_header_to_tx_fifo(payload_len);
|
||||
|
||||
/*
|
||||
* Fill FIFO with data. If SPI is slow it might make sense
|
||||
@ -1849,17 +1970,18 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
|
||||
#else
|
||||
burst_write(CC1200_TXFIFO, payload, payload_len);
|
||||
#endif
|
||||
#endif /* CC1200_WITH_TX_BUF */
|
||||
|
||||
#if USE_SFSTXON
|
||||
/* Wait for synthesizer to be ready */
|
||||
BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
|
||||
#endif
|
||||
|
||||
/* Start TX */
|
||||
strobe(CC1200_STX);
|
||||
|
||||
/* Wait for TX to start. */
|
||||
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100);
|
||||
|
||||
/* Turned off at the latest in idle() */
|
||||
TX_LEDS_ON();
|
||||
@ -1888,7 +2010,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
|
||||
|
||||
}
|
||||
|
||||
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
|
||||
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) && CC1200_WITH_TX_BUF
|
||||
if(bytes_left_to_write != 0) {
|
||||
rtimer_clock_t t0;
|
||||
uint8_t s;
|
||||
@ -1922,7 +2044,7 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
|
||||
*/
|
||||
|
||||
INFO("RF: TX failure!\n");
|
||||
BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100);
|
||||
/* Re-configure GPIO2 */
|
||||
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
|
||||
idle();
|
||||
@ -1936,12 +2058,12 @@ idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
|
||||
|
||||
} else {
|
||||
/* Wait for TX to complete */
|
||||
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
CC1200_RF_CFG.tx_pkt_lifetime);
|
||||
}
|
||||
#else
|
||||
/* Wait for TX to complete */
|
||||
BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
|
||||
CC1200_RF_CFG.tx_pkt_lifetime);
|
||||
#endif
|
||||
|
||||
@ -2026,6 +2148,9 @@ set_channel(uint8_t channel)
|
||||
uint8_t was_off = 0;
|
||||
uint32_t freq;
|
||||
|
||||
channel %= (CC1200_RF_CFG.max_channel - CC1200_RF_CFG.min_channel + 1);
|
||||
channel += CC1200_RF_CFG.min_channel;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* We explicitly allow a channel update even if the channel does not change.
|
||||
@ -2156,6 +2281,7 @@ addr_check_auto_ack(uint8_t *frame, uint16_t frame_len)
|
||||
idle();
|
||||
#endif
|
||||
|
||||
prepare((const uint8_t *)ack, ACK_LEN);
|
||||
idle_tx_rx((const uint8_t *)ack, ACK_LEN);
|
||||
|
||||
/* rx_rx() will follow */
|
||||
@ -2204,6 +2330,23 @@ cc1200_rx_interrupt(void)
|
||||
*/
|
||||
static uint8_t buf[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
|
||||
|
||||
/*
|
||||
* If CC1200_USE_GPIO2 is enabled, we come here either once RX FIFO
|
||||
* threshold is reached (GPIO2 rising edge)
|
||||
* or at the end of the packet (GPIO0 falling edge).
|
||||
*/
|
||||
#if CC1200_USE_GPIO2
|
||||
int gpio2 = cc1200_arch_gpio2_read_pin();
|
||||
int gpio0 = cc1200_arch_gpio0_read_pin();
|
||||
if((rf_flags & RF_RX_ONGOING) == 0 && gpio2 > 0) {
|
||||
rf_flags |= RF_RX_ONGOING;
|
||||
sfd_timestamp = RTIMER_NOW();
|
||||
}
|
||||
if(gpio0 == 0) {
|
||||
rf_flags &= ~RF_RX_ONGOING;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(SPI_IS_LOCKED()) {
|
||||
|
||||
/*
|
||||
|
61
arch/dev/cc2420/cc2420-tsch-15ms.c
Normal file
61
arch/dev/cc2420/cc2420-tsch-15ms.c
Normal 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 */
|
||||
};
|
35
arch/dev/cc2420/cc2420-tsch-15ms.h
Normal file
35
arch/dev/cc2420/cc2420-tsch-15ms.h
Normal 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[];
|
@ -96,9 +96,6 @@ static const struct output_config output_power[] = {
|
||||
|
||||
void cc2420_arch_init(void);
|
||||
|
||||
/* XXX hack: these will be made as Chameleon packet attributes */
|
||||
rtimer_clock_t cc2420_time_of_arrival, cc2420_time_of_departure;
|
||||
|
||||
int cc2420_authority_level_of_sender;
|
||||
|
||||
volatile uint8_t cc2420_sfd_counter;
|
||||
|
@ -102,9 +102,6 @@ int cc2420_get_txpower(void);
|
||||
*/
|
||||
int cc2420_interrupt(void);
|
||||
|
||||
/* XXX hack: these will be made as Chameleon packet attributes */
|
||||
extern rtimer_clock_t cc2420_time_of_arrival,
|
||||
cc2420_time_of_departure;
|
||||
extern int cc2420_authority_level_of_sender;
|
||||
|
||||
int cc2420_on(void);
|
||||
|
@ -99,7 +99,7 @@
|
||||
#define VERIFY_PART_POWERED_DOWN 0
|
||||
#define VERIFY_PART_OK 1
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static spi_device_t flash_spi_configuration_default = {
|
||||
static const spi_device_t flash_spi_configuration_default = {
|
||||
.spi_controller = EXT_FLASH_SPI_CONTROLLER,
|
||||
.pin_spi_sck = EXT_FLASH_SPI_PIN_SCK,
|
||||
.pin_spi_miso = EXT_FLASH_SPI_PIN_MISO,
|
||||
@ -113,8 +113,8 @@ static spi_device_t flash_spi_configuration_default = {
|
||||
/**
|
||||
* Get spi configuration, return default configuration if NULL
|
||||
*/
|
||||
static spi_device_t *
|
||||
get_spi_conf(spi_device_t *conf)
|
||||
static const spi_device_t *
|
||||
get_spi_conf(const spi_device_t *conf)
|
||||
{
|
||||
if(conf == NULL) {
|
||||
return &flash_spi_configuration_default;
|
||||
@ -126,7 +126,7 @@ get_spi_conf(spi_device_t *conf)
|
||||
* Clear external flash CSN line
|
||||
*/
|
||||
static bool
|
||||
select_on_bus(spi_device_t *flash_spi_configuration)
|
||||
select_on_bus(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
if(spi_select(flash_spi_configuration) == SPI_DEV_STATUS_OK) {
|
||||
return true;
|
||||
@ -138,7 +138,7 @@ select_on_bus(spi_device_t *flash_spi_configuration)
|
||||
* Set external flash CSN line
|
||||
*/
|
||||
static void
|
||||
deselect(spi_device_t *flash_spi_configuration)
|
||||
deselect(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
spi_deselect(flash_spi_configuration);
|
||||
}
|
||||
@ -148,7 +148,7 @@ deselect(spi_device_t *flash_spi_configuration)
|
||||
* \return True when successful.
|
||||
*/
|
||||
static bool
|
||||
wait_ready(spi_device_t *flash_spi_configuration)
|
||||
wait_ready(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
bool ret;
|
||||
const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
|
||||
@ -196,7 +196,7 @@ wait_ready(spi_device_t *flash_spi_configuration)
|
||||
* was powered down
|
||||
*/
|
||||
static uint8_t
|
||||
verify_part(spi_device_t *flash_spi_configuration)
|
||||
verify_part(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
|
||||
uint8_t rbuf[2] = { 0, 0 };
|
||||
@ -230,7 +230,7 @@ verify_part(spi_device_t *flash_spi_configuration)
|
||||
* the status register is accessible.
|
||||
*/
|
||||
static bool
|
||||
power_down(spi_device_t *flash_spi_configuration)
|
||||
power_down(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t i;
|
||||
@ -271,7 +271,7 @@ power_down(spi_device_t *flash_spi_configuration)
|
||||
* \return True if the command was written successfully
|
||||
*/
|
||||
static bool
|
||||
power_standby(spi_device_t *flash_spi_configuration)
|
||||
power_standby(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
uint8_t cmd;
|
||||
bool success;
|
||||
@ -297,7 +297,7 @@ power_standby(spi_device_t *flash_spi_configuration)
|
||||
* \return True when successful.
|
||||
*/
|
||||
static bool
|
||||
write_enable(spi_device_t *flash_spi_configuration)
|
||||
write_enable(const spi_device_t *flash_spi_configuration)
|
||||
{
|
||||
bool ret;
|
||||
const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
|
||||
@ -316,9 +316,9 @@ write_enable(spi_device_t *flash_spi_configuration)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_open(spi_device_t *conf)
|
||||
ext_flash_open(const spi_device_t *conf)
|
||||
{
|
||||
spi_device_t *flash_spi_configuration;
|
||||
const spi_device_t *flash_spi_configuration;
|
||||
|
||||
flash_spi_configuration = get_spi_conf(conf);
|
||||
|
||||
@ -346,10 +346,10 @@ ext_flash_open(spi_device_t *conf)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_close(spi_device_t *conf)
|
||||
ext_flash_close(const spi_device_t *conf)
|
||||
{
|
||||
bool ret;
|
||||
spi_device_t *flash_spi_configuration;
|
||||
const spi_device_t *flash_spi_configuration;
|
||||
|
||||
flash_spi_configuration = get_spi_conf(conf);
|
||||
|
||||
@ -365,12 +365,12 @@ ext_flash_close(spi_device_t *conf)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
|
||||
ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
uint8_t wbuf[4];
|
||||
bool ret;
|
||||
|
||||
spi_device_t *flash_spi_configuration;
|
||||
const spi_device_t *flash_spi_configuration;
|
||||
|
||||
flash_spi_configuration = get_spi_conf(conf);
|
||||
|
||||
@ -406,12 +406,12 @@ ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *bu
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
|
||||
ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
|
||||
{
|
||||
uint8_t wbuf[4];
|
||||
uint32_t ilen; /* interim length per instruction */
|
||||
|
||||
spi_device_t *flash_spi_configuration;
|
||||
const spi_device_t *flash_spi_configuration;
|
||||
|
||||
flash_spi_configuration = get_spi_conf(conf);
|
||||
|
||||
@ -466,7 +466,7 @@ ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
|
||||
ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length)
|
||||
{
|
||||
/*
|
||||
* Note that Block erase might be more efficient when the floor map
|
||||
@ -477,7 +477,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
|
||||
uint32_t i, numsectors;
|
||||
uint32_t endoffset = offset + length - 1;
|
||||
|
||||
spi_device_t *flash_spi_configuration;
|
||||
const spi_device_t *flash_spi_configuration;
|
||||
|
||||
flash_spi_configuration = get_spi_conf(conf);
|
||||
|
||||
@ -518,7 +518,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
ext_flash_init(spi_device_t *conf)
|
||||
ext_flash_init(const spi_device_t *conf)
|
||||
{
|
||||
if(ext_flash_open(conf) == false) {
|
||||
return false;
|
||||
|
@ -61,7 +61,7 @@
|
||||
* \param conf SPI bus configuration struct. NULL for default.
|
||||
* \return True when successful.
|
||||
*/
|
||||
bool ext_flash_open(spi_device_t *conf);
|
||||
bool ext_flash_open(const spi_device_t *conf);
|
||||
|
||||
/**
|
||||
* \brief Close the storage driver
|
||||
@ -70,7 +70,7 @@ bool ext_flash_open(spi_device_t *conf);
|
||||
*
|
||||
* This call will put the device in its lower power mode (power down).
|
||||
*/
|
||||
bool ext_flash_close(spi_device_t *conf);
|
||||
bool ext_flash_close(const spi_device_t *conf);
|
||||
|
||||
/**
|
||||
* \brief Read storage content
|
||||
@ -82,7 +82,7 @@ bool ext_flash_close(spi_device_t *conf);
|
||||
*
|
||||
* buf must be allocated by the caller
|
||||
*/
|
||||
bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf);
|
||||
bool ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* \brief Erase storage sectors corresponding to the range.
|
||||
@ -94,7 +94,7 @@ bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_
|
||||
* The erase operation will be sector-wise, therefore a call to this function
|
||||
* will generally start the erase procedure at an address lower than offset
|
||||
*/
|
||||
bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length);
|
||||
bool ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length);
|
||||
|
||||
/**
|
||||
* \brief Write to storage sectors.
|
||||
@ -105,7 +105,7 @@ bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length);
|
||||
*
|
||||
* \return True when successful.
|
||||
*/
|
||||
bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf);
|
||||
bool ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* \brief Initialise the external flash
|
||||
@ -117,7 +117,7 @@ bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const
|
||||
* In order to perform any operation, the caller must first wake the device
|
||||
* up by calling ext_flash_open()
|
||||
*/
|
||||
bool ext_flash_init(spi_device_t *conf);
|
||||
bool ext_flash_init(const spi_device_t *conf);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* EXT_FLASH_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -122,6 +122,10 @@ typedef unsigned long clock_time_t;
|
||||
/* Use 64-bit rtimer (default in Contiki-NG is 32) */
|
||||
#define RTIMER_CONF_CLOCK_SIZE 8
|
||||
|
||||
/* 1 len byte, 2 bytes CRC */
|
||||
#define RADIO_PHY_OVERHEAD 3
|
||||
/* 250kbps data rate. One byte = 32us */
|
||||
#define RADIO_BYTE_AIR_TIME 32
|
||||
#define RADIO_DELAY_BEFORE_TX 0
|
||||
#define RADIO_DELAY_BEFORE_RX 0
|
||||
#define RADIO_DELAY_BEFORE_DETECT 0
|
||||
|
@ -330,6 +330,10 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||
case RADIO_PARAM_LAST_LINK_QUALITY:
|
||||
*value = simLQI;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_RSSI:
|
||||
/* return a fixed value depending on the channel */
|
||||
*value = -90 + simRadioChannel - 11;
|
||||
return RADIO_RESULT_OK;
|
||||
default:
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
|
@ -30,8 +30,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* Dummy watchdog routines for the Raven 1284p */
|
||||
/* Dummy watchdog routines for Cooja motes */
|
||||
#include "dev/watchdog.h"
|
||||
#include "lib/simEnvChange.h"
|
||||
#include "sys/cooja_mt.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
@ -47,6 +49,9 @@ watchdog_start(void)
|
||||
void
|
||||
watchdog_periodic(void)
|
||||
{
|
||||
/* Yield and give control back to the simulator scheduler */
|
||||
simProcessRunValue = 1;
|
||||
cooja_mt_yield();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -103,8 +103,6 @@ endif
|
||||
CONTIKI_TARGET_DIRS = . dev
|
||||
CONTIKI_TARGET_MAIN = platform.c
|
||||
|
||||
MODULES += os/lib/dbg-io
|
||||
|
||||
ifeq ($(JN516x_WITH_DR1175),1)
|
||||
JN516x_WITH_DR1174 = 1
|
||||
CFLAGS += -DSENSOR_BOARD_DR1175
|
||||
|
@ -130,13 +130,6 @@
|
||||
#define MICROMAC_CONF_ALWAYS_ON 1
|
||||
#endif /* MICROMAC_CONF_ALWAYS_ON */
|
||||
|
||||
#define BUSYWAIT_UNTIL(cond, max_time) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
|
||||
} while(0)
|
||||
|
||||
/* Local variables */
|
||||
static volatile signed char radio_last_rssi;
|
||||
static volatile uint8_t radio_last_correlation; /* LQI */
|
||||
@ -377,14 +370,14 @@ transmit(unsigned short payload_len)
|
||||
(send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA));
|
||||
#endif
|
||||
if(poll_mode) {
|
||||
BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
|
||||
RTIMER_BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
|
||||
} else {
|
||||
if(in_ack_transmission) {
|
||||
/* as nested interupts are not possible, the tx flag will never be cleared */
|
||||
BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION);
|
||||
RTIMER_BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION);
|
||||
} else {
|
||||
/* wait until the tx flag is cleared */
|
||||
BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
|
||||
RTIMER_BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,14 +66,6 @@ extern volatile unsigned char xonxoff_state;
|
||||
|
||||
#endif /* UART_XONXOFF_FLOW_CTRL */
|
||||
|
||||
/*** Macro Definitions ***/
|
||||
#define BUSYWAIT_UNTIL(cond, max_time) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
|
||||
} while(0)
|
||||
|
||||
#define DEBUG_UART_BUFFERED FALSE
|
||||
|
||||
#define CHAR_DEADLINE (uart_char_delay * 100)
|
||||
@ -276,7 +268,7 @@ uart_driver_write_with_deadline(uint8_t uart_dev, uint8_t ch)
|
||||
volatile int16_t write = 0;
|
||||
watchdog_periodic();
|
||||
/* wait until there is space in tx fifo */
|
||||
BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0),
|
||||
RTIMER_BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0),
|
||||
CHAR_DEADLINE);
|
||||
/* write only if there is space so we do not get stuck */
|
||||
if(write) {
|
||||
|
@ -38,6 +38,10 @@
|
||||
|
||||
#undef putchar
|
||||
|
||||
/* 1 len byte, 2 bytes CRC */
|
||||
#define RADIO_PHY_OVERHEAD 3
|
||||
/* 250kbps data rate. One byte = 32us */
|
||||
#define RADIO_BYTE_AIR_TIME 32
|
||||
/* Delay between GO signal and SFD
|
||||
* Measured 153us between GO and preamble. Add 5 bytes (preamble + SFD) air time: 153+5*32 = 313 */
|
||||
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(313))
|
||||
|
@ -9,12 +9,12 @@ CONTIKI_TARGET_DIRS += . dev config
|
||||
CONTIKI_SOURCEFILES += platform.c leds-arch.c nrf52dk-sensors.c button-sensor.c temperature-sensor.c
|
||||
|
||||
ifeq ($(NRF52_USE_RTT),1)
|
||||
### Use the existing debug I/O in arch/cpu/arm/common
|
||||
### Suppress the existing debug I/O in os/lib
|
||||
MAKE_WITH_LIB_DBG_IO = 0
|
||||
CONTIKI_TARGET_DIRS += rtt
|
||||
CONTIKI_SOURCEFILES += rtt-printf.c segger-rtt.c segger-rtt-printf.c
|
||||
else
|
||||
CONTIKI_SOURCEFILES += dbg.c
|
||||
MODULES += os/lib/dbg-io
|
||||
endif
|
||||
|
||||
### Unless the example dictates otherwise, build with code size optimisations switched off
|
||||
|
@ -17,11 +17,14 @@
|
||||
#define NETSTACK_CONF_RADIO cc2420_driver
|
||||
#endif /* NETSTACK_CONF_RADIO */
|
||||
|
||||
/* Symbol for the TSCH 15ms timeslot timing template */
|
||||
#define TSCH_CONF_ARCH_HDR_PATH "dev/cc2420/cc2420-tsch-15ms.h"
|
||||
|
||||
/* The TSCH default slot length of 10ms is a bit too short for this platform,
|
||||
* use 15ms instead. */
|
||||
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000
|
||||
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */
|
||||
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
|
||||
#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_15000
|
||||
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */
|
||||
|
||||
/* Save RAM through a smaller uIP buffer */
|
||||
#ifndef UIP_CONF_BUFFER_SIZE
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "lib/random.h"
|
||||
#include "net/netstack.h"
|
||||
#include "net/mac/framer/frame802154.h"
|
||||
#include "net/mac/tsch/tsch.h"
|
||||
|
||||
#if NETSTACK_CONF_WITH_IPV6
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
|
@ -43,6 +43,11 @@
|
||||
* Definitions below are dictated by the hardware and not really
|
||||
* changeable!
|
||||
*/
|
||||
|
||||
/* 1 len byte, 2 bytes CRC */
|
||||
#define RADIO_PHY_OVERHEAD 3
|
||||
/* 250kbps data rate. One byte = 32us */
|
||||
#define RADIO_BYTE_AIR_TIME 32
|
||||
/* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us
|
||||
* ~327us + 129preample = 456 us */
|
||||
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456))
|
||||
|
@ -55,6 +55,25 @@
|
||||
#endif /* PROJECT_CONF_PATH */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "cc2538-def.h"
|
||||
|
||||
unsigned radio_phy_overhead(void);
|
||||
unsigned radio_byte_air_time(void);
|
||||
unsigned radio_delay_before_tx(void);
|
||||
unsigned radio_delay_before_rx(void);
|
||||
unsigned radio_delay_before_detect(void);
|
||||
uint16_t *radio_tsch_timeslot_timing(void);
|
||||
|
||||
/** @} */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define RADIO_PHY_OVERHEAD radio_phy_overhead()
|
||||
#define RADIO_BYTE_AIR_TIME radio_byte_air_time()
|
||||
#define RADIO_DELAY_BEFORE_TX radio_delay_before_tx()
|
||||
#define RADIO_DELAY_BEFORE_RX radio_delay_before_rx()
|
||||
#define RADIO_DELAY_BEFORE_DETECT radio_delay_before_detect()
|
||||
|
||||
#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING radio_tsch_timeslot_timing()
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \name Serial Boot Loader Backdoor configuration
|
||||
|
@ -76,18 +76,8 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if DEBUG_CC1200_ARCH > 0
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#define BUSYWAIT_UNTIL(cond, max_time) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) {} \
|
||||
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)))) { \
|
||||
printf("ARCH: Timeout exceeded in line %d!\n", __LINE__); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#define BUSYWAIT_UNTIL(cond, max_time) while(!cond)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern int cc1200_rx_interrupt(void);
|
||||
@ -105,7 +95,7 @@ cc1200_arch_spi_select(void)
|
||||
/* Set CSn to low (0) */
|
||||
GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
|
||||
/* The MISO pin should go low before chip is fully enabled. */
|
||||
BUSYWAIT_UNTIL(
|
||||
RTIMER_BUSYWAIT_UNTIL(
|
||||
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0,
|
||||
RTIMER_SECOND / 100);
|
||||
}
|
||||
@ -288,7 +278,7 @@ cc1200_arch_init(void)
|
||||
cc1200_arch_spi_deselect();
|
||||
|
||||
/* Ensure MISO is high */
|
||||
BUSYWAIT_UNTIL(
|
||||
RTIMER_BUSYWAIT_UNTIL(
|
||||
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK),
|
||||
RTIMER_SECOND / 10);
|
||||
}
|
||||
@ -297,4 +287,3 @@ cc1200_arch_init(void)
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
@ -51,15 +51,6 @@
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define BUSYWAIT_UNTIL(max_time) \
|
||||
do { \
|
||||
rtimer_clock_t t0; \
|
||||
t0 = RTIMER_NOW(); \
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \
|
||||
watchdog_periodic(); \
|
||||
} \
|
||||
} while(0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define DHT22_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT)
|
||||
#define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -80,12 +71,12 @@ dht22_read(void)
|
||||
/* Exit low power mode and initialize variables */
|
||||
GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
|
||||
GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
|
||||
BUSYWAIT_UNTIL(DHT22_AWAKE_TIME);
|
||||
RTIMER_BUSYWAIT(DHT22_AWAKE_TIME);
|
||||
memset(dht22_data, 0, DHT22_BUFFER);
|
||||
|
||||
/* Initialization sequence */
|
||||
GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
|
||||
BUSYWAIT_UNTIL(DHT22_START_TIME);
|
||||
RTIMER_BUSYWAIT(DHT22_START_TIME);
|
||||
GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
|
||||
clock_delay_usec(DHT22_READY_TIME);
|
||||
|
||||
|
@ -257,6 +257,48 @@ platform_idle()
|
||||
lpm_enter();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned
|
||||
radio_phy_overhead(void) {
|
||||
radio_value_t ret;
|
||||
NETSTACK_RADIO.get_value(RADIO_CONST_PHY_OVERHEAD, &ret);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned
|
||||
radio_byte_air_time(void) {
|
||||
radio_value_t ret;
|
||||
NETSTACK_RADIO.get_value(RADIO_CONST_BYTE_AIR_TIME, &ret);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned
|
||||
radio_delay_before_tx(void) {
|
||||
radio_value_t ret;
|
||||
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_TX, &ret);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned
|
||||
radio_delay_before_rx(void) {
|
||||
radio_value_t ret;
|
||||
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_RX, &ret);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned
|
||||
radio_delay_before_detect(void) {
|
||||
radio_value_t ret;
|
||||
NETSTACK_RADIO.get_value(RADIO_CONST_DELAY_BEFORE_DETECT, &ret);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t *
|
||||
radio_tsch_timeslot_timing(void) {
|
||||
uint16_t *ret;
|
||||
NETSTACK_RADIO.get_object(RADIO_CONST_TSCH_TIMING, &ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
34
examples/6tisch/channel-selection-demo/Makefile
Normal file
34
examples/6tisch/channel-selection-demo/Makefile
Normal 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
|
8
examples/6tisch/channel-selection-demo/README.md
Normal file
8
examples/6tisch/channel-selection-demo/README.md
Normal 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/
|
94
examples/6tisch/channel-selection-demo/node.c
Normal file
94
examples/6tisch/channel-selection-demo/node.c
Normal 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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
109
examples/6tisch/channel-selection-demo/project-conf.h
Normal file
109
examples/6tisch/channel-selection-demo/project-conf.h
Normal 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__ */
|
@ -74,33 +74,4 @@
|
||||
|
||||
#endif /* WITH_SECURITY */
|
||||
|
||||
/*******************************************************/
|
||||
/************* Other system configuration **************/
|
||||
/*******************************************************/
|
||||
|
||||
#if CONTIKI_TARGET_Z1
|
||||
/* Save some space to fit the limited RAM of the z1 */
|
||||
#define UIP_CONF_TCP 0
|
||||
#define QUEUEBUF_CONF_NUM 2
|
||||
#define NETSTACK_MAX_ROUTE_ENTRIES 2
|
||||
#define NBR_TABLE_CONF_MAX_NEIGHBORS 2
|
||||
#define UIP_CONF_ND6_SEND_NA 0
|
||||
#define SICSLOWPAN_CONF_FRAG 0
|
||||
|
||||
#if WITH_SECURITY
|
||||
/* Note: on sky or z1 in cooja, crypto operations are done in S/W and
|
||||
* cannot be accommodated in normal slots. Use 65ms slots instead, and
|
||||
* a very short 6TiSCH minimal schedule length */
|
||||
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 65000
|
||||
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 2
|
||||
#endif /* WITH_SECURITY */
|
||||
|
||||
#endif /* CONTIKI_TARGET_Z1 */
|
||||
|
||||
#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL || \
|
||||
CONTIKI_TARGET_OPENMOTE_CC2538
|
||||
#define TSCH_CONF_HW_FRAME_FILTERING 0
|
||||
#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \
|
||||
|| CONTIKI_TARGET_OPENMOTE_CC2538 */
|
||||
|
||||
#endif /* PROJECT_CONF_H_ */
|
||||
|
31
examples/6tisch/tsch-stats/Makefile
Normal file
31
examples/6tisch/tsch-stats/Makefile
Normal 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
|
1
examples/6tisch/tsch-stats/README.md
Normal file
1
examples/6tisch/tsch-stats/README.md
Normal file
@ -0,0 +1 @@
|
||||
Demonstration of TSCH stats.
|
93
examples/6tisch/tsch-stats/node.c
Normal file
93
examples/6tisch/tsch-stats/node.c
Normal 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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
92
examples/6tisch/tsch-stats/project-conf.h
Normal file
92
examples/6tisch/tsch-stats/project-conf.h
Normal 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__ */
|
@ -194,7 +194,7 @@ PROCESS_THREAD(node_process, ev, data)
|
||||
if (host_found) {
|
||||
/* Make sample count dependent on asn. After a disconnect, waveforms remain
|
||||
synchronous. Use node_mac to create phase offset between waveforms in different nodes */
|
||||
sample_count = ((tsch_current_asn.ls4b/((1000/(TSCH_CONF_DEFAULT_TIMESLOT_LENGTH/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1);
|
||||
sample_count = ((tsch_current_asn.ls4b/((1000/(tsch_timing_us[tsch_ts_timeslot_length]/1000)))/INTERVAL)+node_mac[7]) % (SIZE_OF_WAVEFORM-1);
|
||||
printf("%d sec. waveform=%s. cnt=%d. value=%d\n", total_time, waveform_table[selected_waveform].str, sample_count, waveform_table[selected_waveform].table[sample_count]);
|
||||
my_sprintf(udp_buf, waveform_table[selected_waveform].table[sample_count]);
|
||||
uip_udp_packet_send(udp_conn_tx, udp_buf, strlen(udp_buf));
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "services/orchestra/orchestra.h"
|
||||
#include "services/shell/serial-shell.h"
|
||||
#include "services/simple-energest/simple-energest.h"
|
||||
#include "services/tsch-cs/tsch-cs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@ -146,6 +147,11 @@ main(void)
|
||||
simple_energest_init();
|
||||
#endif /* BUILD_WITH_SIMPLE_ENERGEST */
|
||||
|
||||
#if BUILD_WITH_TSCH_CS
|
||||
/* Initialize the channel selection module */
|
||||
tsch_cs_adaptations_init();
|
||||
#endif /* BUILD_WITH_TSCH_CS */
|
||||
|
||||
autostart_start(autostart_processes);
|
||||
|
||||
watchdog_start();
|
||||
|
@ -170,6 +170,9 @@ enum {
|
||||
* it needs to be used with radio.get_object()/set_object(). */
|
||||
RADIO_PARAM_LAST_PACKET_TIMESTAMP,
|
||||
|
||||
/* For enabling and disabling the SHR search */
|
||||
RADIO_PARAM_SHR_SEARCH,
|
||||
|
||||
/* Constants (read only) */
|
||||
|
||||
/* The lowest radio channel. */
|
||||
@ -180,7 +183,14 @@ enum {
|
||||
/* The minimum transmission power in dBm. */
|
||||
RADIO_CONST_TXPOWER_MIN,
|
||||
/* The maximum transmission power in dBm. */
|
||||
RADIO_CONST_TXPOWER_MAX
|
||||
RADIO_CONST_TXPOWER_MAX,
|
||||
|
||||
RADIO_CONST_TSCH_TIMING,
|
||||
RADIO_CONST_PHY_OVERHEAD,
|
||||
RADIO_CONST_BYTE_AIR_TIME,
|
||||
RADIO_CONST_DELAY_BEFORE_TX,
|
||||
RADIO_CONST_DELAY_BEFORE_RX,
|
||||
RADIO_CONST_DELAY_BEFORE_DETECT,
|
||||
};
|
||||
|
||||
/* Radio power modes */
|
||||
|
26
os/dev/spi.c
26
os/dev/spi.c
@ -43,7 +43,7 @@
|
||||
#include <stdbool.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_acquire(spi_device_t *dev)
|
||||
spi_acquire(const spi_device_t *dev)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -54,7 +54,7 @@ spi_acquire(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_release(spi_device_t *dev)
|
||||
spi_release(const spi_device_t *dev)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -65,19 +65,19 @@ spi_release(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_select(spi_device_t *dev)
|
||||
spi_select(const spi_device_t *dev)
|
||||
{
|
||||
return spi_arch_select(dev);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_deselect(spi_device_t *dev)
|
||||
spi_deselect(const spi_device_t *dev)
|
||||
{
|
||||
return spi_arch_deselect(dev);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
spi_has_bus(spi_device_t *dev)
|
||||
spi_has_bus(const spi_device_t *dev)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return false;
|
||||
@ -87,7 +87,7 @@ spi_has_bus(spi_device_t *dev)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_write_byte(spi_device_t *dev, uint8_t data)
|
||||
spi_write_byte(const spi_device_t *dev, uint8_t data)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -101,7 +101,7 @@ spi_write_byte(spi_device_t *dev, uint8_t data)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_write(spi_device_t *dev, const uint8_t *data, int size)
|
||||
spi_write(const spi_device_t *dev, const uint8_t *data, int size)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -115,7 +115,7 @@ spi_write(spi_device_t *dev, const uint8_t *data, int size)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_read_byte(spi_device_t *dev, uint8_t *buf)
|
||||
spi_read_byte(const spi_device_t *dev, uint8_t *buf)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -129,7 +129,7 @@ spi_read_byte(spi_device_t *dev, uint8_t *buf)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_read(spi_device_t *dev, uint8_t *buf, int size)
|
||||
spi_read(const spi_device_t *dev, uint8_t *buf, int size)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -143,7 +143,7 @@ spi_read(spi_device_t *dev, uint8_t *buf, int size)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_read_skip(spi_device_t *dev, int size)
|
||||
spi_read_skip(const spi_device_t *dev, int size)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
@ -157,7 +157,7 @@ spi_read_skip(spi_device_t *dev, int size)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_transfer(spi_device_t *dev,
|
||||
spi_transfer(const spi_device_t *dev,
|
||||
const uint8_t *wdata, int wsize,
|
||||
uint8_t *rbuf, int rsize, int ignore)
|
||||
{
|
||||
@ -181,7 +181,7 @@ spi_transfer(spi_device_t *dev,
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
|
||||
spi_read_register(const spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
|
||||
{
|
||||
spi_status_t status;
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
@ -204,7 +204,7 @@ spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
spi_status_t
|
||||
spi_strobe(spi_device_t *dev, uint8_t strobe, uint8_t *result)
|
||||
spi_strobe(const spi_device_t *dev, uint8_t strobe, uint8_t *result)
|
||||
{
|
||||
if(dev == NULL || dev->spi_controller >= SPI_CONTROLLER_COUNT) {
|
||||
return SPI_DEV_STATUS_EINVAL;
|
||||
|
40
os/dev/spi.h
40
os/dev/spi.h
@ -115,7 +115,7 @@ typedef struct spi_device {
|
||||
* to be locked and the opening configuration.
|
||||
* \return SPI return code
|
||||
*/
|
||||
spi_status_t spi_acquire(spi_device_t *dev);
|
||||
spi_status_t spi_acquire(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Closes and then unlocks an SPI controller
|
||||
@ -127,7 +127,7 @@ spi_status_t spi_acquire(spi_device_t *dev);
|
||||
* This should work only if the device has already locked the SPI
|
||||
* controller.
|
||||
*/
|
||||
spi_status_t spi_release(spi_device_t *dev);
|
||||
spi_status_t spi_release(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Selects the SPI peripheral
|
||||
@ -137,7 +137,7 @@ spi_status_t spi_release(spi_device_t *dev);
|
||||
* Clears the CS pin. This should work only if the device has
|
||||
* already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_select(spi_device_t *dev);
|
||||
spi_status_t spi_select(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Deselects the SPI peripheral
|
||||
@ -146,14 +146,14 @@ spi_status_t spi_select(spi_device_t *dev);
|
||||
*
|
||||
* Sets the CS pin. Lock is not required.
|
||||
*/
|
||||
spi_status_t spi_deselect(spi_device_t *dev);
|
||||
spi_status_t spi_deselect(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Checks if a device has locked an SPI controller
|
||||
* \param dev An SPI device configuration which defines the controller.
|
||||
* \return true if the device has the lock, false otherwise.
|
||||
*/
|
||||
bool spi_has_bus(spi_device_t *dev);
|
||||
bool spi_has_bus(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Writes a single byte to an SPI device
|
||||
@ -163,7 +163,7 @@ bool spi_has_bus(spi_device_t *dev);
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data);
|
||||
spi_status_t spi_write_byte(const spi_device_t *dev, uint8_t data);
|
||||
|
||||
/**
|
||||
* \brief Reads a single byte from an SPI device
|
||||
@ -173,7 +173,7 @@ spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data);
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data);
|
||||
spi_status_t spi_read_byte(const spi_device_t *dev, uint8_t *data);
|
||||
|
||||
/**
|
||||
* \brief Writes a buffer to an SPI device
|
||||
@ -184,7 +184,7 @@ spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data);
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_write(spi_device_t *dev,
|
||||
spi_status_t spi_write(const spi_device_t *dev,
|
||||
const uint8_t *data, int size);
|
||||
|
||||
/**
|
||||
@ -196,7 +196,7 @@ spi_status_t spi_write(spi_device_t *dev,
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size);
|
||||
spi_status_t spi_read(const spi_device_t *dev, uint8_t *data, int size);
|
||||
|
||||
/**
|
||||
* \brief Reads and ignores data from an SPI device
|
||||
@ -207,7 +207,7 @@ spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size);
|
||||
* Reads size bytes from the SPI and throws them away.
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_read_skip(spi_device_t *dev, int size);
|
||||
spi_status_t spi_read_skip(const spi_device_t *dev, int size);
|
||||
|
||||
/**
|
||||
* \brief Performs a generic SPI transfer
|
||||
@ -226,7 +226,7 @@ spi_status_t spi_read_skip(spi_device_t *dev, int size);
|
||||
* be copied to buf. The remaining ignore_len bytes won't be copied to the
|
||||
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
|
||||
*/
|
||||
spi_status_t spi_transfer(spi_device_t *dev,
|
||||
spi_status_t spi_transfer(const spi_device_t *dev,
|
||||
const uint8_t *data, int wsize,
|
||||
uint8_t *buf, int rsize, int ignore);
|
||||
|
||||
@ -239,7 +239,7 @@ spi_status_t spi_transfer(spi_device_t *dev,
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe,
|
||||
spi_status_t spi_strobe(const spi_device_t *dev, uint8_t strobe,
|
||||
uint8_t *status);
|
||||
|
||||
/**
|
||||
@ -252,7 +252,7 @@ spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe,
|
||||
*
|
||||
* It should work only if the device has already locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg,
|
||||
spi_status_t spi_read_register(const spi_device_t *dev, uint8_t reg,
|
||||
uint8_t *data, int size);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -266,7 +266,7 @@ spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg,
|
||||
* \return 1 if the device has the lock, 0 otherwise.
|
||||
*
|
||||
*/
|
||||
bool spi_arch_has_lock(spi_device_t *dev);
|
||||
bool spi_arch_has_lock(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Checks if an SPI controller is locked by any device
|
||||
@ -275,7 +275,7 @@ bool spi_arch_has_lock(spi_device_t *dev);
|
||||
* \return 1 if the controller is locked, 0 otherwise.
|
||||
*
|
||||
*/
|
||||
bool spi_arch_is_bus_locked(spi_device_t *dev);
|
||||
bool spi_arch_is_bus_locked(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Locks and opens an SPI controller to the configuration specified.
|
||||
@ -286,7 +286,7 @@ bool spi_arch_is_bus_locked(spi_device_t *dev);
|
||||
* controller.
|
||||
*
|
||||
*/
|
||||
spi_status_t spi_arch_lock_and_open(spi_device_t *dev);
|
||||
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Closes and unlocks an SPI controller
|
||||
@ -299,7 +299,7 @@ spi_status_t spi_arch_lock_and_open(spi_device_t *dev);
|
||||
* controller.
|
||||
*
|
||||
*/
|
||||
spi_status_t spi_arch_close_and_unlock(spi_device_t *dev);
|
||||
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Performs an SPI transfer
|
||||
@ -318,7 +318,7 @@ spi_status_t spi_arch_close_and_unlock(spi_device_t *dev);
|
||||
* be copied to buf. The remaining ignore_len bytes won't be copied to the
|
||||
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
|
||||
*/
|
||||
spi_status_t spi_arch_transfer(spi_device_t *dev,
|
||||
spi_status_t spi_arch_transfer(const spi_device_t *dev,
|
||||
const uint8_t *data, int wlen,
|
||||
uint8_t *buf, int rlen,
|
||||
int ignore_len);
|
||||
@ -331,7 +331,7 @@ spi_status_t spi_arch_transfer(spi_device_t *dev,
|
||||
* Clears the CS pin. It should work only if the device has already
|
||||
* locked the SPI controller.
|
||||
*/
|
||||
spi_status_t spi_arch_select(spi_device_t *dev);
|
||||
spi_status_t spi_arch_select(const spi_device_t *dev);
|
||||
|
||||
/**
|
||||
* \brief Deselects an SPI device
|
||||
@ -340,7 +340,7 @@ spi_status_t spi_arch_select(spi_device_t *dev);
|
||||
*
|
||||
* Set the CS pin. Locking the SPI controller is not needed.
|
||||
*/
|
||||
spi_status_t spi_arch_deselect(spi_device_t *dev);
|
||||
spi_status_t spi_arch_deselect(const spi_device_t *dev);
|
||||
|
||||
#endif /* SPI_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -37,12 +37,10 @@
|
||||
#include "net/link-stats.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
/* Log configuration */
|
||||
#include "sys/log.h"
|
||||
#define LOG_MODULE "Link Stats"
|
||||
#define LOG_LEVEL LOG_LEVEL_MAC
|
||||
|
||||
/* Maximum value for the Tx count counter */
|
||||
#define TX_COUNT_MAX 32
|
||||
@ -82,6 +80,13 @@ link_stats_from_lladdr(const linkaddr_t *lladdr)
|
||||
return nbr_table_get_from_lladdr(link_stats, lladdr);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Returns the neighbor's address given a link stats item */
|
||||
const linkaddr_t *
|
||||
link_stats_get_lladdr(const struct link_stats *stat)
|
||||
{
|
||||
return nbr_table_get_lladdr(link_stats, stat);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Are the statistics fresh? */
|
||||
int
|
||||
link_stats_is_fresh(const struct link_stats *stats)
|
||||
@ -156,6 +161,14 @@ link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx)
|
||||
stats->last_tx_time = clock_time();
|
||||
stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX);
|
||||
|
||||
#if LINK_STATS_PACKET_COUNTERS
|
||||
/* Update paket counters */
|
||||
stats->cnt_current.num_packets_tx += numtx;
|
||||
if(status == MAC_TX_OK) {
|
||||
stats->cnt_current.num_packets_acked++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add penalty in case of no-ACK */
|
||||
if(status == MAC_TX_NOACK) {
|
||||
numtx += ETX_NOACK_PENALTY;
|
||||
@ -219,8 +232,38 @@ link_stats_input_callback(const linkaddr_t *lladdr)
|
||||
/* Update RSSI EWMA */
|
||||
stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) +
|
||||
(int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE;
|
||||
|
||||
#if LINK_STATS_PACKET_COUNTERS
|
||||
stats->cnt_current.num_packets_rx++;
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if LINK_STATS_PACKET_COUNTERS
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
print_and_update_counters(void)
|
||||
{
|
||||
struct link_stats *stats;
|
||||
|
||||
for(stats = nbr_table_head(link_stats); stats != NULL;
|
||||
stats = nbr_table_next(link_stats, stats)) {
|
||||
|
||||
struct link_packet_counter *c = &stats->cnt_current;
|
||||
|
||||
LOG_INFO("num packets: tx=%u ack=%u rx=%u to=",
|
||||
c->num_packets_tx, c->num_packets_acked, c->num_packets_rx);
|
||||
LOG_INFO_LLADDR(link_stats_get_lladdr(stats));
|
||||
LOG_INFO_("\n");
|
||||
|
||||
stats->cnt_total.num_packets_tx += stats->cnt_current.num_packets_tx;
|
||||
stats->cnt_total.num_packets_acked += stats->cnt_current.num_packets_acked;
|
||||
stats->cnt_total.num_packets_rx += stats->cnt_current.num_packets_rx;
|
||||
memset(&stats->cnt_current, 0, sizeof(stats->cnt_current));
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* LINK_STATS_PACKET_COUNTERS */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Periodic timer called at a period of FRESHNESS_HALF_LIFE */
|
||||
static void
|
||||
periodic(void *ptr)
|
||||
@ -231,6 +274,10 @@ periodic(void *ptr)
|
||||
for(stats = nbr_table_head(link_stats); stats != NULL; stats = nbr_table_next(link_stats, stats)) {
|
||||
stats->freshness >>= 1;
|
||||
}
|
||||
|
||||
#if LINK_STATS_PACKET_COUNTERS
|
||||
print_and_update_counters();
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Resets link-stats module */
|
||||
|
@ -56,6 +56,25 @@
|
||||
#define LINK_STATS_ETX_FROM_PACKET_COUNT 0
|
||||
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */
|
||||
|
||||
/* Store and periodically print packet counters? */
|
||||
#ifdef LINK_STATS_CONF_PACKET_COUNTERS
|
||||
#define LINK_STATS_PACKET_COUNTERS LINK_STATS_CONF_PACKET_COUNTERS
|
||||
#else /* LINK_STATS_CONF_PACKET_COUNTERS */
|
||||
#define LINK_STATS_PACKET_COUNTERS 0
|
||||
#endif /* LINK_STATS_PACKET_COUNTERS */
|
||||
|
||||
typedef uint16_t link_packet_stat_t;
|
||||
|
||||
struct link_packet_counter {
|
||||
/* total attempts to transmit unicast packets */
|
||||
link_packet_stat_t num_packets_tx;
|
||||
/* total ACKs for unicast packets */
|
||||
link_packet_stat_t num_packets_acked;
|
||||
/* total number of unicast and broadcast packets received */
|
||||
link_packet_stat_t num_packets_rx;
|
||||
};
|
||||
|
||||
|
||||
/* All statistics of a given link */
|
||||
struct link_stats {
|
||||
clock_time_t last_tx_time; /* Last Tx timestamp */
|
||||
@ -66,10 +85,17 @@ struct link_stats {
|
||||
uint8_t tx_count; /* Tx count, used for ETX calculation */
|
||||
uint8_t ack_count; /* ACK count, used for ETX calculation */
|
||||
#endif /* LINK_STATS_ETX_FROM_PACKET_COUNT */
|
||||
|
||||
#if LINK_STATS_PACKET_COUNTERS
|
||||
struct link_packet_counter cnt_current; /* packets in the current period */
|
||||
struct link_packet_counter cnt_total; /* packets in total */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Returns the neighbor's link statistics */
|
||||
const struct link_stats *link_stats_from_lladdr(const linkaddr_t *lladdr);
|
||||
/* Returns the address of the neighbor */
|
||||
const linkaddr_t *link_stats_get_lladdr(const struct link_stats *);
|
||||
/* Are the statistics fresh? */
|
||||
int link_stats_is_fresh(const struct link_stats *stats);
|
||||
/* Resets link-stats module */
|
||||
|
@ -50,11 +50,6 @@
|
||||
#include "lib/list.h"
|
||||
#include "lib/memb.h"
|
||||
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
#include "lib/simEnvChange.h"
|
||||
#include "sys/cooja_mt.h"
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
|
||||
/* Log configuration */
|
||||
#include "sys/log.h"
|
||||
#define LOG_MODULE "CSMA"
|
||||
@ -201,17 +196,10 @@ send_one_packet(void *ptr)
|
||||
if(is_broadcast) {
|
||||
ret = MAC_TX_OK;
|
||||
} else {
|
||||
rtimer_clock_t wt;
|
||||
|
||||
/* Check for ack */
|
||||
wt = RTIMER_NOW();
|
||||
watchdog_periodic();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_ACK_WAIT_TIME)) {
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
simProcessRunValue = 1;
|
||||
cooja_mt_yield();
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
}
|
||||
|
||||
/* Wait for max CSMA_ACK_WAIT_TIME */
|
||||
RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_ACK_WAIT_TIME);
|
||||
|
||||
ret = MAC_TX_NOACK;
|
||||
if(NETSTACK_RADIO.receiving_packet() ||
|
||||
@ -220,17 +208,8 @@ send_one_packet(void *ptr)
|
||||
int len;
|
||||
uint8_t ackbuf[CSMA_ACK_LEN];
|
||||
|
||||
if(CSMA_AFTER_ACK_DETECTED_WAIT_TIME > 0) {
|
||||
wt = RTIMER_NOW();
|
||||
watchdog_periodic();
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
|
||||
wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) {
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
simProcessRunValue = 1;
|
||||
cooja_mt_yield();
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
}
|
||||
}
|
||||
/* Wait an additional CSMA_AFTER_ACK_DETECTED_WAIT_TIME to complete reception */
|
||||
RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_AFTER_ACK_DETECTED_WAIT_TIME);
|
||||
|
||||
if(NETSTACK_RADIO.pending_packet()) {
|
||||
len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
|
||||
|
@ -151,7 +151,7 @@
|
||||
#ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
|
||||
#define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
|
||||
#else
|
||||
#define TSCH_HOPPING_SEQUENCE_MAX_LEN 16
|
||||
#define TSCH_HOPPING_SEQUENCE_MAX_LEN sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)
|
||||
#endif
|
||||
|
||||
/******** Configuration: association *******/
|
||||
@ -365,18 +365,21 @@
|
||||
/******** Configuration: CSMA *******/
|
||||
|
||||
/* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */
|
||||
|
||||
/* Min backoff exponent */
|
||||
#ifdef TSCH_CONF_MAC_MIN_BE
|
||||
#define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE
|
||||
#else
|
||||
#define TSCH_MAC_MIN_BE 1
|
||||
#endif
|
||||
|
||||
/* Max backoff exponent */
|
||||
#ifdef TSCH_CONF_MAC_MAX_BE
|
||||
#define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE
|
||||
#else
|
||||
#define TSCH_MAC_MAX_BE 5
|
||||
#endif
|
||||
|
||||
/* Max number of re-transmissions */
|
||||
#ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES
|
||||
#define TSCH_MAC_MAX_FRAME_RETRIES TSCH_CONF_MAC_MAX_FRAME_RETRIES
|
||||
@ -391,6 +394,13 @@
|
||||
#define TSCH_PACKET_EACK_WITH_SRC_ADDR 0
|
||||
#endif
|
||||
|
||||
/* Perform CCA before sending? */
|
||||
#ifdef TSCH_CONF_CCA_ENABLED
|
||||
#define TSCH_CCA_ENABLED TSCH_CONF_CCA_ENABLED
|
||||
#else
|
||||
#define TSCH_CCA_ENABLED 0
|
||||
#endif
|
||||
|
||||
/* Include destination address in ACK? */
|
||||
#ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
|
||||
#define TSCH_PACKET_EACK_WITH_DEST_ADDR TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
|
||||
@ -415,12 +425,12 @@ by default, useful in case of duplicate seqno */
|
||||
#define TSCH_RADIO_ON_DURING_TIMESLOT 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Timeslot timing */
|
||||
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 10000
|
||||
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */
|
||||
/* TSCH timeslot timing template */
|
||||
#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
|
||||
#define TSCH_DEFAULT_TIMESLOT_TIMING TSCH_CONF_DEFAULT_TIMESLOT_TIMING
|
||||
#else
|
||||
#define TSCH_DEFAULT_TIMESLOT_TIMING tsch_timeslot_timing_us_10000
|
||||
#endif
|
||||
|
||||
/* Configurable Rx guard time is micro-seconds */
|
||||
#ifndef TSCH_CONF_RX_WAIT
|
||||
|
@ -75,87 +75,16 @@
|
||||
#define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32)
|
||||
|
||||
/* The approximate number of slots per second */
|
||||
#define TSCH_SLOTS_PER_SECOND (1000000 / TSCH_DEFAULT_TS_TIMESLOT_LENGTH)
|
||||
#define TSCH_SLOTS_PER_SECOND (1000000 / tsch_timing_us[tsch_ts_timeslot_length])
|
||||
|
||||
/* Calculate packet tx/rx duration in rtimer ticks based on sent
|
||||
* packet len in bytes with 802.15.4 250kbps data rate.
|
||||
* One byte = 32us. Add two bytes for CRC and one for len field */
|
||||
#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(32 * ((len) + 3))
|
||||
#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * ((len) + RADIO_PHY_OVERHEAD))
|
||||
|
||||
/* Convert rtimer ticks to clock and vice versa */
|
||||
#define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND)
|
||||
#define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length)
|
||||
|
||||
/* The default timeslot timing in the standard is a guard time of
|
||||
* 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us.
|
||||
* As a result, the listening device has a guard time not centered
|
||||
* on the expected Tx time. This is to be fixed in the next iteration
|
||||
* of the standard. This can be enabled with:
|
||||
* #define TSCH_DEFAULT_TS_TX_OFFSET 2120
|
||||
* #define TSCH_DEFAULT_TS_RX_OFFSET 1120
|
||||
* #define TSCH_DEFAULT_TS_RX_WAIT 2200
|
||||
*
|
||||
* Instead, we align the Rx guard time on expected Tx time. The Rx
|
||||
* guard time is user-configurable with TSCH_CONF_RX_WAIT.
|
||||
|
||||
* (TS_TX_OFFSET - (TS_RX_WAIT / 2)) instead */
|
||||
|
||||
#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 10000
|
||||
/* Default timeslot timing as per IEEE 802.15.4e */
|
||||
|
||||
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||
#define TSCH_DEFAULT_TS_CCA 128
|
||||
#define TSCH_DEFAULT_TS_TX_OFFSET 2120
|
||||
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 800
|
||||
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 1000
|
||||
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||
#define TSCH_DEFAULT_TS_ACK_WAIT 400
|
||||
#define TSCH_DEFAULT_TS_RX_TX 192
|
||||
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 10000
|
||||
|
||||
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 15000
|
||||
/* Default timeslot timing for platforms requiring 15ms slots */
|
||||
|
||||
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||
#define TSCH_DEFAULT_TS_CCA 128
|
||||
#define TSCH_DEFAULT_TS_TX_OFFSET 4000
|
||||
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 3600
|
||||
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 4000
|
||||
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||
#define TSCH_DEFAULT_TS_ACK_WAIT 800
|
||||
#define TSCH_DEFAULT_TS_RX_TX 2072
|
||||
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 15000
|
||||
|
||||
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 65000U
|
||||
/* 65ms timeslot, i.e. nearly the max length allowed by standard (16-bit unsigned in micro-seconds).
|
||||
* Useful for running link-layer security on sky in Cooja, where only S/W security is supported.
|
||||
* Note: this slot timing would require a total of 120ms. If a slot overlaps with the next active slot,
|
||||
* the latter will be skipped.
|
||||
* This configuration is mostly a work-around to test link-layer security in Cooja, it is recommended
|
||||
* to use it with a 6TiSCH minimal schedule of length >= 2. */
|
||||
|
||||
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||
#define TSCH_DEFAULT_TS_CCA 128
|
||||
#define TSCH_DEFAULT_TS_TX_OFFSET 52000
|
||||
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 58600
|
||||
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 59000
|
||||
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||
#define TSCH_DEFAULT_TS_ACK_WAIT 800
|
||||
#define TSCH_DEFAULT_TS_RX_TX 2072
|
||||
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 65000
|
||||
|
||||
#else
|
||||
#error "TSCH: Unsupported default timeslot length"
|
||||
#endif
|
||||
|
||||
#endif /* __TSCH_CONST_H__ */
|
||||
/** @} */
|
||||
|
@ -173,6 +173,8 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr)
|
||||
old_time_src->is_time_source = 0;
|
||||
}
|
||||
|
||||
tsch_stats_reset_neighbor_stats();
|
||||
|
||||
#ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
|
||||
TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src);
|
||||
#endif
|
||||
|
@ -52,10 +52,6 @@
|
||||
#include "net/queuebuf.h"
|
||||
#include "net/mac/framer/framer-802154.h"
|
||||
#include "net/mac/tsch/tsch.h"
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
#include "lib/simEnvChange.h"
|
||||
#include "sys/cooja_mt.h"
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
|
||||
#include "sys/log.h"
|
||||
/* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH
|
||||
@ -94,7 +90,7 @@
|
||||
|
||||
/* Truncate received drift correction information to maximum half
|
||||
* of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */
|
||||
#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(TSCH_DEFAULT_TS_RX_WAIT / 4))
|
||||
#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(tsch_timing_us[tsch_ts_rx_wait] / 4))
|
||||
|
||||
/* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */
|
||||
#if RTIMER_SECOND < (32 * 1024)
|
||||
@ -206,10 +202,7 @@ tsch_get_lock(void)
|
||||
busy_wait = 1;
|
||||
busy_wait_time = RTIMER_NOW();
|
||||
while(tsch_in_slot_operation) {
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
simProcessRunValue = 1;
|
||||
cooja_mt_yield();
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
watchdog_periodic();
|
||||
}
|
||||
busy_wait_time = RTIMER_NOW() - busy_wait_time;
|
||||
}
|
||||
@ -303,7 +296,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_
|
||||
}
|
||||
|
||||
/* block until the time to schedule comes */
|
||||
BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -314,7 +307,7 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_
|
||||
do { \
|
||||
if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
|
||||
PT_YIELD(pt); \
|
||||
BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
|
||||
} \
|
||||
} while(0);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -464,9 +457,9 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||
/* Did we set the frame pending bit to request an extra burst link? */
|
||||
static int burst_link_requested;
|
||||
|
||||
#if CCA_ENABLED
|
||||
#if TSCH_CCA_ENABLED
|
||||
static uint8_t cca_status;
|
||||
#endif
|
||||
#endif /* TSCH_CCA_ENABLED */
|
||||
|
||||
/* get payload */
|
||||
packet = queuebuf_dataptr(current_packet->qb);
|
||||
@ -507,22 +500,22 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||
if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */
|
||||
static rtimer_clock_t tx_duration;
|
||||
|
||||
#if CCA_ENABLED
|
||||
#if TSCH_CCA_ENABLED
|
||||
cca_status = 1;
|
||||
/* delay before CCA */
|
||||
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca");
|
||||
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_cca_offset], "cca");
|
||||
TSCH_DEBUG_TX_EVENT();
|
||||
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
|
||||
/* CCA */
|
||||
BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()),
|
||||
current_slot_start, TS_CCA_OFFSET + TS_CCA);
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()),
|
||||
current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]);
|
||||
TSCH_DEBUG_TX_EVENT();
|
||||
/* there is not enough time to turn radio off */
|
||||
/* NETSTACK_RADIO.off(); */
|
||||
if(cca_status == 0) {
|
||||
mac_tx_status = MAC_TX_COLLISION;
|
||||
} else
|
||||
#endif /* CCA_ENABLED */
|
||||
#endif /* TSCH_CCA_ENABLED */
|
||||
{
|
||||
/* delay before TX */
|
||||
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx");
|
||||
@ -561,14 +554,14 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||
TSCH_DEBUG_TX_EVENT();
|
||||
tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
|
||||
/* Wait for ACK to come */
|
||||
BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
|
||||
tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait] + RADIO_DELAY_BEFORE_DETECT);
|
||||
TSCH_DEBUG_TX_EVENT();
|
||||
|
||||
ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
|
||||
|
||||
/* Wait for ACK to finish */
|
||||
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||
ack_start_time, tsch_timing[tsch_ts_max_ack]);
|
||||
TSCH_DEBUG_TX_EVENT();
|
||||
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
|
||||
@ -625,6 +618,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||
"!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction);
|
||||
);
|
||||
}
|
||||
tsch_stats_on_time_synchronization(eack_time_correction);
|
||||
is_drift_correction_used = 1;
|
||||
tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction);
|
||||
/* Keep track of sync time */
|
||||
@ -666,6 +660,11 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||
ringbufindex_put(&dequeued_ringbuf);
|
||||
}
|
||||
|
||||
/* If this is an unicast packet to timesource, update stats */
|
||||
if(current_neighbor != NULL && current_neighbor->is_time_source) {
|
||||
tsch_stats_tx_packet(current_neighbor, mac_tx_status, tsch_current_channel);
|
||||
}
|
||||
|
||||
/* Log every tx attempt */
|
||||
TSCH_LOG_ADD(tsch_log_tx,
|
||||
log->tx.mac_tx_status = mac_tx_status;
|
||||
@ -742,7 +741,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet();
|
||||
if(!packet_seen) {
|
||||
/* Check if receiving within guard time */
|
||||
BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
|
||||
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT);
|
||||
}
|
||||
if(!packet_seen) {
|
||||
@ -754,7 +753,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
|
||||
|
||||
/* Wait until packet is received, turn radio off */
|
||||
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]);
|
||||
TSCH_DEBUG_RX_EVENT();
|
||||
tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
|
||||
@ -764,6 +763,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
static int header_len;
|
||||
static frame802154_t frame;
|
||||
radio_value_t radio_last_rssi;
|
||||
radio_value_t radio_last_lqi;
|
||||
|
||||
/* Read packet */
|
||||
current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN);
|
||||
@ -782,6 +782,8 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
#endif
|
||||
|
||||
packet_duration = TSCH_PACKET_DURATION(current_input->len);
|
||||
/* limit packet_duration to its max value */
|
||||
packet_duration = MIN(packet_duration, tsch_timing[tsch_ts_max_tx]);
|
||||
|
||||
if(!frame_valid) {
|
||||
TSCH_LOG_ADD(tsch_log_message,
|
||||
@ -821,6 +823,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
int do_nack = 0;
|
||||
rx_count++;
|
||||
estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
|
||||
tsch_stats_on_time_synchronization(estimated_drift);
|
||||
|
||||
#if TSCH_TIMESYNC_REMOVE_JITTER
|
||||
/* remove jitter due to measurement errors */
|
||||
@ -889,6 +892,12 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||
/* Add current input to ringbuf */
|
||||
ringbufindex_put(&input_ringbuf);
|
||||
|
||||
/* If the neighbor is known, update its stats */
|
||||
if(n != NULL) {
|
||||
NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_LINK_QUALITY, &radio_last_lqi);
|
||||
tsch_stats_rx_packet(n, current_input->rssi, radio_last_lqi, tsch_current_channel);
|
||||
}
|
||||
|
||||
/* Log every reception */
|
||||
TSCH_LOG_ADD(tsch_log_rx,
|
||||
linkaddr_copy(&log->rx.src, (linkaddr_t *)&frame.src_addr);
|
||||
@ -951,6 +960,8 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr))
|
||||
int is_active_slot;
|
||||
TSCH_DEBUG_SLOT_START();
|
||||
tsch_in_slot_operation = 1;
|
||||
/* Measure on-air noise level while TSCH is idle */
|
||||
tsch_stats_sample_rssi();
|
||||
/* Reset drift correction */
|
||||
drift_correction = 0;
|
||||
is_drift_correction_used = 0;
|
||||
|
236
os/net/mac/tsch/tsch-stats.c
Normal file
236
os/net/mac/tsch/tsch-stats.c
Normal 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 */
|
||||
/*---------------------------------------------------------------------------*/
|
223
os/net/mac/tsch/tsch-stats.h
Normal file
223
os/net/mac/tsch/tsch-stats.h
Normal 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__ */
|
||||
/** @} */
|
79
os/net/mac/tsch/tsch-timeslot-timing.c
Normal file
79
os/net/mac/tsch/tsch-timeslot-timing.c
Normal 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 */
|
||||
};
|
||||
|
||||
/** @} */
|
@ -102,20 +102,9 @@ uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
||||
struct tsch_asn_divisor_t tsch_hopping_sequence_length;
|
||||
|
||||
/* Default TSCH timeslot timing (in micro-second) */
|
||||
static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = {
|
||||
TSCH_DEFAULT_TS_CCA_OFFSET,
|
||||
TSCH_DEFAULT_TS_CCA,
|
||||
TSCH_DEFAULT_TS_TX_OFFSET,
|
||||
TSCH_DEFAULT_TS_RX_OFFSET,
|
||||
TSCH_DEFAULT_TS_RX_ACK_DELAY,
|
||||
TSCH_DEFAULT_TS_TX_ACK_DELAY,
|
||||
TSCH_DEFAULT_TS_RX_WAIT,
|
||||
TSCH_DEFAULT_TS_ACK_WAIT,
|
||||
TSCH_DEFAULT_TS_RX_TX,
|
||||
TSCH_DEFAULT_TS_MAX_ACK,
|
||||
TSCH_DEFAULT_TS_MAX_TX,
|
||||
TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
|
||||
};
|
||||
static const uint16_t *tsch_default_timing_us;
|
||||
/* TSCH timeslot timing (in micro-second) */
|
||||
uint16_t tsch_timing_us[tsch_ts_elements_count];
|
||||
/* TSCH timeslot timing (in rtimer ticks) */
|
||||
rtimer_clock_t tsch_timing[tsch_ts_elements_count];
|
||||
|
||||
@ -231,8 +220,10 @@ tsch_reset(void)
|
||||
TSCH_ASN_INIT(tsch_current_asn, 0, 0);
|
||||
current_link = NULL;
|
||||
/* Reset timeslot timing to defaults */
|
||||
tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING;
|
||||
for(i = 0; i < tsch_ts_elements_count; i++) {
|
||||
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
|
||||
tsch_timing_us[i] = tsch_default_timing_us[i];
|
||||
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
|
||||
}
|
||||
#ifdef TSCH_CALLBACK_LEAVING_NETWORK
|
||||
TSCH_CALLBACK_LEAVING_NETWORK();
|
||||
@ -412,6 +403,22 @@ eb_input(struct input_packet *current_input)
|
||||
}
|
||||
#endif /* TSCH_AUTOSELECT_TIME_SOURCE */
|
||||
}
|
||||
|
||||
/* TSCH hopping sequence */
|
||||
if(eb_ies.ie_channel_hopping_sequence_id != 0) {
|
||||
if(eb_ies.ie_hopping_sequence_len != tsch_hopping_sequence_length.val
|
||||
|| memcmp((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, tsch_hopping_sequence_length.val)) {
|
||||
if(eb_ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
|
||||
memcpy((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list,
|
||||
eb_ies.ie_hopping_sequence_len);
|
||||
TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, eb_ies.ie_hopping_sequence_len);
|
||||
|
||||
LOG_WARN("Updating TSCH hopping sequence from EB\n");
|
||||
} else {
|
||||
LOG_WARN("TSCH:! parse_eb: hopping sequence too long (%u)\n", eb_ies.ie_hopping_sequence_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -565,10 +572,11 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
|
||||
/* TSCH timeslot timing */
|
||||
for(i = 0; i < tsch_ts_elements_count; i++) {
|
||||
if(ies.ie_tsch_timeslot_id == 0) {
|
||||
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
|
||||
tsch_timing_us[i] = tsch_default_timing_us[i];
|
||||
} else {
|
||||
tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]);
|
||||
tsch_timing_us[i] = ies.ie_tsch_timeslot[i];
|
||||
}
|
||||
tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
|
||||
}
|
||||
|
||||
/* TSCH hopping sequence */
|
||||
@ -714,11 +722,11 @@ PT_THREAD(tsch_scan(struct pt *pt))
|
||||
/* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
|
||||
uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
|
||||
random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
|
||||
if(current_channel != scan_channel) {
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
|
||||
current_channel = scan_channel;
|
||||
LOG_INFO("scanning on channel %u\n", scan_channel);
|
||||
}
|
||||
|
||||
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
|
||||
current_channel = scan_channel;
|
||||
LOG_INFO("scanning on channel %u\n", scan_channel);
|
||||
|
||||
current_channel_since = now_time;
|
||||
}
|
||||
|
||||
@ -729,20 +737,30 @@ PT_THREAD(tsch_scan(struct pt *pt))
|
||||
if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
|
||||
/* If we are currently receiving a packet, wait until end of reception */
|
||||
t0 = RTIMER_NOW();
|
||||
BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
|
||||
}
|
||||
|
||||
if(is_packet_pending) {
|
||||
rtimer_clock_t t1;
|
||||
/* Read packet */
|
||||
input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
|
||||
|
||||
/* Save packet timestamp */
|
||||
NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
|
||||
t1 = RTIMER_NOW();
|
||||
|
||||
/* Parse EB and attempt to associate */
|
||||
LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
|
||||
|
||||
tsch_associate(&input_eb, t0);
|
||||
/* Sanity-check the timestamp */
|
||||
if(ABS(RTIMER_CLOCK_DIFF(t0, t1)) < tsch_timing[tsch_ts_timeslot_length]) {
|
||||
tsch_associate(&input_eb, t0);
|
||||
} else {
|
||||
LOG_WARN("scan: dropping packet, timestamp too far from current time %u %u\n",
|
||||
(unsigned)t0,
|
||||
(unsigned)t1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(tsch_is_associated) {
|
||||
@ -864,6 +882,9 @@ PROCESS_THREAD(tsch_pending_events_process, ev, data)
|
||||
tsch_rx_process_pending();
|
||||
tsch_tx_process_pending();
|
||||
tsch_log_process_pending();
|
||||
#ifdef TSCH_CALLBACK_SELECT_CHANNELS
|
||||
TSCH_CALLBACK_SELECT_CHANNELS();
|
||||
#endif
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
@ -878,6 +899,12 @@ tsch_init(void)
|
||||
radio_value_t radio_tx_mode;
|
||||
rtimer_clock_t t;
|
||||
|
||||
/* Check that the platform provides a TSCH timeslot timing template */
|
||||
if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) {
|
||||
LOG_ERR("! platform does not provide a timeslot timing template.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Radio Rx mode */
|
||||
if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) {
|
||||
LOG_ERR("! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
|
||||
@ -918,6 +945,7 @@ tsch_init(void)
|
||||
/* Check max hopping sequence length vs default sequence length */
|
||||
if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
|
||||
LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Init the queuebuf and TSCH sub-modules */
|
||||
@ -944,6 +972,8 @@ tsch_init(void)
|
||||
#if TSCH_WITH_SIXTOP
|
||||
sixtop_init();
|
||||
#endif
|
||||
|
||||
tsch_stats_init();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */
|
||||
|
@ -60,28 +60,16 @@ frequency hopping for enhanced reliability.
|
||||
#include "net/mac/tsch/tsch-packet.h"
|
||||
#include "net/mac/tsch/tsch-security.h"
|
||||
#include "net/mac/tsch/tsch-schedule.h"
|
||||
#include "net/mac/tsch/tsch-stats.h"
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
#include "net/mac/tsch/tsch-rpl.h"
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
#include "lib/simEnvChange.h"
|
||||
#include "sys/cooja_mt.h"
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
|
||||
/*********** Macros *********/
|
||||
|
||||
/* Wait for a condition with timeout t0+offset. */
|
||||
#if CONTIKI_TARGET_COOJA
|
||||
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) { \
|
||||
simProcessRunValue = 1; \
|
||||
cooja_mt_yield(); \
|
||||
};
|
||||
#else
|
||||
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ;
|
||||
#endif /* CONTIKI_TARGET_COOJA */
|
||||
/* Include Arch-Specific conf */
|
||||
#ifdef TSCH_CONF_ARCH_HDR_PATH
|
||||
#include TSCH_CONF_ARCH_HDR_PATH
|
||||
#endif /* TSCH_CONF_ARCH_HDR_PATH */
|
||||
|
||||
/*********** Callbacks *********/
|
||||
|
||||
@ -169,6 +157,8 @@ extern uint8_t tsch_current_channel;
|
||||
/* TSCH channel hopping sequence */
|
||||
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
||||
extern struct tsch_asn_divisor_t tsch_hopping_sequence_length;
|
||||
/* TSCH timeslot timing (in micro-second) */
|
||||
uint16_t tsch_timing_us[tsch_ts_elements_count];
|
||||
/* TSCH timeslot timing (in rtimer ticks) */
|
||||
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
|
||||
/* Statistics on the current session */
|
||||
@ -177,6 +167,8 @@ extern unsigned long rx_count;
|
||||
extern unsigned long sync_count;
|
||||
extern int32_t min_drift_seen;
|
||||
extern int32_t max_drift_seen;
|
||||
/* The TSCH standard 10ms timeslot timing */
|
||||
extern const uint16_t tsch_timeslot_timing_us_10000[tsch_ts_elements_count];
|
||||
|
||||
/* TSCH processes */
|
||||
PROCESS_NAME(tsch_process);
|
||||
|
@ -272,7 +272,7 @@
|
||||
#ifdef RPL_CONF_DAG_LIFETIME
|
||||
#define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME
|
||||
#else
|
||||
#define RPL_DAG_LIFETIME (60 * 60) /* one hour */
|
||||
#define RPL_DAG_LIFETIME (8 * 60) /* 8 hours */
|
||||
#endif /* RPL_CONF_DAG_LIFETIME */
|
||||
|
||||
/*
|
||||
|
1
os/services/tsch-cs/Makefile
Normal file
1
os/services/tsch-cs/Makefile
Normal file
@ -0,0 +1 @@
|
||||
CFLAGS += -DBUILD_WITH_TSCH_CS=1
|
328
os/services/tsch-cs/tsch-cs.c
Normal file
328
os/services/tsch-cs/tsch-cs.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
76
os/services/tsch-cs/tsch-cs.h
Normal file
76
os/services/tsch-cs/tsch-cs.h
Normal 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__ */
|
@ -54,6 +54,8 @@
|
||||
#define RTIMER_H_
|
||||
|
||||
#include "contiki.h"
|
||||
#include "dev/watchdog.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/** \brief The rtimer size (in bytes) */
|
||||
#ifdef RTIMER_CONF_CLOCK_SIZE
|
||||
@ -186,6 +188,26 @@ void rtimer_arch_schedule(rtimer_clock_t t);
|
||||
#define RTIMER_GUARD_TIME (RTIMER_ARCH_SECOND >> 14)
|
||||
#endif /* RTIMER_CONF_GUARD_TIME */
|
||||
|
||||
/** \brief Busy-wait until a condition. Start time is t0, max wait time is max_time */
|
||||
#define RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time) \
|
||||
({ \
|
||||
bool c; \
|
||||
while(!(c = cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (max_time))) { \
|
||||
watchdog_periodic(); \
|
||||
} \
|
||||
c; \
|
||||
})
|
||||
|
||||
/** \brief Busy-wait until a condition for at most max_time */
|
||||
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time) \
|
||||
({ \
|
||||
rtimer_clock_t t0 = RTIMER_NOW(); \
|
||||
RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time); \
|
||||
})
|
||||
|
||||
/** \brief Busy-wait for a fixed duration */
|
||||
#define RTIMER_BUSYWAIT(duration) RTIMER_BUSYWAIT_UNTIL(0, duration)
|
||||
|
||||
#endif /* RTIMER_H_ */
|
||||
|
||||
/** @} */
|
||||
|
@ -54,10 +54,10 @@
|
||||
##### "TSCH_CONF_MAX_EB_PERIOD": _______________ -> TSCH_MAX_EB_PERIOD
|
||||
#endif
|
||||
|
||||
#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||
##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ == TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||
#ifdef TSCH_CONF_DEFAULT_TIMESLOT_TIMING
|
||||
##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ == TSCH_CONF_DEFAULT_TIMESLOT_TIMING
|
||||
#else
|
||||
##### "TSCH_CONF_DEFAULT_TIMESLOT_LENGTH": _____ -> TSCH_DEFAULT_TIMESLOT_LENGTH
|
||||
##### "TSCH_CONF_DEFAULT_TIMESLOT_TIMING": _____ -> TSCH_DEFAULT_TIMESLOT_TIMING
|
||||
#endif
|
||||
|
||||
#ifdef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH
|
||||
|
Loading…
Reference in New Issue
Block a user