coding conventions for drivers

This commit is contained in:
Oliver Hahm 2013-06-21 22:36:48 +02:00
parent 201f593641
commit e2130fbd47
26 changed files with 2467 additions and 2150 deletions

View File

@ -79,20 +79,21 @@ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priorit
uint16_t difs;
uint16_t slottime;
switch (priority)
{
switch(priority) {
case PRIORITY_ALARM:
min_window_size = PRIO_ALARM_MIN_WINDOW_SIZE;
max_window_size = PRIO_ALARM_MAX_WINDOW_SIZE;
difs = PRIO_ALARM_DIFS;
slottime = PRIO_ALARM_SLOTTIME;
break;
case PRIORITY_WARNING:
min_window_size = PRIO_WARN_MIN_WINDOW_SIZE;
max_window_size = PRIO_WARN_MAX_WINDOW_SIZE;
difs = PRIO_WARN_DIFS;
slottime = PRIO_WARN_SLOTTIME;
break;
default:
min_window_size = PRIO_DATA_MIN_WINDOW_SIZE;
max_window_size = PRIO_DATA_MAX_WINDOW_SIZE;
@ -100,7 +101,7 @@ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priorit
slottime = PRIO_DATA_SLOTTIME;
}
// Calculate collisions per second
/* Calculate collisions per second */
if(collision_state == COLLISION_STATE_INITIAL) {
timex_t now;
vtimer_now(&now);
@ -108,120 +109,152 @@ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priorit
collision_count = 0;
collisions_per_sec = 0;
collision_state = COLLISION_STATE_MEASURE;
} else if (collision_state == COLLISION_STATE_MEASURE) {
}
else if(collision_state == COLLISION_STATE_MEASURE) {
timex_t now;
vtimer_now(&now);
uint64_t timespan = now.microseconds - collision_measurement_start;
if(timespan > 1000000) {
collisions_per_sec = (collision_count * 1000000) / (double) timespan;
if(collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
timex_t now;
vtimer_now(&now);
collision_measurement_start = now.microseconds;
collision_state = COLLISION_STATE_KEEP;
} else if (collisions_per_sec > 2.2) {
}
else if(collisions_per_sec > 2.2) {
timex_t now;
vtimer_now(&now);
collision_measurement_start = now.microseconds;
collision_state = COLLISION_STATE_KEEP;
} else {
}
else {
collision_state = COLLISION_STATE_INITIAL;
}
}
} else if (collision_state == COLLISION_STATE_KEEP) {
}
else if(collision_state == COLLISION_STATE_KEEP) {
timex_t now;
vtimer_now(&now);
uint64_t timespan = now.microseconds - collision_measurement_start;
if(timespan > 5000000) {
collision_state = COLLISION_STATE_INITIAL;
}
}
// Adjust initial window size according to collision rate
/* Adjust initial window size according to collision rate */
if(collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
min_window_size *= 2;
} else if (collisions_per_sec > 2.2) {
}
else if(collisions_per_sec > 2.2) {
min_window_size *= 4;
}
uint16_t windowSize = min_window_size; // Start with window size of PRIO_XXX_MIN_WINDOW_SIZE
uint16_t backoff = 0; // Backoff between 1 and windowSize
uint32_t total; // Holds the total wait time before send try
uint32_t cs_timeout; // Current carrier sense timeout value
uint16_t windowSize = min_window_size; /* Start with window size of PRIO_XXX_MIN_WINDOW_SIZE */
uint16_t backoff = 0; /* Backoff between 1 and windowSize */
uint32_t total; /* Holds the total wait time before send try */
uint32_t cs_timeout; /* Current carrier sense timeout value */
if (protocol == 0)
{
return RADIO_INVALID_PARAM; // Not allowed, protocol id must be greater zero
if(protocol == 0) {
return RADIO_INVALID_PARAM; /* Not allowed, protocol id must be greater zero */
}
cc1100_phy_mutex_lock(); // Lock radio for exclusive access
cc1100_phy_mutex_lock(); /* Lock radio for exclusive access */
// Get carrier sense timeout based on overall error rate till now
/* Get carrier sense timeout based on overall error rate till now */
send_csmaca_calls++;
int fail_percentage = (send_csmaca_calls_cs_timeout * 100) / send_csmaca_calls;
if (fail_percentage == 0) fail_percentage = 1;
cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage;
if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) cs_timeout = CARRIER_SENSE_TIMEOUT_MIN;
cc1100_cs_init(); // Initialize carrier sensing
if(fail_percentage == 0) {
fail_percentage = 1;
}
cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage;
if(cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) {
cs_timeout = CARRIER_SENSE_TIMEOUT_MIN;
}
cc1100_cs_init(); /* Initialize carrier sensing */
window:
if (backoff != 0) goto cycle; // If backoff was 0
windowSize *= 2; // ...double the current window size
if (windowSize > max_window_size)
{
windowSize = max_window_size; // This is the maximum size allowed
if(backoff != 0) {
goto cycle; /* If backoff was 0 */
}
backoff = rand() % windowSize; // ...and choose new backoff
if (backoff < 0) backoff *= -1;
windowSize *= 2; /* ...double the current window size */
if(windowSize > max_window_size) {
windowSize = max_window_size; /* This is the maximum size allowed */
}
backoff = rand() % windowSize; /* ...and choose new backoff */
if(backoff < 0) {
backoff *= -1;
}
backoff += (uint16_t) 1;
cycle:
cs_timeout_flag = 0; // Carrier sense timeout flag
cs_hwtimer_id = hwtimer_set(cs_timeout, // Set hwtimer to set CS timeout flag
cs_timeout_flag = 0; /* Carrier sense timeout flag */
cs_hwtimer_id = hwtimer_set(cs_timeout, /* Set hwtimer to set CS timeout flag */
cs_timeout_cb, NULL);
while (cc1100_cs_read()) // Wait until air is free
{
if (cs_timeout_flag)
{
while(cc1100_cs_read()) { /* Wait until air is free */
if(cs_timeout_flag) {
send_csmaca_calls_cs_timeout++;
#ifndef CSMACA_MAC_AGGRESSIVE_MODE
cc1100_phy_mutex_unlock();
cc1100_go_after_tx(); // Go from RX to default mode
return RADIO_CS_TIMEOUT; // Return immediately
cc1100_go_after_tx(); /* Go from RX to default mode */
return RADIO_CS_TIMEOUT; /* Return immediately */
#endif
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
goto send; // Send anyway
goto send; /* Send anyway */
#endif
}
}
hwtimer_remove(cs_hwtimer_id); // Remove hwtimer
cc1100_cs_write_cca(1); // Air is free now
hwtimer_remove(cs_hwtimer_id); /* Remove hwtimer */
cc1100_cs_write_cca(1); /* Air is free now */
cc1100_cs_set_enabled(true);
if (cc1100_cs_read()) goto window; // GDO0 triggers on rising edge, so
// test once after interrupt is enabled
if (backoff > 0) backoff--; // Decrement backoff counter
total = slottime; // Calculate total wait time
total *= (uint32_t)backoff; // Slot vector set
total += difs; // ...and standard DIFS wait time
cs_timeout_flag = 0; // Carrier sense timeout flag
cs_hwtimer_id = hwtimer_set(total, // Set hwtimer to set CS timeout flag
if(cc1100_cs_read()) {
goto window; /* GDO0 triggers on rising edge, so */
}
/* test once after interrupt is enabled */
if(backoff > 0) {
backoff--; /* Decrement backoff counter */
}
total = slottime; /* Calculate total wait time */
total *= (uint32_t)backoff; /* Slot vector set */
total += difs; /* ...and standard DIFS wait time */
cs_timeout_flag = 0; /* Carrier sense timeout flag */
cs_hwtimer_id = hwtimer_set(total, /* Set hwtimer to set CS timeout flag */
cs_timeout_cb, NULL);
while(!cs_timeout_flag
|| !cc1100_cs_read_cca()) // Wait until timeout is finished
{
if (cc1100_cs_read_cca() == 0) // Is the air still free?
{
|| !cc1100_cs_read_cca()) { /* Wait until timeout is finished */
if(cc1100_cs_read_cca() == 0) { /* Is the air still free? */
hwtimer_remove(cs_hwtimer_id);
goto window; // No. Go back to new wait period.
goto window; /* No. Go back to new wait period. */
}
}
cc1100_cs_set_enabled(false);
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
send:
#endif
int res = cc1100_send(address, protocol, priority, payload, payload_len);
if(res < 0) {
collision_count++;
}
return res;
}

View File

@ -76,49 +76,49 @@ and the mailinglist (subscription via web site)
* 24 | 240 | 917.61
*/
// 400 kbps, MSK, X-tal: 26 MHz (Chip Revision F)
/* 400 kbps, MSK, X-tal: 26 MHz (Chip Revision F) */
char cc1100_conf[] = {
0x06, // IOCFG2
0x2E, // IOCFG1
0x0E, // IOCFG0
0x0F, // FIFOTHR
0x9B, // SYNC1
0xAD, // SYNC0
0x3D, // PKTLEN (maximum value of packet length byte = 61)
0x06, // PKTCTRL1
0x45, // PKTCTRL0 (variable packet length)
0xFF, // ADDR
CC1100_DEFAULT_CHANNR*10, // CHANNR
0x0B, // FSCTRL1
0x00, // FSCTRL0
0x21, // FREQ2
0x71, // FREQ1
0x7A, // FREQ0
0x2D, // MDMCFG4
0xF8, // MDMCFG3
0x73, // MDMCFG2
0x42, // MDMCFG1
0xF8, // MDMCFG0
0x00, // DEVIATN
0x07, // MCSM2
0x03, // MCSM1
0x18, // MCSM0
0x1D, // FOCCFG
0x1C, // BSCFG
0xC0, // AGCCTRL2
0x49, // AGCCTRL1, (old value was 0x49 -> made carrier sense less sensitive!)
// 0x47 - 7 dB above MAGN_TARGET setting
0xB2, // AGCCTRL0
0x87, // WOREVT1
0x6B, // WOREVT0
0xF8, // WORCTRL
0xB6, // FREND1
0x10, // FREND0
0xEA, // FSCAL3
0x2A, // FSCAL2
0x00, // FSCAL1
0x1F, // FSCAL0
0x00 // padding to 4 bytes
0x06, /* IOCFG2 */
0x2E, /* IOCFG1 */
0x0E, /* IOCFG0 */
0x0F, /* FIFOTHR */
0x9B, /* SYNC1 */
0xAD, /* SYNC0 */
0x3D, /* PKTLEN (maximum value of packet length byte = 61) */
0x06, /* PKTCTRL1 */
0x45, /* PKTCTRL0 (variable packet length) */
0xFF, /* ADDR */
CC1100_DEFAULT_CHANNR * 10, /* CHANNR */
0x0B, /* FSCTRL1 */
0x00, /* FSCTRL0 */
0x21, /* FREQ2 */
0x71, /* FREQ1 */
0x7A, /* FREQ0 */
0x2D, /* MDMCFG4 */
0xF8, /* MDMCFG3 */
0x73, /* MDMCFG2 */
0x42, /* MDMCFG1 */
0xF8, /* MDMCFG0 */
0x00, /* DEVIATN */
0x07, /* MCSM2 */
0x03, /* MCSM1 */
0x18, /* MCSM0 */
0x1D, /* FOCCFG */
0x1C, /* BSCFG */
0xC0, /* AGCCTRL2 */
0x49, /* AGCCTRL1, (old value was 0x49 -> made carrier sense less sensitive!)
* 0x47 - 7 dB above MAGN_TARGET setting */
0xB2, /* AGCCTRL0 */
0x87, /* WOREVT1 */
0x6B, /* WOREVT0 */
0xF8, /* WORCTRL */
0xB6, /* FREND1 */
0x10, /* FREND0 */
0xEA, /* FSCAL3 */
0x2A, /* FSCAL2 */
0x00, /* FSCAL1 */
0x1F, /* FSCAL0 */
0x00 /* padding to 4 bytes */
};
/** @} */

View File

@ -58,7 +58,7 @@ and the mailinglist (subscription via web site)
#include "hwtimer.h"
#include "core/include/bitarithm.h"
// TODO: cc1100 port timer
/* TODO: cc1100 port timer */
#ifdef FEUERWARE_CPU_LPC2387
//#include "cpu/lpc2387/lpc2387-timer2.h"
#endif
@ -70,8 +70,8 @@ and the mailinglist (subscription via web site)
#endif
#define PACKET_LENGTH (0x3E) ///< Packet length = 62 Bytes.
#define CC1100_SYNC_WORD_TX_TIME (90000) // loop count (max. timeout ~ 15 ms) to wait for
// sync word to be transmitted (GDO2 from low to high)
#define CC1100_SYNC_WORD_TX_TIME (90000) /* loop count (max. timeout ~ 15 ms) to wait for */
/* sync word to be transmitted (GDO2 from low to high) */
/**
* @name Virtual Radio Device methods (see vdevice_radio_methods)
@ -100,7 +100,7 @@ static uint8_t pa_table[] = { ///< PATABLE with available output powers
0xCC, ///< + 7 dBm
0xC6, ///< + 9 dBm
0xC3 ///< +10 dBm
}; // If PATABLE is changed in size, adjust MAX_OUTPUT_POWER definition in CC1100 interface!
}; /* If PATABLE is changed in size, adjust MAX_OUTPUT_POWER definition in CC1100 interface! */
static int8_t pa_table_dBm[] = { ///< Values of the PATABLE in dBm
-52,
@ -155,7 +155,7 @@ volatile cc1100_mode_callback_t cc1100_setup_mode; ///< Function to set up selec
volatile int wor_hwtimer_id = -1;
/*---------------------------------------------------------------------------*/
// Low-level hardware access
/* Low-level hardware access */
/*---------------------------------------------------------------------------*/
void cc1100_disable_interrupts(void)
@ -166,9 +166,9 @@ void cc1100_disable_interrupts(void)
void cc110x_gdo0_irq(void)
{
// Air was not free -> Clear CCA flag
/* Air was not free -> Clear CCA flag */
rflags.CAA = false;
// Disable carrier sense detection (GDO0 interrupt)
/* Disable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_disable();
}
@ -178,56 +178,56 @@ void cc110x_gdo2_irq(void)
}
/*---------------------------------------------------------------------------*/
// High level CC1100 SPI functions for transferring packet out
/* High level CC1100 SPI functions for transferring packet out */
// of RX FIFO (don't call when in WOR mode)
/*---------------------------------------------------------------------------*/
static bool spi_receive_packet_variable(uint8_t *rxBuffer, uint8_t length)
{
// Needed here for statistics
/* Needed here for statistics */
extern cc1100_statistic_t cc1100_statistic;
uint8_t status[2];
uint8_t packetLength = 0;
// Any bytes available in RX FIFO?
if ((cc1100_spi_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO))
{
// Read length byte (first byte in RX FIFO)
/* Any bytes available in RX FIFO? */
if((cc1100_spi_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) {
/* Read length byte (first byte in RX FIFO) */
packetLength = cc1100_spi_read_reg(CC1100_RXFIFO);
// Read data from RX FIFO and store in rxBuffer
if (packetLength <= length)
{
// Put length byte at first position in RX Buffer
/* Read data from RX FIFO and store in rxBuffer */
if(packetLength <= length) {
/* Put length byte at first position in RX Buffer */
rxBuffer[0] = packetLength;
// Read the rest of the packet
/* Read the rest of the packet */
cc1100_spi_readburst_reg(CC1100_RXFIFO, (char *)rxBuffer + 1, packetLength);
// Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI)
/* Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) */
cc1100_spi_readburst_reg(CC1100_RXFIFO, (char *)status, 2);
// Store RSSI value of packet
/* Store RSSI value of packet */
rflags.RSSI = status[I_RSSI];
// MSB of LQI is the CRC_OK bit
/* MSB of LQI is the CRC_OK bit */
rflags.CRC_STATE = (status[I_LQI] & CRC_OK) >> 7;
if (!rflags.CRC_STATE) cc1100_statistic.packets_in_crc_fail++;
// Bit 0-6 of LQI indicates the link quality (LQI)
if(!rflags.CRC_STATE) {
cc1100_statistic.packets_in_crc_fail++;
}
/* Bit 0-6 of LQI indicates the link quality (LQI) */
rflags.LQI = status[I_LQI] & LQI_EST;
return rflags.CRC_STATE;
}
else
{
// RX FIFO get automatically flushed if return value is false
else {
/* RX FIFO get automatically flushed if return value is false */
return false;
}
}
else
{
// RX FIFO get automatically flushed if return value is false
else {
/* RX FIFO get automatically flushed if return value is false */
return false;
}
}
@ -235,37 +235,43 @@ static bool spi_receive_packet_variable(uint8_t *rxBuffer, uint8_t length)
bool cc1100_spi_receive_packet(uint8_t *rxBuffer, uint8_t length)
{
uint8_t pkt_len_cfg = cc1100_spi_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG;
if (pkt_len_cfg == VARIABLE_PKTLEN)
{
if(pkt_len_cfg == VARIABLE_PKTLEN) {
return spi_receive_packet_variable(rxBuffer, length);
}
// Fixed packet length not supported.
// RX FIFO get automatically flushed if return value is false
/* Fixed packet length not supported. */
/* RX FIFO get automatically flushed if return value is false */
return false;
}
/*---------------------------------------------------------------------------*/
// CC1100 mode functionality
/* CC1100 mode functionality */
/*---------------------------------------------------------------------------*/
void cc1100_set_idle(void) {
void cc1100_set_idle(void)
{
if(radio_state == RADIO_WOR) {
// Wake up the chip from WOR/sleep
/* Wake up the chip from WOR/sleep */
cc110x_spi_select();
hwtimer_wait(RTIMER_TICKS(122));
cc110x_spi_unselect();
radio_state = RADIO_IDLE;
// XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms)
/* XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms) */
hwtimer_wait(FS_CAL_TIME);
return;
}
cc1100_spi_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE;
}
static void wakeup_from_rx(void)
{
if (radio_state != RADIO_RX) return;
if(radio_state != RADIO_RX) {
return;
}
cc1100_spi_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE;
}
@ -278,7 +284,7 @@ static void switch_to_rx(void)
static void setup_rx_mode(void)
{
// Stay in RX mode until end of packet
/* Stay in RX mode until end of packet */
cc1100_spi_write_reg(CC1100_MCSM2, 0x07);
switch_to_rx();
}
@ -291,12 +297,13 @@ static void wakeup_from_wor(void)
if(radio_state != RADIO_WOR) {
return;
}
// Wake up the chip from WOR/sleep
/* Wake up the chip from WOR/sleep */
cc110x_spi_select();
hwtimer_wait(RTIMER_TICKS(122));
cc110x_spi_unselect();
radio_state = RADIO_IDLE;
// XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms)
/* XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms) */
hwtimer_wait(FS_CAL_TIME);
}
@ -305,18 +312,20 @@ static void wakeup_from_wor(void)
*/
void switch_to_wor2(void)
{
// if (cc110x_get_gdo2()) return; // If incoming packet, then don't go to WOR now
cc1100_spi_strobe(CC1100_SIDLE); // Put CC1100 to IDLE
radio_state = RADIO_IDLE; // Radio state now IDLE
// if (cc110x_get_gdo2()) return; /* If incoming packet, then don't go to WOR now */
cc1100_spi_strobe(CC1100_SIDLE); /* Put CC1100 to IDLE */
radio_state = RADIO_IDLE; /* Radio state now IDLE */
cc1100_spi_write_reg(CC1100_MCSM2,
cc1100_wor_config.rx_time_reg); // Configure RX_TIME (for use in WOR)
cc1100_spi_write_reg(CC1100_MCSM0, 0x18); // Turn on FS-Autocal
cc1100_wor_config.rx_time_reg); /* Configure RX_TIME (for use in WOR) */
cc1100_spi_write_reg(CC1100_MCSM0, 0x18); /* Turn on FS-Autocal */
if(rflags.WOR_RST) {
cc1100_spi_strobe(CC1100_SWORRST); // Resets the real time clock
cc1100_spi_strobe(CC1100_SWORRST); /* Resets the real time clock */
rflags.WOR_RST = false;
}
cc1100_spi_strobe(CC1100_SWOR); // Put radio back to sleep/WOR (must be in IDLE when this is done)
radio_state = RADIO_WOR; // Radio state now WOR
cc1100_spi_strobe(CC1100_SWOR); /* Put radio back to sleep/WOR (must be in IDLE when this is done) */
radio_state = RADIO_WOR; /* Radio state now WOR */
}
/**
@ -324,8 +333,12 @@ void switch_to_wor2(void)
*/
static void hwtimer_switch_to_wor2_wrapper(void *ptr)
{
wor_hwtimer_id = -1; // kernel timer handler function called, clear timer id
if (rflags.TX) return; // Stability: don't allow WOR timers at this point
wor_hwtimer_id = -1; /* kernel timer handler function called, clear timer id */
if(rflags.TX) {
return; /* Stability: don't allow WOR timers at this point */
}
rflags.WOR_RST = true;
switch_to_wor2();
}
@ -335,47 +348,44 @@ static void hwtimer_switch_to_wor2_wrapper(void* ptr)
*/
static void switch_to_wor(void)
{
// Any incoming packet?
if (cc110x_get_gdo2())
{
// Then don't go to WOR now
/* Any incoming packet? */
if(cc110x_get_gdo2()) {
/* Then don't go to WOR now */
return;
}
// Step 1: Set chip for random interval (1..RX_INTERVAL) to power down mode
if (!rflags.MAN_WOR)
{
/* Step 1: Set chip for random interval (1..RX_INTERVAL) to power down mode */
if(!rflags.MAN_WOR) {
rflags.MAN_WOR = true;
radio_state = RADIO_WOR;
// Go to power down mode
/* Go to power down mode */
cc1100_spi_strobe(CC1100_SIDLE);
cc1100_spi_strobe(CC1100_SPWD);
// Set timer to do second step of manual WOR
/* Set timer to do second step of manual WOR */
int r = (rand() / (double)(RAND_MAX + 1.0)) * (cc1100_wor_config.rx_interval * 100.0) + 20;
wor_hwtimer_id = hwtimer_set(r, cc1100_hwtimer_go_receive_wrapper, NULL);
if (wor_hwtimer_id == -1)
{
if(wor_hwtimer_id == -1) {
rflags.KT_RES_ERR = true;
// No hwtimer available, go immediately to WOR mode.
// Else never receiving packets again...
/* No hwtimer available, go immediately to WOR mode. */
/* Else never receiving packets again... */
rflags.MAN_WOR = false;
switch_to_wor2();
}
}
// Step 2: Go to RX and then to WOR mode again
else
{
/* Step 2: Go to RX and then to WOR mode again */
else {
rflags.MAN_WOR = false;
wakeup_from_wor();
cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX;
// Register timer to go to WOR after RX timeout
/* Register timer to go to WOR after RX timeout */
wor_hwtimer_id = hwtimer_set((cc1100_wor_config.rx_time_ms * 100 + 150),
hwtimer_switch_to_wor2_wrapper, NULL); // add 1,5 ms secure time
if (wor_hwtimer_id == -1)
{
hwtimer_switch_to_wor2_wrapper, NULL); /* add 1,5 ms secure time */
if(wor_hwtimer_id == -1) {
rflags.KT_RES_ERR = true;
}
}
@ -383,31 +393,31 @@ static void switch_to_wor(void)
static void setup_wor_mode(void)
{
// Wake up from WOR (if in WOR, else no effect)
/* Wake up from WOR (if in WOR, else no effect) */
cc1100_go_idle();
// Make sure CC1100 is in IDLE state
/* Make sure CC1100 is in IDLE state */
cc1100_spi_strobe(CC1100_SIDLE);
// Enable automatic initial calibration of RCosc.
// Set T_event1 ~ 1.4 ms, enough for XOSC stabilize and FS calibration before RX.
// Enable RC oscillator before starting with WOR (or else it will not wake up).
// Not using AUTO_SYNC function.
/* Enable automatic initial calibration of RCosc. */
/* Set T_event1 ~ 1.4 ms, enough for XOSC stabilize and FS calibration before RX. */
/* Enable RC oscillator before starting with WOR (or else it will not wake up). */
/* Not using AUTO_SYNC function. */
cc1100_spi_write_reg(CC1100_WORCTRL, cc1100_wor_config.wor_ctrl);
// Set Event0 timeout (RX polling interval)
/* Set Event0 timeout (RX polling interval) */
cc1100_spi_write_reg(CC1100_WOREVT1, cc1100_wor_config.wor_evt_1);
cc1100_spi_write_reg(CC1100_WOREVT0, cc1100_wor_config.wor_evt_0);
// Set RX time in WOR mode
/* Set RX time in WOR mode */
cc1100_spi_write_reg(CC1100_MCSM2, cc1100_wor_config.rx_time_reg);
// Enable automatic FS calibration when going from IDLE to RX/TX/FSTXON (in between EVENT0 and EVENT1)
/* Enable automatic FS calibration when going from IDLE to RX/TX/FSTXON (in between EVENT0 and EVENT1) */
cc1100_spi_write_reg(CC1100_MCSM0, 0x18);
// Put the radio to SLEEP by starting Wake-on-Radio.
cc1100_spi_strobe(CC1100_SWORRST); // Resets the real time clock
cc1100_spi_strobe(CC1100_SWOR); // Starts Wake-on-Radio
/* Put the radio to SLEEP by starting Wake-on-Radio. */
cc1100_spi_strobe(CC1100_SWORRST); /* Resets the real time clock */
cc1100_spi_strobe(CC1100_SWOR); /* Starts Wake-on-Radio */
radio_state = RADIO_WOR;
}
@ -426,14 +436,14 @@ uint8_t cc1100_get_mode(void)
static bool cc1100_set_mode0(uint8_t mode, uint16_t opt_mode_data)
{
int result;
switch (mode)
{
switch(mode) {
case CC1100_MODE_WOR:
// Calculate WOR settings, store result (new burst count)
/* Calculate WOR settings, store result (new burst count) */
result = cc1100_phy_calc_wor_settings(opt_mode_data);
// If settings can be applied, set new mode and burst count
if (result != -1)
{
/* If settings can be applied, set new mode and burst count */
if(result != -1) {
radio_mode = mode;
cc1100_go_idle = wakeup_from_wor;
cc1100_go_receive = switch_to_wor;
@ -444,7 +454,9 @@ static bool cc1100_set_mode0(uint8_t mode, uint16_t opt_mode_data)
cc1100_retransmission_count_bc = TRANSMISSION_RETRIES_WOR_BC;
return true;
}
break;
case CC1100_MODE_CONSTANT_RX:
radio_mode = mode;
cc1100_go_idle = wakeup_from_rx;
@ -456,32 +468,31 @@ static bool cc1100_set_mode0(uint8_t mode, uint16_t opt_mode_data)
cc1100_retransmission_count_bc = TRANSMISSION_RETRIES_CRX_BC;
return true;
}
return false;
}
bool cc1100_set_mode(uint8_t mode, uint16_t opt_mode_data)
{
// Wake up from WOR/RX (if in WOR/RX, else no effect)
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */
cc1100_go_idle();
// Make sure CC1100 is in IDLE state
/* Make sure CC1100 is in IDLE state */
cc1100_spi_strobe(CC1100_SIDLE);
// Set the new mode
/* Set the new mode */
bool result = cc1100_set_mode0(mode, opt_mode_data);
// If mode change was successful (mode is valid)
if (result)
{
// Setup new mode configuration
/* If mode change was successful (mode is valid) */
if(result) {
/* Setup new mode configuration */
cc1100_setup_mode();
// Reset statistics
/* Reset statistics */
cc1100_reset_statistic();
return true;
}
else
{
// Still in old mode, go to receive mode again
else {
/* Still in old mode, go to receive mode again */
cc1100_go_receive();
return false;
}
@ -489,12 +500,13 @@ bool cc1100_set_mode(uint8_t mode, uint16_t opt_mode_data)
char *cc1100_mode_to_text(uint8_t mode)
{
switch (mode)
{
switch(mode) {
case CC1100_MODE_WOR:
return "Wake-On-Radio";
case CC1100_MODE_CONSTANT_RX:
return "Constant RX";
default:
return "unknown";
}
@ -502,24 +514,31 @@ char* cc1100_mode_to_text(uint8_t mode)
char *cc1100_state_to_text(uint8_t state)
{
switch (state)
{
switch(state) {
case RADIO_UNKNOWN:
return "Unknown";
case RADIO_AIR_FREE_WAITING:
return "CS";
case RADIO_WOR:
return "WOR";
case RADIO_IDLE:
return "IDLE";
case RADIO_SEND_BURST:
return "TX BURST";
case RADIO_RX:
return "RX";
case RADIO_SEND_ACK:
return "TX ACK";
case RADIO_PWD:
return "PWD";
default:
return "unknown";
}
@ -527,32 +546,37 @@ char* cc1100_state_to_text(uint8_t state)
void cc1100_hwtimer_go_receive_wrapper(void *ptr)
{
// kernel timer handler function called, clear timer id
/* kernel timer handler function called, clear timer id */
wor_hwtimer_id = -1;
// Stability: don't allow WOR timers at this point
if (rflags.TX) return;
/* Stability: don't allow WOR timers at this point */
if(rflags.TX) {
return;
}
if(radio_state == RADIO_PWD) {
// Go to RX state, listen for packets as long as WOR_TIMEOUT_2
/* Go to RX state, listen for packets as long as WOR_TIMEOUT_2 */
cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX;
// Set hwtimer to put CC1100 back to WOR after WOR_TIMEOUT_2
/* Set hwtimer to put CC1100 back to WOR after WOR_TIMEOUT_2 */
wor_hwtimer_id = hwtimer_set(WOR_TIMEOUT_2, cc1100_hwtimer_go_receive_wrapper, NULL);
if (wor_hwtimer_id == -1)
{
if(wor_hwtimer_id == -1) {
rflags.KT_RES_ERR = true;
// No hwtimer available, go immediately to WOR mode.
// Else never receiving packets again...
/* No hwtimer available, go immediately to WOR mode. */
/* Else never receiving packets again... */
rflags.MAN_WOR = false;
switch_to_wor2();
}
} else {
}
else {
cc1100_go_receive();
}
}
/*---------------------------------------------------------------------------*/
// CC1100 reset functionality
/* CC1100 reset functionality */
/*---------------------------------------------------------------------------*/
static void reset(void)
@ -574,64 +598,73 @@ static void power_up_reset(void)
}
/*---------------------------------------------------------------------------*/
// CC1100 low level send function
/* CC1100 low level send function */
/*---------------------------------------------------------------------------*/
void cc1100_send_raw(uint8_t *tx_buffer, uint8_t size)
{
volatile uint32_t abort_count;
// The number of bytes to be transmitted must be smaller
// or equal to PACKET_LENGTH (62 bytes). So the receiver
// can put the whole packet in its RX-FIFO (with appended
// packet status bytes).
if (size > PACKET_LENGTH) return;
// Disables RX interrupt etc.
/* The number of bytes to be transmitted must be smaller */
/* or equal to PACKET_LENGTH (62 bytes). So the receiver */
/* can put the whole packet in its RX-FIFO (with appended */
/* packet status bytes). */
if(size > PACKET_LENGTH) {
return;
}
/* Disables RX interrupt etc. */
cc110x_before_send();
// But CC1100 in IDLE mode to flush the FIFO
/* But CC1100 in IDLE mode to flush the FIFO */
cc1100_spi_strobe(CC1100_SIDLE);
// Flush TX FIFO to be sure it is empty
/* Flush TX FIFO to be sure it is empty */
cc1100_spi_strobe(CC1100_SFTX);
// Write packet into TX FIFO
/* Write packet into TX FIFO */
cc1100_spi_writeburst_reg(CC1100_TXFIFO, (char *) tx_buffer, size);
// Switch to TX mode
/* Switch to TX mode */
abort_count = 0;
unsigned int cpsr = disableIRQ();
cc1100_spi_strobe(CC1100_STX);
// Wait for GDO2 to be set -> sync word transmitted
/* Wait for GDO2 to be set -> sync word transmitted */
while(cc110x_get_gdo2() == 0) {
abort_count++;
if(abort_count > CC1100_SYNC_WORD_TX_TIME) {
// Abort waiting. CC1100 maybe in wrong mode
// e.g. sending preambles for always
/* Abort waiting. CC1100 maybe in wrong mode */
/* e.g. sending preambles for always */
puts("[CC1100 TX] fatal error\n");
break;
}
}
restoreIRQ(cpsr);
// Wait for GDO2 to be cleared -> end of packet
/* Wait for GDO2 to be cleared -> end of packet */
while(cc110x_get_gdo2() != 0);
// Experimental - TOF Measurement
/* Experimental - TOF Measurement */
cc110x_after_send();
}
/*---------------------------------------------------------------------------*/
// Various functions (mode safe - they can be called in any radio mode)
/* Various functions (mode safe - they can be called in any radio mode) */
/*---------------------------------------------------------------------------*/
uint8_t
read_register(uint8_t r)
{
uint8_t result;
// Save old radio state
/* Save old radio state */
uint8_t old_state = radio_state;
// Wake up from WOR/RX (if in WOR/RX, else no effect)
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */
cc1100_go_idle();
result = cc1100_spi_read_reg(r);
// Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary
/* Have to put radio back to WOR/RX if old radio state */
/* was WOR/RX, otherwise no action is necessary */
if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive();
}
@ -642,15 +675,15 @@ read_register(uint8_t r)
static void
write_register(uint8_t r, uint8_t value)
{
// Save old radio state
/* Save old radio state */
uint8_t old_state = radio_state;
// Wake up from WOR/RX (if in WOR/RX, else no effect)
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */
cc1100_go_idle();
cc1100_spi_write_reg(r, value);
// Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary
/* Have to put radio back to WOR/RX if old radio state */
/* was WOR/RX, otherwise no action is necessary */
if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive();
}
@ -670,7 +703,10 @@ uint8_t cc1100_get_channel(void)
bool
cc1100_set_channel(uint8_t channr)
{
if (channr > MAX_CHANNR) return false;
if(channr > MAX_CHANNR) {
return false;
}
write_register(CC1100_CHANNR, channr * 10);
radio_channel = channr;
return true;
@ -679,7 +715,10 @@ cc1100_set_channel(uint8_t channr)
bool
cc1100_set_output_power(uint8_t pa_idx)
{
if (pa_idx >= sizeof(pa_table)) return false;
if(pa_idx >= sizeof(pa_table)) {
return false;
}
write_register(CC1100_PATABLE, pa_table[pa_idx]);
pa_table_index = pa_idx;
return true;
@ -689,40 +728,73 @@ char* cc1100_get_marc_state(void)
{
uint8_t state;
// Save old radio state
/* Save old radio state */
uint8_t old_state = radio_state;
// Read content of status register
/* Read content of status register */
state = cc1100_spi_read_status(CC1100_MARCSTATE) & MARC_STATE;
// Make sure in IDLE state.
// Only goes to IDLE if state was RX/WOR
/* Make sure in IDLE state. */
/* Only goes to IDLE if state was RX/WOR */
cc1100_go_idle();
// Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary
/* Have to put radio back to WOR/RX if old radio state */
/* was WOR/RX, otherwise no action is necessary */
if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive();
}
switch (state)
{
// Note: it is not possible to read back the SLEEP or XOFF state numbers
// because setting CSn low will make the chip enter the IDLE mode from the
// SLEEP (0) or XOFF (2) states.
case 1: return "IDLE";
case 3: case 4: case 5: return "MANCAL";
case 6: case 7: return "FS_WAKEUP";
case 8: case 12: return "CALIBRATE";
case 9: case 10: case 11: return "SETTLING";
case 13: case 14: case 15: return "RX";
case 16: return "TXRX_SETTLING";
case 17: return "RXFIFO_OVERFLOW";
case 18: return "FSTXON";
case 19: case 20: return "TX";
case 21: return "RXTX_SETTLING";
case 22: return "TXFIFO_UNDERFLOW";
default: return "UNKNOWN";
switch(state) {
/* Note: it is not possible to read back the SLEEP or XOFF state numbers */
/* because setting CSn low will make the chip enter the IDLE mode from the */
/* SLEEP (0) or XOFF (2) states. */
case 1:
return "IDLE";
case 3:
case 4:
case 5:
return "MANCAL";
case 6:
case 7:
return "FS_WAKEUP";
case 8:
case 12:
return "CALIBRATE";
case 9:
case 10:
case 11:
return "SETTLING";
case 13:
case 14:
case 15:
return "RX";
case 16:
return "TXRX_SETTLING";
case 17:
return "RXFIFO_OVERFLOW";
case 18:
return "FSTXON";
case 19:
case 20:
return "TX";
case 21:
return "RXTX_SETTLING";
case 22:
return "TXFIFO_UNDERFLOW";
default:
return "UNKNOWN";
}
}
@ -737,27 +809,27 @@ rssi_2_dbm(uint8_t rssi)
}*/
/*---------------------------------------------------------------------------*/
// Radio Driver API
/* Radio Driver API */
/*---------------------------------------------------------------------------*/
void cc1100_init(void)
{
// Initialize SPI
/* Initialize SPI */
cc110x_spi_init();
// Set default mode (with default (energy optimized) RX interval)
/* Set default mode (with default (energy optimized) RX interval) */
cc1100_set_mode0(CC1100_RADIO_MODE, T_RX_INTERVAL);
// Load driver & reset
/* Load driver & reset */
power_up_reset();
// Write configuration to configuration registers
/* Write configuration to configuration registers */
extern char cc1100_conf[];
cc1100_spi_writeburst_reg(0x00, cc1100_conf, CC1100_CONF_SIZE);
// Write PATABLE (power settings)
/* Write PATABLE (power settings) */
cc1100_spi_write_reg(CC1100_PATABLE, pa_table[pa_table_index]);
// Initialize Radio Flags
/* Initialize Radio Flags */
rflags.RSSI = 0x00;
rflags.LL_ACK = false;
rflags.CAA = false;
@ -768,28 +840,29 @@ void cc1100_init(void)
rflags.TX = false;
rflags.WOR_RST = false;
// Initialize physical layer
/* Initialize physical layer */
cc1100_phy_init();
// Set radio address of CC1100
/* Set radio address of CC1100 */
cc1100_set_address(radio_address);
// Set default channel number
/* Set default channel number */
radio_channel = CC1100_DEFAULT_CHANNR;
// Switch to desired mode (WOR or RX)
/* Switch to desired mode (WOR or RX) */
rd_set_mode(RADIO_MODE_ON);
}
int cc1100_get_avg_transmission_duration(void)
{
if(radio_mode == CC1100_MODE_WOR) {
// Transmission duration ~ RX interval
// Double value because of MAC delay.
/* Transmission duration ~ RX interval */
/* Double value because of MAC delay. */
return 2 * cc1100_wor_config.rx_interval;
} else {
// Transmission duration ~ 32 ms
// Double value because of MAC delay.
}
else {
/* Transmission duration ~ 32 ms */
/* Double value because of MAC delay. */
return 2 * 32;
}
}
@ -801,14 +874,13 @@ radio_address_t cc1100_get_address(void)
bool cc1100_set_address(radio_address_t address)
{
if (address < MIN_UID || address > MAX_UID)
{
if(address < MIN_UID || address > MAX_UID) {
return false;
}
uint8_t id = (uint8_t) address;
if (radio_state != RADIO_UNKNOWN)
{
if(radio_state != RADIO_UNKNOWN) {
write_register(CC1100_ADDR, id);
}
@ -821,67 +893,66 @@ rd_set_mode(int mode)
{
int result;
// Get current radio mode
if (radio_state == RADIO_UNKNOWN || radio_state == RADIO_PWD)
{
/* Get current radio mode */
if(radio_state == RADIO_UNKNOWN || radio_state == RADIO_PWD) {
result = RADIO_MODE_OFF;
}
else
{
else {
result = RADIO_MODE_ON;
}
switch (mode)
{
switch(mode) {
case RADIO_MODE_ON:
cc110x_init_interrupts(); // Enable interrupts
cc1100_setup_mode(); // Set chip to desired mode
cc110x_init_interrupts(); /* Enable interrupts */
cc1100_setup_mode(); /* Set chip to desired mode */
break;
case RADIO_MODE_OFF:
cc1100_disable_interrupts(); // Disable interrupts
switch_to_pwd(); // Set chip to power down mode
cc1100_disable_interrupts(); /* Disable interrupts */
switch_to_pwd(); /* Set chip to power down mode */
break;
case RADIO_MODE_GET:
// do nothing, just return current mode
/* do nothing, just return current mode */
default:
// do nothing
/* do nothing */
break;
}
// Return previous mode
/* Return previous mode */
return result;
}
/*---------------------------------------------------------------------------*/
// Carrier sense interface functions
/* Carrier sense interface functions */
/*---------------------------------------------------------------------------*/
void cc1100_cs_init(void)
{
cc1100_go_idle(); // Wake CC1100 up from Wake-On-Radio mode
if (radio_state == RADIO_RX) // If radio in RX mode
{
cc1100_spi_strobe(CC1100_SIDLE); // Go back to IDLE for calibration
cc1100_go_idle(); /* Wake CC1100 up from Wake-On-Radio mode */
if(radio_state == RADIO_RX) { /* If radio in RX mode */
cc1100_spi_strobe(CC1100_SIDLE); /* Go back to IDLE for calibration */
}
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal
cc1100_spi_strobe(CC1100_SCAL); // Calibrate manually (721 us)
hwtimer_wait(MANUAL_FS_CAL_TIME); // Wait for calibration to finish before packet burst can start
radio_state = RADIO_AIR_FREE_WAITING; // Set status "waiting for air free"
cc1100_spi_write_reg(CC1100_MCSM2, 0x07); // Configure RX_TIME = Until end of packet (no timeout)
cc1100_spi_strobe(CC1100_SRX); // Switch to RX (88.4 us) (Carrier Sense)
hwtimer_wait(CS_READY_TIME); // Wait until CC1100 is in RX + carrier sense ready (GDO0 ready for readout -> data rate dependent!!!)
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); /* Turn off FS-Autocal */
cc1100_spi_strobe(CC1100_SCAL); /* Calibrate manually (721 us) */
hwtimer_wait(MANUAL_FS_CAL_TIME); /* Wait for calibration to finish before packet burst can start */
radio_state = RADIO_AIR_FREE_WAITING; /* Set status "waiting for air free" */
cc1100_spi_write_reg(CC1100_MCSM2, 0x07); /* Configure RX_TIME = Until end of packet (no timeout) */
cc1100_spi_strobe(CC1100_SRX); /* Switch to RX (88.4 us) (Carrier Sense) */
hwtimer_wait(CS_READY_TIME); /* Wait until CC1100 is in RX + carrier sense ready (GDO0 ready for readout -> data rate dependent!!!) */
}
void cc1100_cs_set_enabled(bool enabled)
{
if (enabled)
{
// Enable carrier sense detection (GDO0 interrupt)
if(enabled) {
/* Enable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_enable();
}
else
{
// Disable carrier sense detection (GDO0 interrupt)
else {
/* Disable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_disable();
}
}

View File

@ -120,8 +120,7 @@ typedef struct cc1100_cfg_t {
/**
* @brief Radio Control Flags
*/
typedef struct cc1100_flags
{
typedef struct cc1100_flags {
uint32_t TOF; ///< Time of flight of the last packet and last ACK
uint32_t TCP; ///< Time to compute packet
unsigned RPS : 16; ///< Raw packets sent to transmit last packet

View File

@ -37,6 +37,7 @@ and the mailinglist (subscription via web site)
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@inf.fu-berlin.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @version $Revision: 2130 $
*
* @note $Id: cc1100_phy.c 2130 2010-05-12 13:19:07Z hillebra $
@ -69,11 +70,10 @@ and the mailinglist (subscription via web site)
#define W_FLAGS_PROTOCOL(x) ((x<<1) & 0x0E) ///< Macro for writing the protocol in the flags field
/*---------------------------------------------------------------------------*/
// RX/TX buffer data structures
/* RX/TX buffer data structures */
/*---------------------------------------------------------------------------*/
typedef struct rx_buffer_t
{
typedef struct {
cc1100_packet_layer0_t packet;
packet_info_t info;
} rx_buffer_t;
@ -86,7 +86,7 @@ static rx_buffer_t rx_buffer[RX_BUFF_SIZE]; ///< RX buffer
static cc1100_packet_layer0_t tx_buffer; ///< TX buffer (for one packet)
/*---------------------------------------------------------------------------*/
// Process/Event management data structures
/* Process/Event management data structures */
/*---------------------------------------------------------------------------*/
#define MAX_PACKET_HANDLERS (5)
@ -105,7 +105,7 @@ static void cc1100_event_handler_function(void);
static char event_handler_stack[KERNEL_CONF_STACKSIZE_MAIN];
/*---------------------------------------------------------------------------*/
// Sequence number buffer management data structures
/* Sequence number buffer management data structures */
/*---------------------------------------------------------------------------*/
/**
@ -114,17 +114,16 @@ static char event_handler_stack[KERNEL_CONF_STACKSIZE_MAIN];
*/
#define MAX_SEQ_BUFFER_SIZE (20) ///< Maximum size of the sequence number buffer
typedef struct
{
typedef struct {
uint64_t m_ticks; ///< 64-bit timestamp
uint8_t source; ///< Source address
uint8_t identification; ///< Identification (1-bit)
} seq_buffer_entry_t;
/// Sequence number buffer for this layer
//* Sequence number buffer for this layer */
static seq_buffer_entry_t seq_buffer[MAX_SEQ_BUFFER_SIZE];
/// Next position to enter a new value into ::seqBuffer
//* Next position to enter a new value into ::seqBuffer */
static uint8_t seq_buffer_pos = 0;
/**
@ -151,8 +150,7 @@ uint16_t cc1100_burst_count; ///< Burst count, number of packets in a burst tr
uint8_t cc1100_retransmission_count_uc; ///< Number of retransmissions for unicast
uint8_t cc1100_retransmission_count_bc; ///< Number of retransmissions for broadcast
const static double duty_cycle[2][DUTY_CYCLE_SIZE] = ///< Duty cycle values from AN047
{
const static double duty_cycle[2][DUTY_CYCLE_SIZE] = { ///< Duty cycle values from AN047
{12.5, 6.25, 3.125, 1.563, 0.781, 0.391, 0.195},
{1.95, 0.9765, 0.4883, 0.2441, 0.1221, 0.061035, 0.030518}
};
@ -175,30 +173,30 @@ void cc1100_phy_init()
rx_buffer_tail = 0;
rx_buffer_size = 0;
// Initialize RX-Buffer (clear content)
for (i = 0; i < RX_BUFF_SIZE; i++)
{
/* Initialize RX-Buffer (clear content) */
for(i = 0; i < RX_BUFF_SIZE; i++) {
rx_buffer->packet.length = 0;
}
// Initialize handler table & packet monitor
/* Initialize handler table & packet monitor */
packet_monitor = NULL;
pm_init_table((pm_table_t *)&handler_table, MAX_PACKET_HANDLERS, handlers);
// Clear sequence number buffer
/* Clear sequence number buffer */
memset(seq_buffer, 0, sizeof(seq_buffer_entry_t) * MAX_SEQ_BUFFER_SIZE);
// Initialize mutex
/* Initialize mutex */
cc1100_mutex_pid = -1;
mutex_init(&cc1100_mutex);
// Allocate event numbers and start cc1100 event process
/* Allocate event numbers and start cc1100 event process */
cc1100_event_handler_pid = thread_create(event_handler_stack, sizeof(event_handler_stack), PRIORITY_CC1100, CREATE_STACKTEST,
cc1100_event_handler_function, cc1100_event_handler_name);
// Active watchdog for the first time
/* Active watchdog for the first time */
if(radio_mode == CC1100_MODE_CONSTANT_RX) {
cc1100_watch_dog_period.microseconds = CC1100_WATCHDOG_PERIOD;
if(cc1100_watch_dog_period.microseconds != 0) {
timex_t temp = timex_set(0, 5000000L);
vtimer_set_msg(&cc1100_watch_dog, temp, cc1100_event_handler_pid, NULL);
@ -207,7 +205,7 @@ void cc1100_phy_init()
}
/*---------------------------------------------------------------------------*/
// CC1100 mutual exclusion
/* CC1100 mutual exclusion */
/*---------------------------------------------------------------------------*/
void cc1100_phy_mutex_lock(void)
@ -275,8 +273,8 @@ void cc1100_print_config(void)
printf("Retransmissions (unicast): %u - if no ACK\r\n", cc1100_retransmission_count_uc);
printf("Retransmissions (broadcast): %u - always\r\n", cc1100_retransmission_count_bc);
printf("Output power setting: %s\r\n", cc1100_get_output_power(buf));
if (radio_mode == CC1100_MODE_WOR)
{
if(radio_mode == CC1100_MODE_WOR) {
printf("RX polling interval: %u ms\r\n", cc1100_wor_config.rx_interval);
printf("WOR receive time: 0x%.2X (%f ms)\r\n", cc1100_wor_config.rx_time_reg,
cc1100_wor_config.rx_time_ms);
@ -298,64 +296,68 @@ inline uint16_t iround(double d)
int cc1100_phy_calc_wor_settings(uint16_t millis)
{
// Get packet interval as milliseconds
/* Get packet interval as milliseconds */
double t_packet_interval = (double)((T_PACKET_INTERVAL) / 1000.0);
// Calculate minimal T_EVENT0:
//
// (1) t_rx_time > t_packet_interval
// (2) t_rx_time = T_EVENT0 / 2 ^ (RX_TIME + 3 + WOR_RES)
// ------------------------------------------------------
// with RX_TIME = 0 && WOR_RES = 0 => event0_min > t_packet_interval * 8
//
// t_packet_interval = 3.8 ms (@400kbit/s)
//
// => event0_min = Math.ceil(3.8 * 8) + 10
/* Calculate minimal T_EVENT0:
(1) t_rx_time > t_packet_interval
(2) t_rx_time = T_EVENT0 / 2 ^ (RX_TIME + 3 + WOR_RES)
------------------------------------------------------
with RX_TIME = 0 && WOR_RES = 0 => event0_min > t_packet_interval * 8
t_packet_interval = 3.8 ms (@400kbit/s)
=> event0_min = Math.ceil(3.8 * 8) + 10 */
uint16_t event0_min = (uint16_t)(t_packet_interval * 8) + 1 + 10;
// Check if given value is in allowed range
if (millis < event0_min || millis > EVENT0_MAX)
{
/* Check if given value is in allowed range */
if(millis < event0_min || millis > EVENT0_MAX) {
return -1;
}
// Time resolution for EVENT0 and other WOR parameters,
// possible values are 0 and 1 if WOR is used
/* Time resolution for EVENT0 and other WOR parameters, */
/* possible values are 0 and 1 if WOR is used */
uint8_t wor_res = millis < WOR_RES_SWITCH ? 0 : 1;
// Calculate new value for EVENT0
/* Calculate new value for EVENT0 */
double tmp = (millis * 26) / (double) 750;
if (wor_res == 1) tmp /= 32;
if(wor_res == 1) {
tmp /= 32;
}
tmp *= 1000;
uint16_t event0 = (uint16_t) iround(tmp);
// Calculate all possible RX timeouts
/* Calculate all possible RX timeouts */
int i;
double rx_timeouts[DUTY_CYCLE_SIZE];
for (i = 0; i < DUTY_CYCLE_SIZE; i++)
{
for(i = 0; i < DUTY_CYCLE_SIZE; i++) {
rx_timeouts[i] = (millis * duty_cycle[wor_res][i]) / 100;
}
// Calculate index for optimal rx_timeout (MCSM2.RX_TIME) (if possible)
/* Calculate index for optimal rx_timeout (MCSM2.RX_TIME) (if possible) */
int idx = -1;
for (i = DUTY_CYCLE_SIZE - 1; i >= 0; i--)
{
if (rx_timeouts[i] > t_packet_interval)
{
for(i = DUTY_CYCLE_SIZE - 1; i >= 0; i--) {
if(rx_timeouts[i] > t_packet_interval) {
idx = i;
break;
}
}
// If no index found, exit here (configuration with given value is not possible)
if (idx == -1) return -1;
/* If no index found, exit here (configuration with given value is not possible) */
if(idx == -1) {
return -1;
}
// Calculate burst count (secure burst calculation with 8 extra packets)
/* Calculate burst count (secure burst calculation with 8 extra packets) */
int burst_count = (int) iround(millis / t_packet_interval) + 8;
// All calculations successful, now its safe to store
// final configuration values in global WOR configuration
/* All calculations successful, now its safe to store */
/* final configuration values in global WOR configuration */
cc1100_wor_config.rx_interval = millis;
cc1100_wor_config.wor_ctrl = (wor_res == 0) ? 0x78 : 0x79;
cc1100_wor_config.wor_evt_0 = (uint8_t) event0;
@ -363,7 +365,7 @@ int cc1100_phy_calc_wor_settings(uint16_t millis)
cc1100_wor_config.rx_time_reg = idx;
cc1100_wor_config.rx_time_ms = rx_timeouts[idx];
// If successful, return number of packets in a burst transfer
/* If successful, return number of packets in a burst transfer */
return burst_count;
}
@ -379,76 +381,76 @@ static bool contains_seq_entry(uint8_t src, uint8_t id)
vtimer_now(&now_timex);
uint64_t now = now_timex.microseconds;
for (i = 0; i < MAX_SEQ_BUFFER_SIZE; i++)
{
if ((seq_buffer[i].source == src) && (seq_buffer[i].identification == id))
{
// Check if time stamp is OK
cmp = (radio_mode == CC1100_MODE_WOR) ? cc1100_wor_config.rx_interval : 16000; // constant RX ~16ms
if ((now - seq_buffer[i].m_ticks) <= cmp)
{
for(i = 0; i < MAX_SEQ_BUFFER_SIZE; i++) {
if((seq_buffer[i].source == src) && (seq_buffer[i].identification == id)) {
/* Check if time stamp is OK */
cmp = (radio_mode == CC1100_MODE_WOR) ? cc1100_wor_config.rx_interval : 16000; /* constant RX ~16ms */
if((now - seq_buffer[i].m_ticks) <= cmp) {
return true;
}
else
{
seq_buffer[i].source = 0; // Reset
else {
seq_buffer[i].source = 0; /* Reset */
}
}
}
return false;
}
static void add_seq_entry(uint8_t src, uint8_t id)
{
// Remove all entries with given source to avoid short time overflow
// of one bit counter (of the source node). So a valid packet would get
// lost (especially important in constant RX mode).
/* Remove all entries with given source to avoid short time overflow
* of one bit counter (of the source node). So a valid packet would get
* lost (especially important in constant RX mode). */
int i;
for (i = 0; i < MAX_SEQ_BUFFER_SIZE; i++)
{
if (seq_buffer[i].source == src)
{
seq_buffer[i].source = 0; // Reset
for(i = 0; i < MAX_SEQ_BUFFER_SIZE; i++) {
if(seq_buffer[i].source == src) {
seq_buffer[i].source = 0; /* Reset */
}
}
// Add new entry
/* Add new entry */
seq_buffer[seq_buffer_pos].source = src;
seq_buffer[seq_buffer_pos].identification = id;
timex_t now;
vtimer_now(&now);
seq_buffer[seq_buffer_pos].m_ticks = now.microseconds;
// Store 16 bit sequence number of layer 0 for speedup
/* Store 16 bit sequence number of layer 0 for speedup */
last_seq_num = src;
last_seq_num <<= 8;
last_seq_num += id;
seq_buffer_pos++;
if (seq_buffer_pos == MAX_SEQ_BUFFER_SIZE) seq_buffer_pos = 0;
if(seq_buffer_pos == MAX_SEQ_BUFFER_SIZE) {
seq_buffer_pos = 0;
}
}
/*---------------------------------------------------------------------------*/
// CC1100 physical layer send functions
/* CC1100 physical layer send functions */
/*---------------------------------------------------------------------------*/
static void send_link_level_ack(uint8_t dest)
{
uint8_t oldState = radio_state; // Save old state
cc1100_packet_layer0_t ack; // Local packet, don't overwrite
uint8_t oldState = radio_state; /* Save old state */
cc1100_packet_layer0_t ack; /* Local packet, don't overwrite */
radio_state = RADIO_SEND_ACK; // Set state to "Sending ACK"
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal
cc1100_spi_write_reg(CC1100_MCSM1, 0x00); // TX_OFFMODE = IDLE
ack.length = 3; // possible packet in txBuffer!
radio_state = RADIO_SEND_ACK; /* Set state to "Sending ACK" */
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); /* Turn off FS-Autocal */
cc1100_spi_write_reg(CC1100_MCSM1, 0x00); /* TX_OFFMODE = IDLE */
ack.length = 3; /* possible packet in txBuffer! */
ack.address = dest;
ack.phy_src = rflags.RSSI;
ack.flags = (LAYER_1_PROTOCOL_LL_ACK << 1);
cc1100_send_raw((uint8_t*)&ack, // IDLE -> TX (88.4 us)
cc1100_send_raw((uint8_t *)&ack, /* IDLE -> TX (88.4 us) */
ack.length + 1);
cc1100_spi_write_reg(CC1100_MCSM0, 0x18); // Turn on FS-Autocal
cc1100_spi_write_reg(CC1100_MCSM1, 0x03); // TX_OFFMODE = RX
radio_state = oldState; // Restore state
cc1100_spi_write_reg(CC1100_MCSM0, 0x18); /* Turn on FS-Autocal */
cc1100_spi_write_reg(CC1100_MCSM1, 0x03); /* TX_OFFMODE = RX */
radio_state = oldState; /* Restore state */
cc1100_statistic.acks_send++;
}
@ -458,8 +460,7 @@ static bool send_burst(cc1100_packet_layer0_t *packet, uint8_t retries, uint8_t
radio_state = RADIO_SEND_BURST;
rflags.LL_ACK = false;
for (i = 1; i <= cc1100_burst_count; i++)
{
for(i = 1; i <= cc1100_burst_count; i++) {
/*
* Number of bytes to send is:
* length of phy payload (packet->length)
@ -467,14 +468,14 @@ static bool send_burst(cc1100_packet_layer0_t *packet, uint8_t retries, uint8_t
*/
extern unsigned long hwtimer_now(void);
timer_tick_t t = hwtimer_now() + RTIMER_TICKS(T_PACKET_INTERVAL);
cc1100_send_raw((uint8_t*)packet, packet->length + 1); // RX -> TX (9.6 us)
cc1100_send_raw((uint8_t *)packet, packet->length + 1); /* RX -> TX (9.6 us) */
cc1100_statistic.raw_packets_out++;
// Delay until predefined "send" interval has passed
/* Delay until predefined "send" interval has passed */
timer_tick_t now = hwtimer_now();
if (t > now)
{
if(t > now) {
hwtimer_wait(t - now);
}
@ -485,36 +486,37 @@ static bool send_burst(cc1100_packet_layer0_t *packet, uint8_t retries, uint8_t
* have the broadcast address at startup and would stop the burst
* by sending an ACK).
*/
if (rflags.LL_ACK && packet->address != CC1100_BROADCAST_ADDRESS)
{
if(rflags.LL_ACK && packet->address != CC1100_BROADCAST_ADDRESS) {
cc1100_statistic.raw_packets_out_acked += i;
break;
}
}
// No link level ACK -> do retry if retry counter greater zero
// Note: Event broadcast packets can be sent repeatedly if in
// constant RX mode. In WOR mode it is not necessary, so
// set retry count to zero.
if (!rflags.LL_ACK && retries > 0)
{
/* No link level ACK -> do retry if retry counter greater zero
* Note: Event broadcast packets can be sent repeatedly if in
* constant RX mode. In WOR mode it is not necessary, so
* set retry count to zero.*/
if(!rflags.LL_ACK && retries > 0) {
return send_burst(packet, retries - 1, rtc + 1);
}
// Store number of transmission retries
/* Store number of transmission retries */
rflags.RETC = rtc;
rflags.RPS = rtc * cc1100_burst_count + i;
if (i > cc1100_burst_count) rflags.RPS--;
if(i > cc1100_burst_count) {
rflags.RPS--;
}
rflags.TX = false;
// Go to mode after TX (CONST_RX -> RX, WOR -> WOR)
/* Go to mode after TX (CONST_RX -> RX, WOR -> WOR) */
cc1100_go_after_tx();
// Burst from any other node is definitely over
/* Burst from any other node is definitely over */
last_seq_num = 0;
if (packet->address != CC1100_BROADCAST_ADDRESS && !rflags.LL_ACK)
{
if(packet->address != CC1100_BROADCAST_ADDRESS && !rflags.LL_ACK) {
return false;
}
@ -528,93 +530,93 @@ int cc1100_send(radio_address_t addr, protocol_t protocol, int priority, char *p
uint8_t address;
uint8_t retries;
// Lock mutex, nobody else should send now
/* Lock mutex, nobody else should send now */
cc1100_phy_mutex_lock();
// TX state machine lock -> no timers (WOR), no packets (only ACKs)
/* TX state machine lock -> no timers (WOR), no packets (only ACKs) */
rflags.TX = true;
// Set chip to idle state
/* Set chip to idle state */
cc1100_set_idle();
// CC1100 radio layer only supports 8-bit addresses
/* CC1100 radio layer only supports 8-bit addresses */
address = addr;
// Loopback not supported
if (address == cc1100_get_address())
{
/* Loopback not supported */
if(address == cc1100_get_address()) {
return_code = RADIO_ADDR_OUT_OF_RANGE;
goto mode_before_final;
}
// Check address
if (address > MAX_UID)
{
/* Check address */
if(address > MAX_UID) {
return_code = RADIO_ADDR_OUT_OF_RANGE;
goto mode_before_final;
}
// Packet too long
if (payload_len > MAX_DATA_LENGTH)
{
/* Packet too long */
if(payload_len > MAX_DATA_LENGTH) {
return_code = RADIO_PAYLOAD_TOO_LONG;
goto mode_before_final;
}
if (radio_state == RADIO_PWD)
{
if(radio_state == RADIO_PWD) {
return_code = RADIO_WRONG_MODE;
goto mode_before_final;
}
// Set number of transmission retries
/* Set number of transmission retries */
retries = (address == CC1100_BROADCAST_ADDRESS) ?
cc1100_retransmission_count_bc : cc1100_retransmission_count_uc;
memset(tx_buffer.data, 0, MAX_DATA_LENGTH); // Clean data
memset(tx_buffer.data, 0, MAX_DATA_LENGTH); /* Clean data */
/* TODO: If packets are shorter than max packet size, WOR interval is too long.
* This must be solved in some way. */
tx_buffer.length = 3 + payload_len; // 3 bytes (A&PS&F) + data length
tx_buffer.address = address; // Copy destination address
tx_buffer.flags = 0x00; // Set clean state
tx_buffer.flags = W_FLAGS_PROTOCOL(protocol); // Copy protocol identifier
tx_buffer.phy_src = (uint8_t) cc1100_get_address(); // Copy sender address
tx_buffer.length = 3 + payload_len; /* 3 bytes (A&PS&F) + data length */
tx_buffer.address = address; /* Copy destination address */
tx_buffer.flags = 0x00; /* Set clean state */
tx_buffer.flags = W_FLAGS_PROTOCOL(protocol); /* Copy protocol identifier */
tx_buffer.phy_src = (uint8_t) cc1100_get_address(); /* Copy sender address */
// Set identification number of packet
tx_buffer.flags |= rflags.SEQ; // Set flags.identification (bit 0)
rflags.SEQ = !rflags.SEQ; // Toggle value of layer 0 sequence number bit
/* Set identification number of packet */
tx_buffer.flags |= rflags.SEQ; /* Set flags.identification (bit 0) */
rflags.SEQ = !rflags.SEQ; /* Toggle value of layer 0 sequence number bit */
memcpy(tx_buffer.data, payload, payload_len); // Copy data
memcpy(tx_buffer.data, payload, payload_len); /* Copy data */
// Send the packet
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal
result = send_burst(&tx_buffer, retries, 0); // Send raw burst
/* Send the packet */
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); /* Turn off FS-Autocal */
result = send_burst(&tx_buffer, retries, 0); /* Send raw burst */
return_code = result ? payload_len : RADIO_OP_FAILED;
// Collect statistics
if (address != CC1100_BROADCAST_ADDRESS)
{
/* Collect statistics */
if(address != CC1100_BROADCAST_ADDRESS) {
cc1100_statistic.packets_out++;
if (result) cc1100_statistic.packets_out_acked++;
if(result) {
cc1100_statistic.packets_out_acked++;
}
}
else {
cc1100_statistic.packets_out_broadcast++;
}
else cc1100_statistic.packets_out_broadcast++;
goto final;
mode_before_final:
rflags.TX = false;
// Definitely set secure mode (CONST_RX -> RX, WOR -> WOR)
/* Definitely set secure mode (CONST_RX -> RX, WOR -> WOR) */
cc1100_go_after_tx();
final:
// Release mutex and return
/* Release mutex and return */
cc1100_phy_mutex_unlock();
return return_code;
}
/*---------------------------------------------------------------------------*/
// RX Event Handler
/* RX Event Handler */
/*---------------------------------------------------------------------------*/
bool cc1100_set_packet_monitor(packet_monitor_t monitor)
@ -625,7 +627,10 @@ bool cc1100_set_packet_monitor(packet_monitor_t monitor)
int cc1100_set_packet_handler(protocol_t protocol, packet_handler_t handler)
{
if (protocol > 7) return -1; // Only 3-bit value allowed
if(protocol > 7) {
return -1; /* Only 3-bit value allowed */
}
return pm_set_handler(&handler_table, protocol, handler);
}
@ -633,63 +638,78 @@ static void cc1100_event_handler_function(void)
{
msg_t m;
while (1)
{
while(1) {
if(cc1100_watch_dog_period.microseconds != 0) {
vtimer_remove(&cc1100_watch_dog);
}
// Test if any resource error has occurred
if (rflags.KT_RES_ERR)
{
/* Test if any resource error has occurred */
if(rflags.KT_RES_ERR) {
rflags.KT_RES_ERR = false;
// possibly do something, e.g. log error condition
/* possibly do something, e.g. log error condition */
}
if (m.type == MSG_TIMER)
{
if(m.type == MSG_TIMER) {
uint8_t state;
if(radio_mode == CC1100_MODE_CONSTANT_RX) {
state = cc1100_spi_read_status(CC1100_MARCSTATE) & MARC_STATE;
if((state < 13 || state > 15) && radio_state == RADIO_RX && !rflags.TX) {
cc1100_statistic.watch_dog_resets++;
if(state != 1) {
cc1100_spi_strobe(CC1100_SIDLE);
}
cc1100_spi_strobe(CC1100_SFRX);
cc1100_go_receive();
}
} else {
// Radio mode is WOR, cannot read current MARC state, will
// always be IDLE. So do nothing here, e.g. disable watchdog.
}
else {
/* Radio mode is WOR, cannot read current MARC state, will */
/* always be IDLE. So do nothing here, e.g. disable watchdog. */
}
}
while (rx_buffer_size > 0)
{
while(rx_buffer_size > 0) {
rx_buffer_t *packet = &rx_buffer[rx_buffer_head];
protocol_t p = R_FLAGS_PROTOCOL(packet->packet.flags);
if (packet_monitor != NULL) packet_monitor((void*)&packet->packet.data, packet->packet.length, p, &packet->info);
if(packet_monitor != NULL) {
packet_monitor((void *)&packet->packet.data, packet->packet.length, p, &packet->info);
}
pm_invoke(&handler_table, p, (void *)&packet->packet.data, MAX_DATA_LENGTH, &packet->info);
dINT();
rx_buffer_size--;
rx_buffer_head++;
if (rx_buffer_head == RX_BUFF_SIZE) rx_buffer_head = 0;
if(rx_buffer_head == RX_BUFF_SIZE) {
rx_buffer_head = 0;
}
eINT();
}
dINT();
if (rx_buffer_size == 0)
{
if(rx_buffer_size == 0) {
if(cc1100_watch_dog_period.microseconds != 0) {
timex_t temp = timex_set(0, cc1100_watch_dog_period.microseconds * 1000000L);
vtimer_set_msg(&cc1100_watch_dog, temp,
cc1100_event_handler_pid, NULL);
}
msg_receive(&m);
}
eINT();
}
}
/*---------------------------------------------------------------------------*/
// CC1100 packet (RX) ISR
/* CC1100 packet (RX) ISR */
/*---------------------------------------------------------------------------*/
void cc1100_phy_rx_handler(void)
@ -699,24 +719,22 @@ void cc1100_phy_rx_handler(void)
bool dup = false;
bool res = false;
// Possible packet received, RX -> IDLE (0.1 us)
/* Possible packet received, RX -> IDLE (0.1 us) */
rflags.CAA = false;
rflags.MAN_WOR = false;
cc1100_statistic.packets_in++;
// If WOR timer set, delete it now (new one will be set at end of ISR)
if (wor_hwtimer_id != -1)
{
/* If WOR timer set, delete it now (new one will be set at end of ISR) */
if(wor_hwtimer_id != -1) {
hwtimer_remove(wor_hwtimer_id);
wor_hwtimer_id = -1;
}
// Transfer packet into temporary buffer position
/* Transfer packet into temporary buffer position */
res = cc1100_spi_receive_packet((uint8_t *) & (rx_buffer[rx_buffer_tail].packet), sizeof(cc1100_packet_layer0_t));
if (res)
{
// Get packet pointer and store additional data in packet info structure
if(res) {
/* Get packet pointer and store additional data in packet info structure */
cc1100_packet_layer0_t *p = &(rx_buffer[rx_buffer_tail].packet);
rx_buffer[rx_buffer_tail].info.phy_src = p->phy_src;
rx_buffer[rx_buffer_tail].info.source = p->phy_src;
@ -725,155 +743,157 @@ void cc1100_phy_rx_handler(void)
rx_buffer[rx_buffer_tail].info.lqi = rflags.LQI;
rx_buffer[rx_buffer_tail].info.promiscuous = false;
// Get protocol and id field out of flags field
/* Get protocol and id field out of flags field */
uint8_t protocol = R_FLAGS_PROTOCOL(p->flags);
uint8_t identification = (p->flags & FLAGS_IDENTIFICATION);
// If received packet was an ACK (here we must be in
// TX lock state, otherwise we don't expect an ACK)
if (protocol == LAYER_1_PROTOCOL_LL_ACK && rflags.TX)
{
// And packet was for us
if (p->address == cc1100_get_address())
{
// Stop the burst
/* If received packet was an ACK (here we must be in
* TX lock state, otherwise we don't expect an ACK) */
if(protocol == LAYER_1_PROTOCOL_LL_ACK && rflags.TX) {
/* And packet was for us */
if(p->address == cc1100_get_address()) {
/* Stop the burst */
rflags.LL_ACK = true;
rflags.RSSI_SEND = p->phy_src;
rflags.TCP = (uint32_t)((uint16_t *)p->data)[0];
}
return;
}
else
{
// No ACK received so TOF is unpredictable
else {
/* No ACK received so TOF is unpredictable */
rflags.TOF = 0;
}
// If we are sending a burst, don't accept packets.
// Only ACKs are processed (for stopping the burst).
// Same if state machine is in TX lock.
if (radio_state == RADIO_SEND_BURST || rflags.TX)
{
/* If we are sending a burst, don't accept packets.
* Only ACKs are processed (for stopping the burst).
* Same if state machine is in TX lock. */
if(radio_state == RADIO_SEND_BURST || rflags.TX) {
cc1100_statistic.packets_in_while_tx++;
return;
}
// If buffer is currently full -> don't check sequence numbers, send
// ACK and restore state (keep always one position free for temporary packets)
if (rx_buffer_size >= RX_BUFF_SIZE-1) goto send_ack;
/* If buffer is currently full -> don't check sequence numbers, send
* ACK and restore state (keep always one position free for temporary packets) */
if(rx_buffer_size >= RX_BUFF_SIZE - 1) {
goto send_ack;
}
// Build 16 bit sequence number of layer 0 for fast check
/* Build 16 bit sequence number of layer 0 for fast check */
uint16_t new_seq_num = p->phy_src;
new_seq_num <<= 8;
new_seq_num += identification;
// Duplicate packet detection
/* Duplicate packet detection */
dup = true;
// If new and last sequence number are the same, then discard packet
if (last_seq_num != new_seq_num)
{
// Do a more precise check (takes more time) with larger buffer
if (!contains_seq_entry(p->phy_src, identification))
{
// Sequence number is new, no duplicate packet
/* If new and last sequence number are the same, then discard packet */
if(last_seq_num != new_seq_num) {
/* Do a more precise check (takes more time) with larger buffer */
if(!contains_seq_entry(p->phy_src, identification)) {
/* Sequence number is new, no duplicate packet */
dup = false;
// Store sequence number
/* Store sequence number */
add_seq_entry(p->phy_src, identification);
// Make temporary packet in RX buffer to a "real" packet which is processed
/* Make temporary packet in RX buffer to a "real" packet which is processed */
rx_buffer_size++;
if (rx_buffer_size > cc1100_statistic.rx_buffer_max) cc1100_statistic.rx_buffer_max = rx_buffer_size;
if(rx_buffer_size > cc1100_statistic.rx_buffer_max) {
cc1100_statistic.rx_buffer_max = rx_buffer_size;
}
rx_buffer_tail++;
if (rx_buffer_tail == RX_BUFF_SIZE) rx_buffer_tail = 0;
// Send empty message to wake up receiver process.
// Receiver process could already be running (triggered by previous message),
// so function would return 0 and assume the receiver is not waiting but indeed
// all is working fine.
if(rx_buffer_tail == RX_BUFF_SIZE) {
rx_buffer_tail = 0;
}
/* Send empty message to wake up receiver process.
* Receiver process could already be running (triggered by previous message),
* so function would return 0 and assume the receiver is not waiting but indeed
* all is working fine.*/
msg_send_int(&m, cc1100_event_handler_pid);
cc1100_statistic.packets_in_up++;
}
}
send_ack:
// If packet was send directly to us, send an ACK packet back to sender.
// But only not if the packet itself was a LL-ACK!
if (p->address == cc1100_get_address() && protocol != LAYER_1_PROTOCOL_LL_ACK)
{
/* If packet was send directly to us, send an ACK packet back to sender.
* But only not if the packet itself was a LL-ACK! */
if(p->address == cc1100_get_address() && protocol != LAYER_1_PROTOCOL_LL_ACK) {
send_link_level_ack(p->phy_src);
// After LL-ACK burst is over, reset number
/* After LL-ACK burst is over, reset number */
last_seq_num = 0;
}
// If duplicate packet detected, clear rxBuffer position
if (dup)
{
/* If duplicate packet detected, clear rxBuffer position */
if(dup) {
cc1100_statistic.packets_in_dups++;
}
// If packet interrupted this nodes send call,
// don't change anything after this point.
if (radio_state == RADIO_AIR_FREE_WAITING)
{
/* If packet interrupted this nodes send call,
* don't change anything after this point. */
if(radio_state == RADIO_AIR_FREE_WAITING) {
cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
return;
}
// Valid packet. After a wake-up, the radio should be in IDLE.
// So put CC1100 to RX for WOR_TIMEOUT (have to manually put
// the radio back to sleep/WOR).
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal
cc1100_spi_write_reg(CC1100_MCSM2, 0x07); // Configure RX_TIME (until end of packet)
/* Valid packet. After a wake-up, the radio should be in IDLE.
* So put CC1100 to RX for WOR_TIMEOUT (have to manually put
* the radio back to sleep/WOR).*/
cc1100_spi_write_reg(CC1100_MCSM0, 0x08); * Turn off FS-Autocal
cc1100_spi_write_reg(CC1100_MCSM2, 0x07); /* Configure RX_TIME (until end of packet) */
if(radio_mode == CC1100_MODE_CONSTANT_RX) {
cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX;
// Return here if mode is CONSTANT_RX_MODE
/* Return here if mode is CONSTANT_RX_MODE */
return;
} else {
}
else {
cc1100_spi_strobe(CC1100_SPWD);
radio_state = RADIO_PWD;
}
// Set hwtimer to put CC1100 back to RX after WOR_TIMEOUT_1
/* Set hwtimer to put CC1100 back to RX after WOR_TIMEOUT_1 */
wor_hwtimer_id = hwtimer_set(WOR_TIMEOUT_1, cc1100_hwtimer_go_receive_wrapper, NULL);
if (wor_hwtimer_id == -1)
{
// Signal hwtimer resource error, radio stays in RX,
// so no big problem, only energy is wasted.
if(wor_hwtimer_id == -1) {
/* Signal hwtimer resource error, radio stays in RX,
* so no big problem, only energy is wasted. */
rflags.KT_RES_ERR = true;
}
}
else
{
// No ACK received so TOF is unpredictable
else {
/* No ACK received so TOF is unpredictable */
rflags.TOF = 0;
// CRC false or RX buffer full -> clear RX FIFO in both cases
last_seq_num = 0; // Reset for correct burst detection
cc1100_spi_strobe(CC1100_SIDLE); // Switch to IDLE (should already be)...
cc1100_spi_strobe(CC1100_SFRX); // ...for flushing the RX FIFO
/* CRC false or RX buffer full -> clear RX FIFO in both cases */
last_seq_num = 0; /* Reset for correct burst detection */
cc1100_spi_strobe(CC1100_SIDLE); /* Switch to IDLE (should already be)... */
cc1100_spi_strobe(CC1100_SFRX); /* ...for flushing the RX FIFO */
// If packet interrupted this nodes send call,
// don't change anything after this point.
if (radio_state == RADIO_AIR_FREE_WAITING)
{
/* If packet interrupted this nodes send call,
* don't change anything after this point. */
if(radio_state == RADIO_AIR_FREE_WAITING) {
cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
return;
}
// If currently sending, exit here (don't go to RX/WOR)
if (radio_state == RADIO_SEND_BURST)
{
/* If currently sending, exit here (don't go to RX/WOR) */
if(radio_state == RADIO_SEND_BURST) {
cc1100_statistic.packets_in_while_tx++;
return;
}
// No valid packet, so go back to RX/WOR as soon as possible
/* No valid packet, so go back to RX/WOR as soon as possible */
cc1100_go_receive();
}
}

View File

@ -75,8 +75,7 @@ Notes:
\li Identification is increased is used to scan duplicates. It must be increased
for each new packet and kept for packet retransmissions.
*/
typedef struct __attribute__ ((packed)) cc1100_packet_layer0_t
{
typedef struct __attribute__((packed)) cc1100_packet_layer0_t {
uint8_t length; ///< Length of the packet (without length byte)
uint8_t address; ///< Destination address
uint8_t phy_src; ///< Source address (physical source)
@ -84,8 +83,7 @@ typedef struct __attribute__ ((packed)) cc1100_packet_layer0_t
uint8_t data[MAX_DATA_LENGTH]; ///< Data (high layer protocol)
} cc1100_packet_layer0_t;
typedef struct cc1100_wor_config_t
{
typedef struct cc1100_wor_config_t {
uint16_t rx_interval; ///< RX polling interval in milliseconds
float rx_time_ms; ///< WOR_RX_TIME in milliseconds
uint8_t rx_time_reg; ///< WOR_RX_TIME (CC1100 "MCSM2.RX_TIME" register value)

View File

@ -63,10 +63,12 @@ cc1100_spi_writeburst_reg(uint8_t addr, char *src, uint8_t count)
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
cc110x_txrx(addr | CC1100_WRITE_BURST);
while(i < count) {
cc110x_txrx(src[i]);
i++;
}
cc110x_spi_unselect();
restoreIRQ(cpsr);
return count;
@ -79,10 +81,12 @@ cc1100_spi_readburst_reg(uint8_t addr, char *buffer, uint8_t count)
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
cc110x_txrx(addr | CC1100_READ_BURST);
while(i < count) {
buffer[i] = cc110x_txrx(NOBYTE);
i++;
}
cc110x_spi_unselect();
restoreIRQ(cpsr);
}

View File

@ -1,28 +1,12 @@
/******************************************************************************
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
/**
* Default configuration for the cc110x chip
*
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup dev_cc110x
@ -34,9 +18,10 @@ and the mailinglist (subscription via web site)
* @brief TI Chipcon CC110x default settings
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author INRIA
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@inf.fu-berlin.de>
* @version $Revision: 2058 $
* @author Oliver Hahm <oliver.hahm@inria.fr>
*
* @note $Id: cc110x-defaultSettings.c 2058 2010-03-31 08:59:31Z hillebra $
*/

View File

@ -1,3 +1,20 @@
/**
* Functions for packet reception on cc110x
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#include <cc110x_ng.h>
#include <cc110x-internal.h>
#include <cc110x-config.h>
@ -27,43 +44,46 @@ static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length);
rx_buffer_t cc110x_rx_buffer[RX_BUF_SIZE]; ///< RX buffer
volatile uint8_t rx_buffer_next; ///< Next packet in RX queue
void cc110x_rx_handler(void) {
void cc110x_rx_handler(void)
{
uint8_t res = 0;
// Possible packet received, RX -> IDLE (0.1 us)
/* Possible packet received, RX -> IDLE (0.1 us) */
rflags.CAA = 0;
rflags.MAN_WOR = 0;
cc110x_statistic.packets_in++;
res = receive_packet((uint8_t *)&(cc110x_rx_buffer[rx_buffer_next].packet), sizeof(cc110x_packet_t));
if(res) {
// If we are sending a burst, don't accept packets.
// Only ACKs are processed (for stopping the burst).
// Same if state machine is in TX lock.
if (radio_state == RADIO_SEND_BURST || rflags.TX)
{
/* If we are sending a burst, don't accept packets.
* Only ACKs are processed (for stopping the burst).
* Same if state machine is in TX lock. */
if(radio_state == RADIO_SEND_BURST || rflags.TX) {
cc110x_statistic.packets_in_while_tx++;
return;
}
cc110x_rx_buffer[rx_buffer_next].rssi = rflags._RSSI;
cc110x_rx_buffer[rx_buffer_next].lqi = rflags._LQI;
cc110x_strobe(CC1100_SFRX); // ...for flushing the RX FIFO
cc110x_strobe(CC1100_SFRX); /* ...for flushing the RX FIFO */
// Valid packet. After a wake-up, the radio should be in IDLE.
// So put CC1100 to RX for WOR_TIMEOUT (have to manually put
// the radio back to sleep/WOR).
//cc110x_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal
cc110x_write_reg(CC1100_MCSM2, 0x07); // Configure RX_TIME (until end of packet)
/* Valid packet. After a wake-up, the radio should be in IDLE.
* So put CC1100 to RX for WOR_TIMEOUT (have to manually put
* the radio back to sleep/WOR). */
//cc110x_spi_write_reg(CC1100_MCSM0, 0x08); /* Turn off FS-Autocal */
cc110x_write_reg(CC1100_MCSM2, 0x07); /* Configure RX_TIME (until end of packet) */
cc110x_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX;
#ifdef DBG_IGNORE
if(is_ignored(cc110x_rx_buffer[rx_buffer_next].packet.phy_src)) {
LED_RED_TOGGLE;
return;
}
#endif
/* notify transceiver thread if any */
@ -78,116 +98,124 @@ void cc110x_rx_handler(void) {
if(++rx_buffer_next == RX_BUF_SIZE) {
rx_buffer_next = 0;
}
return;
}
else
{
// No ACK received so TOF is unpredictable
else {
/* No ACK received so TOF is unpredictable */
rflags.TOF = 0;
// CRC false or RX buffer full -> clear RX FIFO in both cases
cc110x_strobe(CC1100_SIDLE); // Switch to IDLE (should already be)...
cc110x_strobe(CC1100_SFRX); // ...for flushing the RX FIFO
/* CRC false or RX buffer full -> clear RX FIFO in both cases */
cc110x_strobe(CC1100_SIDLE); /* Switch to IDLE (should already be)... */
cc110x_strobe(CC1100_SFRX); /* ...for flushing the RX FIFO */
// If packet interrupted this nodes send call,
// don't change anything after this point.
if (radio_state == RADIO_AIR_FREE_WAITING)
{
/* If packet interrupted this nodes send call,
* don't change anything after this point. */
if(radio_state == RADIO_AIR_FREE_WAITING) {
cc110x_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME);
return;
}
// If currently sending, exit here (don't go to RX/WOR)
if (radio_state == RADIO_SEND_BURST)
{
/* If currently sending, exit here (don't go to RX/WOR) */
if(radio_state == RADIO_SEND_BURST) {
cc110x_statistic.packets_in_while_tx++;
return;
}
// No valid packet, so go back to RX/WOR as soon as possible
/* No valid packet, so go back to RX/WOR as soon as possible */
cc110x_switch_to_rx();
}
}
static uint8_t receive_packet_variable(uint8_t *rxBuffer, uint8_t length) {
static uint8_t receive_packet_variable(uint8_t *rxBuffer, uint8_t length)
{
uint8_t status[2];
uint8_t packetLength = 0;
/* Any bytes available in RX FIFO? */
if((cc110x_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) {
// Read length byte (first byte in RX FIFO)
/* Read length byte (first byte in RX FIFO) */
cc110x_read_fifo((char *) &packetLength, 1);
// Read data from RX FIFO and store in rxBuffer
if (packetLength <= length)
{
// Put length byte at first position in RX Buffer
/* Read data from RX FIFO and store in rxBuffer */
if(packetLength <= length) {
/* Put length byte at first position in RX Buffer */
rxBuffer[0] = packetLength;
// Read the rest of the packet
/* Read the rest of the packet */
//cc110x_readburst_reg(CC1100_RXFIFO, (char*)rxBuffer+1, packetLength);
cc110x_read_fifo((char *) rxBuffer + 1, packetLength);
// Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI)
/* Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) */
cc110x_readburst_reg(CC1100_RXFIFO, (char *)status, 2);
// Store RSSI value of packet
/* Store RSSI value of packet */
rflags._RSSI = status[I_RSSI];
// MSB of LQI is the CRC_OK bit
/* MSB of LQI is the CRC_OK bit */
rflags.CRC_STATE = (status[I_LQI] & CRC_OK) >> 7;
if(!rflags.CRC_STATE) {
cc110x_statistic.packets_in_crc_fail++;
}
// Bit 0-6 of LQI indicates the link quality (LQI)
/* Bit 0-6 of LQI indicates the link quality (LQI) */
rflags._LQI = status[I_LQI] & LQI_EST;
return rflags.CRC_STATE;
}
/* too many bytes in FIFO */
else {
// RX FIFO get automatically flushed if return value is false
/* RX FIFO get automatically flushed if return value is false */
return 0;
}
}
/* no bytes in RX FIFO */
else {
// RX FIFO get automatically flushed if return value is false
/* RX FIFO get automatically flushed if return value is false */
return 0;
}
}
static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length) {
uint8_t pkt_len_cfg = cc110x_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG;
if (pkt_len_cfg == VARIABLE_PKTLEN)
static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length)
{
uint8_t pkt_len_cfg = cc110x_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG;
if(pkt_len_cfg == VARIABLE_PKTLEN) {
return receive_packet_variable(rxBuffer, length);
}
// Fixed packet length not supported.
// RX FIFO get automatically flushed if return value is false
/* Fixed packet length not supported. */
/* RX FIFO get automatically flushed if return value is false */
return 0;
}
#ifdef DBG_IGNORE
void cc110x_init_ignore(void) {
void cc110x_init_ignore(void)
{
memset(ignored_addr, 0, IGN_MAX * sizeof(radio_address_t));
}
uint8_t cc110x_add_ignored(radio_address_t addr) {
uint8_t cc110x_add_ignored(radio_address_t addr)
{
uint8_t i = 0;
while((i < IGN_MAX) && ignored_addr[i++]) {
printf("i: %hu\n", i);
}
if(i > IGN_MAX) {
return 0;
}
ignored_addr[i - 1] = addr;
return 1;
}
static uint8_t is_ignored(radio_address_t addr) {
static uint8_t is_ignored(radio_address_t addr)
{
uint8_t i;
for(i = 0; i < IGN_MAX; i++) {
@ -195,6 +223,7 @@ static uint8_t is_ignored(radio_address_t addr) {
return 1;
}
}
return 0;
}
#endif

View File

@ -1,3 +1,20 @@
/**
* Functions for packet transmission on cc110x
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#include <stdio.h>
#include <cc110x_ng.h>
@ -11,7 +28,8 @@
#include <board.h>
uint8_t cc110x_send(cc110x_packet_t *packet) {
uint8_t cc110x_send(cc110x_packet_t *packet)
{
volatile uint32_t abort_count;
uint8_t size;
/* TODO: burst sending */
@ -25,52 +43,56 @@ uint8_t cc110x_send(cc110x_packet_t *packet) {
*/
size = packet->length + 1;
// The number of bytes to be transmitted must be smaller
// or equal to PACKET_LENGTH (62 bytes). So the receiver
// can put the whole packet in its RX-FIFO (with appended
// packet status bytes).
/* The number of bytes to be transmitted must be smaller
* or equal to PACKET_LENGTH (62 bytes). So the receiver
* can put the whole packet in its RX-FIFO (with appended
* packet status bytes).*/
if(size > PACKET_LENGTH) {
return 0;
}
packet->phy_src = cc110x_get_address();
// Disables RX interrupt etc.
/* Disables RX interrupt etc. */
cc110x_before_send();
// But CC1100 in IDLE mode to flush the FIFO
/* But CC1100 in IDLE mode to flush the FIFO */
cc110x_strobe(CC1100_SIDLE);
// Flush TX FIFO to be sure it is empty
/* Flush TX FIFO to be sure it is empty */
cc110x_strobe(CC1100_SFTX);
// Write packet into TX FIFO
/* Write packet into TX FIFO */
cc110x_writeburst_reg(CC1100_TXFIFO, (char *) packet, size);
// Switch to TX mode
/* Switch to TX mode */
abort_count = 0;
unsigned int cpsr = disableIRQ();
cc110x_strobe(CC1100_STX);
// Wait for GDO2 to be set -> sync word transmitted
/* Wait for GDO2 to be set -> sync word transmitted */
while(cc110x_get_gdo2() == 0) {
abort_count++;
if(abort_count > CC1100_SYNC_WORD_TX_TIME) {
// Abort waiting. CC1100 maybe in wrong mode
// e.g. sending preambles for always
/* Abort waiting. CC1100 maybe in wrong mode */
/* e.g. sending preambles for always */
puts("[CC1100 TX] fatal error\n");
break;
}
}
restoreIRQ(cpsr);
// Wait for GDO2 to be cleared -> end of packet
while (cc110x_get_gdo2() != 0);
//LED_GREEN_TOGGLE;
// Experimental - TOF Measurement
restoreIRQ(cpsr);
/* Wait for GDO2 to be cleared -> end of packet */
while(cc110x_get_gdo2() != 0);
/* Experimental - TOF Measurement */
cc110x_after_send();
cc110x_statistic.raw_packets_out++;
// Store number of transmission retries
/* Store number of transmission retries */
rflags.TX = 0;
// Go to mode after TX (CONST_RX -> RX, WOR -> WOR)
/* Go to mode after TX (CONST_RX -> RX, WOR -> WOR) */
cc110x_switch_to_rx();
return true;

View File

@ -1,3 +1,19 @@
/**
* Basic functionality of cc110x driver
*
* Copyright (C) 2013 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#include <cc110x_ng.h>
#include <cc110x-arch.h>
#include <cc110x-config.h>
@ -34,10 +50,11 @@ static void reset(void);
static void power_up_reset(void);
static void write_register(uint8_t r, uint8_t value);
/*---------------------------------------------------------------------------*/
// Radio Driver API
/*---------------------------------------------------------------------------*/
void cc110x_init(int tpid) {
/*---------------------------------------------------------------------------*
* Radio Driver API *
*---------------------------------------------------------------------------*/
void cc110x_init(int tpid)
{
transceiver_pid = tpid;
DEBUG("Transceiver PID: %i\n", transceiver_pid);
@ -76,7 +93,7 @@ void cc110x_init(int tpid) {
#endif
DEBUG("CC1100 initialized and set to channel %i\n", radio_channel);
// Switch to desired mode (WOR or RX)
/* Switch to desired mode (WOR or RX) */
rd_set_mode(RADIO_MODE_ON);
#ifdef DBG_IGNORE
@ -84,36 +101,43 @@ void cc110x_init(int tpid) {
#endif
}
void cc110x_disable_interrupts(void) {
void cc110x_disable_interrupts(void)
{
cc110x_gdo2_disable();
cc110x_gdo0_disable();
}
void cc110x_gdo0_irq(void) {
// Air was not free -> Clear CCA flag
void cc110x_gdo0_irq(void)
{
/* Air was not free -> Clear CCA flag */
rflags.CAA = false;
// Disable carrier sense detection (GDO0 interrupt)
/* Disable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_disable();
}
void cc110x_gdo2_irq(void) {
void cc110x_gdo2_irq(void)
{
cc110x_rx_handler();
}
uint8_t cc110x_get_buffer_pos(void) {
uint8_t cc110x_get_buffer_pos(void)
{
return (rx_buffer_next - 1);
}
radio_address_t cc110x_get_address() {
radio_address_t cc110x_get_address()
{
return radio_address;
}
radio_address_t cc110x_set_address(radio_address_t address) {
radio_address_t cc110x_set_address(radio_address_t address)
{
if((address < MIN_UID) || (address > MAX_UID)) {
return 0;
}
uint8_t id = (uint8_t) address;
if(radio_state != RADIO_UNKNOWN) {
write_register(CC1100_ADDR, id);
}
@ -123,17 +147,21 @@ radio_address_t cc110x_set_address(radio_address_t address) {
}
#ifdef MODULE_CONFIG
radio_address_t cc110x_set_config_address(radio_address_t address) {
radio_address_t cc110x_set_config_address(radio_address_t address)
{
radio_address_t a = cc110x_set_address(address);
if(a) {
sysconfig.radio_address = a;
}
config_save();
return a;
}
#endif
void cc110x_set_monitor(uint8_t mode) {
void cc110x_set_monitor(uint8_t mode)
{
if(mode) {
write_register(CC1100_PKTCTRL1, (0x04));
}
@ -142,97 +170,145 @@ void cc110x_set_monitor(uint8_t mode) {
}
}
void cc110x_setup_rx_mode(void) {
// Stay in RX mode until end of packet
void cc110x_setup_rx_mode(void)
{
/* Stay in RX mode until end of packet */
cc110x_write_reg(CC1100_MCSM2, 0x07);
cc110x_switch_to_rx();
}
void cc110x_switch_to_rx(void) {
void cc110x_switch_to_rx(void)
{
radio_state = RADIO_RX;
cc110x_strobe(CC1100_SRX);
}
void cc110x_wakeup_from_rx(void) {
void cc110x_wakeup_from_rx(void)
{
if(radio_state != RADIO_RX) {
return;
}
DEBUG("CC1100 going to idle\n");
cc110x_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE;
}
char* cc110x_get_marc_state(void) {
char *cc110x_get_marc_state(void)
{
uint8_t state;
// Save old radio state
/* Save old radio state */
uint8_t old_state = radio_state;
// Read content of status register
/* Read content of status register */
state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
// Make sure in IDLE state.
// Only goes to IDLE if state was RX/WOR
/* Make sure in IDLE state.
* Only goes to IDLE if state was RX/WOR */
cc110x_wakeup_from_rx();
// Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary
/* Have to put radio back to WOR/RX if old radio state
* was WOR/RX, otherwise no action is necessary */
if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc110x_switch_to_rx();
}
switch (state)
{
// Note: it is not possible to read back the SLEEP or XOFF state numbers
// because setting CSn low will make the chip enter the IDLE mode from the
// SLEEP (0) or XOFF (2) states.
case 1: return "IDLE";
case 3: case 4: case 5: return "MANCAL";
case 6: case 7: return "FS_WAKEUP";
case 8: case 12: return "CALIBRATE";
case 9: case 10: case 11: return "SETTLING";
case 13: case 14: case 15: return "RX";
case 16: return "TXRX_SETTLING";
case 17: return "RXFIFO_OVERFLOW";
case 18: return "FSTXON";
case 19: case 20: return "TX";
case 21: return "RXTX_SETTLING";
case 22: return "TXFIFO_UNDERFLOW";
default: return "UNKNOWN";
switch(state) {
/* Note: it is not possible to read back the SLEEP or XOFF state numbers
* because setting CSn low will make the chip enter the IDLE mode from the
* SLEEP (0) or XOFF (2) states. */
case 1:
return "IDLE";
case 3:
case 4:
case 5:
return "MANCAL";
case 6:
case 7:
return "FS_WAKEUP";
case 8:
case 12:
return "CALIBRATE";
case 9:
case 10:
case 11:
return "SETTLING";
case 13:
case 14:
case 15:
return "RX";
case 16:
return "TXRX_SETTLING";
case 17:
return "RXFIFO_OVERFLOW";
case 18:
return "FSTXON";
case 19:
case 20:
return "TX";
case 21:
return "RXTX_SETTLING";
case 22:
return "TXFIFO_UNDERFLOW";
default:
return "UNKNOWN";
}
}
char* cc110x_state_to_text(uint8_t state) {
switch (state)
char *cc110x_state_to_text(uint8_t state)
{
switch(state) {
case RADIO_UNKNOWN:
return "Unknown";
case RADIO_AIR_FREE_WAITING:
return "CS";
case RADIO_WOR:
return "WOR";
case RADIO_IDLE:
return "IDLE";
case RADIO_SEND_BURST:
return "TX BURST";
case RADIO_RX:
return "RX";
case RADIO_SEND_ACK:
return "TX ACK";
case RADIO_PWD:
return "PWD";
default:
return "unknown";
}
}
void cc110x_print_config(void) {
void cc110x_print_config(void)
{
printf("Current radio state: %s\r\n", cc110x_state_to_text(radio_state));
printf("Current MARC state: %s\r\n", cc110x_get_marc_state());
printf("Current channel number: %u\r\n", radio_channel);
}
void cc110x_switch_to_pwd(void) {
void cc110x_switch_to_pwd(void)
{
DEBUG("[cc110x_ng] switching to powerdown\n");
cc110x_wakeup_from_rx();
cc110x_strobe(CC1100_SPWD);
@ -240,37 +316,45 @@ void cc110x_switch_to_pwd(void) {
}
/*---------------------------------------------------------------------------*/
int16_t cc110x_set_channel(uint8_t channr) {
int16_t cc110x_set_channel(uint8_t channr)
{
uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
if((state != 1) && (channr > MAX_CHANNR)) {
return -1;
}
write_register(CC1100_CHANNR, channr * 10);
radio_channel = channr;
return radio_channel;
}
#ifdef MODULE_CONFIG
int16_t cc110x_set_config_channel(uint8_t channr) {
int16_t cc110x_set_config_channel(uint8_t channr)
{
int16_t c = cc110x_set_channel(channr);
if(c) {
sysconfig.radio_channel = c;
}
config_save();
return c;
}
#endif
int16_t cc110x_get_channel(void) {
int16_t cc110x_get_channel(void)
{
return radio_channel;
}
/*---------------------------------------------------------------------------*/
// CC1100 reset functionality
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
* CC1100 reset functionality
*---------------------------------------------------------------------------*/
static void reset(void) {
static void reset(void)
{
cc110x_wakeup_from_rx();
#ifdef MODULE_CC110x_SPI
cc110x_spi_select();
@ -279,7 +363,8 @@ static void reset(void) {
hwtimer_wait(RTIMER_TICKS(100));
}
static void power_up_reset(void) {
static void power_up_reset(void)
{
#ifdef MODULE_CC110x_SPI
cc110x_spi_unselect();
cc110x_spi_cs();
@ -290,25 +375,27 @@ static void power_up_reset(void) {
radio_state = RADIO_IDLE;
}
static void write_register(uint8_t r, uint8_t value) {
// Save old radio state
static void write_register(uint8_t r, uint8_t value)
{
/* Save old radio state */
uint8_t old_state = radio_state;
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */
cc110x_wakeup_from_rx();
cc110x_write_reg(r, value);
// Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary
/* Have to put radio back to WOR/RX if old radio state
* was WOR/RX, otherwise no action is necessary */
if((old_state == RADIO_WOR) || (old_state == RADIO_RX)) {
cc110x_switch_to_rx();
}
}
static int rd_set_mode(int mode) {
static int rd_set_mode(int mode)
{
int result;
// Get current radio mode
/* Get current radio mode */
if((radio_state == RADIO_UNKNOWN) || (radio_state == RADIO_PWD)) {
result = RADIO_MODE_OFF;
}
@ -319,22 +406,23 @@ static int rd_set_mode(int mode) {
switch(mode) {
case RADIO_MODE_ON:
DEBUG("Enabling rx mode\n");
cc110x_init_interrupts(); // Enable interrupts
cc110x_setup_rx_mode(); // Set chip to desired mode
cc110x_init_interrupts(); /* Enable interrupts */
cc110x_setup_rx_mode(); /* Set chip to desired mode */
break;
case RADIO_MODE_OFF:
cc110x_disable_interrupts(); // Disable interrupts
cc110x_switch_to_pwd(); // Set chip to power down mode
cc110x_disable_interrupts(); /* Disable interrupts */
cc110x_switch_to_pwd(); /* Set chip to power down mode */
break;
case RADIO_MODE_GET:
// do nothing, just return current mode
/* do nothing, just return current mode */
default:
// do nothing
/* do nothing */
break;
}
// Return previous mode
/* Return previous mode */
return result;
}

View File

@ -1,3 +1,19 @@
/**
* Configuration parameters for the cc110x radio chip
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#ifndef CC1100_CONFIG_H
#define CC1100_CONFIG_H
@ -56,8 +72,7 @@ typedef struct {
/**
* @brief Radio Control Flags
*/
typedef struct
{
typedef struct {
uint32_t TOF; ///< Time of flight of the last packet and last ACK
timex_t TOA; ///< Time of packet arriveal
uint32_t TCP; ///< Time to compute packet

View File

@ -1,28 +1,19 @@
/******************************************************************************
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
/**
* Driver internal constants for 110x chip configuration
*
* Copyright (C) 2008 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#ifndef CC1100_INTERNAL_H
#define CC1100_INTERNAL_H

View File

@ -3,9 +3,8 @@
* @ingroup dev_cc110x_ng
* @brief Access to CC110X registers
*
* @author Freie Uniersität Berlin, Computer Systems & Telematics, RIOT
* @author Oliver Hahm <oliver.hahm@fu-berlin.de
* version $Revision$
* @author INRIA
* @author Oliver Hahm <oliver.hahm@inria.fr>
*
*/

View File

@ -1,3 +1,19 @@
/**
* Data structures and variables for the cc110x driver interface
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#ifndef CC1100_H
#define CC1100_H
@ -65,13 +81,15 @@ Notes:
\li Identification is increased is used to scan duplicates. It must be increased
for each new packet and kept for packet retransmissions.
*/
typedef struct __attribute__ ((packed)) {
typedef struct __attribute__((packed))
{
uint8_t length; ///< Length of the packet (without length byte)
uint8_t address; ///< Destination address
uint8_t phy_src; ///< Source address (physical source)
uint8_t flags; ///< Flags
uint8_t data[CC1100_MAX_DATA_LENGTH]; ///< Data (high layer protocol)
} cc110x_packet_t;
}
cc110x_packet_t;
typedef struct {
uint8_t rssi;

View File

@ -58,38 +58,46 @@ and the mailinglist (subscription via web site)
#define NOBYTE 0xFF
uint8_t cc110x_writeburst_reg(uint8_t addr, char *src, uint8_t count) {
uint8_t cc110x_writeburst_reg(uint8_t addr, char *src, uint8_t count)
{
int i = 0;
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
cc110x_txrx(addr | CC1100_WRITE_BURST);
while(i < count) {
cc110x_txrx(src[i]);
i++;
}
cc110x_spi_unselect();
restoreIRQ(cpsr);
return count;
}
void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count) {
void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count)
{
int i = 0;
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
cc110x_txrx(addr | CC1100_READ_BURST);
while(i < count) {
buffer[i] = cc110x_txrx(NOBYTE);
i++;
}
cc110x_spi_unselect();
restoreIRQ(cpsr);
}
void cc110x_read_fifo(char *buffer, uint8_t count) {
void cc110x_read_fifo(char *buffer, uint8_t count)
{
cc110x_readburst_reg(CC1100_RXFIFO, buffer, count);
}
void cc110x_write_reg(uint8_t addr, uint8_t value) {
void cc110x_write_reg(uint8_t addr, uint8_t value)
{
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
cc110x_txrx(addr);
@ -98,7 +106,8 @@ void cc110x_write_reg(uint8_t addr, uint8_t value) {
restoreIRQ(cpsr);
}
uint8_t cc110x_read_reg(uint8_t addr) {
uint8_t cc110x_read_reg(uint8_t addr)
{
uint8_t result;
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
@ -109,7 +118,8 @@ uint8_t cc110x_read_reg(uint8_t addr) {
return result;
}
uint8_t cc110x_read_status(uint8_t addr) {
uint8_t cc110x_read_status(uint8_t addr)
{
uint8_t result;
unsigned int cpsr = disableIRQ();
cc110x_spi_select();
@ -120,7 +130,8 @@ uint8_t cc110x_read_status(uint8_t addr) {
return result;
}
uint8_t cc110x_strobe(uint8_t c) {
uint8_t cc110x_strobe(uint8_t c)
{
uint8_t result;
unsigned int cpsr = disableIRQ();
cc110x_spi_select();

View File

@ -46,51 +46,63 @@ static unsigned int last_int_time;
static unsigned int last_int_duration;
static unsigned int start_time;
static double __attribute__((__no_instrument_function__)) int_to_coulomb(int ints) {
static double __attribute__((__no_instrument_function__)) int_to_coulomb(int ints)
{
return ((double)ints) / (_GFH * _R_SENSE);
}
static double __attribute__((__no_instrument_function__)) coulomb_to_mA(double coulomb){
static double __attribute__((__no_instrument_function__)) coulomb_to_mA(double coulomb)
{
return (coulomb * 1000) / 3600;
}
static double mAh_to_Joule(double mAh) {
static double mAh_to_Joule(double mAh)
{
return (SUPPLY_VOLTAGE * mAh * 3600);
}
uint32_t ltc4150_get_last_int_duration_us(void) {
uint32_t ltc4150_get_last_int_duration_us(void)
{
return HWTIMER_TICKS_TO_US(last_int_duration);
}
double ltc4150_get_current_mA(void) {
double ltc4150_get_current_mA(void)
{
return 1000000000 / (ltc4150_get_last_int_duration_us() * (_GFH * _R_SENSE));
}
double __attribute__((__no_instrument_function__)) ltc4150_get_total_mAh(void) {
double __attribute__((__no_instrument_function__)) ltc4150_get_total_mAh(void)
{
return coulomb_to_mA(int_to_coulomb(int_count));
}
double ltc4150_get_total_Joule(void) {
double ltc4150_get_total_Joule(void)
{
return mAh_to_Joule(ltc4150_get_total_mAh());
}
double ltc4150_get_avg_mA(void) {
double ltc4150_get_avg_mA(void)
{
return (int_to_coulomb(int_count) * 1000000000) / HWTIMER_TICKS_TO_US(last_int_time - start_time);
}
int ltc4150_get_interval(void) {
int ltc4150_get_interval(void)
{
return HWTIMER_TICKS_TO_US(last_int_time - start_time);
}
unsigned long __attribute__((__no_instrument_function__)) ltc4150_get_intcount(void) {
unsigned long __attribute__((__no_instrument_function__)) ltc4150_get_intcount(void)
{
return int_count;
}
void ltc4150_init(void) {
void ltc4150_init(void)
{
ltc4150_arch_init();
}
void ltc4150_start(void) {
void ltc4150_start(void)
{
ltc4150_disable_int();
int_count = 0;
uint32_t now = hwtimer_now();
@ -100,16 +112,19 @@ void ltc4150_start(void) {
ltc4150_enable_int();
}
void ltc4150_stop(void) {
void ltc4150_stop(void)
{
ltc4150_disable_int();
}
void __attribute__((__no_instrument_function__)) ltc4150_interrupt(void)
{
uint32_t now = hwtimer_now();
if(now >= last_int_time) {
last_int_duration = now - last_int_time;
} else {
}
else {
last_int_duration = (0 - 1) - last_int_time + now + 1;
}

View File

@ -99,7 +99,8 @@ static inline void clk_signal(void);
mutex_t sht11_mutex;
/*---------------------------------------------------------------------------*/
static inline void clk_signal(void) {
static inline void clk_signal(void)
{
SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT);
SHT11_SCK_LOW;
@ -113,12 +114,14 @@ static uint8_t write_byte(uint8_t value)
uint8_t ack;
SHT11_DATA_OUT;
/* send value bit by bit to sht11 */
for(i = 0; i < 8; i++) {
if(value & BIT7) {
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
} else {
}
else {
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT);
}
@ -147,6 +150,7 @@ static uint8_t read_byte (uint8_t ack)
SHT11_DATA_IN;
hwtimer_wait(SHT11_DATA_WAIT);
/* read value bit by bit */
for(i = 0; i < 8; i++) {
value = value << 1;
@ -157,19 +161,23 @@ static uint8_t read_byte (uint8_t ack)
/* increase data by one when DATA is high */
value++;
}
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
}
/* send ack if necessary */
SHT11_DATA_OUT;
if(ack) {
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT);
} else {
}
else {
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
}
clk_signal();
/* release data line */
@ -224,9 +232,11 @@ static void connection_reset(void)
hwtimer_wait(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
for(i = 0; i < 9; i++) {
clk_signal();
}
transmission_start();
}
/*---------------------------------------------------------------------------*/
@ -248,8 +258,10 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
if(!ack) {
break;
}
hwtimer_wait(HWTIMER_TICKS(1000));
}
error += ack;
/* read MSB */
@ -262,14 +274,16 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
return (!error);
}
/*---------------------------------------------------------------------------*/
void sht11_init(void) {
void sht11_init(void)
{
sht11_temperature_offset = 0;
mutex_init(&sht11_mutex);
SHT11_INIT;
hwtimer_wait(11 * HWTIMER_TICKS(1000));
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum) {
uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum)
{
uint8_t error = 0;
transmission_start();
@ -279,7 +293,8 @@ uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum) {
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_write_status(uint8_t *p_value) {
uint8_t sht11_write_status(uint8_t *p_value)
{
uint8_t error = 0;
transmission_start();
@ -288,7 +303,8 @@ uint8_t sht11_write_status(uint8_t *p_value) {
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode)
{
uint8_t error = 0;
uint8_t checksum;
uint16_t humi_int, temp_int;
@ -325,6 +341,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
if(mode & HUMIDITY) {
error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI));
}
/* measure temperature */
if(mode & TEMPERATURE) {
error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP));
@ -340,6 +357,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
if(mode & TEMPERATURE) {
value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset;
}
if(mode & HUMIDITY) {
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
@ -347,6 +365,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
}
}
mutex_unlock(&sht11_mutex, 0);
return 1;
}