diff --git a/AUTHORS b/AUTHORS index 87d19449f..3353e7652 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,7 @@ Kirill Andreev (andreev@iitp.ru) Nicola Baldo (nbaldo@cttc.es) Mirko Banchi (mk.banchi@gmail.com) +Ramon Bauza (monbauza@gmail.com) Mehdi Benamor (mehdi.benamor@telecom-bretagne.eu) Raj Bhattacharjea (raj.b@gatech.edu) Timo Bingmann (timo.bingmann@student.kit.edu) diff --git a/CHANGES.html b/CHANGES.html index 997b0e95f..d4350ab7d 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -107,6 +107,9 @@ router solicitation, DAD +

diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 102e2bdb2..f9fbfb5f8 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -57,6 +57,8 @@ New user-visible features e) 802.11 enhancements: - 10MHz and 5MHz channel width supported by 802.11a model (Ramon Bauza and Kirill Andreev) + - Channel switching support. YansWifiPhy can now switch among different channels + (Ramon Bauza and Pavel Boyko) API changes from ns-3.5 ----------------------- diff --git a/examples/wifi-ap.cc b/examples/wifi-ap.cc index f7f169ab8..f84395fa4 100644 --- a/examples/wifi-ap.cc +++ b/examples/wifi-ap.cc @@ -62,6 +62,9 @@ PhyStateTrace (std::string context, Time start, Time duration, enum WifiPhy::Sta { std::cout << " state="; switch (state) { + case WifiPhy::SWITCHING: + std::cout << "switchng"; + break; case WifiPhy::TX: std::cout << "tx "; break; diff --git a/src/devices/wifi/dca-txop.cc b/src/devices/wifi/dca-txop.cc index 6b4a64f43..e19363591 100644 --- a/src/devices/wifi/dca-txop.cc +++ b/src/devices/wifi/dca-txop.cc @@ -58,6 +58,9 @@ private: virtual void DoNotifyCollision (void) { m_txop->NotifyCollision (); } + virtual void DoNotifyChannelSwitching (void) { + m_txop->NotifyChannelSwitching (); + } DcaTxop *m_txop; }; @@ -446,6 +449,13 @@ DcaTxop::NotifyCollision (void) RestartAccessIfNeeded (); } +void +DcaTxop::NotifyChannelSwitching (void) +{ + m_queue->Flush(); + m_currentPacket = 0; +} + void DcaTxop::GotCts (double snr, WifiMode txMode) { diff --git a/src/devices/wifi/dca-txop.h b/src/devices/wifi/dca-txop.h index 4fd697230..5406ac2fc 100644 --- a/src/devices/wifi/dca-txop.h +++ b/src/devices/wifi/dca-txop.h @@ -127,6 +127,7 @@ private: void NotifyAccessGranted (void); void NotifyInternalCollision (void); void NotifyCollision (void); + void NotifyChannelSwitching (void); /* event handlers */ void GotCts (double snr, WifiMode txMode); void MissedCts (void); diff --git a/src/devices/wifi/dcf-manager-test.cc b/src/devices/wifi/dcf-manager-test.cc index b94f0ed3f..8972e527c 100644 --- a/src/devices/wifi/dcf-manager-test.cc +++ b/src/devices/wifi/dcf-manager-test.cc @@ -38,6 +38,7 @@ private: virtual void DoNotifyAccessGranted (void); virtual void DoNotifyInternalCollision (void); virtual void DoNotifyCollision (void); + virtual void DoNotifyChannelSwitching (void); typedef std::pair ExpectedGrant; typedef std::list ExpectedGrants; @@ -65,6 +66,7 @@ public: void NotifyAccessGranted (uint32_t i); void NotifyInternalCollision (uint32_t i); void NotifyCollision (uint32_t i); + void NotifyChannelSwitching (uint32_t i); private: @@ -88,6 +90,9 @@ private: void AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from); void DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, DcfStateTest *state); + void AddCcaBusyEvt (uint64_t at, uint64_t duration); + void AddSwitchingEvt (uint64_t at, uint64_t duration); + void AddRxStartEvt (uint64_t at, uint64_t duration); typedef std::vector DcfStates; @@ -122,7 +127,11 @@ DcfStateTest::DoNotifyCollision (void) { m_test->NotifyCollision (m_i); } - +void +DcfStateTest::DoNotifyChannelSwitching (void) +{ + m_test->NotifyChannelSwitching (m_i); +} DcfManagerTest::DcfManagerTest () @@ -182,7 +191,22 @@ DcfManagerTest::NotifyCollision (uint32_t i) m_result = result; } } - +void +DcfManagerTest::NotifyChannelSwitching (uint32_t i) +{ + DcfStateTest *state = m_dcfStates[i]; + bool result = true; + if (!state->m_expectedGrants.empty ()) + { + std::pair expected = state->m_expectedGrants.front (); + state->m_expectedGrants.pop_front (); + NS_TEST_ASSERT_EQUAL (Simulator::Now (), MicroSeconds (expected.second)); + } + if (!result) + { + m_result = result; + } +} void DcfManagerTest::ExpectInternalCollision (uint64_t time, uint32_t nSlots, uint32_t from) @@ -320,7 +344,27 @@ DcfManagerTest::DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, Dc state->QueueTx (txTime, expectedGrantTime); m_dcfManager->RequestAccess (state); } - +void +DcfManagerTest::AddCcaBusyEvt (uint64_t at, uint64_t duration) +{ + Simulator::Schedule (MicroSeconds (at) - Now (), + &DcfManager::NotifyMaybeCcaBusyStartNow, m_dcfManager, + MicroSeconds (duration)); +} +void +DcfManagerTest::AddSwitchingEvt (uint64_t at, uint64_t duration) +{ + Simulator::Schedule (MicroSeconds (at) - Now (), + &DcfManager::NotifySwitchingStartNow, m_dcfManager, + MicroSeconds (duration)); +} +void +DcfManagerTest::AddRxStartEvt (uint64_t at, uint64_t duration) +{ + Simulator::Schedule (MicroSeconds (at) - Now (), + &DcfManager::NotifyRxStartNow, m_dcfManager, + MicroSeconds (duration)); +} @@ -559,7 +603,95 @@ DcfManagerTest::RunTests (void) AddAccessRequest (30, 50, 108, 0); ExpectCollision (30, 3, 0); // backoff: 3 slots EndTest (); - + + + // Channel switching tests + + // 0 20 23 24 25 + // | switching | sifs | aifsn | tx | + // | + // 21 access request. + StartTest (1, 3, 10); + AddDcfState (1); + AddSwitchingEvt(0,20); + AddAccessRequest (21, 1, 24, 0); + EndTest (); + + // 20 40 50 53 54 55 + // | switching | busy | sifs | aifsn | tx | + // | | + // 30 busy. 45 access request. + // + StartTest (1, 3, 10); + AddDcfState (1); + AddSwitchingEvt(20,20); + AddCcaBusyEvt(30,20); + AddAccessRequest (45, 1, 54, 0); + EndTest (); + + // 20 30 50 53 54 55 + // | rx | switching | sifs | aifsn | tx | + // | + // 51 access request. + // + StartTest (1, 3, 10); + AddDcfState (1); + AddRxStartEvt (20,40); + AddSwitchingEvt(30,20); + AddAccessRequest (51, 1, 54, 0); + EndTest (); + + // 20 30 50 53 54 55 + // | busy | switching | sifs | aifsn | tx | + // | + // 51 access request. + // + StartTest (1, 3, 10); + AddDcfState (1); + AddCcaBusyEvt (20,40); + AddSwitchingEvt(30,20); + AddAccessRequest (51, 1, 54, 0); + EndTest (); + + // 20 30 50 53 54 55 + // | nav | switching | sifs | aifsn | tx | + // | + // 51 access request. + // + StartTest (1, 3, 10); + AddDcfState (1); + AddNavStart (20,40); + AddSwitchingEvt(30,20); + AddAccessRequest (51, 1, 54, 0); + EndTest (); + + // 20 40 50 55 58 59 60 + // | tx | ack timeout | switching | sifs | aifsn | tx | + // | | + // 45 access request. 56 access request. + // + StartTest (1, 3, 10); + AddDcfState (1); + AddAccessRequestWithAckTimeout (20, 20, 20, 0); + AddAccessRequest (45, 1, 50, 0); + AddSwitchingEvt(50,5); + AddAccessRequest (56, 1, 59, 0); + EndTest (); + + // 20 60 66 70 74 78 80 100 106 110 112 + // | rx | sifs | aifsn | bslot0 | bslot1 | | switching | sifs | aifsn | tx | + // | | + // 30 access request. 101 access request. + // + StartTest (4, 6, 10); + AddDcfState (1); + AddRxOkEvt(20,40); + AddAccessRequest (30, 2, 80, 0); + ExpectCollision(30, 4, 0); // backoff: 4 slots + AddSwitchingEvt(80,20); + AddAccessRequest (101, 2, 110, 0); + EndTest (); + return m_result; } diff --git a/src/devices/wifi/dcf-manager.cc b/src/devices/wifi/dcf-manager.cc index 320bf0621..467caf77f 100644 --- a/src/devices/wifi/dcf-manager.cc +++ b/src/devices/wifi/dcf-manager.cc @@ -154,6 +154,11 @@ DcfState::NotifyInternalCollision (void) { DoNotifyInternalCollision (); } +void +DcfState::NotifyChannelSwitching (void) +{ + DoNotifyChannelSwitching (); +} /*************************************************************** @@ -211,6 +216,9 @@ public: virtual void NotifyMaybeCcaBusyStart (Time duration) { m_dcf->NotifyMaybeCcaBusyStartNow (duration); } + virtual void NotifySwitchingStart (Time duration) { + m_dcf->NotifySwitchingStartNow (duration); + } private: ns3::DcfManager *m_dcf; }; @@ -232,6 +240,8 @@ DcfManager::DcfManager () m_lastTxDuration (MicroSeconds (0)), m_lastBusyStart (MicroSeconds (0)), m_lastBusyDuration (MicroSeconds (0)), + m_lastSwitchingStart (MicroSeconds (0)), + m_lastSwitchingDuration (MicroSeconds (0)), m_rxing (false), m_slotTime (Seconds (0.0)), m_sifs (Seconds (0.0)), @@ -319,6 +329,18 @@ DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const return retval; } +Time +DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const +{ + Time h = Max (a, b); + Time i = Max (c, d); + Time j = Max (e, f); + Time k = Max (h, i); + Time l = Max (j, g); + Time retval = Max (k, l); + return retval; +} + bool DcfManager::IsBusy (void) const { @@ -454,12 +476,14 @@ DcfManager::GetAccessGrantStart (void) const Time navAccessStart = m_lastNavStart + m_lastNavDuration + m_sifs; Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + m_sifs; Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + m_sifs; + Time switchingAccessStart = m_lastSwitchingStart + m_lastSwitchingDuration + m_sifs; Time accessGrantedStart = MostRecent (rxAccessStart, busyAccessStart, txAccessStart, navAccessStart, ackTimeoutAccessStart, - ctsTimeoutAccessStart + ctsTimeoutAccessStart, + switchingAccessStart ); NS_LOG_INFO ("access grant start=" << accessGrantedStart << ", rx access start=" << rxAccessStart << @@ -596,6 +620,67 @@ DcfManager::NotifyMaybeCcaBusyStartNow (Time duration) m_lastBusyStart = Simulator::Now (); m_lastBusyDuration = duration; } + + +void +DcfManager::NotifySwitchingStartNow (Time duration) +{ + Time now = Simulator::Now (); + NS_ASSERT (m_lastTxStart + m_lastTxDuration <= now); + NS_ASSERT (m_lastSwitchingStart + m_lastSwitchingDuration <= now); + + if (m_rxing) + { + // channel switching during packet reception + m_lastRxEnd = Simulator::Now (); + m_lastRxDuration = m_lastRxEnd - m_lastRxStart; + m_lastRxReceivedOk = true; + m_rxing = false; + } + if (m_lastNavStart + m_lastNavDuration > now) + { + m_lastNavDuration = now - m_lastNavStart; + } + if (m_lastBusyStart + m_lastBusyDuration > now) + { + m_lastBusyDuration = now - m_lastBusyStart; + } + if (m_lastAckTimeoutEnd > now) + { + m_lastAckTimeoutEnd = now; + } + if (m_lastCtsTimeoutEnd > now) + { + m_lastCtsTimeoutEnd = now; + } + + // Cancel timeout + if (m_accessTimeout.IsRunning ()) + { + m_accessTimeout.Cancel (); + } + + // Reset backoffs + for (States::iterator i = m_states.begin (); i != m_states.end (); i++) + { + DcfState *state = *i; + uint32_t remainingSlots = state->GetBackoffSlots (); + if (remainingSlots > 0) + { + state->UpdateBackoffSlotsNow (remainingSlots, now); + NS_ASSERT(state->GetBackoffSlots()==0); + } + state->ResetCw(); + state->m_accessRequested = false; + state->NotifyChannelSwitching(); + } + + MY_DEBUG ("switching start for "<NotifyCollision (); } + virtual void DoNotifyChannelSwitching (void) { + m_txop->NotifyChannelSwitching (); + } EdcaTxopN *m_txop; }; @@ -427,6 +430,13 @@ EdcaTxopN::MissedCts (void) RestartAccessIfNeeded (); } +void +EdcaTxopN::NotifyChannelSwitching (void) +{ + m_queue->Flush(); + m_currentPacket = 0; +} + void EdcaTxopN::Queue (Ptr packet, WifiMacHeader const &hdr) { diff --git a/src/devices/wifi/edca-txop-n.h b/src/devices/wifi/edca-txop-n.h index 216c77bb1..37f43e52e 100644 --- a/src/devices/wifi/edca-txop-n.h +++ b/src/devices/wifi/edca-txop-n.h @@ -101,6 +101,7 @@ public: void NotifyAccessGranted (void); void NotifyInternalCollision (void); void NotifyCollision (void); + void NotifyChannelSwitching (void); /*event handlers*/ void GotCts (double snr, WifiMode txMode); diff --git a/src/devices/wifi/interference-helper.cc b/src/devices/wifi/interference-helper.cc index c375d095e..4e0301ba0 100644 --- a/src/devices/wifi/interference-helper.cc +++ b/src/devices/wifi/interference-helper.cc @@ -603,6 +603,10 @@ InterferenceHelper::CalculateSnrPer (Ptr event) return snrPer; } - +void +InterferenceHelper::EraseEvents (void) +{ + m_events.erase (m_events.begin (), m_events.end ()); +} } // namespace ns3 diff --git a/src/devices/wifi/interference-helper.h b/src/devices/wifi/interference-helper.h index 2140cb12a..0ae37b280 100644 --- a/src/devices/wifi/interference-helper.h +++ b/src/devices/wifi/interference-helper.h @@ -95,6 +95,7 @@ public: Time duration, double rxPower); struct InterferenceHelper::SnrPer CalculateSnrPer (Ptr event); + void EraseEvents (void); private: class NiChange { public: diff --git a/src/devices/wifi/mac-low.cc b/src/devices/wifi/mac-low.cc index bc0ee2035..c18a7638f 100644 --- a/src/devices/wifi/mac-low.cc +++ b/src/devices/wifi/mac-low.cc @@ -244,6 +244,30 @@ std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters return os; } + +/*************************************************************** + * Listener for PHY events. Forwards to MacLow + ***************************************************************/ + + +class PhyMacLowListener : public ns3::WifiPhyListener { +public: + PhyMacLowListener (ns3::MacLow *macLow) + : m_macLow (macLow) {} + virtual ~PhyMacLowListener () {} + virtual void NotifyRxStart (Time duration) {} + virtual void NotifyRxEndOk (void) {} + virtual void NotifyRxEndError (void) {} + virtual void NotifyTxStart (Time duration) {} + virtual void NotifyMaybeCcaBusyStart (Time duration) {} + virtual void NotifySwitchingStart (Time duration) { + m_macLow->NotifySwitchingStartNow (duration); + } +private: + ns3::MacLow *m_macLow; +}; + + MacLow::MacLow () : m_normalAckTimeoutEvent (), m_fastAckTimeoutEvent (), @@ -267,6 +291,14 @@ MacLow::~MacLow () NS_LOG_FUNCTION (this); } +void +MacLow::SetupPhyMacLowListener (Ptr phy) +{ + m_phyMacLowListener = new PhyMacLowListener (this); + phy->RegisterListener (m_phyMacLowListener); +} + + void MacLow::DoDispose (void) { @@ -274,6 +306,8 @@ MacLow::DoDispose (void) CancelAllEvents (); m_phy = 0; m_stationManager = 0; + delete m_phyMacLowListener; + m_phyMacLowListener = 0; } void @@ -339,6 +373,7 @@ MacLow::SetPhy (Ptr phy) m_phy = phy; m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this)); m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this)); + SetupPhyMacLowListener(phy); } void MacLow::SetWifiRemoteStationManager (Ptr manager) @@ -488,6 +523,22 @@ MacLow::ReceiveError (Ptr packet, double rxSnr) return; } +void +MacLow::NotifySwitchingStartNow (Time duration) +{ + NS_LOG_DEBUG ("switching channel. Cancelling MAC pending events"); + m_stationManager->Reset(); + CancelAllEvents(); + if (m_navCounterResetCtsMissed.IsRunning ()) + { + m_navCounterResetCtsMissed.Cancel(); + } + m_lastNavStart = Simulator::Now (); + m_lastNavDuration = Seconds (0); + m_currentPacket = 0; + m_listener = 0; +} + void MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamble preamble) { diff --git a/src/devices/wifi/mac-low.h b/src/devices/wifi/mac-low.h index 7f1bca086..2a1ee4002 100644 --- a/src/devices/wifi/mac-low.h +++ b/src/devices/wifi/mac-low.h @@ -356,6 +356,13 @@ public: * the MAC layer that a packet was unsuccessfully received. */ void ReceiveError (Ptr packet, double rxSnr); + /** + * \param duration switching delay duration. + * + * This method is typically invoked by the PhyMacLowListener to notify + * the MAC layer that a channel switching occured. + */ + void NotifySwitchingStartNow (Time duration); private: void CancelAllEvents (void); uint32_t GetAckSize (void) const; @@ -402,6 +409,8 @@ private: void StartDataTxTimers (void); virtual void DoDispose (void); + void SetupPhyMacLowListener (Ptr phy); + Ptr m_phy; Ptr m_stationManager; MacLowRxCallback m_rxCallback; @@ -434,6 +443,9 @@ private: Time m_lastNavStart; Time m_lastNavDuration; + + // Listerner needed to monitor when a channel switching occurs. + class PhyMacLowListener *m_phyMacLowListener; }; } // namespace ns3 diff --git a/src/devices/wifi/wifi-phy-state-helper.cc b/src/devices/wifi/wifi-phy-state-helper.cc index 5626e4281..9a4d1cae8 100644 --- a/src/devices/wifi/wifi-phy-state-helper.cc +++ b/src/devices/wifi/wifi-phy-state-helper.cc @@ -54,9 +54,11 @@ WifiPhyStateHelper::WifiPhyStateHelper () m_endTx (Seconds (0)), m_endSync (Seconds (0)), m_endCcaBusy (Seconds (0)), + m_endSwitching (Seconds (0)), m_startTx (Seconds (0)), m_startSync (Seconds (0)), m_startCcaBusy (Seconds (0)), + m_startSwitching (Seconds (0)), m_previousStateChangeTime (Seconds (0)) { NS_LOG_FUNCTION (this); @@ -104,6 +106,11 @@ WifiPhyStateHelper::IsStateTx (void) { return (GetState () == WifiPhy::TX)?true:false; } +bool +WifiPhyStateHelper::IsStateSwitching (void) +{ + return (GetState () == WifiPhy::SWITCHING)?true:false; +} @@ -128,6 +135,9 @@ WifiPhyStateHelper::GetDelayUntilIdle (void) case WifiPhy::CCA_BUSY: retval = m_endCcaBusy - Simulator::Now (); break; + case WifiPhy::SWITCHING: + retval = m_endSwitching - Simulator::Now (); + break; case WifiPhy::IDLE: retval = Seconds (0); break; @@ -163,6 +173,9 @@ WifiPhyStateHelper::StateToString (enum WifiPhy::State state) case WifiPhy::SYNC: return "SYNC"; break; + case WifiPhy::SWITCHING: + return "SWITCHING"; + break; default: NS_ASSERT (false); // quiet compiler @@ -182,6 +195,10 @@ WifiPhyStateHelper::GetState (void) { return WifiPhy::SYNC; } + else if (m_endSwitching > Simulator::Now ()) + { + return WifiPhy::SWITCHING; + } else if (m_endCcaBusy > Simulator::Now ()) { return WifiPhy::CCA_BUSY; @@ -228,6 +245,13 @@ WifiPhyStateHelper::NotifyMaybeCcaBusyStart (Time duration) (*i)->NotifyMaybeCcaBusyStart (duration); } } +void +WifiPhyStateHelper::NotifySwitchingStart (Time duration) +{ + for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++) { + (*i)->NotifySwitchingStart (duration); + } +} void WifiPhyStateHelper::LogPreviousIdleAndCcaBusyStates (void) @@ -235,11 +259,14 @@ WifiPhyStateHelper::LogPreviousIdleAndCcaBusyStates (void) Time now = Simulator::Now (); Time idleStart = Max (m_endCcaBusy, m_endSync); idleStart = Max (idleStart, m_endTx); + idleStart = Max (idleStart, m_endSwitching); NS_ASSERT (idleStart <= now); if (m_endCcaBusy > m_endSync && + m_endCcaBusy > m_endSwitching && m_endCcaBusy > m_endTx) { Time ccaBusyStart = Max (m_endTx, m_endSync); ccaBusyStart = Max (ccaBusyStart, m_startCcaBusy); + ccaBusyStart = Max (ccaBusyStart, m_endSwitching); m_stateLogger (ccaBusyStart, idleStart - ccaBusyStart, WifiPhy::CCA_BUSY); } m_stateLogger (idleStart, now - idleStart, WifiPhy::IDLE); @@ -264,11 +291,13 @@ WifiPhyStateHelper::SwitchToTx (Time txDuration, Ptr packet, WifiM case WifiPhy::CCA_BUSY: { Time ccaStart = Max (m_endSync, m_endTx); ccaStart = Max (ccaStart, m_startCcaBusy); + ccaStart = Max (ccaStart, m_endSwitching); m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY); } break; case WifiPhy::IDLE: LogPreviousIdleAndCcaBusyStates (); break; + case WifiPhy::SWITCHING: default: NS_ASSERT (false); break; @@ -292,8 +321,10 @@ WifiPhyStateHelper::SwitchToSync (Time rxDuration) case WifiPhy::CCA_BUSY: { Time ccaStart = Max (m_endSync, m_endTx); ccaStart = Max (ccaStart, m_startCcaBusy); + ccaStart = Max (ccaStart, m_endSwitching); m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY); } break; + case WifiPhy::SWITCHING: case WifiPhy::SYNC: case WifiPhy::TX: NS_ASSERT (false); @@ -305,6 +336,49 @@ WifiPhyStateHelper::SwitchToSync (Time rxDuration) m_endSync = now + rxDuration; NS_ASSERT (IsStateSync ()); } + +void +WifiPhyStateHelper::SwitchToChannelSwitching (Time switchingDuration) +{ + NotifySwitchingStart (switchingDuration); + Time now = Simulator::Now (); + switch (GetState ()) { + case WifiPhy::SYNC: + /* The packet which is being received as well + * as its endSync event are cancelled by the caller. + */ + m_syncing = false; + m_stateLogger (m_startSync, now - m_startSync, WifiPhy::SYNC); + m_endSync = now; + break; + case WifiPhy::CCA_BUSY: { + Time ccaStart = Max (m_endSync, m_endTx); + ccaStart = Max (ccaStart, m_startCcaBusy); + ccaStart = Max (ccaStart, m_endSwitching); + m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY); + } break; + case WifiPhy::IDLE: + LogPreviousIdleAndCcaBusyStates (); + break; + case WifiPhy::TX: + case WifiPhy::SWITCHING: + default: + NS_ASSERT (false); + break; + } + + if (now < m_endCcaBusy) + { + m_endCcaBusy = now; + } + + m_stateLogger (now, switchingDuration, WifiPhy::SWITCHING); + m_previousStateChangeTime = now; + m_startSwitching = now; + m_endSwitching = now + switchingDuration; + NS_ASSERT (IsStateSwitching ()); +} + void WifiPhyStateHelper::SwitchFromSyncEndOk (Ptr packet, double snr, WifiMode mode, enum WifiPreamble preamble) { @@ -348,6 +422,8 @@ WifiPhyStateHelper::SwitchMaybeToCcaBusy (Time duration) NotifyMaybeCcaBusyStart (duration); Time now = Simulator::Now (); switch (GetState ()) { + case WifiPhy::SWITCHING: + break; case WifiPhy::IDLE: LogPreviousIdleAndCcaBusyStates (); break; diff --git a/src/devices/wifi/wifi-phy-state-helper.h b/src/devices/wifi/wifi-phy-state-helper.h index b28561550..de8443b18 100644 --- a/src/devices/wifi/wifi-phy-state-helper.h +++ b/src/devices/wifi/wifi-phy-state-helper.h @@ -43,12 +43,14 @@ public: bool IsStateBusy (void); bool IsStateSync (void); bool IsStateTx (void); + bool IsStateSwitching (void); Time GetStateDuration (void); Time GetDelayUntilIdle (void); Time GetLastRxStartTime (void) const; void SwitchToTx (Time txDuration, Ptr packet, WifiMode txMode, WifiPreamble preamble, uint8_t txPower); void SwitchToSync (Time syncDuration); + void SwitchToChannelSwitching (Time switchingDuration); void SwitchFromSyncEndOk (Ptr packet, double snr, WifiMode mode, enum WifiPreamble preamble); void SwitchFromSyncEndError (Ptr packet, double snr); void SwitchMaybeToCcaBusy (Time duration); @@ -66,15 +68,18 @@ private: void NotifySyncEndOk (void); void NotifySyncEndError (void); void NotifyMaybeCcaBusyStart (Time duration); + void NotifySwitchingStart (Time duration); void DoSwitchFromSync (void); bool m_syncing; Time m_endTx; Time m_endSync; Time m_endCcaBusy; + Time m_endSwitching; Time m_startTx; Time m_startSync; Time m_startCcaBusy; + Time m_startSwitching; Time m_previousStateChangeTime; Listeners m_listeners; diff --git a/src/devices/wifi/wifi-phy.h b/src/devices/wifi/wifi-phy.h index d75ff70da..2e2092748 100644 --- a/src/devices/wifi/wifi-phy.h +++ b/src/devices/wifi/wifi-phy.h @@ -97,6 +97,14 @@ public: * what duration it reported. */ virtual void NotifyMaybeCcaBusyStart (Time duration) = 0; + /** + * \param duration the expected channel switching duration. + * + * We do not send any event to notify the end of + * channel switching. Listeners should assume that the + * channel implicitely reverts to the idle or busy states. + */ + virtual void NotifySwitchingStart (Time duration) = 0; }; @@ -127,7 +135,11 @@ public: /** * The PHY layer is IDLE. */ - IDLE + IDLE, + /** + * The PHY layer is switching to other channel. + */ + SWITCHING }; /** * arg1: packet received successfully diff --git a/src/devices/wifi/yans-wifi-phy.cc b/src/devices/wifi/yans-wifi-phy.cc index eead8afae..7efbf6739 100644 --- a/src/devices/wifi/yans-wifi-phy.cc +++ b/src/devices/wifi/yans-wifi-phy.cc @@ -302,27 +302,53 @@ YansWifiPhy::SetChannel (Ptr channel) { m_channel = channel; m_channel->Add (this); - m_channelId = 1; // always start on channel starting frequency (channel 1) + m_channelNumber = 1; // always start on channel starting frequency (channel 1) } void YansWifiPhy::SetChannelNumber (uint16_t nch) { - // TODO implement channel switching state machine here - DoSetChannelNumber (nch); -} + NS_ASSERT(!IsStateSwitching()); + switch (m_state->GetState ()) { + case YansWifiPhy::SYNC: + NS_LOG_DEBUG ("drop packet because of channel switching while reception"); + m_endSyncEvent.Cancel(); + goto switchChannel; + break; + case YansWifiPhy::TX: + NS_LOG_DEBUG ("channel switching postponed until end of current transmission"); + Simulator::Schedule (GetDelayUntilIdle(), &YansWifiPhy::SetChannelNumber, this, nch); + break; + case YansWifiPhy::CCA_BUSY: + case YansWifiPhy::IDLE: + goto switchChannel; + break; + default: + NS_ASSERT (false); + break; + } -void -YansWifiPhy::DoSetChannelNumber (uint16_t nch) -{ - NS_LOG_DEBUG("switching channel " << m_channelId << " -> " << nch); - m_channelId = nch; + return; + + switchChannel: + + NS_LOG_DEBUG("switching channel " << m_channelNumber << " -> " << nch); + m_state->SwitchToChannelSwitching(m_channelSwitchDelay); + m_interference.EraseEvents(); + /* + * Needed here to be able to correctly sensed the medium for the first + * time after the switching. The actual switching is not performed until + * after m_channelSwitchDelay. Packets received during the switching + * state are added to the event list and are employed later to figure + * out the state of the medium after the switching. + */ + m_channelNumber = nch; } uint16_t YansWifiPhy::GetChannelNumber() const { - return m_channelId; + return m_channelNumber; } double @@ -361,6 +387,24 @@ YansWifiPhy::StartReceivePacket (Ptr packet, rxPowerW); switch (m_state->GetState ()) { + case YansWifiPhy::SWITCHING: + NS_LOG_DEBUG ("drop packet because of channel switching"); + NotifyRxDrop (packet); + /* + * Packets received on the upcoming channel are added to the event list + * during the switching state. This way the medium can be correctly sensed + * when the device listens to the channel for the first time after the + * switching e.g. after channel switching, the channel may be sensed as + * busy due to other devices' tramissions started before the end of + * the switching. + */ + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + // that packet will be noise _after_ the completion of the + // channel switching. + goto maybeCcaBusy; + } + break; case YansWifiPhy::SYNC: NS_LOG_DEBUG ("drop packet because already in Sync (power="<< rxPowerW<<"W)"); @@ -431,7 +475,7 @@ YansWifiPhy::SendPacket (Ptr packet, WifiMode txMode, WifiPreamble * prevent it. * - we are idle */ - NS_ASSERT (!m_state->IsStateTx ()); + NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ()); Time txDuration = CalculateTxDuration (packet->GetSize (), txMode, preamble); if (m_state->IsStateSync ()) @@ -563,6 +607,11 @@ YansWifiPhy::IsStateTx (void) { return m_state->IsStateTx (); } +bool +YansWifiPhy::IsStateSwitching (void) +{ + return m_state->IsStateSwitching (); +} Time YansWifiPhy::GetStateDuration (void) diff --git a/src/devices/wifi/yans-wifi-phy.h b/src/devices/wifi/yans-wifi-phy.h index 34c3313e7..c39be9f25 100644 --- a/src/devices/wifi/yans-wifi-phy.h +++ b/src/devices/wifi/yans-wifi-phy.h @@ -124,6 +124,7 @@ public: virtual bool IsStateBusy (void); virtual bool IsStateSync (void); virtual bool IsStateTx (void); + virtual bool IsStateSwitching (void); virtual Time GetStateDuration (void); virtual Time GetDelayUntilIdle (void); virtual Time GetLastRxStartTime (void) const; @@ -152,7 +153,6 @@ private: double RatioToDb (double ratio) const; double GetPowerDbm (uint8_t power) const; void EndSync (Ptr packet, Ptr event); - void DoSetChannelNumber(uint16_t id); private: double m_edThresholdW; @@ -164,7 +164,7 @@ private: uint32_t m_nTxPower; Ptr m_channel; - uint16_t m_channelId; + uint16_t m_channelNumber; Ptr m_device; Ptr m_mobility; Modes m_modes;