interface FrameExtracted as FrameExtracted[uint8_t frameType];
interface FrameTxNow as BroadcastTx;
interface Notify<bool> as WasRxEnabled;
+ interface Notify<bool> as FindBeacon;
}
uses
{
interface GetNow<bool> as IsRxBroadcastPending;
interface GetNow<bool> as IsRxEnableActive;
interface Notify<bool> as RxEnableStateChange;
+ interface GetNow<bool> as IsTrackingBeacons;
interface FrameUtility;
interface RadioTx;
interface RadioRx;
norace ieee154_txframe_t *m_bcastFrame;
norace ieee154_txframe_t *m_lastFrame;
norace ieee154_macMaxBE_t m_BE;
- norace ieee154_macMaxCSMABackoffs_t m_allowedBackoffs;
+ norace ieee154_macMaxBE_t m_NB;
+ norace ieee154_macMaxBE_t m_numCCA;
+ norace ieee154_macMaxCSMABackoffs_t m_macMaxCSMABackoffs;
+ norace ieee154_macMaxFrameRetries_t m_macMaxFrameRetries;
norace ieee154_macMaxBE_t m_macMaxBE;
+ norace ieee154_macMinBE_t m_macMinBE;
norace uint16_t m_backoff;
norace uint16_t m_backoffElapsed;
norace ieee154_status_t m_result;
norace bool m_indirectTxPending = FALSE;
norace bool m_broadcastRxPending;
norace ieee154_macMaxFrameTotalWaitTime_t m_macMaxFrameTotalWaitTime;
+ norace bool m_isBeaconEnabledPAN;
uint16_t generateRandomBackoff(uint8_t BE);
void stopAllAlarms();
signalTxBroadcastDone(m_bcastFrame, IEEE154_TRANSACTION_OVERFLOW);
m_currentFrame = m_lastFrame = m_bcastFrame = NULL;
m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
+ m_isBeaconEnabledPAN = call IsBeaconEnabledPAN.get();
stopAllAlarms();
return SUCCESS;
}
- async event void TokenTransferred.transferred()
+ event void TokenTransferred.transferred()
{
// we got the token, i.e. CAP has just started
uint32_t actualCapLen = call CapLen.getNow();
- if (actualCapLen < IEEE154_RADIO_GUARD_TIME){
+ if (m_isBeaconEnabledPAN && (DEVICE_ROLE && !call IsTrackingBeacons.getNow())){
+ // rare case: we're on a beacon-enabled PAN, not tracking beacons, searched
+ // and didn't find a beacon for aBaseSuperframeDuration*(2n+1) symbols
+ // -> transmit current frame using unslotted CSMA-CA
+ m_numCCA = 1;
+ signal Token.granted();
+ return;
+ }
+ else if (actualCapLen < IEEE154_RADIO_GUARD_TIME){
call Debug.log(LEVEL_IMPORTANT, CapP_TOO_SHORT, superframeDirection, actualCapLen, IEEE154_RADIO_GUARD_TIME);
call TokenToCfp.transfer();
return;
call CapEndAlarm.startAt(call CapStart.getNow(), actualCapLen);
if (call IsBLEActive.getNow())
call BLEAlarm.startAt(call CapStart.getNow(), call BLELen.getNow());
- call Debug.log(LEVEL_IMPORTANT, CapP_SET_CAP_END, call CapStart.getNow(), actualCapLen, call CapStart.getNow()+ actualCapLen);
+ call Debug.log(LEVEL_IMPORTANT, CapP_SET_CAP_END, call CapStart.getNow(),
+ actualCapLen, call CapStart.getNow()+ actualCapLen);
}
updateState();
+ call Debug.flush();
}
command ieee154_status_t CapTx.transmit(ieee154_txframe_t *frame)
return IEEE154_TRANSACTION_OVERFLOW;
else {
setCurrentFrame(frame);
- updateState();
+ if (!m_isBeaconEnabledPAN){
+ call Token.request(); // prepare for unslotted CSMA-CA
+ } else {
+ // a beacon must be found before transmitting in a beacon-enabled PAN
+ if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()){
+ signal FindBeacon.notify(TRUE);
+ // we'll receive the Token at latest after aBaseSuperframeDuration*(2n+1) symbols;
+ // if the beacon was not found, then we'll send the frame using unslotted CSMA-CA
+ }
+ updateState();
+ }
return IEEE154_SUCCESS;
}
}
ieee154_macDSN_t dsn = call MLME_GET.macDSN();
frame->header->mhr[MHR_INDEX_SEQNO] = dsn++;
call MLME_SET.macDSN(dsn);
- // m_allowedBackoffs will be decreased in every iteration (at zero the transmission failed)
- m_allowedBackoffs = call MLME_GET.macMaxCSMABackoffs();
+ m_macMaxCSMABackoffs = call MLME_GET.macMaxCSMABackoffs();
+ m_macMaxFrameRetries = call MLME_GET.macMaxFrameRetries();
m_macMaxBE = call MLME_GET.macMaxBE();
- m_BE = call MLME_GET.macMinBE();
- if (call MLME_GET.macBattLifeExt() && m_BE > 2)
- m_BE = 2;
+ m_macMinBE = call MLME_GET.macMinBE();
+ if (call MLME_GET.macBattLifeExt() && m_macMinBE > 2)
+ m_macMinBE = 2;
+ m_BE = m_macMinBE;
+ if (m_isBeaconEnabledPAN)
+ m_numCCA = 2;
+ else
+ m_numCCA = 1;
+ m_NB = 0;
m_transactionTime = IEEE154_SHR_DURATION +
(frame->headerLen + frame->payloadLen) * IEEE154_SYMBOLS_PER_OCTET;
- if (frame->header->mhr[0] & FC1_ACK_REQUEST)
+ if (frame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST)
m_transactionTime += (IEEE154_aTurnaroundTime + IEEE154_aUnitBackoffPeriod +
11 * IEEE154_SYMBOLS_PER_OCTET);
if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
return;
m_lock = TRUE; // lock
- // Check 1: has the CAP finished?
- if (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_RADIO_GUARD_TIME) ||
- !call CapEndAlarm.isRunning()){
+ // Check 1: for beacon-enabled PANs, has the CAP finished?
+ if (m_isBeaconEnabledPAN
+ && (COORD_ROLE || call IsTrackingBeacons.getNow()) // FALSE only if device could't find a beacon
+ && (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_RADIO_GUARD_TIME) ||
+ !call CapEndAlarm.isRunning())){
if (call RadioOff.isOff()) {
stopAllAlarms(); // may still fire, locked through isOwner()
if (DEVICE_ROLE && m_indirectTxPending)
// Check 8: just make sure the radio is switched off
else {
next = trySwitchOff();
+ if (next == DO_NOTHING && (!m_isBeaconEnabledPAN || (DEVICE_ROLE && !call IsTrackingBeacons.getNow()))){
+ // nothing more to do... just release the Token
+ m_lock = FALSE; // unlock
+ call TokenToCfp.transfer();
+ return;
+ }
}
// if there is nothing to do, then we must clear the lock
// in other module variables (m_backoff, etc.)
next_state_t next;
if (call RadioTx.getLoadedFrame() == m_currentFrame){
- // the frame is already loaded -> transmit it now (if there's enough time)
- uint32_t capLen = call CapLen.getNow(), capStart = call CapStart.getNow();
- uint32_t elapsed, totalTime;
- totalTime = IEEE154_RADIO_TX_SEND_DELAY +
- m_backoff - m_backoffElapsed + m_transactionTime + IEEE154_RADIO_GUARD_TIME;
- if (totalTime > capLen)
- totalTime = capLen; // CAP is too short
- elapsed = call TimeCalc.timeElapsed(capStart, call CapEndAlarm.getNow());
- elapsed += (20 - (elapsed % 20)); // round to backoff boundary
- if (!call TimeCalc.hasExpired(capStart, capLen - totalTime)){
- call RadioTx.transmit(call CapStartRefTime.getNow(),
- elapsed + IEEE154_RADIO_TX_SEND_DELAY + m_backoff - m_backoffElapsed,
- 2,
- m_currentFrame->header->mhr[0] & FC1_ACK_REQUEST ? TRUE : FALSE);
- next = WAIT_FOR_TXDONE; // ATTENTION: this will NOT clear the lock
+ // the frame is already loaded -> transmit it now
+ if (m_numCCA == 1){
+ // unslotted CSMA-CA
+ call RadioTx.transmit(NULL, m_backoff, m_numCCA, m_currentFrame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST ? TRUE : FALSE);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
} else {
- // frame does not fit in remaing portion of the CAP
- if (elapsed < call CapLen.getNow()){
- m_backoffElapsed += call CapLen.getNow() - elapsed;
- if (m_backoffElapsed > m_backoff)
- m_backoffElapsed = m_backoff;
+ // slotted CSMA-CA
+ uint32_t capLen = call CapLen.getNow(), capStart = call CapStart.getNow();
+ uint32_t elapsed, totalTime;
+ totalTime = IEEE154_RADIO_TX_SEND_DELAY +
+ m_backoff - m_backoffElapsed + m_transactionTime + IEEE154_RADIO_GUARD_TIME;
+ if (totalTime > capLen)
+ totalTime = capLen; // CAP is too short
+ elapsed = call TimeCalc.timeElapsed(capStart, call CapEndAlarm.getNow());
+ elapsed += (20 - (elapsed % 20)); // round to backoff boundary
+ if (!call TimeCalc.hasExpired(capStart, capLen - totalTime)){
+ call RadioTx.transmit(call CapStartRefTime.getNow(),
+ elapsed + IEEE154_RADIO_TX_SEND_DELAY + m_backoff - m_backoffElapsed,
+ m_numCCA,
+ m_currentFrame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST ? TRUE : FALSE);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
+ } else {
+ // frame does not fit in remaing portion of the CAP
+ if (elapsed < call CapLen.getNow()){
+ m_backoffElapsed += call CapLen.getNow() - elapsed;
+ if (m_backoffElapsed > m_backoff)
+ m_backoffElapsed = m_backoff;
+ }
+ next = SWITCH_OFF;
}
- next = SWITCH_OFF;
}
} else {
// the frame to transmit has not yet been loaded -> load it now
next = SWITCH_OFF;
else {
if (m_lastFrame){
- // we just transmitted a frame and have not yet
- // signalled the done to the upper layer -> wait
+ // the done event for the previous frame has not yet been
+ // signalled to the upper layer -> wait
next = DO_NOTHING;
} else
next = LOAD_TX;
async event void RadioTx.transmitDone(ieee154_txframe_t *frame,
ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
- {
+ {
+ bool retry = FALSE;
switch (error)
{
- case SUCCESS:
+ case SUCCESS:
m_result = IEEE154_SUCCESS;
if (DEVICE_ROLE && frame->payload[0] == CMD_FRAME_DATA_REQUEST &&
((frame->header->mhr[MHR_INDEX_FC1]) & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_CMD){
}
}
break;
- case EBUSY:
+ case EBUSY:
+ // we're following the SDL Spec in IEEE 802.15.4-2003 Annex D
m_result = IEEE154_CHANNEL_ACCESS_FAILURE;
- if (m_allowedBackoffs > 0){
- m_allowedBackoffs -= 1;
+ m_NB += 1;
+ if (m_NB < m_macMaxCSMABackoffs){
m_BE += 1;
if (m_BE > m_macMaxBE)
m_BE = m_macMaxBE;
- m_backoff = generateRandomBackoff(m_BE) * IEEE154_aUnitBackoffPeriod; // next backoff
- m_backoffElapsed = 0;
- m_lock = FALSE;
- updateState();
- return;
+ retry = TRUE;
}
break;
- case ENOACK:
+ case ENOACK:
+ // we're following the SDL Spec in IEEE 802.15.4-2003 Annex D
m_result = IEEE154_NO_ACK;
+ m_NB += 1;
+ // shouldn't the next check be (m_NB-1 < m_macMaxFrameRetries)? but
+ // on the other hand, NB is used for CHANNEL_ACCESS_FAILURE and NO_ACK,
+ // i.e. m_NB does not tell us much about past retransmissions anyway...
+ if (m_NB < m_macMaxFrameRetries){
+ m_BE = m_macMinBE;
+ retry = TRUE;
+ }
break;
default: break;
}
- if (COORD_ROLE && frame == m_bcastFrame){
+ if (retry){
+ m_backoff = generateRandomBackoff(m_BE) * IEEE154_aUnitBackoffPeriod; // next backoff
+ m_backoffElapsed = 0;
+ } else if (COORD_ROLE && frame == m_bcastFrame){
// signal result of broadcast transmissions immediately
restoreFrameFromBackup();
signalTxBroadcastDone(m_bcastFrame, m_result);
void backupCurrentFrame()
{
- ieee154_cap_frame_backup_t backup = {m_currentFrame, m_BE, m_allowedBackoffs,
- m_macMaxBE, m_backoff, m_backoffElapsed, m_transactionTime};
+ ieee154_cap_frame_backup_t backup = {m_currentFrame, m_BE, m_macMaxCSMABackoffs,
+ m_macMaxBE, m_macMinBE, m_NB, m_backoff, m_backoffElapsed, m_transactionTime};
call FrameBackup.setNow(&backup);
}
if (backup != NULL){
m_currentFrame = backup->frame;
m_BE = backup->BE;
- m_allowedBackoffs = backup->allowedBackoffs;
+ m_macMaxCSMABackoffs = backup->allowedBackoffs;
m_macMaxBE = backup->macMaxBE;
+ m_macMinBE = backup->macMinBE;
+ m_NB = backup->NB;
m_backoff = backup->backoff;
m_backoffElapsed = backup->backoffElapsed;
m_transactionTime = backup->transactionTime;
signal WasRxEnabled.notify(TRUE);
}
- async event void TokenRequested.requested() {}
+ bool isUnslottedCSMA_CA()
+ {
+ return (m_numCCA == 1);
+ }
+
+ event void Token.granted()
+ {
+ // the current frame should be transmitted using unslotted CSMA-CA
+ updateState();
+ }
+
+ task void tokenRequestedTask()
+ {
+ signal TokenRequested.requested();
+ }
+
+ async event void TokenRequested.requested()
+ {
+ atomic {
+ if (call Token.isOwner()){
+ if (!m_lock && !(DEVICE_ROLE && m_indirectTxPending) && !(COORD_ROLE && m_bcastFrame))
+ call Token.release();
+ else
+ post tokenRequestedTask();
+ }
+ }
+ }
+
async event void TokenRequested.immediateRequested() {}
- event void Token.granted(){}
default event void CapTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status){}
default event message_t* FrameRx.received[uint8_t client](message_t* data){return data;}
command error_t WasRxEnabled.enable(){return FAIL;}
command error_t WasRxEnabled.disable(){return FAIL;}
+ command error_t FindBeacon.enable(){return FAIL;}
+ command error_t FindBeacon.disable(){return FAIL;}
}