coding conventions for drivers
This commit is contained in:
parent
201f593641
commit
e2130fbd47
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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$
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user