* ========================================================================
*/
+/**
+ * This module is responsible for periodic beacon transmission in a
+ * beacon-enabled PAN.
+ */
+
#include "TKN154_MAC.h"
#include "TKN154_PHY.h"
module BeaconTransmitP
{
interface Init as Reset;
interface MLME_START;
- interface WriteBeaconField as SuperframeSpecWrite;
- interface Get<bool> as IsSendingBeacons;
- interface GetNow<uint32_t> as CapStart;
- interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
- interface GetNow<uint32_t> as CapLen;
- interface GetNow<uint32_t> as CapEnd;
- interface GetNow<uint32_t> as CfpEnd;
- interface GetNow<uint32_t> as CfpLen;
- interface GetNow<bool> as IsBLEActive;
- interface GetNow<uint16_t> as BLELen;
- interface GetNow<uint8_t*> as GtsField;
- interface GetNow<uint32_t> as SfSlotDuration;
- interface GetNow<uint32_t> as BeaconInterval;
- interface GetNow<uint8_t> as FinalCapSlot;
- interface GetNow<uint8_t> as NumGtsSlots;
- interface GetNow<bool> as BeaconFramePendingBit;
interface IEEE154TxBeaconPayload;
+ interface SuperframeStructure as OutgoingSF;
+ interface GetNow<bool> as IsSendingBeacons;
} uses {
interface Notify<bool> as GtsSpecUpdated;
interface Notify<bool> as PendingAddrSpecUpdated;
interface Notify<const void*> as PIBUpdate[uint8_t attributeID];
- interface Alarm<TSymbolIEEE802154,uint32_t> as BeaconTxAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as BeaconSendAlarm;
interface Timer<TSymbolIEEE802154> as BeaconPayloadUpdateTimer;
interface RadioOff;
- interface Get<bool> as IsBeaconEnabledPAN;
interface RadioTx as BeaconTx;
interface MLME_GET;
interface MLME_SET;
- interface Resource as Token;
- interface ResourceTransfer as TokenToBroadcast;
+ interface TransferableResource as RadioToken;
interface FrameTx as RealignmentBeaconEnabledTx;
interface FrameTx as RealignmentNonBeaconEnabledTx;
interface FrameRx as BeaconRequestRx;
interface WriteBeaconField as PendingAddrWrite;
interface FrameUtility;
interface GetNow<bool> as IsTrackingBeacons;
- interface GetNow<uint32_t> as LastBeaconRxTime;
- interface GetNow<ieee154_reftime_t*> as LastBeaconRxRefTime;
- interface Ieee802154Debug as Debug;
+ interface SuperframeStructure as IncomingSF;
interface Set<ieee154_macSuperframeOrder_t> as SetMacSuperframeOrder;
interface Set<ieee154_macBeaconTxTime_t> as SetMacBeaconTxTime;
interface Set<ieee154_macPanCoordinator_t> as SetMacPanCoordinator;
interface GetSet<ieee154_txframe_t*> as GetSetRealignmentFrame;
interface GetNow<bool> as IsBroadcastReady;
interface TimeCalc;
+ interface Random;
interface Leds;
}
}
implementation
{
+ /* state variables */
+ norace uint8_t m_requestBitmap;
+ norace uint8_t m_txState;
+ uint8_t m_payloadState;
+ norace bool m_txOneBeaconImmediately;
+
+ /* variables that describe the current superframe configuration */
+ norace uint32_t m_startTime;
+ norace uint8_t m_beaconOrder;
+ norace uint8_t m_superframeOrder;
+ norace uint32_t m_beaconInterval;
+ norace uint32_t m_previousBeaconInterval;
+ norace uint32_t m_dt;
+ norace uint32_t m_lastBeaconTxTime;
+ norace ieee154_timestamp_t m_lastBeaconTxRefTime;
+ norace ieee154_macBattLifeExtPeriods_t m_battLifeExtPeriods;
+
+ /* variables that describe the latest superframe */
+ norace uint32_t m_sfSlotDuration;
+ norace bool m_framePendingBit;
+ norace uint8_t m_numCapSlots;
+ norace uint8_t m_numGtsSlots;
+ norace uint16_t m_battLifeExtDuration;
+ uint8_t m_gtsField[1+1+3*7];
+
+ /* variables that describe the beacon (payload) */
+ norace ieee154_txframe_t m_beaconFrame;
+ ieee154_header_t m_header;
+ ieee154_metadata_t m_metadata;
+ void *m_updateBeaconPayload;
+ uint8_t m_updateBeaconOffset;
+ uint8_t m_updateBeaconLength;
+ uint8_t m_beaconPayloadLen;
+ uint8_t m_pendingAddrLen;
+ uint8_t m_pendingGtsLen;
+
+ /* buffers for the parameters of the MLME-START request */
+ uint16_t m_updatePANId;
+ uint8_t m_updateLogicalChannel;
+ uint32_t m_updateStartTime;
+ norace uint8_t m_updateBeaconOrder;
+ uint8_t m_updateSuperframeOrder;
+ bool m_updatePANCoordinator;
+ bool m_updateBatteryLifeExtension;
enum {
MAX_BEACON_PAYLOAD_SIZE = IEEE154_aMaxBeaconOverhead + IEEE154_aMaxBeaconPayloadLength,
S_TX_LOCKED = 1,
S_TX_WAITING = 2,
};
-
- norace ieee154_txframe_t m_beaconFrame;
- ieee154_header_t m_header;
uint8_t m_payload[MAX_BEACON_PAYLOAD_SIZE];
- ieee154_metadata_t m_metadata;
- uint8_t m_gtsField[1+1+3*7];
-
- void *m_updateBeaconPayload;
- uint8_t m_updateBeaconOffset;
- uint8_t m_updateBeaconLength;
- uint8_t m_beaconPayloadLen;
- uint8_t m_pendingAddrLen;
- uint8_t m_pendingGtsLen;
-
- norace uint8_t m_requests; // TODO: check why norace?
- norace uint8_t m_txState;
- uint8_t m_payloadState;
- norace bool m_txOneBeaconImmediately;
-
- uint16_t m_PANId;
- norace uint32_t m_startTime;
- uint8_t m_logicalChannel;
- norace uint8_t m_beaconOrder;
- norace uint8_t m_superframeOrder;
- ieee154_macBattLifeExt_t m_batteryLifeExtension;
- bool m_PANCoordinator;
- norace uint32_t m_beaconInterval;
- norace uint32_t m_previousBeaconInterval;
- norace uint32_t m_dt;
- norace uint8_t m_bsn;
- norace uint32_t m_lastBeaconTxTime;
- norace ieee154_reftime_t m_lastBeaconTxRefTime;
- norace uint32_t m_coordCapLen;
- norace uint32_t m_coordCfpEnd;
- norace uint32_t m_sfSlotDuration;
- norace uint8_t m_finalCAPSlot;
- norace uint8_t m_numGtsSlots;
- norace uint16_t m_BLELen;
- norace ieee154_macBattLifeExtPeriods_t m_battLifeExtPeriods;
- norace bool m_framePendingBit;
-
- uint16_t m_updatePANId;
- uint8_t m_updateLogicalChannel;
- uint32_t m_updateStartTime;
- uint8_t m_updateBeaconOrder;
- uint8_t m_updateSuperframeOrder;
- bool m_updatePANCoordinator;
- bool m_updateBatteryLifeExtension;
+ /* function/task prototypes */
task void txDoneTask();
task void signalStartConfirmSuccessTask();
- void prepareNextBeaconTransmission();
+ void nextRound();
+ void prepareBeaconTransmission();
void continueStartRequest();
void finishRealignment(ieee154_txframe_t *frame, ieee154_status_t status);
command error_t Reset.init()
{
+ // reset this component, will only be called while we're not owning the token
+ // TODO: check to signal MLME_START.confirm ?
+
+ call MLME_SET.macBSN(call Random.rand16());
m_beaconFrame.header = &m_header;
m_beaconFrame.headerLen = 0;
m_beaconFrame.payload = m_payload;
m_beaconFrame.payloadLen = 0;
m_beaconFrame.metadata = &m_metadata;
- m_updateBeaconPayload = 0;
+ m_updateBeaconPayload = NULL;
m_updateBeaconLength = 0;
- m_requests = m_payloadState = m_txState = 0;
- m_PANCoordinator = FALSE;
+ m_requestBitmap = m_payloadState = m_txState = 0;
m_beaconPayloadLen = m_pendingAddrLen = m_pendingGtsLen = 0;
m_gtsField[0] = 0;
- m_finalCAPSlot = 15;
+ m_numCapSlots = 0;
+ m_numGtsSlots = 0;
m_beaconOrder = 15;
call BeaconPayloadUpdateTimer.stop();
- call BeaconTxAlarm.stop();
+ call BeaconSendAlarm.stop();
return SUCCESS;
}
-/* ----------------------- MLME-START ----------------------- */
-/* "The MLME-START.request primitive allows the PAN coordinator to initiate a
- * new PAN or to begin using a new superframe configuration. This primitive may
- * also be used by a device already associated with an existing PAN to begin
- * using a new superframe configuration." (IEEE 802.15.4-2006 Sect. 7.1.14.1)
- **/
+ /* ----------------------- MLME-START ----------------------- */
+ /* "The MLME-START.request primitive allows the PAN coordinator to initiate a
+ * new PAN or to begin using a new superframe configuration. This primitive may
+ * also be used by a device already associated with an existing PAN to begin
+ * using a new superframe configuration." (IEEE 802.15.4-2006 Sect. 7.1.14.1)
+ **/
command ieee154_status_t MLME_START.request (
uint16_t panID,
ieee154_security_t *coordRealignSecurity,
ieee154_security_t *beaconSecurity)
{
- ieee154_macShortAddress_t shortAddress = call MLME_GET.macShortAddress();
ieee154_status_t status = IEEE154_SUCCESS;
+ ieee154_macShortAddress_t shortAddress = call MLME_GET.macShortAddress();
+ // check parameters
if ((coordRealignSecurity && coordRealignSecurity->SecurityLevel) ||
(beaconSecurity && beaconSecurity->SecurityLevel))
status = IEEE154_UNSUPPORTED_SECURITY;
status = IEEE154_INVALID_PARAMETER;
else if (startTime && !call IsTrackingBeacons.getNow())
status = IEEE154_TRACKING_OFF;
- else if (startTime && 0xFF000000)
+ else if (startTime & 0xFF000000)
status = IEEE154_INVALID_PARAMETER;
- else if (m_requests & (REQUEST_CONFIRM_PENDING | REQUEST_UPDATE_SF))
+ else if (m_requestBitmap & (REQUEST_CONFIRM_PENDING | REQUEST_UPDATE_SF))
status = IEEE154_TRANSACTION_OVERFLOW;
- else if ((call IsBeaconEnabledPAN.get() && beaconOrder > 14) ||
- (!call IsBeaconEnabledPAN.get() && beaconOrder < 15))
- status = IEEE154_INVALID_PARAMETER;
else {
- // new configuration *will* be put in operation
- status = IEEE154_SUCCESS;
+
+ // New configuration *will* be put in operation, we'll buffer
+ // the parameters now, and continue once we get the token.
if (panCoordinator)
- startTime = 0; // start immediately
- call Debug.log(LEVEL_INFO, StartP_REQUEST, logicalChannel, beaconOrder, superframeOrder);
- if (beaconOrder == 15){
- // beaconless PAN
- superframeOrder = 15;
- }
+ startTime = 0; // start immediately
+ if (beaconOrder == 15)
+ superframeOrder = 15; // beaconless PAN
m_updatePANId = panID;
m_updateLogicalChannel = logicalChannel;
m_updateStartTime = startTime;
m_updateSuperframeOrder = superframeOrder;
m_updatePANCoordinator = panCoordinator;
m_updateBatteryLifeExtension = batteryLifeExtension;
- m_requests = (REQUEST_CONFIRM_PENDING | REQUEST_UPDATE_SF); // lock
+ m_requestBitmap = (REQUEST_CONFIRM_PENDING | REQUEST_UPDATE_SF); // lock
+
if (coordRealignment)
- m_requests |= REQUEST_REALIGNMENT;
- if (!call IsSendingBeacons.get())
- call Token.request();
+ m_requestBitmap |= REQUEST_REALIGNMENT;
+ if (m_beaconOrder == 15) {
+ // We're not already transmitting beacons, i.e. we have to request the token
+ // (otherwise we'd get the token "automatically" for the next scheduled beacon).
+ call RadioToken.request();
+ }
+ // We'll continue the MLME_START operation in continueStartRequest() once we have the token
}
+ dbg_serial("BeaconTransmitP", "MLME_START.request -> result: %lu\n", (uint32_t) status);
return status;
}
bool isShortAddr;
// (1) coord realignment?
- if (m_requests & REQUEST_REALIGNMENT){
+ if (m_requestBitmap & REQUEST_REALIGNMENT) {
ieee154_txframe_t *realignmentFrame = call GetSetRealignmentFrame.get();
- m_requests &= ~REQUEST_REALIGNMENT;
- if (realignmentFrame == NULL){
+ m_requestBitmap &= ~REQUEST_REALIGNMENT;
+ if (realignmentFrame == NULL) {
// allocation failed!
- m_requests = 0;
+ m_requestBitmap = 0;
signal MLME_START.confirm(IEEE154_TRANSACTION_OVERFLOW);
return;
}
*((nxle_uint16_t*) &realignmentFrame->payload[6]) = 0xFFFF;
realignmentFrame->payloadLen = 8;
- if (call IsSendingBeacons.get()){
+ if (m_beaconOrder < 15) {
// we're already transmitting beacons; the realignment frame
// must be sent (broadcast) after the next beacon
- if (call RealignmentBeaconEnabledTx.transmit(realignmentFrame) != IEEE154_SUCCESS){
- m_requests = 0;
+ if (call RealignmentBeaconEnabledTx.transmit(realignmentFrame) != IEEE154_SUCCESS) {
+ m_requestBitmap = 0;
call GetSetRealignmentFrame.set(realignmentFrame);
signal MLME_START.confirm(IEEE154_TRANSACTION_OVERFLOW);
} else {
// the next beacon - the result will be signalled in
// RealignmentBeaconEnabledTx.transmitDone(). Only then the superframe
// structure is updated and MLME_START.confirm signalled.
- m_requests |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
+ m_requestBitmap |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
}
} else {
// send realignment frame in unslotted csma-ca now
- if (call RealignmentNonBeaconEnabledTx.transmit(realignmentFrame) != IEEE154_SUCCESS){
- m_requests = 0;
+ if (call RealignmentNonBeaconEnabledTx.transmit(realignmentFrame) != IEEE154_SUCCESS) {
+ m_requestBitmap = 0;
call GetSetRealignmentFrame.set(realignmentFrame);
signal MLME_START.confirm(IEEE154_TRANSACTION_OVERFLOW);
} else {
// be signalled in RealignmentNonBeaconEnabledTx.transmitDone(). Only
// then the superframe structure is updated and MLME_START.confirm
// signalled.
- m_requests |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
+ m_requestBitmap |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
}
}
return;
m_startTime = m_updateStartTime;
m_txOneBeaconImmediately = FALSE;
m_previousBeaconInterval = 0;
- if (m_startTime){
- m_lastBeaconTxRefTime = *call LastBeaconRxRefTime.getNow();
- m_lastBeaconTxTime = call LastBeaconRxTime.getNow();
+ if (m_startTime) {
+ memcpy(&m_lastBeaconTxRefTime, call IncomingSF.sfStartTimeRef(), sizeof(ieee154_timestamp_t));
+ m_lastBeaconTxTime = call IncomingSF.sfStartTime();
} else {
// no StartTime defined by next higher layer - but
// if a realignment frame was transmitted, the next
// beacon tx time must take the old BI into consideration
- if (m_requests & REQUEST_REALIGNMENT_DONE_PENDING)
+ if (m_requestBitmap & REQUEST_REALIGNMENT_DONE_PENDING)
m_previousBeaconInterval = m_beaconInterval;
else
m_txOneBeaconImmediately = TRUE;
}
- m_PANId = m_updatePANId;
- m_logicalChannel = m_updateLogicalChannel;
m_beaconOrder = m_updateBeaconOrder;
m_superframeOrder = m_updateSuperframeOrder;
- m_PANCoordinator = m_updatePANCoordinator;
- if (m_beaconOrder < 15){
- m_batteryLifeExtension = m_updateBatteryLifeExtension;
+ if (m_beaconOrder < 15) {
m_beaconInterval = ((uint32_t) 1 << m_updateBeaconOrder) * IEEE154_aBaseSuperframeDuration;
} else {
- m_batteryLifeExtension = FALSE;
m_beaconInterval = 0;
}
+ m_dt = m_beaconInterval;
m_txState = S_TX_IDLE;
- m_bsn = call MLME_GET.macBSN()+1;
m_battLifeExtPeriods = call MLME_GET.macBattLifeExtPeriods();
// (3) update PIB
call MLME_SET.macBeaconOrder(m_beaconOrder);
call SetMacSuperframeOrder.set(m_superframeOrder);
- call MLME_SET.macPANId(m_PANId);
- call MLME_SET.phyCurrentChannel(m_logicalChannel);
+ call MLME_SET.macPANId(m_updatePANId);
+ call MLME_SET.phyCurrentChannel(m_updateLogicalChannel);
if (m_beaconOrder < 15)
- call MLME_SET.macBattLifeExt(m_batteryLifeExtension);
- call SetMacPanCoordinator.set(m_PANCoordinator);
+ call MLME_SET.macBattLifeExt(m_updateBatteryLifeExtension);
+ call SetMacPanCoordinator.set(m_updatePANCoordinator);
// (4) assemble beacon header and payload
shortAddress = call MLME_GET.macShortAddress();
isShortAddr = (shortAddress != 0xFFFE);
m_beaconFrame.header->mhr[MHR_INDEX_FC1] = FC1_FRAMETYPE_BEACON;
m_beaconFrame.header->mhr[MHR_INDEX_FC2] = isShortAddr ? FC2_SRC_MODE_SHORT : FC2_SRC_MODE_EXTENDED;
+ m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] = call MLME_GET.macBSN() + 1;
offset = MHR_INDEX_ADDRESS;
- *((nxle_uint16_t*) &m_beaconFrame.header->mhr[offset]) = m_PANId;
+ *((nxle_uint16_t*) &m_beaconFrame.header->mhr[offset]) = m_updatePANId;
offset += sizeof(ieee154_macPANId_t);
- if (isShortAddr){
+ if (isShortAddr) {
*((nxle_uint16_t*) &m_beaconFrame.header->mhr[offset]) = shortAddress;
offset += sizeof(ieee154_macShortAddress_t);
} else {
m_payloadState |= MODIFIED_SPECS_MASK; // update beacon payload
signal BeaconPayloadUpdateTimer.fired(); // assemble initial beacon payload
- if (m_beaconOrder < 15){
+ if (m_beaconOrder < 15) {
// beacon-enabled PAN, signal confirm after next
// beacon has been transmitted (see MSC, Fig. 38)
- m_requests = REQUEST_CONFIRM_PENDING;
+ m_requestBitmap = REQUEST_CONFIRM_PENDING;
} else {
// beaconless PAN, we're done
- m_requests = 0;
+ m_requestBitmap = 0;
signal MLME_START.confirm(IEEE154_SUCCESS);
}
}
- task void grantedTask()
+ task void signalGrantedTask()
{
- signal Token.granted();
+ signal RadioToken.granted();
}
- event void Token.granted()
+ event void RadioToken.granted()
{
- call Debug.flush();
- call Debug.log(LEVEL_INFO, StartP_GOT_RESOURCE, m_lastBeaconTxTime, m_beaconInterval, m_requests);
- if (m_requests & REQUEST_REALIGNMENT_DONE_PENDING){
- // unlikely to occur: we have not yet received a done()
+ dbg_serial("BeaconSynchronizeP","Token granted.\n");
+ if (m_requestBitmap & REQUEST_REALIGNMENT_DONE_PENDING) {
+ // very unlikely: we have not yet received a done()
// event after sending out a realignment frame
- post grantedTask(); // spin
+ dbg_serial("BeaconTransmitP", "Realignment pending (request: %lu) !\n", (uint32_t) m_requestBitmap);
+ post signalGrantedTask(); // spin
return;
- }
- if (m_requests & REQUEST_UPDATE_SF){
- m_requests &= ~REQUEST_UPDATE_SF;
+ } else if (m_requestBitmap & REQUEST_UPDATE_SF) {
+ dbg_serial("BeaconTransmitP","Putting new superframe spec into operation\n");
+ m_requestBitmap &= ~REQUEST_UPDATE_SF;
continueStartRequest();
- call Debug.log(LEVEL_INFO, StartP_UPDATE_STATE, 0, 0, 0);
}
+ nextRound();
+ }
+
+ void nextRound()
+ {
if (call RadioOff.isOff())
- prepareNextBeaconTransmission();
+ prepareBeaconTransmission();
else
- call RadioOff.off();
+ ASSERT(call RadioOff.off() == SUCCESS); // will continue in prepareBeaconTransmission()
}
+ async event void RadioToken.transferredFrom(uint8_t fromClientID)
+ {
+ dbg_serial("BeaconSynchronizeP","Token transferred, will Tx beacon in %lu\n",
+ (uint32_t) ((m_lastBeaconTxTime + m_dt) - call BeaconSendAlarm.getNow()));
+ if (m_requestBitmap & (REQUEST_REALIGNMENT_DONE_PENDING | REQUEST_UPDATE_SF))
+ post signalGrantedTask(); // need to be in sync context
+ else
+ nextRound();
+ }
+
async event void RadioOff.offDone()
{
- prepareNextBeaconTransmission();
+ prepareBeaconTransmission();
}
- void prepareNextBeaconTransmission()
+ void prepareBeaconTransmission()
{
- if (m_txState == S_TX_LOCKED){
+ if (m_txState == S_TX_LOCKED) {
// have not had time to finish processing the last sent beacon
- post grantedTask();
- call Debug.log(LEVEL_CRITICAL, StartP_OWNER_TOO_FAST, 0, 0, 0);
- return;
- } else if (m_beaconOrder > 14){
- call Token.release();
+ dbg_serial("BeaconTransmitP", "Token was returned too fast!\n");
+ post signalGrantedTask();
+ } else if (m_beaconOrder == 15) {
+ // we're not sending any beacons!?
+ dbg_serial("BeaconTransmitP", "Stop sending beacons.\n");
+ call RadioToken.release();
} else {
+ // get ready for next beacon transmission
atomic {
+ uint32_t delay = IEEE154_RADIO_TX_DELAY;
m_txState = S_TX_WAITING;
- if (m_txOneBeaconImmediately){
- signal BeaconTxAlarm.fired();
+ if (m_txOneBeaconImmediately) {
+ // transmit the beacon now
+ dbg_serial("BeaconTransmitP", "Sending a beacon immediately.\n");
+ signal BeaconSendAlarm.fired();
return;
- } else if (m_startTime != 0){
- // a new sf spec was put into operation, with a user-defined StartTime
+ } else if (m_startTime != 0) {
+ // a new sf spec was put into operation, with a user-defined StartTime
// here m_lastBeaconTxTime is actually the last time a beacon was received
+
+ dbg_serial("BeaconTransmitP", "First beacon to be sent at %lu.\n", m_startTime);
m_dt = m_startTime;
m_startTime = 0;
- } else if (m_previousBeaconInterval != 0){
- // a new sf spec was put into operation, after a realignment frame was
+ } else if (m_previousBeaconInterval != 0) {
+ // a new sf spec was put into operation, after a realignment frame
// broadcast; the next beacon time should still be calculated using the
// old BI (one last time)
+
+ dbg_serial("BeaconTransmitP", "Sending beacon after realignment dt=%lu.\n", m_previousBeaconInterval);
m_dt = m_previousBeaconInterval;
m_previousBeaconInterval = 0;
- if (m_requests & REQUEST_CONFIRM_PENDING){
+ if (m_requestBitmap & REQUEST_CONFIRM_PENDING) {
// only now the next higher layer is to be informed
- m_requests &= ~REQUEST_CONFIRM_PENDING;
+ m_requestBitmap &= ~REQUEST_CONFIRM_PENDING;
post signalStartConfirmSuccessTask();
}
- } else {
- // the usual case: next beacon tx time = last time + BI
- m_dt = m_beaconInterval;
}
- while (call TimeCalc.hasExpired(m_lastBeaconTxTime, m_dt)){ // missed sending a beacon
- call Debug.log(LEVEL_INFO, StartP_SKIPPED_BEACON, m_lastBeaconTxTime, m_dt, 0);
+
+ // The next beacon should be transmitted at time m_lastBeaconTxTime + m_dt, where m_dt
+ // is typically the beacon interval. First we check if we're still in time.
+ while (call TimeCalc.hasExpired(m_lastBeaconTxTime, m_dt)) {
+ // too late, we need to skip a beacon!
+ dbg_serial("BeaconTransmitP", "Skipping a beacon: scheduled=%lu, now=%lu.\n",
+ (uint32_t) m_lastBeaconTxTime + m_dt, (uint32_t) call BeaconSendAlarm.getNow());
m_dt += m_beaconInterval;
}
- if (m_dt < IEEE154_RADIO_TX_PREPARE_DELAY)
- m_dt = IEEE154_RADIO_TX_PREPARE_DELAY;
- // don't call BeaconTx.load just yet, otherwise the next
- // higher layer cannot modify the beacon payload anymore;
- // rather, set an alarm
- call BeaconTxAlarm.startAt(m_lastBeaconTxTime, m_dt - IEEE154_RADIO_TX_PREPARE_DELAY);
+ if (!call TimeCalc.hasExpired(m_lastBeaconTxTime - delay, m_dt)) {
+ // don't load the beacon frame in the radio just yet - rather set a timer and
+ // give the next higher layer the chance to modify the beacon payload
+ call BeaconSendAlarm.startAt(m_lastBeaconTxTime - delay, m_dt);
+ } else
+ signal BeaconSendAlarm.fired();
}
}
}
- async event void BeaconTxAlarm.fired()
+ task void signalStartConfirmSuccessTask()
{
- atomic {
- switch (m_txState)
- {
- case S_TX_WAITING:
- m_txState = S_TX_LOCKED;
- if (call IsBroadcastReady.getNow())
- m_beaconFrame.header->mhr[MHR_INDEX_FC1] |= FC1_FRAME_PENDING;
- else
- m_beaconFrame.header->mhr[MHR_INDEX_FC1] &= ~FC1_FRAME_PENDING;
- m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] = m_bsn; // update beacon seqno
- call Debug.log(LEVEL_INFO, StartP_PREPARE_TX, 0, m_lastBeaconTxTime, 0);
- call BeaconTx.load(&m_beaconFrame);
- break;
- case S_TX_LOCKED:
- call Debug.log(LEVEL_INFO, StartP_TRANSMIT, m_lastBeaconTxTime, m_dt, ((uint32_t)m_lastBeaconTxRefTime));
- call BeaconTx.transmit(&m_lastBeaconTxRefTime, m_dt, 0, FALSE);
- break;
- }
- }
+ signal MLME_START.confirm(SUCCESS);
}
- async event void BeaconTx.loadDone()
+ async event void BeaconSendAlarm.fired()
{
- atomic {
- call Debug.log(LEVEL_INFO, StartP_PREPARE_TXDONE, 0, m_lastBeaconTxTime, 0);
- if (m_txOneBeaconImmediately){
- m_txOneBeaconImmediately = FALSE;
- call BeaconTx.transmit(0, 0, 0, FALSE); // now!
- } else
- call BeaconTxAlarm.startAt(m_lastBeaconTxTime, m_dt - IEEE154_RADIO_TX_SEND_DELAY);
+ // start/schedule beacon transmission
+ ieee154_timestamp_t *timestamp = &m_lastBeaconTxRefTime;
+ m_txState = S_TX_LOCKED;
+
+ if (call IsBroadcastReady.getNow())
+ m_beaconFrame.header->mhr[MHR_INDEX_FC1] |= FC1_FRAME_PENDING;
+ else
+ m_beaconFrame.header->mhr[MHR_INDEX_FC1] &= ~FC1_FRAME_PENDING;
+
+ if (m_txOneBeaconImmediately) {
+ m_txOneBeaconImmediately = FALSE;
+ timestamp = NULL;
}
+ call BeaconTx.transmit(&m_beaconFrame, timestamp, m_dt);
+ dbg_serial("BeaconTransmitP","Beacon Tx scheduled for %lu.\n", (uint32_t) (*timestamp + m_dt));
}
-
- async event void BeaconTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool pendingFlag, error_t error)
+
+ async event void BeaconTx.transmitDone(ieee154_txframe_t *frame, const ieee154_timestamp_t *timestamp, error_t result)
{
- // Coord CAP has just started...
+ // The beacon frame was transmitted, i.e. the CAP has just started
+ // update the state then pass the token on to the next component
+
uint8_t gtsFieldLength;
- // Sec. 7.5.1.1: "start of slot 0 is defined as the point at which
- // the first symbol of the beacon PPDU is transmitted"
- call Debug.log(LEVEL_INFO, StartP_BEACON_TRANSMITTED, frame->metadata->timestamp, m_lastBeaconTxTime, m_dt);
- m_lastBeaconTxTime = frame->metadata->timestamp;
- memcpy(&m_lastBeaconTxRefTime, referenceTime, sizeof(ieee154_reftime_t));
- m_numGtsSlots = (frame->payload[2] & 0x07);
+
+ ASSERT(result == SUCCESS); // must succeed, we're sending without CCA or ACK request
+ if (timestamp != NULL) {
+ m_lastBeaconTxTime = frame->metadata->timestamp;
+ memcpy(&m_lastBeaconTxRefTime, timestamp, sizeof(ieee154_timestamp_t));
+ m_dt = m_beaconInterval; // transmit the next beacon at m_lastBeaconTxTime + m_dt
+ dbg_serial("BeaconTransmitP", "Beacon Tx success at %lu\n", (uint32_t) m_lastBeaconTxTime);
+ } else {
+ // Timestamp is invalid; this is bad. We need the beacon timestamp for the
+ // slotted CSMA-CA, because it defines the slot reference time. We can't use this superframe
+ // TODO: check if this was the initial beacon (then m_lastBeaconTxRefTime is invalid)
+ dbg_serial("BeaconTransmitP", "Invalid timestamp!\n");
+ m_dt += m_beaconInterval;
+ call RadioToken.request();
+ call RadioToken.release();
+ return;
+ }
+
+ // update superframe-related variables
+ m_numGtsSlots =
+ (frame->payload[BEACON_INDEX_GTS_SPEC] & GTS_DESCRIPTOR_COUNT_MASK) >> GTS_DESCRIPTOR_COUNT_OFFSET;
gtsFieldLength = 1 + ((m_numGtsSlots > 0) ? 1 + m_numGtsSlots * 3: 0);
- m_finalCAPSlot = (frame->payload[1] & 0x0F);
- m_sfSlotDuration = (((uint32_t) 1) << ((frame->payload[0] & 0xF0) >> 4)) * IEEE154_aBaseSlotDuration;
- if (frame->header->mhr[0] & FC1_FRAME_PENDING)
+ m_numCapSlots =
+ ((frame->payload[BEACON_INDEX_SF_SPEC2] & SF_SPEC2_FINAL_CAPSLOT_MASK) >> SF_SPEC2_FINAL_CAPSLOT_OFFSET) + 1;
+ m_sfSlotDuration =
+ (((uint32_t) 1) << ((frame->payload[BEACON_INDEX_SF_SPEC1] & SF_SPEC1_SO_MASK) >> SF_SPEC1_SO_OFFSET)) *
+ IEEE154_aBaseSlotDuration;
+
+ if (frame->header->mhr[MHR_INDEX_FC1] & FC1_FRAME_PENDING)
m_framePendingBit = TRUE;
else
m_framePendingBit = FALSE;
- memcpy(m_gtsField, &frame->payload[2], gtsFieldLength);
- if (frame->payload[1] & 0x10){
- // BLE is active; calculate the time offset from slot0
- m_BLELen = IEEE154_SHR_DURATION +
- (frame->headerLen + frame->payloadLen) * IEEE154_SYMBOLS_PER_OCTET;
- if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
- m_BLELen += IEEE154_MIN_LIFS_PERIOD;
+ memcpy(m_gtsField, &frame->payload[BEACON_INDEX_GTS_SPEC], gtsFieldLength);
+ if (frame->payload[BEACON_INDEX_SF_SPEC2] & SF_SPEC2_BATT_LIFE_EXT) {
+ // BLE is active; calculate the time offset from slot 0
+ m_battLifeExtDuration = IEEE154_SHR_DURATION +
+ (frame->headerLen + frame->payloadLen + 2) * IEEE154_SYMBOLS_PER_OCTET;
+ if (frame->headerLen + frame->payloadLen + 2 > IEEE154_aMaxSIFSFrameSize)
+ m_battLifeExtDuration += IEEE154_MIN_LIFS_PERIOD;
else
- m_BLELen += IEEE154_MIN_SIFS_PERIOD;
- m_BLELen += m_battLifeExtPeriods;
+ m_battLifeExtDuration += IEEE154_MIN_SIFS_PERIOD;
+ m_battLifeExtDuration = m_battLifeExtDuration + m_battLifeExtPeriods * 20;
} else
- m_BLELen = 0;
- call Token.request(); // register another request, before ...
- call TokenToBroadcast.transfer(); // ... we let Broadcast module take over
+ m_battLifeExtDuration = 0;
+
+ // we pass on the token now, but make a reservation to get it back
+ // to transmit the next beacon (at the start of the next superframe)
+ call RadioToken.request();
+ call RadioToken.transferTo(RADIO_CLIENT_COORDBROADCAST);
post txDoneTask();
}
task void txDoneTask()
{
- call MLME_SET.macBSN(m_bsn++);
+ call MLME_SET.macBSN(m_beaconFrame.header->mhr[MHR_INDEX_SEQNO]);
+ m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] += 1; // may be overwritten by the next higher layer
call SetMacBeaconTxTime.set(m_lastBeaconTxTime); // start of slot0, ie. first preamble byte of beacon
call BeaconPayloadUpdateTimer.startOneShotAt(m_lastBeaconTxTime,
(m_beaconInterval>BEACON_PAYLOAD_UPDATE_INTERVAL) ? (m_beaconInterval - BEACON_PAYLOAD_UPDATE_INTERVAL): 0);
- if (m_requests & REQUEST_CONFIRM_PENDING){
- m_requests &= ~REQUEST_CONFIRM_PENDING;
+ if (m_requestBitmap & REQUEST_CONFIRM_PENDING) {
+ m_requestBitmap &= ~REQUEST_CONFIRM_PENDING;
signal MLME_START.confirm(IEEE154_SUCCESS);
}
m_txState = S_TX_IDLE;
signal IEEE154TxBeaconPayload.beaconTransmitted();
- call Debug.flush();
+ dbg_serial_flush();
}
-/* ----------------------- Beacon Payload ----------------------- */
-/*
- * All access to the payload fields in the beacon happen
- * through a set of temporary variables/flags, and just before
- * the frame is loaded into the radio these changes are
- * propagated into the actual payload portion of the beacon frame.
- */
+ /* ----------------------- Beacon Payload ----------------------- */
+ /*
+ * All access to the payload fields in the beacon happen
+ * through a set of temporary variables/flags, and just before
+ * the frame is loaded into the radio these changes are
+ * written into the actual payload portion of the beacon frame.
+ */
command error_t IEEE154TxBeaconPayload.setBeaconPayload(void *beaconPayload, uint8_t length)
{
uint8_t getNumGtsSlots(uint8_t *gtsInfoField)
{
uint8_t i, num=0;
- for (i=0; i<(gtsInfoField[0] & GTS_DESCRIPTOR_COUNT_MASK); i++)
+ for (i=0; i<((gtsInfoField[0] & GTS_DESCRIPTOR_COUNT_MASK) >> GTS_DESCRIPTOR_COUNT_OFFSET); i++)
num += ((gtsInfoField[4+i*3] & GTS_LENGTH_MASK) >> GTS_LENGTH_OFFSET);
return num;
}
// in this order the MAC payload is updated:
// (1) pending addresses
// (2) GTS spec
- // (3) sf spec
+ // (3) SF spec
// (4) beacon payload (if there's enough time)
uint8_t len=0, *beaconSpecs = &m_payload[IEEE154_aMaxBeaconOverhead]; // going backwards
- uint8_t beaconPayloadUpdated = 0, numGtsSlots = 15 - m_finalCAPSlot;
+ uint8_t beaconPayloadUpdated = 0, numGtsSlots = m_numGtsSlots;
atomic {
if (m_txState == S_TX_LOCKED)
{
- call Debug.log(LEVEL_INFO, StartP_BEACON_UPDATE, 0, 0, m_txState);
+ dbg_serial("BeaconTransmitP", "BeaconPayloadUpdateTimer fired too late!\n");
return; // too late !
}
- if (m_payloadState & MODIFIED_PENDING_ADDR_FIELD){
+
+ // (1) update pending addresses
+ if (m_payloadState & MODIFIED_PENDING_ADDR_FIELD) {
len = call PendingAddrWrite.getLength();
beaconSpecs -= len;
call PendingAddrWrite.write(beaconSpecs, len);
- if (len != m_pendingAddrLen){
+ if (len != m_pendingAddrLen) {
m_pendingAddrLen = len;
m_payloadState |= MODIFIED_SPECS_MASK; // need to rewrite specs before
}
} else
beaconSpecs -= m_pendingAddrLen;
- if (m_payloadState & MODIFIED_GTS_FIELD){
+
+ // (2) update GTS spec
+ if (m_payloadState & MODIFIED_GTS_FIELD) {
len = call GtsInfoWrite.getLength();
beaconSpecs -= len;
call GtsInfoWrite.write(beaconSpecs, len);
numGtsSlots = getNumGtsSlots(beaconSpecs);
- if (len != m_pendingGtsLen || ((15-numGtsSlots) != m_finalCAPSlot)){
+ if (len != m_pendingGtsLen || ((15-numGtsSlots) != m_numCapSlots-1)) {
m_pendingGtsLen = len;
m_payloadState |= MODIFIED_SPECS_MASK; // need to rewrite specs before
}
} else
beaconSpecs -= m_pendingGtsLen;
+
+ // (3) update SF spec
beaconSpecs -= 2; // sizeof SF Spec
- if (m_payloadState & MODIFIED_SF_SPEC){
- call SuperframeSpecWrite.write(beaconSpecs, 2);
- beaconSpecs[1] &= 0xF0; // clear FinalCAPSlot field
- beaconSpecs[1] |= ((15-numGtsSlots) & 0x0F); // update FinalCAPSlot field
+ if (m_payloadState & MODIFIED_SF_SPEC) {
+ beaconSpecs[BEACON_INDEX_SF_SPEC1] =
+ (m_beaconOrder << SF_SPEC1_BO_OFFSET) | (m_superframeOrder << SF_SPEC1_SO_OFFSET);
+ beaconSpecs[BEACON_INDEX_SF_SPEC2] = 0;
+ if (call MLME_GET.macAssociationPermit())
+ beaconSpecs[BEACON_INDEX_SF_SPEC2] |= SF_SPEC2_ASSOCIATION_PERMIT;
+ if (call MLME_GET.macPanCoordinator())
+ beaconSpecs[BEACON_INDEX_SF_SPEC2] |= SF_SPEC2_PAN_COORD;
+ beaconSpecs[BEACON_INDEX_SF_SPEC2] |=
+ ((15-numGtsSlots) & SF_SPEC2_FINAL_CAPSLOT_MASK);
}
m_beaconFrame.payloadLen = (m_pendingAddrLen + m_pendingGtsLen + 2) + m_beaconPayloadLen;
m_beaconFrame.payload = beaconSpecs;
m_payloadState &= ~MODIFIED_SPECS_MASK; // clear flags
- } // end atomic (give BeaconTxAlarm.fired() the chance to execute)
+ } // end atomic (give BeaconSendAlarm.fired() the chance to execute)
+
signal IEEE154TxBeaconPayload.aboutToTransmit();
+ m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] = call MLME_GET.macBSN() + 1;
+
atomic {
+ // (4) try to update beacon payload
if (m_txState == S_TX_LOCKED)
{
- call Debug.log(LEVEL_INFO, StartP_BEACON_UPDATE_2, 0, 0, m_txState);
+ dbg_serial("BeaconTransmitP", "Not enough time for beacon payload update!\n");
return; // too late !
}
- if (m_payloadState & MODIFIED_BEACON_PAYLOAD){
+ if (m_payloadState & MODIFIED_BEACON_PAYLOAD) {
memcpy(&m_payload[IEEE154_aMaxBeaconOverhead + m_updateBeaconOffset],
m_updateBeaconPayload, m_updateBeaconLength);
beaconPayloadUpdated = (m_payloadState & MODIFIED_BEACON_PAYLOAD_MASK);
m_beaconFrame.payloadLen = (m_pendingAddrLen + m_pendingGtsLen + 2) + m_beaconPayloadLen;
m_payloadState &= ~MODIFIED_BEACON_PAYLOAD_MASK;
}
- if (beaconPayloadUpdated){
+ if (beaconPayloadUpdated) {
if ((beaconPayloadUpdated & MODIFIED_BEACON_PAYLOAD_NEW))
signal IEEE154TxBeaconPayload.setBeaconPayloadDone(m_updateBeaconPayload, m_updateBeaconLength);
else
}
}
-/* ----------------------- SuperframeSpec ----------------------- */
-
- command uint8_t SuperframeSpecWrite.write(uint8_t *superframeSpecField, uint8_t maxlen)
- {
- if (call SuperframeSpecWrite.getLength() > maxlen)
- return 0;
- superframeSpecField[0] = m_beaconOrder | (m_superframeOrder << 4);
- superframeSpecField[1] = m_finalCAPSlot;
- if (m_PANCoordinator)
- superframeSpecField[1] |= SF_SPEC2_PAN_COORD;
- if (call MLME_GET.macAssociationPermit())
- superframeSpecField[1] |= SF_SPEC2_ASSOCIATION_PERMIT;
- return 2;
- }
-
- command uint8_t SuperframeSpecWrite.getLength()
- {
- return 2;
- }
-
-/* ----------------------- Realignment ----------------------- */
-/* In beacon-enabled mode a realignment frame was broadcast in the CAP
- * immediately after the beacon was transmitted. In non-beacon-enabled mode a
- * realignment frame was sent using unslotted CSMA. In both cases, if the
- * transmission was successful, the superframe spec must be updated now.
- **/
+ /* ----------------------- Realignment ----------------------- */
+ /* In beaconenabled mode a realignment frame is broadcast in the CAP
+ * immediately after the beacon was transmitted. In non-beaconenabled mode a
+ * realignment frame is sent using unslotted CSMA. In both cases, if the
+ * transmission was successful, the superframe spec should be updated now.
+ **/
event void RealignmentBeaconEnabledTx.transmitDone(ieee154_txframe_t *frame, ieee154_status_t status)
{
void finishRealignment(ieee154_txframe_t *frame, ieee154_status_t status)
{
call GetSetRealignmentFrame.set(frame);
- if (status == IEEE154_SUCCESS){
+ if (status == IEEE154_SUCCESS) {
continueStartRequest();
- m_requests &= ~REQUEST_REALIGNMENT_DONE_PENDING; // unlock
+ m_requestBitmap &= ~REQUEST_REALIGNMENT_DONE_PENDING; // unlock
// signal confirm where we calculate the next beacon transmission time
} else {
- m_requests = 0;
+ m_requestBitmap = 0;
signal MLME_START.confirm(status);
}
}
-/* ----------------------- BeaconRequest ----------------------- */
+ /* ----------------------- BeaconRequest ----------------------- */
event message_t* BeaconRequestRx.received(message_t* frame)
{
- if (!call IsSendingBeacons.get()){
+ if (m_beaconOrder == 15) {
// transmit the beacon frame using unslotted CSMA-CA
// TODO
}
return frame;
}
-/* ----------------------- Defaults, etc. ----------------------- */
+ /* ----------------------- SF Structure, etc. ----------------------- */
- task void signalStartConfirmSuccessTask()
- {
- signal MLME_START.confirm(SUCCESS);
+ async command uint32_t OutgoingSF.sfStartTime()
+ {
+ return m_lastBeaconTxTime;
}
- command bool IsSendingBeacons.get(){ return m_beaconOrder < 15;}
+ async command uint16_t OutgoingSF.sfSlotDuration()
+ {
+ return m_sfSlotDuration;
+ }
- async command uint32_t BeaconInterval.getNow() { return m_beaconInterval; }
- async command uint32_t CapStart.getNow() { return m_lastBeaconTxTime; }
- async command ieee154_reftime_t* CapStartRefTime.getNow() { return &m_lastBeaconTxRefTime; }
- async command uint32_t CapLen.getNow() { return call SfSlotDuration.getNow() * (call FinalCapSlot.getNow() + 1);}
- async command uint32_t CapEnd.getNow()
+ async command uint8_t OutgoingSF.numCapSlots()
{
- return call CapStart.getNow() + call CapLen.getNow();
+ return m_numCapSlots;
}
- async command uint32_t CfpEnd.getNow()
+
+ async command uint8_t OutgoingSF.numGtsSlots()
{
- return call CapStart.getNow() + call SfSlotDuration.getNow() * IEEE154_aNumSuperframeSlots;
+ return m_numGtsSlots;
}
- async command uint32_t CfpLen.getNow()
+
+ async command uint16_t OutgoingSF.battLifeExtDuration()
{
- return call SfSlotDuration.getNow() * (15 - call FinalCapSlot.getNow());
+ return m_battLifeExtDuration;
}
- async command bool IsBLEActive.getNow(){ return m_BLELen>0;}
- async command uint16_t BLELen.getNow(){ return m_BLELen;}
- async command bool BeaconFramePendingBit.getNow(){ return m_framePendingBit;}
- async command uint8_t* GtsField.getNow() { return m_gtsField; }
- async command uint32_t SfSlotDuration.getNow() { return m_sfSlotDuration; }
- async command uint8_t FinalCapSlot.getNow() { return m_finalCAPSlot; }
- async command uint8_t NumGtsSlots.getNow() { return m_numGtsSlots; }
+ async command const uint8_t* OutgoingSF.gtsFields()
+ {
+ return m_gtsField;
+ }
- default event void MLME_START.confirm (
- ieee154_status_t status
- ){}
+ async command uint16_t OutgoingSF.guardTime()
+ {
+ return IEEE154_MAX_BEACON_JITTER(m_beaconOrder) + IEEE154_RADIO_TX_DELAY;
+ }
- default event void IEEE154TxBeaconPayload.setBeaconPayloadDone(void *beaconPayload, uint8_t length){}
+ async command const ieee154_timestamp_t* OutgoingSF.sfStartTimeRef()
+ {
+ return &m_lastBeaconTxRefTime;
+ }
- default event void IEEE154TxBeaconPayload.modifyBeaconPayloadDone(uint8_t offset, void *buffer, uint8_t bufferLength){}
+ async command bool OutgoingSF.isBroadcastPending()
+ {
+ return m_framePendingBit;
+ }
- default event void IEEE154TxBeaconPayload.aboutToTransmit(){}
+ async command bool IsSendingBeacons.getNow()
+ {
+ return (m_beaconOrder < 15) || ((m_requestBitmap & REQUEST_CONFIRM_PENDING) && m_updateBeaconOrder < 15);
+ }
- default event void IEEE154TxBeaconPayload.beaconTransmitted(){}
+ default event void MLME_START.confirm(ieee154_status_t status) {}
+ default event void IEEE154TxBeaconPayload.setBeaconPayloadDone(void *beaconPayload, uint8_t length) {}
+ default event void IEEE154TxBeaconPayload.modifyBeaconPayloadDone(uint8_t offset, void *buffer, uint8_t bufferLength) {}
+ default event void IEEE154TxBeaconPayload.aboutToTransmit() {}
+ default event void IEEE154TxBeaconPayload.beaconTransmitted() {}
}