📄 csmamacp.nc
字号:
/* -*- mode:c++; indent-tabs-mode: nil -*- * Copyright (c) 2004-2006, Technische Universitaet Berlin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of the Technische Universitaet Berlin nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */#include "radiopacketfunctions.h"#include "flagfunctions.h"#include "PacketAck.h" /** * An implementation of a Csma Mac. * * @author: Andreas Koepke (koepke@tkn.tu-berlin.de) * @author: Kevin Klues (klues@tkn.tu-berlin.de) * @author Philipp Huppertz (huppertz@tkn.tu-berlin.de)*/// #define MACM_DEBUG // debug...module CsmaMacP { provides { interface Init; interface SplitControl; interface MacSend; interface MacReceive; interface Packet; } uses { interface StdControl as CcaStdControl; interface PhySend as PacketSend; interface PhyReceive as PacketReceive; interface RadioTimeStamping; interface Tda5250Control as RadioModes; interface ResourceRequested as RadioResourceRequested; interface UartPhyControl; interface Packet as SubPacket; interface ChannelMonitor; interface ChannelMonitorControl; interface ChannelMonitorData; interface Resource as RssiAdcResource; interface Random; interface Timer<TMilli> as ReRxTimer; interface Duplicate; interface TimeDiff16; interface Alarm<T32khz, uint16_t> as Timer; async command am_addr_t amAddress(); interface LocalTime<T32khz> as LocalTime32kHz; #ifdef MACM_DEBUG interface GeneralIO as Led0; interface GeneralIO as Led1; interface GeneralIO as Led2; interface GeneralIO as Led3;#endif }}implementation{ enum { BYTE_TIME=ENCODED_32KHZ_BYTE_TIME, // phy encoded PREAMBLE_BYTE_TIME=TDA5250_32KHZ_BYTE_TIME, // no coding PHY_HEADER_TIME=6*PREAMBLE_BYTE_TIME, // 6 Phy Preamble TIME_CORRECTION=TDA5250_32KHZ_BYTE_TIME+2, // difference between txSFD and rxSFD SUB_HEADER_TIME=PHY_HEADER_TIME + sizeof(tda5250_header_t)*BYTE_TIME, SUB_FOOTER_TIME=2*BYTE_TIME, // 2 bytes crc MAXTIMERVALUE=0xFFFF, // helps to compute backoff DATA_DETECT_TIME=17, RX_SETUP_TIME=102, // time to set up receiver TX_SETUP_TIME=58, // time to set up transmitter ADDED_DELAY = 30, RX_ACK_TIMEOUT=RX_SETUP_TIME + PHY_HEADER_TIME + 2*ADDED_DELAY, TX_GAP_TIME=RX_ACK_TIMEOUT + TX_SETUP_TIME + 33, MAX_SHORT_RETRY=7, MAX_LONG_RETRY=4, BACKOFF_MASK=0xFFF, // minimum time around one packet time MIN_PREAMBLE_BYTES=2, TOKEN_ACK_FLAG = 64, TOKEN_ACK_MASK = 0x3f, INVALID_SNR = 0xffff }; /**************** Module Global Variables *****************/ /* state vars & defs */ typedef enum { CCA, // clear channel assessment CCA_ACK, SW_RX, // switch to receive RX, // rx mode done, listening & waiting for packet SW_RX_ACK, RX_ACK, RX_ACK_P, RX_P, SW_TX, TX, SW_TX_ACK, TX_ACK, INIT } macState_t; /* flags */ typedef enum { RSSI_STABLE = 1, RESUME_BACKOFF = 2, CANCEL_SEND = 4, CCA_PENDING = 8 } flags_t; /* Packet vars */ message_t* txBufPtr; message_t ackMsg; uint8_t txLen; uint8_t shortRetryCounter; uint8_t longRetryCounter; unsigned checkCounter; macState_t macState; uint8_t flags; uint8_t seqNo; uint16_t restLaufzeit; uint16_t rssiValue = 0; uint32_t rxTime = 0; /****** debug vars & defs & functions ***********************/#ifdef MACM_DEBUG#define HISTORY_ENTRIES 100 typedef struct { int index; macState_t state; int place; } history_t; history_t history[HISTORY_ENTRIES]; unsigned histIndex; void storeOldState(int p) { atomic { history[histIndex].index = histIndex; history[histIndex].state = macState; history[histIndex].place = p; histIndex++; if(histIndex >= HISTORY_ENTRIES) histIndex = 0; } }#else void storeOldState(int p) {};#endif void signalFailure(uint8_t place) {#ifdef MACM_DEBUG unsigned long i; atomic { for(;;) { call Led0.set(); call Led1.clr(); call Led2.clr(); call Led3.clr(); for(i = 0; i < 1000000; i++) { ; } (place & 1) ? call Led0.set() : call Led0.clr(); (place & 2) ? call Led1.set() : call Led1.clr(); (place & 4) ? call Led2.set() : call Led2.clr(); (place & 8) ? call Led3.set() : call Led3.clr(); for(i = 0; i < 1000000; i++) { ; } (macState & 1) ? call Led0.set() : call Led0.clr(); (macState & 2) ? call Led1.set() : call Led1.clr(); (macState & 4) ? call Led2.set() : call Led2.clr(); (macState & 8) ? call Led3.set() : call Led3.clr(); for(i = 0; i < 1000000; i++) { ; } } }#endif } void signalMacState() {#ifdef MACM_DEBUG/* (macState & 1) ? call Led0.set() : call Led0.clr(); (macState & 2) ? call Led1.set() : call Led1.clr(); (macState & 4) ? call Led2.set() : call Led2.clr(); (macState & 8) ? call Led3.set() : call Led3.clr();*/#endif } /****** Secure switching of radio modes ***/ task void SetRxModeTask(); task void SetTxModeTask(); task void ReleaseAdcTask() { macState_t ms; atomic ms = macState; if(isFlagSet(&flags, CCA_PENDING)) { post ReleaseAdcTask(); } else { if((ms > CCA) && (ms != INIT) && call RssiAdcResource.isOwner()) { call RssiAdcResource.release(); } } } void setRxMode(); void setTxMode(); void requestAdc() { if(macState != INIT) { call RssiAdcResource.immediateRequest(); } else { call RssiAdcResource.request(); } } void setRxMode() { rssiValue = INVALID_SNR; if(call RadioModes.RxMode() == FAIL) { post SetRxModeTask(); } if(macState == INIT) { requestAdc(); } else { post ReleaseAdcTask(); } } task void SetRxModeTask() { atomic { if((macState == SW_RX) || (macState == SW_RX_ACK) || (macState == INIT)) setRxMode(); } } void setTxMode() { clearFlag(&flags, RSSI_STABLE); if(call RadioModes.TxMode() == FAIL) { post SetTxModeTask(); } post ReleaseAdcTask(); } task void SetTxModeTask() { atomic { if((macState == SW_TX) || (macState == SW_TX_ACK)) setTxMode(); } } /**************** Helper functions ********/ task void postponeReRx() { call ReRxTimer.startOneShot(5000); } uint16_t backoff(uint8_t counter) { uint16_t mask = BACKOFF_MASK >> (MAX_LONG_RETRY - counter); return (call Random.rand16() & mask); } void interruptBackoffTimer() { if(call Timer.isRunning()) { restLaufzeit = call TimeDiff16.computeDelta(call Timer.getAlarm(), call Timer.getNow()); call Timer.stop(); if(restLaufzeit > BACKOFF_MASK) { restLaufzeit = call Random.rand16() & 0xFF; } setFlag(&flags, RESUME_BACKOFF); } } void storeStrength(message_t *m) { if(rssiValue != INVALID_SNR) { (getMetadata(m))->strength = rssiValue; } else { if(call RssiAdcResource.isOwner()) { (getMetadata(m))->strength = call ChannelMonitorData.readSnr(); } else { (getMetadata(m))->strength = 1; } } } void signalSendDone(error_t error) { message_t *m; error_t e = error; atomic { m = txBufPtr; txBufPtr = 0; txLen = 0; longRetryCounter = 0; shortRetryCounter = 0; if(isFlagSet(&flags, CANCEL_SEND)) { e = ECANCEL; } storeStrength(m); clearFlag(&flags, CANCEL_SEND); } signal MacSend.sendDone(m, e); } void updateLongRetryCounters() { longRetryCounter++; shortRetryCounter = 1; if(longRetryCounter > MAX_LONG_RETRY) { storeOldState(13); getMetadata(txBufPtr)->ack = WAS_NOT_ACKED; signalSendDone(FAIL); } } void updateRetryCounters() { shortRetryCounter++; if(shortRetryCounter > MAX_SHORT_RETRY) { longRetryCounter++; shortRetryCounter = 1; if(longRetryCounter > MAX_LONG_RETRY) { getMetadata(txBufPtr)->ack = WAS_NOT_ACKED; signalSendDone(FAIL); } } } void computeBackoff() { if(!isFlagSet(&flags, RESUME_BACKOFF)) { setFlag(&flags, RESUME_BACKOFF); restLaufzeit = backoff(longRetryCounter); updateRetryCounters(); storeOldState(92); } } bool isNewMsg(message_t* msg) { return call Duplicate.isNew(getHeader(msg)->src, getHeader(msg)->dest, (getHeader(msg)->token) & TOKEN_ACK_MASK); } void rememberMsg(message_t* msg) { call Duplicate.remember(getHeader(msg)->src, getHeader(msg)->dest, (getHeader(msg)->token) & TOKEN_ACK_MASK); } void checkSend() { if((txBufPtr != NULL) && (macState == RX) && (!call Timer.isRunning())) { macState = CCA; signalMacState(); checkCounter = 0; requestAdc(); call Timer.start(DATA_DETECT_TIME); storeOldState(170); } else { storeOldState(171); post ReleaseAdcTask(); } } bool needsAckRx(message_t* msg) { bool rVal = FALSE; uint8_t token; if(getHeader(msg)->dest < AM_BROADCAST_ADDR) { token = getHeader(msg)->token; if(isFlagSet(&token, ACK_REQUESTED)) rVal = TRUE; } return rVal; } bool needsAckTx(message_t* msg) { bool rVal = FALSE; if(getHeader(msg)->dest < AM_BROADCAST_ADDR) { if((getMetadata(msg)->ack == ACK_REQUESTED) || (getMetadata(msg)->ack != NO_ACK_REQUESTED)) { rVal = TRUE; } } return rVal; } void prepareAck(message_t* msg) { uint8_t rToken = getHeader(msg)->token & TOKEN_ACK_MASK; setFlag(&rToken, TOKEN_ACK_FLAG); getHeader(&ackMsg)->token = rToken; getHeader(&ackMsg)->src = call amAddress(); getHeader(&ackMsg)->dest = getHeader(msg)->src; getHeader(&ackMsg)->type = getHeader(msg)->type; } bool msgIsForMe(message_t* msg) { if(getHeader(msg)->dest == AM_BROADCAST_ADDR) return TRUE; if(getHeader(msg)->dest == call amAddress()) return TRUE; return FALSE; } bool ackIsForMe(message_t* msg) { uint8_t localToken = seqNo; setFlag(&localToken, TOKEN_ACK_FLAG); if((getHeader(msg)->dest == call amAddress()) && (localToken == getHeader(msg)->token)) return TRUE; return FALSE; } bool isControl(message_t* m) { uint8_t token = getHeader(m)->token; return isFlagSet(&token, TOKEN_ACK_FLAG); } /**************** Init ************************/ command error_t Init.init(){ atomic { txBufPtr = NULL; macState = INIT; signalMacState(); shortRetryCounter = 0; longRetryCounter = 0; flags = 0;#ifdef MACM_DEBUG histIndex = 0;#endif } return SUCCESS; } /**************** SplitControl *****************/ task void StartDoneTask() { atomic { macState = RX; signalMacState(); call UartPhyControl.setNumPreambles(MIN_PREAMBLE_BYTES); } post ReleaseAdcTask(); signal SplitControl.startDone(SUCCESS); } command error_t SplitControl.start() { call CcaStdControl.start(); atomic { macState = INIT; signalMacState(); setRxMode(); storeOldState(1); } return SUCCESS; } task void StopDone() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -