📄 dispatchslottedcsmap.nc
字号:
/*
* Copyright (c) 2008, 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.
*
* - Revision -------------------------------------------------------------
* $Revision: 1.7 $
* $Date: 2009/05/14 13:20:35 $
* @author Jan Hauer <hauer@tkn.tu-berlin.de>
* ========================================================================
*/
#include "TKN154_PHY.h"
#include "TKN154_MAC.h"
/**
* This module is responsible for the transmission/reception of DATA and
* COMMAND frames in the CAP of beacon-enabled PANs. Its main tasks are
* initialization of the parameters of the slotted CSMA-CA algorithm (NB, BE,
* etc.), initiating retransmissions and dealing with broadcast transmissions.
* It does not implement the actual CSMA-CA algorithm, because due to its
* timing requirements the CSMA-CA algorithm is not part of the MAC
* implementation but of the chip-specific radio driver.
*
* This module does slightly different things depending on whether it is the
* CAP for an outgoing superframe (sfDirection = OUTGOING_SUPERFRAME), i.e. the
* CAP from the perspective of a coordinator after it has transmitted its own
* beacon; or for an incoming superframe (sfDirection = INCOMING_SUPERFRAME),
* i.e. the CAP from the perspective of a device after it has received a
* beacon from its coordinator. For example, in the CAP a coordinator will
* typically listen for incoming frames from the devices, and a device will
* typically switch the radio off unless it has a frame to transmit.
*/
generic module DispatchSlottedCsmaP(uint8_t sfDirection)
{
provides
{
interface Init as Reset;
interface FrameTx as FrameTx;
interface FrameRx as FrameRx[uint8_t frameType];
interface FrameExtracted as FrameExtracted[uint8_t frameType];
interface FrameTxNow as BroadcastTx;
interface Notify<bool> as WasRxEnabled;
}
uses
{
interface Alarm<TSymbolIEEE802154,uint32_t> as CapEndAlarm;
interface Alarm<TSymbolIEEE802154,uint32_t> as BLEAlarm;
interface Alarm<TSymbolIEEE802154,uint32_t> as RxWaitAlarm;
interface TransferableResource as RadioToken;
interface ResourceRequested as RadioTokenRequested;
interface SuperframeStructure;
interface GetNow<token_requested_t> as IsRadioTokenRequested;
interface GetNow<bool> as IsRxEnableActive;
interface Get<ieee154_txframe_t*> as GetIndirectTxFrame;
interface Notify<bool> as RxEnableStateChange;
interface GetNow<bool> as IsTrackingBeacons;
interface Notify<const void*> as PIBUpdateMacRxOnWhenIdle;
interface FrameUtility;
interface SlottedCsmaCa;
interface RadioRx;
interface RadioOff;
interface MLME_GET;
interface MLME_SET;
interface TimeCalc;
interface Leds;
interface SetNow<ieee154_cap_frame_backup_t*> as FrameBackup;
interface GetNow<ieee154_cap_frame_backup_t*> as FrameRestore;
interface StdControl as TrackSingleBeacon;
}
}
implementation
{
typedef enum {
SWITCH_OFF,
WAIT_FOR_RXDONE,
WAIT_FOR_TXDONE,
DO_NOTHING,
} next_state_t;
typedef enum {
INDIRECT_TX_ALARM,
BROADCAST_ALARM,
NO_ALARM,
} rx_alarm_t;
enum {
COORD_ROLE = (sfDirection == OUTGOING_SUPERFRAME),
DEVICE_ROLE = !COORD_ROLE,
RADIO_CLIENT_CFP = COORD_ROLE ? RADIO_CLIENT_COORDCFP : RADIO_CLIENT_DEVICECFP,
};
/* state / frame management */
norace bool m_lock;
norace bool m_resume;
norace ieee154_txframe_t *m_currentFrame;
norace ieee154_txframe_t *m_bcastFrame;
norace ieee154_txframe_t *m_lastFrame;
norace uint16_t m_remainingBackoff;
ieee154_macRxOnWhenIdle_t macRxOnWhenIdle;
/* variables for the slotted CSMA-CA */
norace ieee154_csma_t m_csma;
norace ieee154_macMaxBE_t m_BE;
norace ieee154_macMaxCSMABackoffs_t m_macMaxCSMABackoffs;
norace ieee154_macMaxBE_t m_macMaxBE;
norace ieee154_macMaxFrameRetries_t m_macMaxFrameRetries;
norace ieee154_status_t m_txStatus;
norace uint32_t m_transactionTime;
norace bool m_indirectTxPending = FALSE;
norace bool m_broadcastRxPending;
norace ieee154_macMaxFrameTotalWaitTime_t m_macMaxFrameTotalWaitTime;
/* function / task prototypes */
void stopAllAlarms();
next_state_t tryReceive();
next_state_t tryTransmit();
next_state_t trySwitchOff();
void backupCurrentFrame();
void restoreFrameFromBackup();
void updateState();
void setCurrentFrame(ieee154_txframe_t *frame);
void signalTxBroadcastDone(ieee154_txframe_t *frame, ieee154_status_t error);
task void signalTxDoneTask();
task void setupTxBroadcastTask();
task void wasRxEnabledTask();
#ifdef TKN154_DEBUG
enum {
HEADER_STR_LEN = 27,
DBG_STR_SIZE = 250,
};
norace uint16_t m_dbgNumEntries;
norace char m_dbgStr[HEADER_STR_LEN + DBG_STR_SIZE] = "updateState() transitions: ";
void dbg_push_state(uint8_t state) {
if (m_dbgNumEntries < DBG_STR_SIZE-3)
m_dbgStr[HEADER_STR_LEN + m_dbgNumEntries++] = '0' + state;
}
void dbg_flush_state() {
m_dbgStr[HEADER_STR_LEN + m_dbgNumEntries++] = '\n';
m_dbgStr[HEADER_STR_LEN + m_dbgNumEntries++] = 0;
dbg_serial("DispatchSlottedCsmaP",m_dbgStr);
m_dbgNumEntries = 0;
}
#else
#define dbg_push_state(X)
#define dbg_flush_state()
#endif
command error_t Reset.init()
{
if (m_currentFrame)
signal FrameTx.transmitDone(m_currentFrame, IEEE154_TRANSACTION_OVERFLOW);
if (m_lastFrame)
signal FrameTx.transmitDone(m_lastFrame, IEEE154_TRANSACTION_OVERFLOW);
if (m_bcastFrame)
signalTxBroadcastDone(m_bcastFrame, IEEE154_TRANSACTION_OVERFLOW);
m_currentFrame = m_lastFrame = m_bcastFrame = NULL;
m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
stopAllAlarms();
return SUCCESS;
}
async event void RadioToken.transferredFrom(uint8_t fromClient)
{
// we got the token, i.e. CAP has just started
uint32_t capDuration = (uint32_t) call SuperframeStructure.numCapSlots() *
(uint32_t) call SuperframeStructure.sfSlotDuration();
uint16_t guardTime = call SuperframeStructure.guardTime();
dbg_serial("DispatchSlottedCsmaP", "Got token, remaining CAP time: %lu\n",
call SuperframeStructure.sfStartTime() + capDuration - guardTime - call CapEndAlarm.getNow());
if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()) {
// very rare case:
// this can only happen, if we're on a beacon-enabled PAN, not tracking beacons,
// and searched but didn't find a beacon for aBaseSuperframeDuration*(2n+1) symbols
// we'd actually have to transmit the current frame using unslotted CSMA-CA
// but we don't have that functionality available... signal FAIL...
m_lastFrame = m_currentFrame;
m_currentFrame = NULL;
m_txStatus = IEEE154_NO_BEACON;
post signalTxDoneTask();
return;
} else if (capDuration < guardTime) {
// CAP is too short to do anything practical
dbg_serial("DispatchSlottedCsmaP", "CAP too short!\n");
call RadioToken.transferTo(RADIO_CLIENT_CFP);
return;
} else {
capDuration -= guardTime;
if (DEVICE_ROLE)
m_broadcastRxPending = call SuperframeStructure.isBroadcastPending();
else {
// COORD_ROLE
if (m_bcastFrame != NULL) {
// we have to transmit a broadcast frame immediately; this
// may require to a backup of the previously active frame
// and a reinitializing the CSMA parameters -> will do it
// in task context and then continue
m_lock = TRUE;
post setupTxBroadcastTask();
dbg_serial("DispatchSlottedCsmaP", "Preparing broadcast.\n");
}
}
call CapEndAlarm.startAt(call SuperframeStructure.sfStartTime(), capDuration);
if (call SuperframeStructure.battLifeExtDuration() > 0)
call BLEAlarm.startAt(call SuperframeStructure.sfStartTime(), call SuperframeStructure.battLifeExtDuration());
}
updateState();
}
command ieee154_status_t FrameTx.transmit(ieee154_txframe_t *frame)
{
if (m_currentFrame != NULL) {
// we've not finished transmitting the current frame yet
dbg_serial("DispatchSlottedCsmaP", "Overflow\n");
return IEEE154_TRANSACTION_OVERFLOW;
} else {
setCurrentFrame(frame);
dbg("DispatchSlottedCsmaP", "New frame to transmit, DSN: %lu\n", (uint32_t) MHR(frame)[MHR_INDEX_SEQNO]);
// a beacon must be found before transmitting in a beacon-enabled PAN
if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()) {
call TrackSingleBeacon.start();
dbg_serial("DispatchSlottedCsmaP", "Tracking single beacon now\n");
// we'll receive the Token after a beacon was found or after
// aBaseSuperframeDuration*(2n+1) symbols if none was found
}
updateState();
return IEEE154_SUCCESS;
}
}
task void setupTxBroadcastTask()
{
ieee154_macDSN_t tmp;
ieee154_txframe_t *oldFrame = m_currentFrame;
if (COORD_ROLE) {
if (m_bcastFrame != NULL) {
// broadcasts should be transmitted *immediately* after the beacon,
// which may interrupt a pending transmit operation from the previous
// CAP; back up the last active frame configuration (may be none)
// and restore it after the broadcast frame has been transmitted;
// do this through interfaces and don't wire them for DEVICE_ROLE,
// so we don't waste the RAM of devices
backupCurrentFrame();
setCurrentFrame(m_bcastFrame);
if (oldFrame) {
// now the sequence number are out of order... swap them back
tmp = m_bcastFrame->header->mhr[MHR_INDEX_SEQNO];
m_bcastFrame->header->mhr[MHR_INDEX_SEQNO] =
oldFrame->header->mhr[MHR_INDEX_SEQNO];
oldFrame->header->mhr[MHR_INDEX_SEQNO] = tmp;
}
}
}
m_lock = FALSE;
updateState();
}
void setCurrentFrame(ieee154_txframe_t *frame)
{
ieee154_macDSN_t dsn = call MLME_GET.macDSN();
frame->header->mhr[MHR_INDEX_SEQNO] = dsn++;
call MLME_SET.macDSN(dsn);
m_csma.NB = 0;
m_csma.macMaxCsmaBackoffs = m_macMaxCSMABackoffs = call MLME_GET.macMaxCSMABackoffs();
m_csma.macMaxBE = m_macMaxBE = call MLME_GET.macMaxBE();
m_csma.BE = call MLME_GET.macMinBE();
if (call MLME_GET.macBattLifeExt() && m_csma.BE > 2)
m_csma.BE = 2;
m_BE = m_csma.BE;
if (COORD_ROLE && call GetIndirectTxFrame.get() == frame)
m_macMaxFrameRetries = 0; // this is an indirect transmissions (never retransmit)
else
m_macMaxFrameRetries = call MLME_GET.macMaxFrameRetries();
m_transactionTime = IEEE154_SHR_DURATION +
(frame->headerLen + frame->payloadLen + 2) * IEEE154_SYMBOLS_PER_OCTET; // extra 2 for CRC
if (frame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST)
m_transactionTime += (IEEE154_aTurnaroundTime + IEEE154_aUnitBackoffPeriod +
11 * IEEE154_SYMBOLS_PER_OCTET); // 11 byte for the ACK PPDU
// if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
// m_transactionTime += call MLME_GET.macMinLIFSPeriod();
// else
// m_transactionTime += call MLME_GET.macMinSIFSPeriod();
m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
m_currentFrame = frame;
}
void stopAllAlarms()
{
call CapEndAlarm.stop();
if (DEVICE_ROLE)
call RxWaitAlarm.stop();
call BLEAlarm.stop();
}
/**
* The updateState() function is called whenever something happened that
* might require a state transition; it implements a lock mechanism (m_lock)
* to prevent race conditions. Whenever the lock is set a "done"-event (from
* the SlottedCsmaCa/RadioRx/RadioOff interface) is pending and will "soon"
* unset the lock (and then updateState() will called again). The
* updateState() function decides about the next state by checking a list of
* possible current states ordered by priority, e.g. it first always checks
* whether the CAP is still active. Calling this function more than necessary
* can do no harm.
*/
void updateState()
{
uint32_t capDuration;
next_state_t next;
atomic {
// long atomics are bad... but in this block, once the/ current state has
// been determined only one branch will/ be taken (there are no loops)
if (m_lock || !call RadioToken.isOwner())
return;
m_lock = TRUE; // lock
capDuration = (uint32_t) call SuperframeStructure.numCapSlots() *
(uint32_t) call SuperframeStructure.sfSlotDuration();
// Check 1: has the CAP finished?
if ((COORD_ROLE || call IsTrackingBeacons.getNow()) &&
(call TimeCalc.hasExpired(call SuperframeStructure.sfStartTime(),
capDuration - call SuperframeStructure.guardTime()) ||
!call CapEndAlarm.isRunning())) {
dbg_push_state(1);
if (call RadioOff.isOff()) {
stopAllAlarms(); // may still fire, but is locked through isOwner()
if (DEVICE_ROLE && m_indirectTxPending)
signal RxWaitAlarm.fired();
m_broadcastRxPending = FALSE;
if (COORD_ROLE && m_bcastFrame) {
// didn't manage to transmit a broadcast
restoreFrameFromBackup();
signalTxBroadcastDone(m_bcastFrame, IEEE154_CHANNEL_ACCESS_FAILURE);
m_bcastFrame = NULL;
}
m_lock = FALSE; // unlock
dbg_flush_state();
dbg_serial("DispatchSlottedCsmaP", "Handing over to CFP.\n");
call RadioToken.transferTo(RADIO_CLIENT_CFP);
return;
} else
next = SWITCH_OFF;
}
// Check 2: should a broadcast frame be received/transmitted
// immediately at the start of CAP?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -