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

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

View File

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

View File

@ -66,7 +66,7 @@ and the mailinglist (subscription via web site)
// Define default radio mode to constant RX if no // Define default radio mode to constant RX if no
// project specific setting is available. // project specific setting is available.
#ifndef CC1100_RADIO_MODE #ifndef CC1100_RADIO_MODE
#define CC1100_RADIO_MODE CC1100_MODE_CONSTANT_RX #define CC1100_RADIO_MODE CC1100_MODE_CONSTANT_RX
#endif #endif
/// CC1100 radio interface /// CC1100 radio interface

View File

@ -58,7 +58,7 @@ and the mailinglist (subscription via web site)
#include "hwtimer.h" #include "hwtimer.h"
#include "core/include/bitarithm.h" #include "core/include/bitarithm.h"
// TODO: cc1100 port timer /* TODO: cc1100 port timer */
#ifdef FEUERWARE_CPU_LPC2387 #ifdef FEUERWARE_CPU_LPC2387
//#include "cpu/lpc2387/lpc2387-timer2.h" //#include "cpu/lpc2387/lpc2387-timer2.h"
#endif #endif
@ -70,8 +70,8 @@ and the mailinglist (subscription via web site)
#endif #endif
#define PACKET_LENGTH (0x3E) ///< Packet length = 62 Bytes. #define PACKET_LENGTH (0x3E) ///< Packet length = 62 Bytes.
#define CC1100_SYNC_WORD_TX_TIME (90000) // loop count (max. timeout ~ 15 ms) to wait for #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) /* sync word to be transmitted (GDO2 from low to high) */
/** /**
* @name Virtual Radio Device methods (see vdevice_radio_methods) * @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 0xCC, ///< + 7 dBm
0xC6, ///< + 9 dBm 0xC6, ///< + 9 dBm
0xC3 ///< +10 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 static int8_t pa_table_dBm[] = { ///< Values of the PATABLE in dBm
-52, -52,
@ -155,7 +155,7 @@ volatile cc1100_mode_callback_t cc1100_setup_mode; ///< Function to set up selec
volatile int wor_hwtimer_id = -1; volatile int wor_hwtimer_id = -1;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
// Low-level hardware access /* Low-level hardware access */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void cc1100_disable_interrupts(void) void cc1100_disable_interrupts(void)
@ -166,9 +166,9 @@ void cc1100_disable_interrupts(void)
void cc110x_gdo0_irq(void) void cc110x_gdo0_irq(void)
{ {
// Air was not free -> Clear CCA flag /* Air was not free -> Clear CCA flag */
rflags.CAA = false; rflags.CAA = false;
// Disable carrier sense detection (GDO0 interrupt) /* Disable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_disable(); 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) // of RX FIFO (don't call when in WOR mode)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static bool spi_receive_packet_variable(uint8_t *rxBuffer, uint8_t length) 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; extern cc1100_statistic_t cc1100_statistic;
uint8_t status[2]; uint8_t status[2];
uint8_t packetLength = 0; uint8_t packetLength = 0;
// Any bytes available in RX FIFO? /* Any bytes available in RX FIFO? */
if ((cc1100_spi_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) if((cc1100_spi_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) {
{ /* Read length byte (first byte in RX FIFO) */
// Read length byte (first byte in RX FIFO)
packetLength = cc1100_spi_read_reg(CC1100_RXFIFO); packetLength = cc1100_spi_read_reg(CC1100_RXFIFO);
// Read data from RX FIFO and store in rxBuffer
if (packetLength <= length) /* Read data from RX FIFO and store in rxBuffer */
{ if(packetLength <= length) {
// Put length byte at first position in RX Buffer /* Put length byte at first position in RX Buffer */
rxBuffer[0] = packetLength; 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); 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); cc1100_spi_readburst_reg(CC1100_RXFIFO, (char *)status, 2);
// Store RSSI value of packet /* Store RSSI value of packet */
rflags.RSSI = status[I_RSSI]; 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; 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; rflags.LQI = status[I_LQI] & LQI_EST;
return rflags.CRC_STATE; return rflags.CRC_STATE;
} }
else else {
{ /* RX FIFO get automatically flushed if return value is false */
// RX FIFO get automatically flushed if return value is false
return false; return false;
} }
} }
else else {
{ /* RX FIFO get automatically flushed if return value is false */
// RX FIFO get automatically flushed if return value is false
return 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) 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; 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); 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; 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 if(radio_state == RADIO_WOR) {
/* Wake up the chip from WOR/sleep */
cc110x_spi_select(); cc110x_spi_select();
hwtimer_wait(RTIMER_TICKS(122)); hwtimer_wait(RTIMER_TICKS(122));
cc110x_spi_unselect(); cc110x_spi_unselect();
radio_state = RADIO_IDLE; 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); hwtimer_wait(FS_CAL_TIME);
return; return;
} }
cc1100_spi_strobe(CC1100_SIDLE); cc1100_spi_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE; radio_state = RADIO_IDLE;
} }
static void wakeup_from_rx(void) static void wakeup_from_rx(void)
{ {
if (radio_state != RADIO_RX) return; if(radio_state != RADIO_RX) {
return;
}
cc1100_spi_strobe(CC1100_SIDLE); cc1100_spi_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE; radio_state = RADIO_IDLE;
} }
@ -278,7 +284,7 @@ static void switch_to_rx(void)
static void setup_rx_mode(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); cc1100_spi_write_reg(CC1100_MCSM2, 0x07);
switch_to_rx(); switch_to_rx();
} }
@ -288,15 +294,16 @@ static void setup_rx_mode(void)
*/ */
static void wakeup_from_wor(void) static void wakeup_from_wor(void)
{ {
if (radio_state != RADIO_WOR) { if(radio_state != RADIO_WOR) {
return; return;
} }
// Wake up the chip from WOR/sleep
/* Wake up the chip from WOR/sleep */
cc110x_spi_select(); cc110x_spi_select();
hwtimer_wait(RTIMER_TICKS(122)); hwtimer_wait(RTIMER_TICKS(122));
cc110x_spi_unselect(); cc110x_spi_unselect();
radio_state = RADIO_IDLE; 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); hwtimer_wait(FS_CAL_TIME);
} }
@ -305,27 +312,33 @@ static void wakeup_from_wor(void)
*/ */
void switch_to_wor2(void) void switch_to_wor2(void)
{ {
// if (cc110x_get_gdo2()) return; // If incoming packet, then don't go to WOR now // if (cc110x_get_gdo2()) return; /* If incoming packet, then don't go to WOR now */
cc1100_spi_strobe(CC1100_SIDLE); // Put CC1100 to IDLE cc1100_spi_strobe(CC1100_SIDLE); /* Put CC1100 to IDLE */
radio_state = RADIO_IDLE; // Radio state now IDLE radio_state = RADIO_IDLE; /* Radio state now IDLE */
cc1100_spi_write_reg(CC1100_MCSM2, cc1100_spi_write_reg(CC1100_MCSM2,
cc1100_wor_config.rx_time_reg); // Configure RX_TIME (for use in WOR) 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_spi_write_reg(CC1100_MCSM0, 0x18); /* Turn on FS-Autocal */
if (rflags.WOR_RST) {
cc1100_spi_strobe(CC1100_SWORRST); // Resets the real time clock if(rflags.WOR_RST) {
cc1100_spi_strobe(CC1100_SWORRST); /* Resets the real time clock */
rflags.WOR_RST = false; 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 */
} }
/** /**
* Note: This code is executed in the hwtimer ISR! * Note: This code is executed in the hwtimer ISR!
*/ */
static void hwtimer_switch_to_wor2_wrapper(void* ptr) static void hwtimer_switch_to_wor2_wrapper(void *ptr)
{ {
wor_hwtimer_id = -1; // kernel timer handler function called, clear timer id 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
if(rflags.TX) {
return; /* Stability: don't allow WOR timers at this point */
}
rflags.WOR_RST = true; rflags.WOR_RST = true;
switch_to_wor2(); switch_to_wor2();
} }
@ -335,47 +348,44 @@ static void hwtimer_switch_to_wor2_wrapper(void* ptr)
*/ */
static void switch_to_wor(void) static void switch_to_wor(void)
{ {
// Any incoming packet? /* Any incoming packet? */
if (cc110x_get_gdo2()) if(cc110x_get_gdo2()) {
{ /* Then don't go to WOR now */
// Then don't go to WOR now
return; return;
} }
// Step 1: Set chip for random interval (1..RX_INTERVAL) to power down mode /* Step 1: Set chip for random interval (1..RX_INTERVAL) to power down mode */
if (!rflags.MAN_WOR) if(!rflags.MAN_WOR) {
{
rflags.MAN_WOR = true; rflags.MAN_WOR = true;
radio_state = RADIO_WOR; radio_state = RADIO_WOR;
// Go to power down mode /* Go to power down mode */
cc1100_spi_strobe(CC1100_SIDLE); cc1100_spi_strobe(CC1100_SIDLE);
cc1100_spi_strobe(CC1100_SPWD); 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; 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); 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; rflags.KT_RES_ERR = true;
// No hwtimer available, go immediately to WOR mode. /* No hwtimer available, go immediately to WOR mode. */
// Else never receiving packets again... /* Else never receiving packets again... */
rflags.MAN_WOR = false; rflags.MAN_WOR = false;
switch_to_wor2(); switch_to_wor2();
} }
} }
// Step 2: Go to RX and then to WOR mode again /* Step 2: Go to RX and then to WOR mode again */
else else {
{
rflags.MAN_WOR = false; rflags.MAN_WOR = false;
wakeup_from_wor(); wakeup_from_wor();
cc1100_spi_strobe(CC1100_SRX); cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME); hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX; 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), 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 hwtimer_switch_to_wor2_wrapper, NULL); /* add 1,5 ms secure time */
if (wor_hwtimer_id == -1)
{ if(wor_hwtimer_id == -1) {
rflags.KT_RES_ERR = true; rflags.KT_RES_ERR = true;
} }
} }
@ -383,31 +393,31 @@ static void switch_to_wor(void)
static void setup_wor_mode(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(); cc1100_go_idle();
// Make sure CC1100 is in IDLE state /* Make sure CC1100 is in IDLE state */
cc1100_spi_strobe(CC1100_SIDLE); cc1100_spi_strobe(CC1100_SIDLE);
// Enable automatic initial calibration of RCosc. /* Enable automatic initial calibration of RCosc. */
// Set T_event1 ~ 1.4 ms, enough for XOSC stabilize and FS calibration before RX. /* 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). /* Enable RC oscillator before starting with WOR (or else it will not wake up). */
// Not using AUTO_SYNC function. /* Not using AUTO_SYNC function. */
cc1100_spi_write_reg(CC1100_WORCTRL, cc1100_wor_config.wor_ctrl); 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_WOREVT1, cc1100_wor_config.wor_evt_1);
cc1100_spi_write_reg(CC1100_WOREVT0, cc1100_wor_config.wor_evt_0); 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); 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); cc1100_spi_write_reg(CC1100_MCSM0, 0x18);
// Put the radio to SLEEP by starting 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_SWORRST); /* Resets the real time clock */
cc1100_spi_strobe(CC1100_SWOR); // Starts Wake-on-Radio cc1100_spi_strobe(CC1100_SWOR); /* Starts Wake-on-Radio */
radio_state = RADIO_WOR; 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) static bool cc1100_set_mode0(uint8_t mode, uint16_t opt_mode_data)
{ {
int result; int result;
switch (mode)
{ switch(mode) {
case CC1100_MODE_WOR: 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); 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; radio_mode = mode;
cc1100_go_idle = wakeup_from_wor; cc1100_go_idle = wakeup_from_wor;
cc1100_go_receive = switch_to_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; cc1100_retransmission_count_bc = TRANSMISSION_RETRIES_WOR_BC;
return true; return true;
} }
break; break;
case CC1100_MODE_CONSTANT_RX: case CC1100_MODE_CONSTANT_RX:
radio_mode = mode; radio_mode = mode;
cc1100_go_idle = wakeup_from_rx; cc1100_go_idle = wakeup_from_rx;
@ -456,70 +468,77 @@ static bool cc1100_set_mode0(uint8_t mode, uint16_t opt_mode_data)
cc1100_retransmission_count_bc = TRANSMISSION_RETRIES_CRX_BC; cc1100_retransmission_count_bc = TRANSMISSION_RETRIES_CRX_BC;
return true; return true;
} }
return false; return false;
} }
bool cc1100_set_mode(uint8_t mode, uint16_t opt_mode_data) 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(); cc1100_go_idle();
// Make sure CC1100 is in IDLE state /* Make sure CC1100 is in IDLE state */
cc1100_spi_strobe(CC1100_SIDLE); cc1100_spi_strobe(CC1100_SIDLE);
// Set the new mode /* Set the new mode */
bool result = cc1100_set_mode0(mode, opt_mode_data); bool result = cc1100_set_mode0(mode, opt_mode_data);
// If mode change was successful (mode is valid) /* If mode change was successful (mode is valid) */
if (result) if(result) {
{ /* Setup new mode configuration */
// Setup new mode configuration
cc1100_setup_mode(); cc1100_setup_mode();
// Reset statistics /* Reset statistics */
cc1100_reset_statistic(); cc1100_reset_statistic();
return true; return true;
} }
else else {
{ /* Still in old mode, go to receive mode again */
// Still in old mode, go to receive mode again
cc1100_go_receive(); cc1100_go_receive();
return false; return false;
} }
} }
char* cc1100_mode_to_text(uint8_t mode) char *cc1100_mode_to_text(uint8_t mode)
{ {
switch (mode) switch(mode) {
{
case CC1100_MODE_WOR: case CC1100_MODE_WOR:
return "Wake-On-Radio"; return "Wake-On-Radio";
case CC1100_MODE_CONSTANT_RX: case CC1100_MODE_CONSTANT_RX:
return "Constant RX"; return "Constant RX";
default: default:
return "unknown"; return "unknown";
} }
} }
char* cc1100_state_to_text(uint8_t state) char *cc1100_state_to_text(uint8_t state)
{ {
switch (state) switch(state) {
{
case RADIO_UNKNOWN: case RADIO_UNKNOWN:
return "Unknown"; return "Unknown";
case RADIO_AIR_FREE_WAITING: case RADIO_AIR_FREE_WAITING:
return "CS"; return "CS";
case RADIO_WOR: case RADIO_WOR:
return "WOR"; return "WOR";
case RADIO_IDLE: case RADIO_IDLE:
return "IDLE"; return "IDLE";
case RADIO_SEND_BURST: case RADIO_SEND_BURST:
return "TX BURST"; return "TX BURST";
case RADIO_RX: case RADIO_RX:
return "RX"; return "RX";
case RADIO_SEND_ACK: case RADIO_SEND_ACK:
return "TX ACK"; return "TX ACK";
case RADIO_PWD: case RADIO_PWD:
return "PWD"; return "PWD";
default: default:
return "unknown"; return "unknown";
} }
@ -527,32 +546,37 @@ char* cc1100_state_to_text(uint8_t state)
void cc1100_hwtimer_go_receive_wrapper(void *ptr) 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; 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 (radio_state == RADIO_PWD) { if(rflags.TX) {
// Go to RX state, listen for packets as long as WOR_TIMEOUT_2 return;
}
if(radio_state == RADIO_PWD) {
/* Go to RX state, listen for packets as long as WOR_TIMEOUT_2 */
cc1100_spi_strobe(CC1100_SRX); cc1100_spi_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME); hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX; 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); 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; rflags.KT_RES_ERR = true;
// No hwtimer available, go immediately to WOR mode. /* No hwtimer available, go immediately to WOR mode. */
// Else never receiving packets again... /* Else never receiving packets again... */
rflags.MAN_WOR = false; rflags.MAN_WOR = false;
switch_to_wor2(); switch_to_wor2();
} }
} else { }
else {
cc1100_go_receive(); cc1100_go_receive();
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
// CC1100 reset functionality /* CC1100 reset functionality */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void reset(void) static void reset(void)
@ -574,65 +598,74 @@ 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) void cc1100_send_raw(uint8_t *tx_buffer, uint8_t size)
{ {
volatile uint32_t abort_count; 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(); 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); 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); 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); cc1100_spi_writeburst_reg(CC1100_TXFIFO, (char *) tx_buffer, size);
// Switch to TX mode /* Switch to TX mode */
abort_count = 0; abort_count = 0;
unsigned int cpsr = disableIRQ(); unsigned int cpsr = disableIRQ();
cc1100_spi_strobe(CC1100_STX); cc1100_spi_strobe(CC1100_STX);
// Wait for GDO2 to be set -> sync word transmitted
while (cc110x_get_gdo2() == 0) { /* Wait for GDO2 to be set -> sync word transmitted */
while(cc110x_get_gdo2() == 0) {
abort_count++; abort_count++;
if (abort_count > CC1100_SYNC_WORD_TX_TIME) {
// Abort waiting. CC1100 maybe in wrong mode if(abort_count > CC1100_SYNC_WORD_TX_TIME) {
// 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"); puts("[CC1100 TX] fatal error\n");
break; break;
} }
} }
restoreIRQ(cpsr); restoreIRQ(cpsr);
// Wait for GDO2 to be cleared -> end of packet
while (cc110x_get_gdo2() != 0); /* Wait for GDO2 to be cleared -> end of packet */
// Experimental - TOF Measurement while(cc110x_get_gdo2() != 0);
/* Experimental - TOF Measurement */
cc110x_after_send(); 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 uint8_t
read_register(uint8_t r) read_register(uint8_t r)
{ {
uint8_t result; uint8_t result;
// Save old radio state /* Save old radio state */
uint8_t old_state = 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_go_idle();
result = cc1100_spi_read_reg(r); 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 */
if (old_state == RADIO_WOR || old_state == RADIO_RX) { /* was WOR/RX, otherwise no action is necessary */
if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive(); cc1100_go_receive();
} }
@ -642,21 +675,21 @@ read_register(uint8_t r)
static void static void
write_register(uint8_t r, uint8_t value) write_register(uint8_t r, uint8_t value)
{ {
// Save old radio state /* Save old radio state */
uint8_t old_state = 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_go_idle();
cc1100_spi_write_reg(r, value); cc1100_spi_write_reg(r, value);
// Have to put radio back to WOR/RX if old radio state /* Have to put radio back to WOR/RX if old radio state */
// was WOR/RX, otherwise no action is necessary /* was WOR/RX, otherwise no action is necessary */
if (old_state == RADIO_WOR || old_state == RADIO_RX) { if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive(); cc1100_go_receive();
} }
} }
char* cc1100_get_output_power(char* buf) char *cc1100_get_output_power(char *buf)
{ {
sprintf(buf, "%+i dBm", pa_table_dBm[pa_table_index]); sprintf(buf, "%+i dBm", pa_table_dBm[pa_table_index]);
return buf; return buf;
@ -670,8 +703,11 @@ uint8_t cc1100_get_channel(void)
bool bool
cc1100_set_channel(uint8_t channr) cc1100_set_channel(uint8_t channr)
{ {
if (channr > MAX_CHANNR) return false; if(channr > MAX_CHANNR) {
write_register(CC1100_CHANNR, channr*10); return false;
}
write_register(CC1100_CHANNR, channr * 10);
radio_channel = channr; radio_channel = channr;
return true; return true;
} }
@ -679,50 +715,86 @@ cc1100_set_channel(uint8_t channr)
bool bool
cc1100_set_output_power(uint8_t pa_idx) 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]); write_register(CC1100_PATABLE, pa_table[pa_idx]);
pa_table_index = pa_idx; pa_table_index = pa_idx;
return true; return true;
} }
char* cc1100_get_marc_state(void) char *cc1100_get_marc_state(void)
{ {
uint8_t state; uint8_t state;
// Save old radio state /* Save old radio state */
uint8_t old_state = 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; state = cc1100_spi_read_status(CC1100_MARCSTATE) & MARC_STATE;
// Make sure in IDLE state. /* Make sure in IDLE state. */
// Only goes to IDLE if state was RX/WOR /* Only goes to IDLE if state was RX/WOR */
cc1100_go_idle(); cc1100_go_idle();
// Have to put radio back to WOR/RX if old radio state /* Have to put radio back to WOR/RX if old radio state */
// was WOR/RX, otherwise no action is necessary /* was WOR/RX, otherwise no action is necessary */
if (old_state == RADIO_WOR || old_state == RADIO_RX) { if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc1100_go_receive(); cc1100_go_receive();
} }
switch (state) switch(state) {
{ /* Note: it is not possible to read back the SLEEP or XOFF state numbers */
// 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 */
// because setting CSn low will make the chip enter the IDLE mode from the /* SLEEP (0) or XOFF (2) states. */
// SLEEP (0) or XOFF (2) states. case 1:
case 1: return "IDLE"; return "IDLE";
case 3: case 4: case 5: return "MANCAL";
case 6: case 7: return "FS_WAKEUP"; case 3:
case 8: case 12: return "CALIBRATE"; case 4:
case 9: case 10: case 11: return "SETTLING"; case 5:
case 13: case 14: case 15: return "RX"; return "MANCAL";
case 16: return "TXRX_SETTLING";
case 17: return "RXFIFO_OVERFLOW"; case 6:
case 18: return "FSTXON"; case 7:
case 19: case 20: return "TX"; return "FS_WAKEUP";
case 21: return "RXTX_SETTLING";
case 22: return "TXFIFO_UNDERFLOW"; case 8:
default: return "UNKNOWN"; 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) void cc1100_init(void)
{ {
// Initialize SPI /* Initialize SPI */
cc110x_spi_init(); 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); cc1100_set_mode0(CC1100_RADIO_MODE, T_RX_INTERVAL);
// Load driver & reset /* Load driver & reset */
power_up_reset(); power_up_reset();
// Write configuration to configuration registers /* Write configuration to configuration registers */
extern char cc1100_conf[]; extern char cc1100_conf[];
cc1100_spi_writeburst_reg(0x00, cc1100_conf, CC1100_CONF_SIZE); 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]); cc1100_spi_write_reg(CC1100_PATABLE, pa_table[pa_table_index]);
// Initialize Radio Flags /* Initialize Radio Flags */
rflags.RSSI = 0x00; rflags.RSSI = 0x00;
rflags.LL_ACK = false; rflags.LL_ACK = false;
rflags.CAA = false; rflags.CAA = false;
@ -768,28 +840,29 @@ void cc1100_init(void)
rflags.TX = false; rflags.TX = false;
rflags.WOR_RST = false; rflags.WOR_RST = false;
// Initialize physical layer /* Initialize physical layer */
cc1100_phy_init(); cc1100_phy_init();
// Set radio address of CC1100 /* Set radio address of CC1100 */
cc1100_set_address(radio_address); cc1100_set_address(radio_address);
// Set default channel number /* Set default channel number */
radio_channel = CC1100_DEFAULT_CHANNR; 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); rd_set_mode(RADIO_MODE_ON);
} }
int cc1100_get_avg_transmission_duration(void) int cc1100_get_avg_transmission_duration(void)
{ {
if (radio_mode == CC1100_MODE_WOR) { if(radio_mode == CC1100_MODE_WOR) {
// Transmission duration ~ RX interval /* Transmission duration ~ RX interval */
// Double value because of MAC delay. /* Double value because of MAC delay. */
return 2 * cc1100_wor_config.rx_interval; return 2 * cc1100_wor_config.rx_interval;
} else { }
// Transmission duration ~ 32 ms else {
// Double value because of MAC delay. /* Transmission duration ~ 32 ms */
/* Double value because of MAC delay. */
return 2 * 32; return 2 * 32;
} }
} }
@ -801,14 +874,13 @@ radio_address_t cc1100_get_address(void)
bool cc1100_set_address(radio_address_t address) bool cc1100_set_address(radio_address_t address)
{ {
if (address < MIN_UID || address > MAX_UID) if(address < MIN_UID || address > MAX_UID) {
{
return false; return false;
} }
uint8_t id = (uint8_t) address; uint8_t id = (uint8_t) address;
if (radio_state != RADIO_UNKNOWN)
{ if(radio_state != RADIO_UNKNOWN) {
write_register(CC1100_ADDR, id); write_register(CC1100_ADDR, id);
} }
@ -821,67 +893,66 @@ rd_set_mode(int mode)
{ {
int result; int result;
// Get current radio mode /* Get current radio mode */
if (radio_state == RADIO_UNKNOWN || radio_state == RADIO_PWD) if(radio_state == RADIO_UNKNOWN || radio_state == RADIO_PWD) {
{
result = RADIO_MODE_OFF; result = RADIO_MODE_OFF;
} }
else else {
{
result = RADIO_MODE_ON; result = RADIO_MODE_ON;
} }
switch (mode) switch(mode) {
{
case RADIO_MODE_ON: case RADIO_MODE_ON:
cc110x_init_interrupts(); // Enable interrupts cc110x_init_interrupts(); /* Enable interrupts */
cc1100_setup_mode(); // Set chip to desired mode cc1100_setup_mode(); /* Set chip to desired mode */
break; break;
case RADIO_MODE_OFF: case RADIO_MODE_OFF:
cc1100_disable_interrupts(); // Disable interrupts cc1100_disable_interrupts(); /* Disable interrupts */
switch_to_pwd(); // Set chip to power down mode switch_to_pwd(); /* Set chip to power down mode */
break; break;
case RADIO_MODE_GET: case RADIO_MODE_GET:
// do nothing, just return current mode
/* do nothing, just return current mode */
default: default:
// do nothing /* do nothing */
break; break;
} }
// Return previous mode /* Return previous mode */
return result; return result;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
// Carrier sense interface functions /* Carrier sense interface functions */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void cc1100_cs_init(void) void cc1100_cs_init(void)
{ {
cc1100_go_idle(); // Wake CC1100 up from Wake-On-Radio mode cc1100_go_idle(); /* Wake CC1100 up from Wake-On-Radio mode */
if (radio_state == RADIO_RX) // If radio in RX mode
{ if(radio_state == RADIO_RX) { /* If radio in RX mode */
cc1100_spi_strobe(CC1100_SIDLE); // Go back to IDLE for calibration 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) cc1100_spi_write_reg(CC1100_MCSM0, 0x08); /* Turn off FS-Autocal */
hwtimer_wait(MANUAL_FS_CAL_TIME); // Wait for calibration to finish before packet burst can start cc1100_spi_strobe(CC1100_SCAL); /* Calibrate manually (721 us) */
radio_state = RADIO_AIR_FREE_WAITING; // Set status "waiting for air free" hwtimer_wait(MANUAL_FS_CAL_TIME); /* Wait for calibration to finish before packet burst can start */
cc1100_spi_write_reg(CC1100_MCSM2, 0x07); // Configure RX_TIME = Until end of packet (no timeout) radio_state = RADIO_AIR_FREE_WAITING; /* Set status "waiting for air free" */
cc1100_spi_strobe(CC1100_SRX); // Switch to RX (88.4 us) (Carrier Sense) cc1100_spi_write_reg(CC1100_MCSM2, 0x07); /* Configure RX_TIME = Until end of packet (no timeout) */
hwtimer_wait(CS_READY_TIME); // Wait until CC1100 is in RX + carrier sense ready (GDO0 ready for readout -> data rate dependent!!!) 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) void cc1100_cs_set_enabled(bool enabled)
{ {
if (enabled) if(enabled) {
{ /* Enable carrier sense detection (GDO0 interrupt) */
// Enable carrier sense detection (GDO0 interrupt)
cc110x_gdo0_enable(); cc110x_gdo0_enable();
} }
else else {
{ /* Disable carrier sense detection (GDO0 interrupt) */
// Disable carrier sense detection (GDO0 interrupt)
cc110x_gdo0_disable(); cc110x_gdo0_disable();
} }
} }

View File

@ -120,8 +120,7 @@ typedef struct cc1100_cfg_t {
/** /**
* @brief Radio Control Flags * @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 TOF; ///< Time of flight of the last packet and last ACK
uint32_t TCP; ///< Time to compute packet uint32_t TCP; ///< Time to compute packet
unsigned RPS : 16; ///< Raw packets sent to transmit last packet unsigned RPS : 16; ///< Raw packets sent to transmit last packet
@ -207,7 +206,7 @@ void cc1100_set_idle(void);
* *
* @return Textual representation of radio mode. * @return Textual representation of radio mode.
*/ */
char* cc1100_mode_to_text(uint8_t mode); char *cc1100_mode_to_text(uint8_t mode);
/** /**
* @brief Convert radio state to textual representation. * @brief Convert radio state to textual representation.
@ -216,21 +215,21 @@ char* cc1100_mode_to_text(uint8_t mode);
* *
* @return Textual representation of radio state. * @return Textual representation of radio state.
*/ */
char* cc1100_state_to_text(uint8_t state); char *cc1100_state_to_text(uint8_t state);
/** /**
* @brief Convert current output power to textual representation. * @brief Convert current output power to textual representation.
* *
* @return Textual representation of current output power in dBm. * @return Textual representation of current output power in dBm.
*/ */
char* cc1100_get_output_power(char* buf); char *cc1100_get_output_power(char *buf);
/** /**
* @brief Read out main radio control FSM state. * @brief Read out main radio control FSM state.
* *
* @return Textual representation of current main radio control FSM state. * @return Textual representation of current main radio control FSM state.
*/ */
char* cc1100_get_marc_state(void); char *cc1100_get_marc_state(void);
/** /**
* @brief hwtimer wrapper function. * @brief hwtimer wrapper function.

View File

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

View File

@ -75,8 +75,7 @@ Notes:
\li Identification is increased is used to scan duplicates. It must be increased \li Identification is increased is used to scan duplicates. It must be increased
for each new packet and kept for packet retransmissions. 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 length; ///< Length of the packet (without length byte)
uint8_t address; ///< Destination address uint8_t address; ///< Destination address
uint8_t phy_src; ///< Source address (physical source) 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) uint8_t data[MAX_DATA_LENGTH]; ///< Data (high layer protocol)
} cc1100_packet_layer0_t; } 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 uint16_t rx_interval; ///< RX polling interval in milliseconds
float rx_time_ms; ///< WOR_RX_TIME 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) 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(); unsigned int cpsr = disableIRQ();
cc110x_spi_select(); cc110x_spi_select();
cc110x_txrx(addr | CC1100_WRITE_BURST); cc110x_txrx(addr | CC1100_WRITE_BURST);
while (i < count) {
while(i < count) {
cc110x_txrx(src[i]); cc110x_txrx(src[i]);
i++; i++;
} }
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
return count; return count;
@ -79,10 +81,12 @@ cc1100_spi_readburst_reg(uint8_t addr, char *buffer, uint8_t count)
unsigned int cpsr = disableIRQ(); unsigned int cpsr = disableIRQ();
cc110x_spi_select(); cc110x_spi_select();
cc110x_txrx(addr | CC1100_READ_BURST); cc110x_txrx(addr | CC1100_READ_BURST);
while (i < count) {
while(i < count) {
buffer[i] = cc110x_txrx(NOBYTE); buffer[i] = cc110x_txrx(NOBYTE);
i++; i++;
} }
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
} }

View File

@ -1,28 +1,12 @@
/****************************************************************************** /**
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. * Default configuration for the cc110x chip
*
These sources were developed at the Freie Universitaet Berlin, Computer Systems * Copyright (C) 2013 INRIA
and Telematics group (http://cst.mi.fu-berlin.de). *
------------------------------------------------------------------------------- * This file subject to the terms and conditions of the GNU Lesser General
This file is part of RIOT. * Public License. See the file LICENSE in the top level directory for more
* details.
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
*******************************************************************************/
/** /**
* @ingroup dev_cc110x * @ingroup dev_cc110x
@ -34,9 +18,10 @@ and the mailinglist (subscription via web site)
* @brief TI Chipcon CC110x default settings * @brief TI Chipcon CC110x default settings
* *
* @author Freie Universität Berlin, Computer Systems & Telematics * @author Freie Universität Berlin, Computer Systems & Telematics
* @author INRIA
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de> * @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@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 $ * @note $Id: cc110x-defaultSettings.c 2058 2010-03-31 08:59:31Z hillebra $
*/ */
@ -88,7 +73,7 @@ char cc110x_conf[] = {
0x06, // PKTCTRL1 0x06, // PKTCTRL1
0x45, // PKTCTRL0 (variable packet length) 0x45, // PKTCTRL0 (variable packet length)
0xFF, // ADDR 0xFF, // ADDR
CC1100_DEFAULT_CHANNR*10, // CHANNR CC1100_DEFAULT_CHANNR * 10, // CHANNR
0x0B, // FSCTRL1 0x0B, // FSCTRL1
0x00, // FSCTRL0 0x00, // FSCTRL0
0x21, // FREQ2 0x21, // FREQ2

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_ng.h>
#include <cc110x-internal.h> #include <cc110x-internal.h>
#include <cc110x-config.h> #include <cc110x-config.h>
@ -27,47 +44,50 @@ static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length);
rx_buffer_t cc110x_rx_buffer[RX_BUF_SIZE]; ///< RX buffer rx_buffer_t cc110x_rx_buffer[RX_BUF_SIZE]; ///< RX buffer
volatile uint8_t rx_buffer_next; ///< Next packet in RX queue 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; uint8_t res = 0;
// Possible packet received, RX -> IDLE (0.1 us) /* Possible packet received, RX -> IDLE (0.1 us) */
rflags.CAA = 0; rflags.CAA = 0;
rflags.MAN_WOR = 0; rflags.MAN_WOR = 0;
cc110x_statistic.packets_in++; cc110x_statistic.packets_in++;
res = receive_packet((uint8_t*)&(cc110x_rx_buffer[rx_buffer_next].packet), sizeof(cc110x_packet_t)); 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. if(res) {
// Only ACKs are processed (for stopping the burst). /* If we are sending a burst, don't accept packets.
// Same if state machine is in TX lock. * Only ACKs are processed (for stopping the burst).
if (radio_state == RADIO_SEND_BURST || rflags.TX) * Same if state machine is in TX lock. */
{ if(radio_state == RADIO_SEND_BURST || rflags.TX) {
cc110x_statistic.packets_in_while_tx++; cc110x_statistic.packets_in_while_tx++;
return; return;
} }
cc110x_rx_buffer[rx_buffer_next].rssi = rflags._RSSI; cc110x_rx_buffer[rx_buffer_next].rssi = rflags._RSSI;
cc110x_rx_buffer[rx_buffer_next].lqi = rflags._LQI; 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. /* Valid packet. After a wake-up, the radio should be in IDLE.
// So put CC1100 to RX for WOR_TIMEOUT (have to manually put * So put CC1100 to RX for WOR_TIMEOUT (have to manually put
// the radio back to sleep/WOR). * the radio back to sleep/WOR). */
//cc110x_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal //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_write_reg(CC1100_MCSM2, 0x07); /* Configure RX_TIME (until end of packet) */
cc110x_strobe(CC1100_SRX); cc110x_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME); hwtimer_wait(IDLE_TO_RX_TIME);
radio_state = RADIO_RX; radio_state = RADIO_RX;
#ifdef DBG_IGNORE #ifdef DBG_IGNORE
if (is_ignored(cc110x_rx_buffer[rx_buffer_next].packet.phy_src)) {
if(is_ignored(cc110x_rx_buffer[rx_buffer_next].packet.phy_src)) {
LED_RED_TOGGLE; LED_RED_TOGGLE;
return; return;
} }
#endif #endif
/* notify transceiver thread if any */ /* notify transceiver thread if any */
if (transceiver_pid) { if(transceiver_pid) {
msg_t m; msg_t m;
m.type = (uint16_t) RCV_PKT_CC1100; m.type = (uint16_t) RCV_PKT_CC1100;
m.content.value = rx_buffer_next; m.content.value = rx_buffer_next;
@ -75,126 +95,135 @@ void cc110x_rx_handler(void) {
} }
/* shift to next buffer element */ /* shift to next buffer element */
if (++rx_buffer_next == RX_BUF_SIZE) { if(++rx_buffer_next == RX_BUF_SIZE) {
rx_buffer_next = 0; rx_buffer_next = 0;
} }
return; return;
} }
else else {
{ /* No ACK received so TOF is unpredictable */
// No ACK received so TOF is unpredictable
rflags.TOF = 0; rflags.TOF = 0;
// CRC false or RX buffer full -> clear RX FIFO in both cases /* 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_SIDLE); /* Switch to IDLE (should already be)... */
cc110x_strobe(CC1100_SFRX); // ...for flushing the RX FIFO cc110x_strobe(CC1100_SFRX); /* ...for flushing the RX FIFO */
// If packet interrupted this nodes send call, /* If packet interrupted this nodes send call,
// don't change anything after this point. * don't change anything after this point. */
if (radio_state == RADIO_AIR_FREE_WAITING) if(radio_state == RADIO_AIR_FREE_WAITING) {
{
cc110x_strobe(CC1100_SRX); cc110x_strobe(CC1100_SRX);
hwtimer_wait(IDLE_TO_RX_TIME); hwtimer_wait(IDLE_TO_RX_TIME);
return; 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++; cc110x_statistic.packets_in_while_tx++;
return; 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(); 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 status[2];
uint8_t packetLength = 0; uint8_t packetLength = 0;
/* Any bytes available in RX FIFO? */ /* Any bytes available in RX FIFO? */
if ((cc110x_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) { 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); cc110x_read_fifo((char *) &packetLength, 1);
// Read data from RX FIFO and store in rxBuffer
if (packetLength <= length) /* Read data from RX FIFO and store in rxBuffer */
{ if(packetLength <= length) {
// Put length byte at first position in RX Buffer /* Put length byte at first position in RX Buffer */
rxBuffer[0] = packetLength; 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_readburst_reg(CC1100_RXFIFO, (char*)rxBuffer+1, packetLength);
cc110x_read_fifo((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); cc110x_readburst_reg(CC1100_RXFIFO, (char *)status, 2);
// Store RSSI value of packet /* Store RSSI value of packet */
rflags._RSSI = status[I_RSSI]; 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; rflags.CRC_STATE = (status[I_LQI] & CRC_OK) >> 7;
if (!rflags.CRC_STATE) {
if(!rflags.CRC_STATE) {
cc110x_statistic.packets_in_crc_fail++; 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; rflags._LQI = status[I_LQI] & LQI_EST;
return rflags.CRC_STATE; return rflags.CRC_STATE;
} }
/* too many bytes in FIFO */ /* too many bytes in FIFO */
else { else {
// RX FIFO get automatically flushed if return value is false /* RX FIFO get automatically flushed if return value is false */
return 0; return 0;
} }
} }
/* no bytes in RX FIFO */ /* no bytes in RX FIFO */
else { else {
// RX FIFO get automatically flushed if return value is false /* RX FIFO get automatically flushed if return value is false */
return 0; return 0;
} }
} }
static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length) { static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length)
{
uint8_t pkt_len_cfg = cc110x_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG; uint8_t pkt_len_cfg = cc110x_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG;
if (pkt_len_cfg == VARIABLE_PKTLEN)
{ if(pkt_len_cfg == VARIABLE_PKTLEN) {
return receive_packet_variable(rxBuffer, length); 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; return 0;
} }
#ifdef DBG_IGNORE #ifdef DBG_IGNORE
void cc110x_init_ignore(void) { void cc110x_init_ignore(void)
memset(ignored_addr, 0, IGN_MAX*sizeof(radio_address_t)); {
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; uint8_t i = 0;
while ((i < IGN_MAX) && ignored_addr[i++]) { while((i < IGN_MAX) && ignored_addr[i++]) {
printf("i: %hu\n", i); printf("i: %hu\n", i);
} }
if (i > IGN_MAX) {
if(i > IGN_MAX) {
return 0; return 0;
} }
ignored_addr[i-1] = addr;
ignored_addr[i - 1] = addr;
return 1; return 1;
} }
static uint8_t is_ignored(radio_address_t addr) { static uint8_t is_ignored(radio_address_t addr)
{
uint8_t i; uint8_t i;
for (i = 0; i < IGN_MAX; i++) { for(i = 0; i < IGN_MAX; i++) {
if (ignored_addr[i] == addr) { if(ignored_addr[i] == addr) {
return 1; return 1;
} }
} }
return 0; return 0;
} }
#endif #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 <stdio.h>
#include <cc110x_ng.h> #include <cc110x_ng.h>
@ -11,7 +28,8 @@
#include <board.h> #include <board.h>
uint8_t cc110x_send(cc110x_packet_t *packet) { uint8_t cc110x_send(cc110x_packet_t *packet)
{
volatile uint32_t abort_count; volatile uint32_t abort_count;
uint8_t size; uint8_t size;
/* TODO: burst sending */ /* TODO: burst sending */
@ -25,52 +43,56 @@ uint8_t cc110x_send(cc110x_packet_t *packet) {
*/ */
size = packet->length + 1; size = packet->length + 1;
// The number of bytes to be transmitted must be smaller /* The number of bytes to be transmitted must be smaller
// or equal to PACKET_LENGTH (62 bytes). So the receiver * or equal to PACKET_LENGTH (62 bytes). So the receiver
// can put the whole packet in its RX-FIFO (with appended * can put the whole packet in its RX-FIFO (with appended
// packet status bytes). * packet status bytes).*/
if (size > PACKET_LENGTH) { if(size > PACKET_LENGTH) {
return 0; return 0;
} }
packet->phy_src = cc110x_get_address(); packet->phy_src = cc110x_get_address();
// Disables RX interrupt etc. /* Disables RX interrupt etc. */
cc110x_before_send(); 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); 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); cc110x_strobe(CC1100_SFTX);
// Write packet into TX FIFO /* Write packet into TX FIFO */
cc110x_writeburst_reg(CC1100_TXFIFO, (char*) packet, size); cc110x_writeburst_reg(CC1100_TXFIFO, (char *) packet, size);
// Switch to TX mode /* Switch to TX mode */
abort_count = 0; abort_count = 0;
unsigned int cpsr = disableIRQ(); unsigned int cpsr = disableIRQ();
cc110x_strobe(CC1100_STX); cc110x_strobe(CC1100_STX);
// Wait for GDO2 to be set -> sync word transmitted
while (cc110x_get_gdo2() == 0) { /* Wait for GDO2 to be set -> sync word transmitted */
while(cc110x_get_gdo2() == 0) {
abort_count++; abort_count++;
if (abort_count > CC1100_SYNC_WORD_TX_TIME) {
// Abort waiting. CC1100 maybe in wrong mode if(abort_count > CC1100_SYNC_WORD_TX_TIME) {
// 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"); puts("[CC1100 TX] fatal error\n");
break; 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_after_send();
cc110x_statistic.raw_packets_out++; cc110x_statistic.raw_packets_out++;
// Store number of transmission retries /* Store number of transmission retries */
rflags.TX = 0; 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(); cc110x_switch_to_rx();
return true; 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_ng.h>
#include <cc110x-arch.h> #include <cc110x-arch.h>
#include <cc110x-config.h> #include <cc110x-config.h>
@ -34,10 +50,11 @@ static void reset(void);
static void power_up_reset(void); static void power_up_reset(void);
static void write_register(uint8_t r, uint8_t value); static void write_register(uint8_t r, uint8_t value);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*
// Radio Driver API * Radio Driver API *
/*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
void cc110x_init(int tpid) { void cc110x_init(int tpid)
{
transceiver_pid = tpid; transceiver_pid = tpid;
DEBUG("Transceiver PID: %i\n", transceiver_pid); DEBUG("Transceiver PID: %i\n", transceiver_pid);
@ -76,7 +93,7 @@ void cc110x_init(int tpid) {
#endif #endif
DEBUG("CC1100 initialized and set to channel %i\n", radio_channel); 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); rd_set_mode(RADIO_MODE_ON);
#ifdef DBG_IGNORE #ifdef DBG_IGNORE
@ -84,37 +101,44 @@ void cc110x_init(int tpid) {
#endif #endif
} }
void cc110x_disable_interrupts(void) { void cc110x_disable_interrupts(void)
{
cc110x_gdo2_disable(); cc110x_gdo2_disable();
cc110x_gdo0_disable(); cc110x_gdo0_disable();
} }
void cc110x_gdo0_irq(void) { void cc110x_gdo0_irq(void)
// Air was not free -> Clear CCA flag {
/* Air was not free -> Clear CCA flag */
rflags.CAA = false; rflags.CAA = false;
// Disable carrier sense detection (GDO0 interrupt) /* Disable carrier sense detection (GDO0 interrupt) */
cc110x_gdo0_disable(); cc110x_gdo0_disable();
} }
void cc110x_gdo2_irq(void) { void cc110x_gdo2_irq(void)
{
cc110x_rx_handler(); cc110x_rx_handler();
} }
uint8_t cc110x_get_buffer_pos(void) { uint8_t cc110x_get_buffer_pos(void)
return (rx_buffer_next-1); {
return (rx_buffer_next - 1);
} }
radio_address_t cc110x_get_address() { radio_address_t cc110x_get_address()
{
return radio_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)) { {
if((address < MIN_UID) || (address > MAX_UID)) {
return 0; return 0;
} }
uint8_t id = (uint8_t) address; uint8_t id = (uint8_t) address;
if (radio_state != RADIO_UNKNOWN) {
if(radio_state != RADIO_UNKNOWN) {
write_register(CC1100_ADDR, id); write_register(CC1100_ADDR, id);
} }
@ -123,18 +147,22 @@ radio_address_t cc110x_set_address(radio_address_t address) {
} }
#ifdef MODULE_CONFIG #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); radio_address_t a = cc110x_set_address(address);
if (a) {
if(a) {
sysconfig.radio_address = a; sysconfig.radio_address = a;
} }
config_save(); config_save();
return a; return a;
} }
#endif #endif
void cc110x_set_monitor(uint8_t mode) { void cc110x_set_monitor(uint8_t mode)
if (mode) { {
if(mode) {
write_register(CC1100_PKTCTRL1, (0x04)); write_register(CC1100_PKTCTRL1, (0x04));
} }
else { else {
@ -142,97 +170,145 @@ void cc110x_set_monitor(uint8_t mode) {
} }
} }
void cc110x_setup_rx_mode(void) { void cc110x_setup_rx_mode(void)
// Stay in RX mode until end of packet {
/* Stay in RX mode until end of packet */
cc110x_write_reg(CC1100_MCSM2, 0x07); cc110x_write_reg(CC1100_MCSM2, 0x07);
cc110x_switch_to_rx(); cc110x_switch_to_rx();
} }
void cc110x_switch_to_rx(void) { void cc110x_switch_to_rx(void)
{
radio_state = RADIO_RX; radio_state = RADIO_RX;
cc110x_strobe(CC1100_SRX); cc110x_strobe(CC1100_SRX);
} }
void cc110x_wakeup_from_rx(void) { void cc110x_wakeup_from_rx(void)
if (radio_state != RADIO_RX) { {
if(radio_state != RADIO_RX) {
return; return;
} }
DEBUG("CC1100 going to idle\n"); DEBUG("CC1100 going to idle\n");
cc110x_strobe(CC1100_SIDLE); cc110x_strobe(CC1100_SIDLE);
radio_state = RADIO_IDLE; radio_state = RADIO_IDLE;
} }
char* cc110x_get_marc_state(void) { char *cc110x_get_marc_state(void)
{
uint8_t state; uint8_t state;
// Save old radio state /* Save old radio state */
uint8_t old_state = 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; state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
// Make sure in IDLE state. /* Make sure in IDLE state.
// Only goes to IDLE if state was RX/WOR * Only goes to IDLE if state was RX/WOR */
cc110x_wakeup_from_rx(); cc110x_wakeup_from_rx();
// Have to put radio back to WOR/RX if old radio state /* Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary * was WOR/RX, otherwise no action is necessary */
if (old_state == RADIO_WOR || old_state == RADIO_RX) { if(old_state == RADIO_WOR || old_state == RADIO_RX) {
cc110x_switch_to_rx(); cc110x_switch_to_rx();
} }
switch (state) switch(state) {
{ /* Note: it is not possible to read back the SLEEP or XOFF state numbers
// 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
// because setting CSn low will make the chip enter the IDLE mode from the * SLEEP (0) or XOFF (2) states. */
// SLEEP (0) or XOFF (2) states. case 1:
case 1: return "IDLE"; return "IDLE";
case 3: case 4: case 5: return "MANCAL";
case 6: case 7: return "FS_WAKEUP"; case 3:
case 8: case 12: return "CALIBRATE"; case 4:
case 9: case 10: case 11: return "SETTLING"; case 5:
case 13: case 14: case 15: return "RX"; return "MANCAL";
case 16: return "TXRX_SETTLING";
case 17: return "RXFIFO_OVERFLOW"; case 6:
case 18: return "FSTXON"; case 7:
case 19: case 20: return "TX"; return "FS_WAKEUP";
case 21: return "RXTX_SETTLING";
case 22: return "TXFIFO_UNDERFLOW"; case 8:
default: return "UNKNOWN"; 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) { char *cc110x_state_to_text(uint8_t state)
switch (state) {
{ switch(state) {
case RADIO_UNKNOWN: case RADIO_UNKNOWN:
return "Unknown"; return "Unknown";
case RADIO_AIR_FREE_WAITING: case RADIO_AIR_FREE_WAITING:
return "CS"; return "CS";
case RADIO_WOR: case RADIO_WOR:
return "WOR"; return "WOR";
case RADIO_IDLE: case RADIO_IDLE:
return "IDLE"; return "IDLE";
case RADIO_SEND_BURST: case RADIO_SEND_BURST:
return "TX BURST"; return "TX BURST";
case RADIO_RX: case RADIO_RX:
return "RX"; return "RX";
case RADIO_SEND_ACK: case RADIO_SEND_ACK:
return "TX ACK"; return "TX ACK";
case RADIO_PWD: case RADIO_PWD:
return "PWD"; return "PWD";
default: default:
return "unknown"; 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 radio state: %s\r\n", cc110x_state_to_text(radio_state));
printf("Current MARC state: %s\r\n", cc110x_get_marc_state()); printf("Current MARC state: %s\r\n", cc110x_get_marc_state());
printf("Current channel number: %u\r\n", radio_channel); 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"); DEBUG("[cc110x_ng] switching to powerdown\n");
cc110x_wakeup_from_rx(); cc110x_wakeup_from_rx();
cc110x_strobe(CC1100_SPWD); 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; uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
if ((state != 1) && (channr > MAX_CHANNR)) {
if((state != 1) && (channr > MAX_CHANNR)) {
return -1; return -1;
} }
write_register(CC1100_CHANNR, channr*10);
write_register(CC1100_CHANNR, channr * 10);
radio_channel = channr; radio_channel = channr;
return radio_channel; return radio_channel;
} }
#ifdef MODULE_CONFIG #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); int16_t c = cc110x_set_channel(channr);
if (c) {
if(c) {
sysconfig.radio_channel = c; sysconfig.radio_channel = c;
} }
config_save(); config_save();
return c; return c;
} }
#endif #endif
int16_t cc110x_get_channel(void) { int16_t cc110x_get_channel(void)
{
return radio_channel; return radio_channel;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------
// CC1100 reset functionality * CC1100 reset functionality
/*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
static void reset(void) { static void reset(void)
{
cc110x_wakeup_from_rx(); cc110x_wakeup_from_rx();
#ifdef MODULE_CC110x_SPI #ifdef MODULE_CC110x_SPI
cc110x_spi_select(); cc110x_spi_select();
@ -279,7 +363,8 @@ static void reset(void) {
hwtimer_wait(RTIMER_TICKS(100)); hwtimer_wait(RTIMER_TICKS(100));
} }
static void power_up_reset(void) { static void power_up_reset(void)
{
#ifdef MODULE_CC110x_SPI #ifdef MODULE_CC110x_SPI
cc110x_spi_unselect(); cc110x_spi_unselect();
cc110x_spi_cs(); cc110x_spi_cs();
@ -290,51 +375,54 @@ static void power_up_reset(void) {
radio_state = RADIO_IDLE; radio_state = RADIO_IDLE;
} }
static void write_register(uint8_t r, uint8_t value) { static void write_register(uint8_t r, uint8_t value)
// Save old radio state {
/* Save old radio state */
uint8_t old_state = 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) */
cc110x_wakeup_from_rx(); cc110x_wakeup_from_rx();
cc110x_write_reg(r, value); cc110x_write_reg(r, value);
// Have to put radio back to WOR/RX if old radio state /* Have to put radio back to WOR/RX if old radio state
// was WOR/RX, otherwise no action is necessary * was WOR/RX, otherwise no action is necessary */
if ((old_state == RADIO_WOR) || (old_state == RADIO_RX)) { if((old_state == RADIO_WOR) || (old_state == RADIO_RX)) {
cc110x_switch_to_rx(); cc110x_switch_to_rx();
} }
} }
static int rd_set_mode(int mode) { static int rd_set_mode(int mode)
{
int result; int result;
// Get current radio mode /* Get current radio mode */
if ((radio_state == RADIO_UNKNOWN) || (radio_state == RADIO_PWD)) { if((radio_state == RADIO_UNKNOWN) || (radio_state == RADIO_PWD)) {
result = RADIO_MODE_OFF; result = RADIO_MODE_OFF;
} }
else { else {
result = RADIO_MODE_ON; result = RADIO_MODE_ON;
} }
switch (mode) { switch(mode) {
case RADIO_MODE_ON: case RADIO_MODE_ON:
DEBUG("Enabling rx mode\n"); DEBUG("Enabling rx mode\n");
cc110x_init_interrupts(); // Enable interrupts cc110x_init_interrupts(); /* Enable interrupts */
cc110x_setup_rx_mode(); // Set chip to desired mode cc110x_setup_rx_mode(); /* Set chip to desired mode */
break; break;
case RADIO_MODE_OFF: case RADIO_MODE_OFF:
cc110x_disable_interrupts(); // Disable interrupts cc110x_disable_interrupts(); /* Disable interrupts */
cc110x_switch_to_pwd(); // Set chip to power down mode cc110x_switch_to_pwd(); /* Set chip to power down mode */
break; break;
case RADIO_MODE_GET: case RADIO_MODE_GET:
// do nothing, just return current mode
/* do nothing, just return current mode */
default: default:
// do nothing /* do nothing */
break; break;
} }
// Return previous mode /* Return previous mode */
return result; 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 #ifndef CC1100_CONFIG_H
#define CC1100_CONFIG_H #define CC1100_CONFIG_H
@ -56,8 +72,7 @@ typedef struct {
/** /**
* @brief Radio Control Flags * @brief Radio Control Flags
*/ */
typedef struct typedef struct {
{
uint32_t TOF; ///< Time of flight of the last packet and last ACK uint32_t TOF; ///< Time of flight of the last packet and last ACK
timex_t TOA; ///< Time of packet arriveal timex_t TOA; ///< Time of packet arriveal
uint32_t TCP; ///< Time to compute packet uint32_t TCP; ///< Time to compute packet

View File

@ -1,28 +1,19 @@
/****************************************************************************** /**
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. * Driver internal constants for 110x chip configuration
*
These sources were developed at the Freie Universitaet Berlin, Computer Systems * Copyright (C) 2008 Freie Universität Berlin
and Telematics group (http://cst.mi.fu-berlin.de). * Copyright (C) 2013 INRIA
------------------------------------------------------------------------------- *
This file is part of RIOT. * 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
This program is free software: you can redistribute it and/or modify it under * details.
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 * @ingroup dev_cc110x_ng
version. * @{
* @file
RIOT is distributed in the hope that it will be useful, but WITHOUT * @author Oliver Hahm <oliver.hahm@inria.fr>
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
*******************************************************************************/
#ifndef CC1100_INTERNAL_H #ifndef CC1100_INTERNAL_H
#define CC1100_INTERNAL_H #define CC1100_INTERNAL_H

View File

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

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 #ifndef CC1100_H
#define CC1100_H #define CC1100_H
@ -65,13 +81,15 @@ Notes:
\li Identification is increased is used to scan duplicates. It must be increased \li Identification is increased is used to scan duplicates. It must be increased
for each new packet and kept for packet retransmissions. 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 length; ///< Length of the packet (without length byte)
uint8_t address; ///< Destination address uint8_t address; ///< Destination address
uint8_t phy_src; ///< Source address (physical source) uint8_t phy_src; ///< Source address (physical source)
uint8_t flags; ///< Flags uint8_t flags; ///< Flags
uint8_t data[CC1100_MAX_DATA_LENGTH]; ///< Data (high layer protocol) uint8_t data[CC1100_MAX_DATA_LENGTH]; ///< Data (high layer protocol)
} cc110x_packet_t; }
cc110x_packet_t;
typedef struct { typedef struct {
uint8_t rssi; uint8_t rssi;

View File

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

View File

@ -20,8 +20,8 @@
#endif #endif
/* These functions are defined in asmfunc.S */ /* These functions are defined in asmfunc.S */
void Copy_al2un (unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */ void Copy_al2un(unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */
void Copy_un2al (unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */ void Copy_un2al(unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */
/* Status of Disk Functions */ /* Status of Disk Functions */
@ -40,11 +40,11 @@ typedef enum {
/*---------------------------------------*/ /*---------------------------------------*/
/* Prototypes for disk control functions */ /* Prototypes for disk control functions */
DSTATUS disk_initialize (unsigned char); DSTATUS disk_initialize(unsigned char);
DSTATUS disk_status (unsigned char); DSTATUS disk_status(unsigned char);
DRESULT disk_read (unsigned char, unsigned char*, unsigned long, unsigned char); DRESULT disk_read(unsigned char, unsigned char *, unsigned long, unsigned char);
DRESULT disk_write (unsigned char, const unsigned char*, unsigned long, unsigned char); DRESULT disk_write(unsigned char, const unsigned char *, unsigned long, unsigned char);
DRESULT disk_ioctl (unsigned char, unsigned char, void*); DRESULT disk_ioctl(unsigned char, unsigned char, void *);
@ -90,18 +90,18 @@ DRESULT disk_ioctl (unsigned char, unsigned char, void*);
/* Prototypes for each physical disk functions */ /* Prototypes for each physical disk functions */
DSTATUS NAND_initialize (void); DSTATUS NAND_initialize(void);
DSTATUS NAND_status (void); DSTATUS NAND_status(void);
DRESULT NAND_read (unsigned char*, unsigned long, unsigned char); DRESULT NAND_read(unsigned char *, unsigned long, unsigned char);
DRESULT NAND_write (const unsigned char*, unsigned long, unsigned char); DRESULT NAND_write(const unsigned char *, unsigned long, unsigned char);
DRESULT NAND_ioctl (unsigned char, void*); DRESULT NAND_ioctl(unsigned char, void *);
DSTATUS MCI_initialize (void); DSTATUS MCI_initialize(void);
DSTATUS MCI_status (void); DSTATUS MCI_status(void);
DRESULT MCI_read (unsigned char*, unsigned long, unsigned char); DRESULT MCI_read(unsigned char *, unsigned long, unsigned char);
DRESULT MCI_write (const unsigned char*, unsigned long, unsigned char); DRESULT MCI_write(const unsigned char *, unsigned long, unsigned char);
DRESULT MCI_ioctl (unsigned char, void*); DRESULT MCI_ioctl(unsigned char, void *);
void MCI_timerproc (void); void MCI_timerproc(void);
#endif #endif

View File

@ -56,13 +56,13 @@ void rtc_disable(void);
* @brief Sets the current time in broken down format directly from to RTC * @brief Sets the current time in broken down format directly from to RTC
* @param[in] localt Pointer to structure with time to set * @param[in] localt Pointer to structure with time to set
*/ */
void rtc_set_localtime(struct tm* localt); void rtc_set_localtime(struct tm *localt);
/** /**
* @brief Returns the current time in broken down format directly from the RTC * @brief Returns the current time in broken down format directly from the RTC
* @param[out] localt Pointer to structure to receive time * @param[out] localt Pointer to structure to receive time
*/ */
void rtc_get_localtime(struct tm* localt); void rtc_get_localtime(struct tm *localt);
extern int rtc_second_pid; extern int rtc_second_pid;

View File

@ -44,7 +44,7 @@ and the mailinglist (subscription via web site)
#define SHT11_NO_ACK (0) #define SHT11_NO_ACK (0)
#define SHT11_ACK (1) #define SHT11_ACK (1)
//adr command r/w //adr command r/w
#define SHT11_STATUS_REG_W (0x06) //000 0011 0 #define SHT11_STATUS_REG_W (0x06) //000 0011 0
#define SHT11_STATUS_REG_R (0x07) //000 0011 1 #define SHT11_STATUS_REG_R (0x07) //000 0011 1
#define SHT11_MEASURE_TEMP (0x03) //000 0001 1 #define SHT11_MEASURE_TEMP (0x03) //000 0001 1

View File

@ -46,51 +46,63 @@ static unsigned int last_int_time;
static unsigned int last_int_duration; static unsigned int last_int_duration;
static unsigned int start_time; 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); 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; return (coulomb * 1000) / 3600;
} }
static double mAh_to_Joule(double mAh) { static double mAh_to_Joule(double mAh)
{
return (SUPPLY_VOLTAGE * mAh * 3600); 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); 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)); {
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)); 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()); 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); {
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); 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; return int_count;
} }
void ltc4150_init(void) { void ltc4150_init(void)
{
ltc4150_arch_init(); ltc4150_arch_init();
} }
void ltc4150_start(void) { void ltc4150_start(void)
{
ltc4150_disable_int(); ltc4150_disable_int();
int_count = 0; int_count = 0;
uint32_t now = hwtimer_now(); uint32_t now = hwtimer_now();
@ -100,17 +112,20 @@ void ltc4150_start(void) {
ltc4150_enable_int(); ltc4150_enable_int();
} }
void ltc4150_stop(void) { void ltc4150_stop(void)
{
ltc4150_disable_int(); ltc4150_disable_int();
} }
void __attribute__((__no_instrument_function__)) ltc4150_interrupt(void) void __attribute__((__no_instrument_function__)) ltc4150_interrupt(void)
{ {
uint32_t now = hwtimer_now(); uint32_t now = hwtimer_now();
if (now >= last_int_time) {
if(now >= last_int_time) {
last_int_duration = now - last_int_time; last_int_duration = now - last_int_time;
} else { }
last_int_duration = (0-1) - last_int_time + now + 1; else {
last_int_duration = (0 - 1) - last_int_time + now + 1;
} }
last_int_time = now; last_int_time = now;

View File

@ -99,7 +99,8 @@ static inline void clk_signal(void);
mutex_t sht11_mutex; mutex_t sht11_mutex;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static inline void clk_signal(void) { static inline void clk_signal(void)
{
SHT11_SCK_HIGH; SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
SHT11_SCK_LOW; SHT11_SCK_LOW;
@ -113,12 +114,14 @@ static uint8_t write_byte(uint8_t value)
uint8_t ack; uint8_t ack;
SHT11_DATA_OUT; SHT11_DATA_OUT;
/* send value bit by bit to sht11 */ /* send value bit by bit to sht11 */
for (i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
if (value & BIT7) { if(value & BIT7) {
SHT11_DATA_HIGH; SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} else { }
else {
SHT11_DATA_LOW; SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} }
@ -140,36 +143,41 @@ static uint8_t write_byte(uint8_t value)
return ack; return ack;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint8_t read_byte (uint8_t ack) static uint8_t read_byte(uint8_t ack)
{ {
uint8_t i; uint8_t i;
uint8_t value = 0; uint8_t value = 0;
SHT11_DATA_IN; SHT11_DATA_IN;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
/* read value bit by bit */ /* read value bit by bit */
for (i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
value = value << 1; value = value << 1;
SHT11_SCK_HIGH; SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
if (SHT11_DATA) { if(SHT11_DATA) {
/* increase data by one when DATA is high */ /* increase data by one when DATA is high */
value++; value++;
} }
SHT11_SCK_LOW; SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
} }
/* send ack if necessary */ /* send ack if necessary */
SHT11_DATA_OUT; SHT11_DATA_OUT;
if (ack) {
if(ack) {
SHT11_DATA_LOW; SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} else { }
else {
SHT11_DATA_HIGH; SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} }
clk_signal(); clk_signal();
/* release data line */ /* release data line */
@ -224,9 +232,11 @@ static void connection_reset(void)
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
SHT11_SCK_LOW; SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
for (i = 0; i < 9; i++) {
for(i = 0; i < 9; i++) {
clk_signal(); clk_signal();
} }
transmission_start(); transmission_start();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -242,14 +252,16 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
hwtimer_wait(HWTIMER_TICKS(1000)); hwtimer_wait(HWTIMER_TICKS(1000));
/* wait untile sensor has finished measurement or timeout */ /* wait untile sensor has finished measurement or timeout */
for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) { for(i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) {
ack = SHT11_DATA; ack = SHT11_DATA;
if (!ack) { if(!ack) {
break; break;
} }
hwtimer_wait(HWTIMER_TICKS(1000)); hwtimer_wait(HWTIMER_TICKS(1000));
} }
error += ack; error += ack;
/* read MSB */ /* read MSB */
@ -262,14 +274,16 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
return (!error); return (!error);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void sht11_init(void) { void sht11_init(void)
{
sht11_temperature_offset = 0; sht11_temperature_offset = 0;
mutex_init(&sht11_mutex); mutex_init(&sht11_mutex);
SHT11_INIT; SHT11_INIT;
hwtimer_wait(11 * HWTIMER_TICKS(1000)); 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; uint8_t error = 0;
transmission_start(); transmission_start();
@ -279,7 +293,8 @@ uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum) {
return (!error); return (!error);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
uint8_t sht11_write_status(uint8_t *p_value) { uint8_t sht11_write_status(uint8_t *p_value)
{
uint8_t error = 0; uint8_t error = 0;
transmission_start(); transmission_start();
@ -288,7 +303,8 @@ uint8_t sht11_write_status(uint8_t *p_value) {
return (!error); 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 error = 0;
uint8_t checksum; uint8_t checksum;
uint16_t humi_int, temp_int; uint16_t humi_int, temp_int;
@ -310,7 +326,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
const float T2 = +0.00008; const float T2 = +0.00008;
/* check for valid buffer */ /* check for valid buffer */
if (value == NULL) { if(value == NULL) {
return 0; return 0;
} }
@ -322,32 +338,35 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) {
connection_reset(); connection_reset();
/* measure humidity */ /* measure humidity */
if (mode & HUMIDITY) { if(mode & HUMIDITY) {
error += (!measure((uint8_t*) &humi_int, &checksum, SHT11_MEASURE_HUMI)); error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI));
} }
/* measure temperature */ /* measure temperature */
if (mode & TEMPERATURE) { if(mode & TEMPERATURE) {
error += (!measure((uint8_t*) &temp_int, &checksum, SHT11_MEASURE_TEMP)); error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP));
} }
/* break on error */ /* break on error */
if (error != 0) { if(error != 0) {
connection_reset(); connection_reset();
mutex_unlock(&sht11_mutex,0); mutex_unlock(&sht11_mutex, 0);
return 0; return 0;
} }
if (mode & TEMPERATURE) { if(mode & TEMPERATURE) {
value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset; value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset;
} }
if (mode & HUMIDITY) {
if(mode & HUMIDITY) {
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int)); value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
if (mode & TEMPERATURE) { if(mode & TEMPERATURE) {
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum; value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
} }
} }
mutex_unlock(&sht11_mutex,0);
mutex_unlock(&sht11_mutex, 0);
return 1; return 1;
} }