2014-08-27 18:47:31 +02:00
|
|
|
/*
|
2013-08-16 10:20:23 +02:00
|
|
|
* Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
|
|
|
|
*
|
2014-07-31 19:45:27 +02:00
|
|
|
* 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.
|
2014-08-27 18:47:31 +02:00
|
|
|
*/
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
2014-10-26 22:02:18 +01:00
|
|
|
* @ingroup dev_cc110x_legacy_csma
|
2014-07-31 20:49:35 +02:00
|
|
|
* @brief ScatterWeb MSB-A2 mac-layer
|
2010-09-22 15:10:42 +02:00
|
|
|
*
|
2014-07-31 20:49:35 +02:00
|
|
|
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
|
|
|
|
* @author Heiko Will <hwill@inf.fu-berlin.de>
|
2010-09-22 15:10:42 +02:00
|
|
|
* @version $Revision: 2128 $
|
|
|
|
*
|
2014-07-31 20:49:35 +02:00
|
|
|
* @note $Id: cc1100-csmaca-mac.c 2128 2010-05-12 12:07:59Z hillebra $
|
2010-09-22 15:10:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2011-04-06 11:09:29 +02:00
|
|
|
#include <stdlib.h>
|
2010-09-22 15:10:42 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "cc1100.h"
|
|
|
|
#include "cc1100_phy.h"
|
|
|
|
#include "cc1100-csmaca-mac.h"
|
2013-10-28 16:14:52 +01:00
|
|
|
#include "protocol-multiplex.h"
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
#include "hwtimer.h"
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "vtimer.h"
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#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;
|
2013-12-25 17:33:01 +01:00
|
|
|
static timex_t collision_measurement_start;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-11-21 14:18:54 +01:00
|
|
|
static volatile int cs_hwtimer_id = -1;
|
|
|
|
static volatile int cs_timeout_flag = 0;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2013-06-21 22:36:48 +02:00
|
|
|
static void cs_timeout_cb(void *ptr)
|
2010-09-22 15:10:42 +02:00
|
|
|
{
|
2013-11-21 14:18:54 +01:00
|
|
|
(void) ptr;
|
2013-06-21 22:36:48 +02:00
|
|
|
cs_timeout_flag = 1;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
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)
|
2010-09-22 15:10:42 +02:00
|
|
|
{
|
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 */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (collision_state == COLLISION_STATE_INITIAL) {
|
2013-12-25 17:33:01 +01:00
|
|
|
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;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
else if (collision_state == COLLISION_STATE_MEASURE) {
|
2013-06-21 22:36:48 +02:00
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
2013-12-25 17:33:01 +01:00
|
|
|
timex_t timespan = timex_sub(now, collision_measurement_start);
|
2013-06-21 22:36:48 +02:00
|
|
|
|
2013-12-25 17:33:01 +01: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
|
|
|
|
2013-06-24 22:37:35 +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);
|
2013-12-25 17:33:01 +01:00
|
|
|
collision_measurement_start = now;
|
2013-06-21 22:36:48 +02:00
|
|
|
collision_state = COLLISION_STATE_KEEP;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
else if (collisions_per_sec > 2.2) {
|
2013-06-21 22:36:48 +02:00
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
2013-12-25 17:33:01 +01:00
|
|
|
collision_measurement_start = now;
|
2013-06-21 22:36:48 +02:00
|
|
|
collision_state = COLLISION_STATE_KEEP;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
collision_state = COLLISION_STATE_INITIAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
else if (collision_state == COLLISION_STATE_KEEP) {
|
2013-06-21 22:36:48 +02:00
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
2013-12-25 17:33:01 +01:00
|
|
|
timex_t timespan = timex_sub(now, collision_measurement_start);
|
2013-06-21 22:36:48 +02:00
|
|
|
|
2013-12-25 17:33:01 +01: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 */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
|
2013-06-21 22:36:48 +02:00
|
|
|
min_window_size *= 2;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
else if (collisions_per_sec > 2.2) {
|
2013-06-21 22:36:48 +02:00
|
|
|
min_window_size *= 4;
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
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
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (protocol == 0) {
|
2014-07-31 20:49:35 +02:00
|
|
|
return RADIO_INVALID_PARAM; /* Not allowed, protocol id must be greater zero */
|
2013-06-21 22:36:48 +02:00
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +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;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (fail_percentage == 0) {
|
2013-06-21 22:36:48 +02:00
|
|
|
fail_percentage = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) {
|
2013-06-21 22:36:48 +02:00
|
|
|
cs_timeout = CARRIER_SENSE_TIMEOUT_MIN;
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
cc1100_cs_init(); /* Initialize carrier sensing */
|
2013-06-21 22:36:48 +02:00
|
|
|
|
|
|
|
window:
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (backoff != 0) {
|
2013-06-21 22:36:48 +02:00
|
|
|
goto cycle; /* If backoff was 0 */
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
windowSize *= 2; /* ...double the current window size */
|
2013-06-21 22:36:48 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (windowSize > max_window_size) {
|
2014-07-31 20:49:35 +02:00
|
|
|
windowSize = max_window_size; /* This is the maximum size allowed */
|
2013-06-21 22:36:48 +02:00
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
backoff = rand() % windowSize; /* ...and choose new backoff */
|
2013-06-21 22:36:48 +02:00
|
|
|
|
|
|
|
backoff += (uint16_t) 1;
|
|
|
|
cycle:
|
2014-07-31 20:49:35 +02:00
|
|
|
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);
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
while (cc1100_cs_read()) { /* Wait until air is free */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (cs_timeout_flag) {
|
2013-06-21 22:36:48 +02:00
|
|
|
send_csmaca_calls_cs_timeout++;
|
2010-09-22 15:10:42 +02:00
|
|
|
#ifndef CSMACA_MAC_AGGRESSIVE_MODE
|
2013-06-21 22:36:48 +02:00
|
|
|
cc1100_phy_mutex_unlock();
|
2014-07-31 20:49:35 +02:00
|
|
|
cc1100_go_after_tx(); /* Go from RX to default mode */
|
|
|
|
return RADIO_CS_TIMEOUT; /* Return immediately */
|
2010-09-22 15:10:42 +02:00
|
|
|
#endif
|
|
|
|
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
|
2014-07-31 20:49:35 +02:00
|
|
|
goto send; /* Send anyway */
|
2010-09-22 15:10:42 +02:00
|
|
|
#endif
|
2013-06-21 22:36:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +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);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
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 */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (backoff > 0) {
|
2013-06-21 22:36:48 +02:00
|
|
|
backoff--; /* Decrement backoff counter */
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:49:35 +02:00
|
|
|
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);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
while (!cs_timeout_flag
|
2014-07-31 20:49:35 +02:00
|
|
|
|| !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);
|
2014-07-31 20:49:35 +02:00
|
|
|
goto window; /* No. Go back to new wait period. */
|
2013-06-21 22:36:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cc1100_cs_set_enabled(false);
|
2010-09-22 15:10:42 +02:00
|
|
|
#ifdef CSMACA_MAC_AGGRESSIVE_MODE
|
2013-06-21 22:36:48 +02:00
|
|
|
send:
|
2010-09-22 15:10:42 +02:00
|
|
|
#endif
|
2013-06-21 22:36:48 +02:00
|
|
|
int res = cc1100_send(address, protocol, priority, payload, payload_len);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (res < 0) {
|
2013-06-21 22:36:48 +02:00
|
|
|
collision_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|