1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/cc110x_legacy_csma/cc1100-csmaca-mac.c

237 lines
7.7 KiB
C
Raw Normal View History

/*
* Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @ingroup dev_cc110x_legacy_csma
* @brief ScatterWeb MSB-A2 mac-layer
*
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@inf.fu-berlin.de>
* @version $Revision: 2128 $
*
* @note $Id: cc1100-csmaca-mac.c 2128 2010-05-12 12:07:59Z hillebra $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2013-12-16 17:54:58 +01:00
#include "cc1100.h"
#include "cc1100_phy.h"
#include "cc1100-csmaca-mac.h"
#include "protocol-multiplex.h"
#include "hwtimer.h"
2013-12-16 17:54:58 +01:00
#include "vtimer.h"
/*---------------------------------------------------------------------------*/
#define COLLISION_STATE_INITIAL 1
#define COLLISION_STATE_MEASURE 2
#define COLLISION_STATE_KEEP 3
static uint32_t send_csmaca_calls = 0;
static uint32_t send_csmaca_calls_cs_timeout = 0;
static int collision_count;
static double collisions_per_sec = 0;
static int collision_state = COLLISION_STATE_INITIAL;
static timex_t collision_measurement_start;
2013-11-21 14:18:54 +01:00
static volatile int cs_hwtimer_id = -1;
static volatile int cs_timeout_flag = 0;
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
static void cs_timeout_cb(void *ptr)
{
2013-11-21 14:18:54 +01:00
(void) ptr;
2013-06-21 22:36:48 +02:00
cs_timeout_flag = 1;
}
/*---------------------------------------------------------------------------*/
2014-07-07 00:35:29 +02:00
int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priority, char *payload, radio_packet_length_t payload_len)
{
2013-06-21 22:36:48 +02:00
uint16_t min_window_size;
uint16_t max_window_size;
uint16_t difs;
uint16_t slottime;
switch(priority) {
case PRIORITY_ALARM:
min_window_size = PRIO_ALARM_MIN_WINDOW_SIZE;
max_window_size = PRIO_ALARM_MAX_WINDOW_SIZE;
difs = PRIO_ALARM_DIFS;
slottime = PRIO_ALARM_SLOTTIME;
break;
case PRIORITY_WARNING:
min_window_size = PRIO_WARN_MIN_WINDOW_SIZE;
max_window_size = PRIO_WARN_MAX_WINDOW_SIZE;
difs = PRIO_WARN_DIFS;
slottime = PRIO_WARN_SLOTTIME;
break;
default:
min_window_size = PRIO_DATA_MIN_WINDOW_SIZE;
max_window_size = PRIO_DATA_MAX_WINDOW_SIZE;
difs = PRIO_DATA_DIFS;
slottime = PRIO_DATA_SLOTTIME;
}
/* Calculate collisions per second */
if (collision_state == COLLISION_STATE_INITIAL) {
vtimer_now(&collision_measurement_start);
2013-06-21 22:36:48 +02:00
collision_count = 0;
collisions_per_sec = 0;
collision_state = COLLISION_STATE_MEASURE;
}
else if (collision_state == COLLISION_STATE_MEASURE) {
2013-06-21 22:36:48 +02:00
timex_t now;
vtimer_now(&now);
timex_t timespan = timex_sub(now, collision_measurement_start);
2013-06-21 22:36:48 +02:00
if (timex_cmp(timespan, timex_set(1, 0)) > 0) {
collisions_per_sec = (collision_count * 1000000) / (double) timex_uint64(timespan);
2013-06-21 22:36:48 +02:00
if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
2013-06-21 22:36:48 +02:00
timex_t now;
vtimer_now(&now);
collision_measurement_start = now;
2013-06-21 22:36:48 +02:00
collision_state = COLLISION_STATE_KEEP;
}
else if (collisions_per_sec > 2.2) {
2013-06-21 22:36:48 +02:00
timex_t now;
vtimer_now(&now);
collision_measurement_start = now;
2013-06-21 22:36:48 +02:00
collision_state = COLLISION_STATE_KEEP;
}
else {
collision_state = COLLISION_STATE_INITIAL;
}
}
}
else if (collision_state == COLLISION_STATE_KEEP) {
2013-06-21 22:36:48 +02:00
timex_t now;
vtimer_now(&now);
timex_t timespan = timex_sub(now, collision_measurement_start);
2013-06-21 22:36:48 +02:00
if (timex_cmp(timespan, timex_set(5, 0)) > 0) {
2013-06-21 22:36:48 +02:00
collision_state = COLLISION_STATE_INITIAL;
}
}
/* Adjust initial window size according to collision rate */
if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
2013-06-21 22:36:48 +02:00
min_window_size *= 2;
}
else if (collisions_per_sec > 2.2) {
2013-06-21 22:36:48 +02:00
min_window_size *= 4;
}
uint16_t windowSize = min_window_size; /* Start with window size of PRIO_XXX_MIN_WINDOW_SIZE */
uint16_t backoff = 0; /* Backoff between 1 and windowSize */
uint32_t total; /* Holds the total wait time before send try */
uint32_t cs_timeout; /* Current carrier sense timeout value */
2013-06-21 22:36:48 +02:00
if (protocol == 0) {
return RADIO_INVALID_PARAM; /* Not allowed, protocol id must be greater zero */
2013-06-21 22:36:48 +02:00
}
cc1100_phy_mutex_lock(); /* Lock radio for exclusive access */
2013-06-21 22:36:48 +02:00
/* Get carrier sense timeout based on overall error rate till now */
send_csmaca_calls++;
int fail_percentage = (send_csmaca_calls_cs_timeout * 100) / send_csmaca_calls;
if (fail_percentage == 0) {
2013-06-21 22:36:48 +02:00
fail_percentage = 1;
}
cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage;
if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) {
2013-06-21 22:36:48 +02:00
cs_timeout = CARRIER_SENSE_TIMEOUT_MIN;
}
cc1100_cs_init(); /* Initialize carrier sensing */
2013-06-21 22:36:48 +02:00
window:
if (backoff != 0) {
2013-06-21 22:36:48 +02:00
goto cycle; /* If backoff was 0 */
}
windowSize *= 2; /* ...double the current window size */
2013-06-21 22:36:48 +02:00
if (windowSize > max_window_size) {
windowSize = max_window_size; /* This is the maximum size allowed */
2013-06-21 22:36:48 +02:00
}
backoff = rand() % windowSize; /* ...and choose new backoff */
2013-06-21 22:36:48 +02:00
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 */
2013-06-21 22:36:48 +02:00
cs_timeout_cb, NULL);
while (cc1100_cs_read()) { /* Wait until air is free */
if (cs_timeout_flag) {
2013-06-21 22:36:48 +02:00
send_csmaca_calls_cs_timeout++;
#ifndef CSMACA_MAC_AGGRESSIVE_MODE
2013-06-21 22:36:48 +02:00
cc1100_phy_mutex_unlock();
cc1100_go_after_tx(); /* Go from RX to default mode */
return RADIO_CS_TIMEOUT; /* Return immediately */
#endif
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
goto send; /* Send anyway */
#endif
2013-06-21 22:36:48 +02:00
}
}
hwtimer_remove(cs_hwtimer_id); /* Remove hwtimer */
cc1100_cs_write_cca(1); /* Air is free now */
2013-06-21 22:36:48 +02:00
cc1100_cs_set_enabled(true);
if (cc1100_cs_read()) {
2013-06-21 22:36:48 +02:00
goto window; /* GDO0 triggers on rising edge, so */
}
/* test once after interrupt is enabled */
if (backoff > 0) {
2013-06-21 22:36:48 +02:00
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 */
2013-06-21 22:36:48 +02:00
cs_timeout_cb, NULL);
while (!cs_timeout_flag
|| !cc1100_cs_read_cca()) { /* Wait until timeout is finished */
if (cc1100_cs_read_cca() == 0) { /* Is the air still free? */
2013-06-21 22:36:48 +02:00
hwtimer_remove(cs_hwtimer_id);
goto window; /* No. Go back to new wait period. */
2013-06-21 22:36:48 +02:00
}
}
cc1100_cs_set_enabled(false);
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
2013-06-21 22:36:48 +02:00
send:
#endif
2013-06-21 22:36:48 +02:00
int res = cc1100_send(address, protocol, priority, payload, payload_len);
if (res < 0) {
2013-06-21 22:36:48 +02:00
collision_count++;
}
return res;
}