You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

260 lines
8.6 KiB

/******************************************************************************
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
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
*******************************************************************************/
/**
* @file
* @ingroup dev_cc110x
* @brief ScatterWeb MSB-A2 mac-layer
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @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>
#include <cc1100.h>
#include <cc1100_phy.h>
#include <cc1100-csmaca-mac.h>
#include "protocol-multiplex/protocol-multiplex.h"
#include "hwtimer.h"
#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 uint64_t collision_measurement_start = 0;
volatile static int cs_hwtimer_id = -1;
volatile static int cs_timeout_flag = 0;
/*---------------------------------------------------------------------------*/
static void cs_timeout_cb(void *ptr)
{
cs_timeout_flag = 1;
}
/*---------------------------------------------------------------------------*/
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 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) {
timex_t now;
vtimer_now(&now);
collision_measurement_start = now.microseconds;
collision_count = 0;
collisions_per_sec = 0;
collision_state = COLLISION_STATE_MEASURE;
}
else if (collision_state == COLLISION_STATE_MEASURE) {
timex_t now;
vtimer_now(&now);
uint64_t timespan = now.microseconds - collision_measurement_start;
if (timespan > 1000000) {
collisions_per_sec = (collision_count * 1000000) / (double) timespan;
if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) {
timex_t now;
vtimer_now(&now);
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 (timespan > 5000000) {
collision_state = COLLISION_STATE_INITIAL;
}
}
/* 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;
}
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 */
if (protocol == 0) {
return RADIO_INVALID_PARAM; /* Not allowed, protocol id must be greater zero */
}
cc1100_phy_mutex_lock(); /* Lock radio for exclusive access */
/* 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) {
fail_percentage = 1;
}
cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage;
if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) {
cs_timeout = CARRIER_SENSE_TIMEOUT_MIN;
}
cc1100_cs_init(); /* Initialize carrier sensing */
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
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
}
}
hwtimer_remove(cs_hwtimer_id); /* Remove hwtimer */
cc1100_cs_write_cca(1); /* Air is free now */
cc1100_cs_set_enabled(true);
if (cc1100_cs_read()) {
goto window; /* GDO0 triggers on rising edge, so */
}
/* test once after interrupt is enabled */
if (backoff > 0) {
backoff--; /* Decrement backoff counter */
}
total = slottime; /* Calculate total wait time */
total *= (uint32_t)backoff; /* Slot vector set */
total += difs; /* ...and standard DIFS wait time */
cs_timeout_flag = 0; /* Carrier sense timeout flag */
cs_hwtimer_id = hwtimer_set(total, /* Set hwtimer to set CS timeout flag */
cs_timeout_cb, NULL);
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
send:
#endif
int res = cc1100_send(address, protocol, priority, payload, payload_len);
if (res < 0) {
collision_count++;
}
return res;
}