]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/mac/tkn154/CapP.nc
Proper MSP_BSL_FLAGS for telosa and telosb based platforms using TMI modular tos...
[tinyos-2.x.git] / tos / lib / mac / tkn154 / CapP.nc
index c07ccc56db960a79ee6667dbec5912253885ab43..2fec1c0a8ad744e974ae2068d180c07dd6bdb8c2 100644 (file)
@@ -59,6 +59,7 @@ generic module CapP(uint8_t superframeDirection)
     interface FrameExtracted as FrameExtracted[uint8_t frameType];
     interface FrameTxNow as BroadcastTx;
     interface Notify<bool> as WasRxEnabled;
+    interface Notify<bool> as FindBeacon;
   }
   uses
   {
@@ -80,6 +81,7 @@ generic module CapP(uint8_t superframeDirection)
     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;
@@ -120,8 +122,12 @@ implementation
   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;
@@ -129,6 +135,7 @@ implementation
   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();
@@ -158,15 +165,24 @@ implementation
       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;
@@ -188,9 +204,11 @@ implementation
       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)
@@ -200,7 +218,17 @@ implementation
       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;
     }
   }
@@ -237,15 +265,21 @@ implementation
     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)
@@ -304,9 +338,11 @@ implementation
         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)
@@ -377,6 +413,12 @@ implementation
       // 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
@@ -402,29 +444,36 @@ implementation
     // 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
@@ -432,8 +481,8 @@ implementation
         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;
@@ -497,10 +546,11 @@ implementation
 
   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){
@@ -518,26 +568,35 @@ implementation
           }
         }
         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);
@@ -591,8 +650,8 @@ implementation
 
   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);
   }
 
@@ -602,8 +661,10 @@ implementation
     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;
@@ -637,9 +698,35 @@ implementation
     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;}
@@ -661,4 +748,6 @@ implementation
 
   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;}
 }