X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=blobdiff_plain;f=tos%2Flib%2Fmac%2Ftkn154%2FBeaconTransmitP.nc;h=7ddc5a284746da7e24372e5a2d1378fa4d4e43f4;hp=3d0dd438868e2ffc290d7b6aa36890e5ed3b52f5;hb=e9bfab607e051bae6afb47b44892ce37541d1b44;hpb=adf1de6c009d13b7b52e68535c63b28f59c97400 diff --git a/tos/lib/mac/tkn154/BeaconTransmitP.nc b/tos/lib/mac/tkn154/BeaconTransmitP.nc index 3d0dd438..7ddc5a28 100644 --- a/tos/lib/mac/tkn154/BeaconTransmitP.nc +++ b/tos/lib/mac/tkn154/BeaconTransmitP.nc @@ -33,6 +33,11 @@ * ======================================================================== */ +/** + * This module is responsible for periodic beacon transmission in a + * beacon-enabled PAN. + */ + #include "TKN154_MAC.h" #include "TKN154_PHY.h" module BeaconTransmitP @@ -41,36 +46,20 @@ module BeaconTransmitP { interface Init as Reset; interface MLME_START; - interface WriteBeaconField as SuperframeSpecWrite; - interface Get as IsSendingBeacons; - interface GetNow as CapStart; - interface GetNow as CapStartRefTime; - interface GetNow as CapLen; - interface GetNow as CapEnd; - interface GetNow as CfpEnd; - interface GetNow as CfpLen; - interface GetNow as IsBLEActive; - interface GetNow as BLELen; - interface GetNow as GtsField; - interface GetNow as SfSlotDuration; - interface GetNow as BeaconInterval; - interface GetNow as FinalCapSlot; - interface GetNow as NumGtsSlots; - interface GetNow as BeaconFramePendingBit; interface IEEE154TxBeaconPayload; + interface SuperframeStructure as OutgoingSF; + interface GetNow as IsSendingBeacons; } uses { interface Notify as GtsSpecUpdated; interface Notify as PendingAddrSpecUpdated; interface Notify as PIBUpdate[uint8_t attributeID]; - interface Alarm as BeaconTxAlarm; + interface Alarm as BeaconSendAlarm; interface Timer as BeaconPayloadUpdateTimer; interface RadioOff; - interface Get 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; @@ -78,20 +67,63 @@ module BeaconTransmitP interface WriteBeaconField as PendingAddrWrite; interface FrameUtility; interface GetNow as IsTrackingBeacons; - interface GetNow as LastBeaconRxTime; - interface GetNow as LastBeaconRxRefTime; - interface Ieee802154Debug as Debug; + interface SuperframeStructure as IncomingSF; interface Set as SetMacSuperframeOrder; interface Set as SetMacBeaconTxTime; interface Set as SetMacPanCoordinator; interface GetSet as GetSetRealignmentFrame; interface GetNow 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, @@ -114,87 +146,46 @@ implementation 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, @@ -209,9 +200,10 @@ implementation 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; @@ -224,23 +216,18 @@ implementation 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; @@ -248,12 +235,18 @@ implementation 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; } @@ -264,12 +257,12 @@ implementation 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; } @@ -282,11 +275,11 @@ implementation *((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 { @@ -294,12 +287,12 @@ implementation // 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 { @@ -307,7 +300,7 @@ implementation // 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; @@ -317,52 +310,48 @@ implementation 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 { @@ -373,190 +362,228 @@ implementation 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) { @@ -628,7 +655,7 @@ implementation 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; } @@ -638,56 +665,72 @@ implementation // 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); @@ -697,7 +740,7 @@ implementation 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 @@ -706,32 +749,12 @@ implementation } } -/* ----------------------- 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) { @@ -746,71 +769,83 @@ implementation 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() {} }