coding conventions for drivers

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -70,107 +70,106 @@ and the mailinglist (subscription via web site)
/** CC1100 register configuration */ /** CC1100 register configuration */
typedef struct cc1100_reg { typedef struct cc1100_reg {
uint8_t IOCFG2; uint8_t IOCFG2;
uint8_t IOCFG1; uint8_t IOCFG1;
uint8_t IOCFG0; uint8_t IOCFG0;
uint8_t FIFOTHR; uint8_t FIFOTHR;
uint8_t SYNC1; uint8_t SYNC1;
uint8_t SYNC0; uint8_t SYNC0;
uint8_t PKTLEN; uint8_t PKTLEN;
uint8_t PKTCTRL1; uint8_t PKTCTRL1;
uint8_t PKTCTRL0; uint8_t PKTCTRL0;
uint8_t ADDR; uint8_t ADDR;
uint8_t CHANNR; uint8_t CHANNR;
uint8_t FSCTRL1; uint8_t FSCTRL1;
uint8_t FSCTRL0; uint8_t FSCTRL0;
uint8_t FREQ2; uint8_t FREQ2;
uint8_t FREQ1; uint8_t FREQ1;
uint8_t FREQ0; uint8_t FREQ0;
uint8_t MDMCFG4; uint8_t MDMCFG4;
uint8_t MDMCFG3; uint8_t MDMCFG3;
uint8_t MDMCFG2; uint8_t MDMCFG2;
uint8_t MDMCFG1; uint8_t MDMCFG1;
uint8_t MDMCFG0; uint8_t MDMCFG0;
uint8_t DEVIATN; uint8_t DEVIATN;
uint8_t MCSM2; uint8_t MCSM2;
uint8_t MCSM1; uint8_t MCSM1;
uint8_t MCSM0; uint8_t MCSM0;
uint8_t FOCCFG; uint8_t FOCCFG;
uint8_t BSCFG; uint8_t BSCFG;
uint8_t AGCCTRL2; uint8_t AGCCTRL2;
uint8_t AGCCTRL1; uint8_t AGCCTRL1;
uint8_t AGCCTRL0; uint8_t AGCCTRL0;
uint8_t WOREVT1; uint8_t WOREVT1;
uint8_t WOREVT0; uint8_t WOREVT0;
uint8_t WORCTRL; uint8_t WORCTRL;
uint8_t FREND1; uint8_t FREND1;
uint8_t FREND0; uint8_t FREND0;
uint8_t FSCAL3; uint8_t FSCAL3;
uint8_t FSCAL2; uint8_t FSCAL2;
uint8_t FSCAL1; uint8_t FSCAL1;
uint8_t FSCAL0; uint8_t FSCAL0;
} cc1100_reg_t; } cc1100_reg_t;
/** CC1100 radio configuration */ /** CC1100 radio configuration */
typedef struct cc1100_cfg_t { typedef struct cc1100_cfg_t {
cc1100_reg_t reg_cfg; ///< CC1100 register configuration cc1100_reg_t reg_cfg; ///< CC1100 register configuration
uint8_t pa_power; ///< Output power setting uint8_t pa_power; ///< Output power setting
} cc1100_cfg_t; } 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 unsigned RETC : 8; ///< Retransmission count of last send packet
unsigned RETC : 8; ///< Retransmission count of last send packet unsigned RSSI : 8; ///< The RSSI value of last received packet
unsigned RSSI : 8; ///< The RSSI value of last received packet unsigned RSSI_SEND : 8; ///< The RSSI value of the last send unicast packet of this node
unsigned RSSI_SEND : 8; ///< The RSSI value of the last send unicast packet of this node unsigned LQI : 8; ///< The LQI value of the last received packet
unsigned LQI : 8; ///< The LQI value of the last received packet unsigned LL_ACK : 1; ///< Is set if Link-Level ACK is received, otherwise 0 (reset on new burst)
unsigned LL_ACK : 1; ///< Is set if Link-Level ACK is received, otherwise 0 (reset on new burst) unsigned CAA : 1; ///< The status of the air (1 = air free, 0 = air not free)
unsigned CAA : 1; ///< The status of the air (1 = air free, 0 = air not free) unsigned CRC_STATE : 1; ///< The CRC status of last received packet (1 = OK, 0 = not OK)
unsigned CRC_STATE : 1; ///< The CRC status of last received packet (1 = OK, 0 = not OK) unsigned SEQ : 1; ///< Sequence number (toggles between 0 and 1)
unsigned SEQ : 1; ///< Sequence number (toggles between 0 and 1) unsigned MAN_WOR : 1; ///< Manual WOR set (for randomized WOR times => no synch)
unsigned MAN_WOR : 1; ///< Manual WOR set (for randomized WOR times => no synch) unsigned KT_RES_ERR : 1; ///< A hwtimer resource error has occurred (no free timers available)
unsigned KT_RES_ERR : 1; ///< A hwtimer resource error has occurred (no free timers available) unsigned TX : 1; ///< State machine TX lock, only ACKs will be received
unsigned TX : 1; ///< State machine TX lock, only ACKs will be received unsigned WOR_RST : 1; ///< Reset CC1100 real time clock (WOR) on next WOR strobe
unsigned WOR_RST : 1; ///< Reset CC1100 real time clock (WOR) on next WOR strobe
} cc1100_flags; } cc1100_flags;
/** /**
* @brief Statistic interface for debugging * @brief Statistic interface for debugging
*/ */
typedef struct cc1100_statistic { typedef struct cc1100_statistic {
uint32_t packets_in; uint32_t packets_in;
uint32_t packets_in_crc_fail; uint32_t packets_in_crc_fail;
uint32_t packets_in_while_tx; uint32_t packets_in_while_tx;
uint32_t packets_in_dups; uint32_t packets_in_dups;
uint32_t packets_in_up; uint32_t packets_in_up;
uint32_t packets_out; uint32_t packets_out;
uint32_t packets_out_acked; uint32_t packets_out_acked;
uint32_t packets_out_broadcast; uint32_t packets_out_broadcast;
uint32_t raw_packets_out; uint32_t raw_packets_out;
uint32_t raw_packets_out_acked; uint32_t raw_packets_out_acked;
uint32_t acks_send; uint32_t acks_send;
uint32_t rx_buffer_max; uint32_t rx_buffer_max;
uint32_t watch_dog_resets; uint32_t watch_dog_resets;
} cc1100_statistic_t; } cc1100_statistic_t;
enum radio_mode { enum radio_mode {
RADIO_MODE_GET = -1, ///< leave mode unchanged RADIO_MODE_GET = -1, ///< leave mode unchanged
RADIO_MODE_OFF = 0, ///< turn radio off RADIO_MODE_OFF = 0, ///< turn radio off
RADIO_MODE_ON = 1 ///< turn radio on RADIO_MODE_ON = 1 ///< turn radio on
}; };
enum radio_result { enum radio_result {
RADIO_PAYLOAD_TOO_LONG = -1, ///< payload too long RADIO_PAYLOAD_TOO_LONG = -1, ///< payload too long
RADIO_WRONG_MODE = -2, ///< operation not supported in current mode RADIO_WRONG_MODE = -2, ///< operation not supported in current mode
RADIO_ADDR_OUT_OF_RANGE = -3, ///< address out of range RADIO_ADDR_OUT_OF_RANGE = -3, ///< address out of range
RADIO_OP_FAILED = -4, ///< operation failed RADIO_OP_FAILED = -4, ///< operation failed
RADIO_CS_TIMEOUT = -5, ///< Carrier Sense timeout: air was never free RADIO_CS_TIMEOUT = -5, ///< Carrier Sense timeout: air was never free
RADIO_INVALID_PARAM = -6 ///< Invalid parameters passed to radio RADIO_INVALID_PARAM = -6 ///< Invalid parameters passed to radio
}; };
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -75,23 +75,21 @@ 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) uint8_t flags; ///< Flags
uint8_t flags; ///< Flags 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) uint8_t wor_evt_0; ///< CC1100 WOREVT0 register value
uint8_t wor_evt_0; ///< CC1100 WOREVT0 register value uint8_t wor_evt_1; ///< CC1100 WOREVT1 register value
uint8_t wor_evt_1; ///< CC1100 WOREVT1 register value uint8_t wor_ctrl; ///< CC1100 WORCTRL register value
uint8_t wor_ctrl; ///< CC1100 WORCTRL register value
} cc1100_wor_config_t; } cc1100_wor_config_t;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -59,78 +59,82 @@ and the mailinglist (subscription via web site)
uint8_t uint8_t
cc1100_spi_writeburst_reg(uint8_t addr, char *src, uint8_t count) cc1100_spi_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) {
cc110x_txrx(src[i]); while(i < count) {
i++; cc110x_txrx(src[i]);
} i++;
cc110x_spi_unselect(); }
restoreIRQ(cpsr);
return count; cc110x_spi_unselect();
restoreIRQ(cpsr);
return count;
} }
void void
cc1100_spi_readburst_reg(uint8_t addr, char *buffer, uint8_t count) cc1100_spi_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) {
buffer[i] = cc110x_txrx(NOBYTE); while(i < count) {
i++; buffer[i] = cc110x_txrx(NOBYTE);
} i++;
cc110x_spi_unselect(); }
restoreIRQ(cpsr);
cc110x_spi_unselect();
restoreIRQ(cpsr);
} }
void void
cc1100_spi_write_reg(uint8_t addr, uint8_t value) cc1100_spi_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);
cc110x_txrx(value); cc110x_txrx(value);
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
} }
uint8_t cc1100_spi_read_reg(uint8_t addr) uint8_t cc1100_spi_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();
cc110x_txrx(addr | CC1100_READ_SINGLE); cc110x_txrx(addr | CC1100_READ_SINGLE);
result = cc110x_txrx(NOBYTE); result = cc110x_txrx(NOBYTE);
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
return result; return result;
} }
uint8_t cc1100_spi_read_status(uint8_t addr) uint8_t cc1100_spi_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();
cc110x_txrx(addr | CC1100_READ_BURST); cc110x_txrx(addr | CC1100_READ_BURST);
result = cc110x_txrx(NOBYTE); result = cc110x_txrx(NOBYTE);
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
return result; return result;
} }
uint8_t cc1100_spi_strobe(uint8_t c) uint8_t cc1100_spi_strobe(uint8_t c)
{ {
uint8_t result; uint8_t result;
unsigned int cpsr = disableIRQ(); unsigned int cpsr = disableIRQ();
cc110x_spi_select(); cc110x_spi_select();
result = cc110x_txrx(c); result = cc110x_txrx(c);
cc110x_spi_unselect(); cc110x_spi_unselect();
restoreIRQ(cpsr); restoreIRQ(cpsr);
return result; return result;
} }
/** @} */ /** @} */

View File

@ -1,28 +1,12 @@
/****************************************************************************** /**
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. * Default configuration for the cc110x chip
*
These sources were developed at the Freie Universitaet Berlin, Computer Systems * Copyright (C) 2013 INRIA
and Telematics group (http://cst.mi.fu-berlin.de). *
------------------------------------------------------------------------------- * This file subject to the terms and conditions of the GNU Lesser General
This file is part of RIOT. * Public License. See the file LICENSE in the top level directory for more
* details.
This program is free software: you can redistribute it and/or modify it under */
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
/** /**
* @ingroup dev_cc110x * @ingroup dev_cc110x
@ -34,9 +18,10 @@ and the mailinglist (subscription via web site)
* @brief TI Chipcon CC110x default settings * @brief TI Chipcon CC110x default settings
* *
* @author Freie Universität Berlin, Computer Systems & Telematics * @author Freie Universität Berlin, Computer Systems & Telematics
* @author INRIA
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de> * @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@inf.fu-berlin.de> * @author Heiko Will <hwill@inf.fu-berlin.de>
* @version $Revision: 2058 $ * @author Oliver Hahm <oliver.hahm@inria.fr>
* *
* @note $Id: cc110x-defaultSettings.c 2058 2010-03-31 08:59:31Z hillebra $ * @note $Id: cc110x-defaultSettings.c 2058 2010-03-31 08:59:31Z hillebra $
*/ */
@ -78,63 +63,63 @@ and the mailinglist (subscription via web site)
// 400 kbps, MSK, X-tal: 26 MHz (Chip Revision F) // 400 kbps, MSK, X-tal: 26 MHz (Chip Revision F)
char cc110x_conf[] = { char cc110x_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
}; };
uint8_t pa_table_index = PATABLE; ///< Current PATABLE Index uint8_t pa_table_index = PATABLE; ///< Current PATABLE Index
uint8_t pa_table[] = { ///< PATABLE with available output powers uint8_t pa_table[] = { ///< PATABLE with available output powers
0x00, ///< -52 dBm 0x00, ///< -52 dBm
0x03, ///< -30 dBm 0x03, ///< -30 dBm
0x0D, ///< -20 dBm 0x0D, ///< -20 dBm
0x1C, ///< -15 dBm 0x1C, ///< -15 dBm
0x34, ///< -10 dBm 0x34, ///< -10 dBm
0x57, ///< - 5 dBm 0x57, ///< - 5 dBm
0x3F, ///< - 1 dBm 0x3F, ///< - 1 dBm
0x8E, ///< 0 dBm 0x8E, ///< 0 dBm
0x85, ///< + 5 dBm 0x85, ///< + 5 dBm
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!

View File

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

View File

@ -1,3 +1,20 @@
/**
* Functions for packet transmission on cc110x
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#include <stdio.h> #include <stdio.h>
#include <cc110x_ng.h> #include <cc110x_ng.h>
@ -11,12 +28,13 @@
#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 */
radio_state = RADIO_SEND_BURST; radio_state = RADIO_SEND_BURST;
rflags.LL_ACK = 0; rflags.LL_ACK = 0;
/* /*
* Number of bytes to send is: * Number of bytes to send is:
@ -25,54 +43,58 @@ 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) {
abort_count++;
if (abort_count > CC1100_SYNC_WORD_TX_TIME) {
// Abort waiting. CC1100 maybe in wrong mode
// e.g. sending preambles for always
puts("[CC1100 TX] fatal error\n");
break;
}
}
restoreIRQ(cpsr);
// Wait for GDO2 to be cleared -> end of packet
while (cc110x_get_gdo2() != 0);
//LED_GREEN_TOGGLE;
// Experimental - TOF Measurement /* Wait for GDO2 to be set -> sync word transmitted */
while(cc110x_get_gdo2() == 0) {
abort_count++;
if(abort_count > CC1100_SYNC_WORD_TX_TIME) {
/* Abort waiting. CC1100 maybe in wrong mode */
/* e.g. sending preambles for always */
puts("[CC1100 TX] fatal error\n");
break;
}
}
restoreIRQ(cpsr);
/* Wait for GDO2 to be cleared -> end of packet */
while(cc110x_get_gdo2() != 0);
/* Experimental - TOF Measurement */
cc110x_after_send(); cc110x_after_send();
cc110x_statistic.raw_packets_out++; cc110x_statistic.raw_packets_out++;
// Store number of transmission retries /* Store number of transmission retries */
rflags.TX = 0; rflags.TX = 0;
// Go to mode after TX (CONST_RX -> RX, WOR -> WOR) /* Go to mode after TX (CONST_RX -> RX, WOR -> WOR) */
cc110x_switch_to_rx(); cc110x_switch_to_rx();
return true; return true;
} }

View File

@ -1,3 +1,19 @@
/**
* Basic functionality of cc110x driver
*
* Copyright (C) 2013 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#include <cc110x_ng.h> #include <cc110x_ng.h>
#include <cc110x-arch.h> #include <cc110x-arch.h>
#include <cc110x-config.h> #include <cc110x-config.h>
@ -34,107 +50,119 @@ 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);
rx_buffer_next = 0; rx_buffer_next = 0;
#ifdef MODULE_CC110X_SPI #ifdef MODULE_CC110X_SPI
/* Initialize SPI */ /* Initialize SPI */
cc110x_spi_init(); cc110x_spi_init();
#endif #endif
/* Load driver & reset */ /* Load driver & reset */
power_up_reset(); power_up_reset();
/* Write configuration to configuration registers */ /* Write configuration to configuration registers */
cc110x_writeburst_reg(0x00, cc110x_conf, CC1100_CONF_SIZE); cc110x_writeburst_reg(0x00, cc110x_conf, CC1100_CONF_SIZE);
/* Write PATABLE (power settings) */ /* Write PATABLE (power settings) */
cc110x_write_reg(CC1100_PATABLE, pa_table[pa_table_index]); cc110x_write_reg(CC1100_PATABLE, pa_table[pa_table_index]);
/* Initialize Radio Flags */ /* Initialize Radio Flags */
rflags._RSSI = 0x00; rflags._RSSI = 0x00;
rflags.LL_ACK = 0; rflags.LL_ACK = 0;
rflags.CAA = 0; rflags.CAA = 0;
rflags.CRC_STATE = 0; rflags.CRC_STATE = 0;
rflags.SEQ = 0; rflags.SEQ = 0;
rflags.MAN_WOR = 0; rflags.MAN_WOR = 0;
rflags.KT_RES_ERR = 0; rflags.KT_RES_ERR = 0;
rflags.TX = 0; rflags.TX = 0;
rflags.WOR_RST = 0; rflags.WOR_RST = 0;
/* Set default channel number */ /* Set default channel number */
#ifdef MODULE_CONFIG #ifdef MODULE_CONFIG
cc110x_set_config_channel(sysconfig.radio_channel); cc110x_set_config_channel(sysconfig.radio_channel);
#else #else
cc110x_set_channel(CC1100_DEFAULT_CHANNR); cc110x_set_channel(CC1100_DEFAULT_CHANNR);
#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
cc110x_init_ignore(); cc110x_init_ignore();
#endif #endif
} }
void cc110x_disable_interrupts(void) { void cc110x_disable_interrupts(void)
cc110x_gdo2_disable(); {
cc110x_gdo0_disable(); cc110x_gdo2_disable();
cc110x_gdo0_disable();
} }
void cc110x_gdo0_irq(void) { void cc110x_gdo0_irq(void)
// Air was not free -> Clear CCA flag {
rflags.CAA = false; /* Air was not free -> Clear CCA flag */
// Disable carrier sense detection (GDO0 interrupt) rflags.CAA = false;
cc110x_gdo0_disable(); /* Disable carrier sense detection (GDO0 interrupt) */
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)) { {
return 0; if((address < MIN_UID) || (address > MAX_UID)) {
} return 0;
}
uint8_t id = (uint8_t) address; uint8_t id = (uint8_t) address;
if (radio_state != RADIO_UNKNOWN) {
write_register(CC1100_ADDR, id);
}
radio_address = id; if(radio_state != RADIO_UNKNOWN) {
return radio_address; write_register(CC1100_ADDR, id);
}
radio_address = id;
return radio_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,199 +170,259 @@ 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 {
cc110x_write_reg(CC1100_MCSM2, 0x07); /* Stay in RX mode until end of packet */
cc110x_switch_to_rx(); cc110x_write_reg(CC1100_MCSM2, 0x07);
cc110x_switch_to_rx();
} }
void cc110x_switch_to_rx(void) { void cc110x_switch_to_rx(void)
radio_state = RADIO_RX; {
cc110x_strobe(CC1100_SRX); radio_state = RADIO_RX;
cc110x_strobe(CC1100_SRX);
} }
void cc110x_wakeup_from_rx(void) { void cc110x_wakeup_from_rx(void)
if (radio_state != RADIO_RX) { {
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:
return "CS"; case RADIO_AIR_FREE_WAITING:
case RADIO_WOR: return "CS";
return "WOR";
case RADIO_IDLE: case RADIO_WOR:
return "IDLE"; return "WOR";
case RADIO_SEND_BURST:
return "TX BURST"; case RADIO_IDLE:
case RADIO_RX: return "IDLE";
return "RX";
case RADIO_SEND_ACK: case RADIO_SEND_BURST:
return "TX ACK"; return "TX BURST";
case RADIO_PWD:
return "PWD"; case RADIO_RX:
default: return "RX";
return "unknown";
} case RADIO_SEND_ACK:
return "TX ACK";
case RADIO_PWD:
return "PWD";
default:
return "unknown";
}
} }
void cc110x_print_config(void) { void cc110x_print_config(void)
printf("Current radio state: %s\r\n", cc110x_state_to_text(radio_state)); {
printf("Current MARC state: %s\r\n", cc110x_get_marc_state()); printf("Current radio state: %s\r\n", cc110x_state_to_text(radio_state));
printf("Current channel number: %u\r\n", radio_channel); printf("Current MARC state: %s\r\n", cc110x_get_marc_state());
printf("Current channel number: %u\r\n", radio_channel);
} }
void cc110x_switch_to_pwd(void) { void cc110x_switch_to_pwd(void)
{
DEBUG("[cc110x_ng] switching to powerdown\n"); DEBUG("[cc110x_ng] switching to powerdown\n");
cc110x_wakeup_from_rx(); cc110x_wakeup_from_rx();
cc110x_strobe(CC1100_SPWD); cc110x_strobe(CC1100_SPWD);
radio_state = RADIO_PWD; radio_state = RADIO_PWD;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int16_t cc110x_set_channel(uint8_t channr) { int16_t cc110x_set_channel(uint8_t channr)
uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE; {
if ((state != 1) && (channr > MAX_CHANNR)) { uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE;
if((state != 1) && (channr > MAX_CHANNR)) {
return -1; return -1;
} }
write_register(CC1100_CHANNR, channr*10);
radio_channel = channr; write_register(CC1100_CHANNR, channr * 10);
return radio_channel; radio_channel = channr;
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();
#endif #endif
cc110x_strobe(CC1100_SRES); cc110x_strobe(CC1100_SRES);
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();
cc110x_spi_unselect(); cc110x_spi_unselect();
#endif #endif
hwtimer_wait(RESET_WAIT_TIME); hwtimer_wait(RESET_WAIT_TIME);
reset(); reset();
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 {
uint8_t old_state = radio_state; /* Save old radio state */
uint8_t old_state = radio_state;
/* Wake up from WOR/RX (if in WOR/RX, else no effect) */ /* Wake up from WOR/RX (if in WOR/RX, else no effect) */
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:
cc110x_disable_interrupts(); // Disable interrupts
cc110x_switch_to_pwd(); // Set chip to power down mode
break;
case RADIO_MODE_GET:
// do nothing, just return current mode
default:
// do nothing
break;
}
// Return previous mode case RADIO_MODE_OFF:
return result; cc110x_disable_interrupts(); /* Disable interrupts */
cc110x_switch_to_pwd(); /* Set chip to power down mode */
break;
case RADIO_MODE_GET:
/* do nothing, just return current mode */
default:
/* do nothing */
break;
}
/* Return previous mode */
return result;
} }

View File

@ -1,3 +1,19 @@
/**
* Configuration parameters for the cc110x radio chip
*
* Copyright (C) 2009 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* This file subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup dev_cc110x_ng
* @{
* @file
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @}
*/
#ifndef CC1100_CONFIG_H #ifndef CC1100_CONFIG_H
#define CC1100_CONFIG_H #define CC1100_CONFIG_H
@ -6,91 +22,90 @@
/** CC1100 register configuration */ /** CC1100 register configuration */
typedef struct { typedef struct {
uint8_t _IOCFG2; uint8_t _IOCFG2;
uint8_t _IOCFG1; uint8_t _IOCFG1;
uint8_t _IOCFG0; uint8_t _IOCFG0;
uint8_t _FIFOTHR; uint8_t _FIFOTHR;
uint8_t _SYNC1; uint8_t _SYNC1;
uint8_t _SYNC0; uint8_t _SYNC0;
uint8_t _PKTLEN; uint8_t _PKTLEN;
uint8_t _PKTCTRL1; uint8_t _PKTCTRL1;
uint8_t _PKTCTRL0; uint8_t _PKTCTRL0;
uint8_t _ADDR; uint8_t _ADDR;
uint8_t _CHANNR; uint8_t _CHANNR;
uint8_t _FSCTRL1; uint8_t _FSCTRL1;
uint8_t _FSCTRL0; uint8_t _FSCTRL0;
uint8_t _FREQ2; uint8_t _FREQ2;
uint8_t _FREQ1; uint8_t _FREQ1;
uint8_t _FREQ0; uint8_t _FREQ0;
uint8_t _MDMCFG4; uint8_t _MDMCFG4;
uint8_t _MDMCFG3; uint8_t _MDMCFG3;
uint8_t _MDMCFG2; uint8_t _MDMCFG2;
uint8_t _MDMCFG1; uint8_t _MDMCFG1;
uint8_t _MDMCFG0; uint8_t _MDMCFG0;
uint8_t _DEVIATN; uint8_t _DEVIATN;
uint8_t _MCSM2; uint8_t _MCSM2;
uint8_t _MCSM1; uint8_t _MCSM1;
uint8_t _MCSM0; uint8_t _MCSM0;
uint8_t _FOCCFG; uint8_t _FOCCFG;
uint8_t _BSCFG; uint8_t _BSCFG;
uint8_t _AGCCTRL2; uint8_t _AGCCTRL2;
uint8_t _AGCCTRL1; uint8_t _AGCCTRL1;
uint8_t _AGCCTRL0; uint8_t _AGCCTRL0;
uint8_t _WOREVT1; uint8_t _WOREVT1;
uint8_t _WOREVT0; uint8_t _WOREVT0;
uint8_t _WORCTRL; uint8_t _WORCTRL;
uint8_t _FREND1; uint8_t _FREND1;
uint8_t _FREND0; uint8_t _FREND0;
uint8_t _FSCAL3; uint8_t _FSCAL3;
uint8_t _FSCAL2; uint8_t _FSCAL2;
uint8_t _FSCAL1; uint8_t _FSCAL1;
uint8_t _FSCAL0; uint8_t _FSCAL0;
} cc110x_reg_t; } cc110x_reg_t;
/** CC1100 radio configuration */ /** CC1100 radio configuration */
typedef struct { typedef struct {
cc110x_reg_t reg_cfg; ///< CC1100 register configuration cc110x_reg_t reg_cfg; ///< CC1100 register configuration
uint8_t pa_power; ///< Output power setting uint8_t pa_power; ///< Output power setting
} cc110x_cfg_t; } cc110x_cfg_t;
/** /**
* @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
unsigned RPS : 16; ///< Raw packets sent to transmit last packet unsigned RPS : 16; ///< Raw packets sent to transmit last packet
unsigned RETC : 8; ///< Retransmission count of last send packet unsigned RETC : 8; ///< Retransmission count of last send packet
unsigned _RSSI : 8; ///< The RSSI value of last received packet unsigned _RSSI : 8; ///< The RSSI value of last received packet
unsigned RSSI_SEND : 8; ///< The RSSI value of the last send unicast packet of this node unsigned RSSI_SEND : 8; ///< The RSSI value of the last send unicast packet of this node
unsigned _LQI : 8; ///< The LQI value of the last received packet unsigned _LQI : 8; ///< The LQI value of the last received packet
unsigned LL_ACK : 1; ///< Is set if Link-Level ACK is received, otherwise 0 (reset on new burst) unsigned LL_ACK : 1; ///< Is set if Link-Level ACK is received, otherwise 0 (reset on new burst)
unsigned CAA : 1; ///< The status of the air (1 = air free, 0 = air not free) unsigned CAA : 1; ///< The status of the air (1 = air free, 0 = air not free)
unsigned CRC_STATE : 1; ///< The CRC status of last received packet (1 = OK, 0 = not OK) unsigned CRC_STATE : 1; ///< The CRC status of last received packet (1 = OK, 0 = not OK)
unsigned SEQ : 1; ///< Sequence number (toggles between 0 and 1) unsigned SEQ : 1; ///< Sequence number (toggles between 0 and 1)
unsigned MAN_WOR : 1; ///< Manual WOR set (for randomized WOR times => no synch) unsigned MAN_WOR : 1; ///< Manual WOR set (for randomized WOR times => no synch)
unsigned KT_RES_ERR : 1; ///< A hwtimer resource error has occurred (no free timers available) unsigned KT_RES_ERR : 1; ///< A hwtimer resource error has occurred (no free timers available)
unsigned TX : 1; ///< State machine TX lock, only ACKs will be received unsigned TX : 1; ///< State machine TX lock, only ACKs will be received
unsigned WOR_RST : 1; ///< Reset CC1100 real time clock (WOR) on next WOR strobe unsigned WOR_RST : 1; ///< Reset CC1100 real time clock (WOR) on next WOR strobe
} cc110x_flags; } cc110x_flags;
/** /**
* @brief Statistic interface for debugging * @brief Statistic interface for debugging
*/ */
typedef struct cc110x_statistic { typedef struct cc110x_statistic {
uint32_t packets_in; uint32_t packets_in;
uint32_t packets_in_crc_fail; uint32_t packets_in_crc_fail;
uint32_t packets_in_while_tx; uint32_t packets_in_while_tx;
uint32_t packets_in_dups; uint32_t packets_in_dups;
uint32_t packets_in_up; uint32_t packets_in_up;
uint32_t packets_out; uint32_t packets_out;
uint32_t packets_out_broadcast; uint32_t packets_out_broadcast;
uint32_t raw_packets_out; uint32_t raw_packets_out;
uint32_t acks_send; uint32_t acks_send;
uint32_t rx_buffer_max; uint32_t rx_buffer_max;
uint32_t watch_dog_resets; uint32_t watch_dog_resets;
} cc110x_statistic_t; } cc110x_statistic_t;
#endif #endif

View File

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

View File

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

View File

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

View File

@ -58,76 +58,87 @@ 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; {
unsigned int cpsr = disableIRQ(); int i = 0;
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
cc110x_txrx(addr | CC1100_WRITE_BURST); cc110x_spi_select();
while (i < count) { cc110x_txrx(addr | CC1100_WRITE_BURST);
cc110x_txrx(src[i]);
i++; while(i < count) {
} cc110x_txrx(src[i]);
cc110x_spi_unselect(); i++;
restoreIRQ(cpsr); }
return count;
cc110x_spi_unselect();
restoreIRQ(cpsr);
return count;
} }
void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count) { void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count)
int i = 0; {
unsigned int cpsr = disableIRQ(); int i = 0;
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
cc110x_txrx(addr | CC1100_READ_BURST); cc110x_spi_select();
while (i < count) { cc110x_txrx(addr | CC1100_READ_BURST);
buffer[i] = cc110x_txrx(NOBYTE);
i++; while(i < count) {
} buffer[i] = cc110x_txrx(NOBYTE);
cc110x_spi_unselect(); i++;
restoreIRQ(cpsr); }
cc110x_spi_unselect();
restoreIRQ(cpsr);
} }
void cc110x_read_fifo(char *buffer, uint8_t count) { void cc110x_read_fifo(char *buffer, uint8_t count)
cc110x_readburst_reg(CC1100_RXFIFO, buffer,count); {
cc110x_readburst_reg(CC1100_RXFIFO, buffer, count);
} }
void cc110x_write_reg(uint8_t addr, uint8_t value) { void cc110x_write_reg(uint8_t addr, uint8_t value)
unsigned int cpsr = disableIRQ(); {
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
cc110x_txrx(addr); cc110x_spi_select();
cc110x_txrx(value); cc110x_txrx(addr);
cc110x_spi_unselect(); cc110x_txrx(value);
restoreIRQ(cpsr); cc110x_spi_unselect();
restoreIRQ(cpsr);
} }
uint8_t cc110x_read_reg(uint8_t addr) { uint8_t cc110x_read_reg(uint8_t addr)
uint8_t result; {
unsigned int cpsr = disableIRQ(); uint8_t result;
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
cc110x_txrx(addr | CC1100_READ_SINGLE); cc110x_spi_select();
result = cc110x_txrx(NOBYTE); cc110x_txrx(addr | CC1100_READ_SINGLE);
cc110x_spi_unselect(); result = cc110x_txrx(NOBYTE);
restoreIRQ(cpsr); cc110x_spi_unselect();
return result; restoreIRQ(cpsr);
return result;
} }
uint8_t cc110x_read_status(uint8_t addr) { uint8_t cc110x_read_status(uint8_t addr)
uint8_t result; {
unsigned int cpsr = disableIRQ(); uint8_t result;
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
cc110x_txrx(addr | CC1100_READ_BURST); cc110x_spi_select();
result = cc110x_txrx(NOBYTE); cc110x_txrx(addr | CC1100_READ_BURST);
cc110x_spi_unselect(); result = cc110x_txrx(NOBYTE);
restoreIRQ(cpsr); cc110x_spi_unselect();
return result; restoreIRQ(cpsr);
return result;
} }
uint8_t cc110x_strobe(uint8_t c) { uint8_t cc110x_strobe(uint8_t c)
uint8_t result; {
unsigned int cpsr = disableIRQ(); uint8_t result;
cc110x_spi_select(); unsigned int cpsr = disableIRQ();
result = cc110x_txrx(c); cc110x_spi_select();
cc110x_spi_unselect(); result = cc110x_txrx(c);
restoreIRQ(cpsr); cc110x_spi_unselect();
return result; restoreIRQ(cpsr);
return result;
} }
/** @} */ /** @} */

View File

@ -20,8 +20,8 @@
#endif #endif
/* These functions are defined in asmfunc.S */ /* These functions are defined in asmfunc.S */
void Copy_al2un (unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */ void Copy_al2un(unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */
void Copy_un2al (unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */ void Copy_un2al(unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */
/* Status of Disk Functions */ /* Status of Disk Functions */
@ -29,22 +29,22 @@ typedef unsigned char DSTATUS;
/* Results of Disk Functions */ /* Results of Disk Functions */
typedef enum { typedef enum {
RES_OK = 0, /* 0: Successful */ RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */ RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */ RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */ RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */ RES_PARERR /* 4: Invalid Parameter */
} DRESULT; } DRESULT;
/*---------------------------------------*/ /*---------------------------------------*/
/* Prototypes for disk control functions */ /* Prototypes for disk control functions */
DSTATUS disk_initialize (unsigned char); DSTATUS disk_initialize(unsigned char);
DSTATUS disk_status (unsigned char); DSTATUS disk_status(unsigned char);
DRESULT disk_read (unsigned char, unsigned char*, unsigned long, unsigned char); DRESULT disk_read(unsigned char, unsigned char *, unsigned long, unsigned char);
DRESULT disk_write (unsigned char, const unsigned char*, unsigned long, unsigned char); DRESULT disk_write(unsigned char, const unsigned char *, unsigned long, unsigned char);
DRESULT disk_ioctl (unsigned char, unsigned char, void*); DRESULT disk_ioctl(unsigned char, unsigned char, void *);
@ -90,18 +90,18 @@ DRESULT disk_ioctl (unsigned char, unsigned char, void*);
/* Prototypes for each physical disk functions */ /* Prototypes for each physical disk functions */
DSTATUS NAND_initialize (void); DSTATUS NAND_initialize(void);
DSTATUS NAND_status (void); DSTATUS NAND_status(void);
DRESULT NAND_read (unsigned char*, unsigned long, unsigned char); DRESULT NAND_read(unsigned char *, unsigned long, unsigned char);
DRESULT NAND_write (const unsigned char*, unsigned long, unsigned char); DRESULT NAND_write(const unsigned char *, unsigned long, unsigned char);
DRESULT NAND_ioctl (unsigned char, void*); DRESULT NAND_ioctl(unsigned char, void *);
DSTATUS MCI_initialize (void); DSTATUS MCI_initialize(void);
DSTATUS MCI_status (void); DSTATUS MCI_status(void);
DRESULT MCI_read (unsigned char*, unsigned long, unsigned char); DRESULT MCI_read(unsigned char *, unsigned long, unsigned char);
DRESULT MCI_write (const unsigned char*, unsigned long, unsigned char); DRESULT MCI_write(const unsigned char *, unsigned long, unsigned char);
DRESULT MCI_ioctl (unsigned char, void*); DRESULT MCI_ioctl(unsigned char, void *);
void MCI_timerproc (void); void MCI_timerproc(void);
#endif #endif

View File

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

View File

@ -44,7 +44,7 @@ and the mailinglist (subscription via web site)
#define SHT11_NO_ACK (0) #define SHT11_NO_ACK (0)
#define SHT11_ACK (1) #define SHT11_ACK (1)
//adr command r/w //adr command r/w
#define SHT11_STATUS_REG_W (0x06) //000 0011 0 #define SHT11_STATUS_REG_W (0x06) //000 0011 0
#define SHT11_STATUS_REG_R (0x07) //000 0011 1 #define SHT11_STATUS_REG_R (0x07) //000 0011 1
#define SHT11_MEASURE_TEMP (0x03) //000 0001 1 #define SHT11_MEASURE_TEMP (0x03) //000 0001 1
@ -63,17 +63,17 @@ and the mailinglist (subscription via web site)
* @brief sht11 measureable data * @brief sht11 measureable data
*/ */
typedef struct { typedef struct {
float temperature; /**< temperature value */ float temperature; /**< temperature value */
float relhum; /**< linear relative humidity */ float relhum; /**< linear relative humidity */
float relhum_temp; /**< temperature compensated relative humidity */ float relhum_temp; /**< temperature compensated relative humidity */
} sht11_val_t; } sht11_val_t;
/** /**
* @brief SHT11 modes that can be measured * @brief SHT11 modes that can be measured
*/ */
typedef enum { typedef enum {
TEMPERATURE = 1, TEMPERATURE = 1,
HUMIDITY = 2 HUMIDITY = 2
} sht11_mode_t; } sht11_mode_t;
/** /**

View File

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

View File

@ -99,7 +99,8 @@ static inline void clk_signal(void);
mutex_t sht11_mutex; mutex_t sht11_mutex;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static inline void clk_signal(void) { static inline void clk_signal(void)
{
SHT11_SCK_HIGH; SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
SHT11_SCK_LOW; SHT11_SCK_LOW;
@ -109,246 +110,264 @@ static inline void clk_signal(void) {
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint8_t write_byte(uint8_t value) static uint8_t write_byte(uint8_t value)
{ {
uint8_t i; uint8_t i;
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 { }
SHT11_DATA_LOW; else {
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} }
/* trigger clock signal */ /* trigger clock signal */
clk_signal(); clk_signal();
/* shift value to write next bit */ /* shift value to write next bit */
value = value << 1; value = value << 1;
} }
/* wait for ack */ /* wait for ack */
SHT11_DATA_IN; SHT11_DATA_IN;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
ack = SHT11_DATA; ack = SHT11_DATA;
clk_signal(); clk_signal();
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) {
SHT11_DATA_LOW; if(ack) {
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} else { }
SHT11_DATA_HIGH; else {
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT); hwtimer_wait(SHT11_DATA_WAIT);
} }
clk_signal(); clk_signal();
/* release data line */ /* release data line */
SHT11_DATA_IN; SHT11_DATA_IN;
return value; return value;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void transmission_start(void) static void transmission_start(void)
{ {
/* _____ ________ /* _____ ________
DATA: |_______| DATA: |_______|
___ ___ ___ ___
SCK : ___| |___| |______ SCK : ___| |___| |______
*/ */
SHT11_DATA_OUT; SHT11_DATA_OUT;
/* set initial state */ /* set initial state */
SHT11_DATA_HIGH; SHT11_DATA_HIGH;
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);
SHT11_SCK_HIGH; SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
SHT11_DATA_LOW; SHT11_DATA_LOW;
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);
SHT11_SCK_HIGH; SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT); hwtimer_wait(SHT11_CLK_WAIT);
SHT11_DATA_HIGH; SHT11_DATA_HIGH;
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);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void connection_reset(void) static void connection_reset(void)
{ {
/* _____________________________________________________ ____ /* _____________________________________________________ ____
DATA: |_______| DATA: |_______|
_ _ _ _ _ _ _ _ _ ___ ___ _ _ _ _ _ _ _ _ _ ___ ___
SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__ SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__
*/ */
uint8_t i; uint8_t i;
SHT11_DATA_HIGH; SHT11_DATA_HIGH;
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();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
{ {
uint8_t error = 0; uint8_t error = 0;
uint8_t ack = 1; uint8_t ack = 1;
uint16_t i; uint16_t i;
transmission_start(); transmission_start();
error = write_byte(mode); error = write_byte(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 */
*(p_value + 1) = read_byte(SHT11_ACK); *(p_value + 1) = read_byte(SHT11_ACK);
/* read LSB */ /* read LSB */
*(p_value) = read_byte(SHT11_ACK); *(p_value) = read_byte(SHT11_ACK);
/* read checksum */ /* read checksum */
*p_checksum = read_byte(SHT11_NO_ACK); *p_checksum = read_byte(SHT11_NO_ACK);
return (!error); return (!error);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void sht11_init(void) { void sht11_init(void)
sht11_temperature_offset = 0; {
mutex_init(&sht11_mutex); sht11_temperature_offset = 0;
SHT11_INIT; mutex_init(&sht11_mutex);
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();
error |= write_byte(SHT11_STATUS_REG_R); error |= write_byte(SHT11_STATUS_REG_R);
*p_value = read_byte(SHT11_ACK); *p_value = read_byte(SHT11_ACK);
*p_checksum = read_byte(SHT11_NO_ACK); *p_checksum = read_byte(SHT11_NO_ACK);
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();
error += write_byte(SHT11_STATUS_REG_W); error += write_byte(SHT11_STATUS_REG_W);
error += write_byte(*p_value); error += write_byte(*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 checksum; uint8_t error = 0;
uint16_t humi_int, temp_int; uint8_t checksum;
uint16_t humi_int, temp_int;
/* Temperature arithmetic where S0(T) is read value /* Temperature arithmetic where S0(T) is read value
* T = D1 + D2 * S0(T) */ * T = D1 + D2 * S0(T) */
const float D1 = -39.6; const float D1 = -39.6;
const float D2 = 0.01; const float D2 = 0.01;
/* Arithmetic for linear humdity where S0(RH) is read value /* Arithmetic for linear humdity where S0(RH) is read value
* HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */ * HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */
const float C1 = -4.0; const float C1 = -4.0;
const float C2 = +0.0405; const float C2 = +0.0405;
const float C3 = -0.0000028; const float C3 = -0.0000028;
/* Arithmetic for temperature compesated relative humdity /* Arithmetic for temperature compesated relative humdity
* HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */ * HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */
const float T1 = +0.01; const float T1 = +0.01;
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;
} }
value->temperature = 0; value->temperature = 0;
value->relhum = 0; value->relhum = 0;
value->relhum_temp = 0; value->relhum_temp = 0;
mutex_lock(&sht11_mutex); mutex_lock(&sht11_mutex);
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) {
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
if (mode & TEMPERATURE) { if(mode & HUMIDITY) {
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum; value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
}
} if(mode & TEMPERATURE) {
mutex_unlock(&sht11_mutex,0); value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
return 1; }
}
mutex_unlock(&sht11_mutex, 0);
return 1;
} }
/** @} */ /** @} */