mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
217 lines
7.5 KiB
C
217 lines
7.5 KiB
C
|
/******************************************************************************
|
||
|
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 FeuerWare.
|
||
|
|
||
|
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.
|
||
|
|
||
|
FeuerWare 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, FeuerWhere project
|
||
|
* @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.h"
|
||
|
|
||
|
#include "hwtimer.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) {
|
||
|
collision_measurement_start = swtimer_now();
|
||
|
collision_count = 0;
|
||
|
collisions_per_sec = 0;
|
||
|
collision_state = COLLISION_STATE_MEASURE;
|
||
|
} else if (collision_state == COLLISION_STATE_MEASURE) {
|
||
|
uint64_t timespan = swtimer_now() - 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) {
|
||
|
collision_measurement_start = swtimer_now();
|
||
|
collision_state = COLLISION_STATE_KEEP;
|
||
|
} else if (collisions_per_sec > 2.2) {
|
||
|
collision_measurement_start = swtimer_now();
|
||
|
collision_state = COLLISION_STATE_KEEP;
|
||
|
} else {
|
||
|
collision_state = COLLISION_STATE_INITIAL;
|
||
|
}
|
||
|
}
|
||
|
} else if (collision_state == COLLISION_STATE_KEEP) {
|
||
|
uint64_t timespan = swtimer_now() - 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;
|
||
|
}
|