Channel switching support for Wifi

This commit is contained in:
Ramon Bauza
2009-09-15 10:47:02 +02:00
parent a9b0bc855a
commit ddfe9023eb
20 changed files with 496 additions and 20 deletions

View File

@@ -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)

View File

@@ -107,6 +107,9 @@ router solicitation, DAD
<ul>
<li> 10MHz and 5MHz channel width supported by 802.11a model (Ramon Bauza and Kirill Andreev).
</ul>
<ul>
<li> Channel switching support. YansWifiPhy can now switch among different channels (Ramon Bauza and Pavel Boyko).
</ul>
</p>
</li>

View File

@@ -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
-----------------------

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -38,6 +38,7 @@ private:
virtual void DoNotifyAccessGranted (void);
virtual void DoNotifyInternalCollision (void);
virtual void DoNotifyCollision (void);
virtual void DoNotifyChannelSwitching (void);
typedef std::pair<uint64_t,uint64_t> ExpectedGrant;
typedef std::list<ExpectedGrant> 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<DcfStateTest *> 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<uint64_t, uint64_t> 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;
}

View File

@@ -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 "<<duration);
m_lastSwitchingStart = Simulator::Now ();
m_lastSwitchingDuration = duration;
}
void
DcfManager::NotifyNavResetNow (Time duration)
{

View File

@@ -100,6 +100,7 @@ private:
void NotifyAccessGranted (void);
void NotifyCollision (void);
void NotifyInternalCollision (void);
void NotifyChannelSwitching (void);
/**
@@ -130,6 +131,14 @@ private:
* is access is still needed.
*/
virtual void DoNotifyCollision (void) = 0;
/**
* Called by DcfManager to notify a DcfState subclass
* that a channel switching occured.
*
* The subclass is expected to flush the queue of
* packets.
*/
virtual void DoNotifyChannelSwitching () = 0;
uint32_t m_aifsn;
uint32_t m_backoffSlots;
@@ -247,6 +256,12 @@ public:
* Notify the DCF that a CCA busy period has just started.
*/
void NotifyMaybeCcaBusyStartNow (Time duration);
/**
* \param duration expected duration of channel switching period
*
* Notify the DCF that a channel switching period has just started.
*/
void NotifySwitchingStartNow (Time duration);
/**
* \param duration the value of the received NAV.
*
@@ -269,6 +284,7 @@ private:
Time MostRecent (Time a, Time b, Time c) const;
Time MostRecent (Time a, Time b, Time c, Time d) const;
Time MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const;
Time MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const;
/**
* Access will never be granted to the medium _before_
* the time returned by this method.
@@ -299,6 +315,8 @@ private:
Time m_lastTxDuration;
Time m_lastBusyStart;
Time m_lastBusyDuration;
Time m_lastSwitchingStart;
Time m_lastSwitchingDuration;
bool m_rxing;
bool m_sleeping;
Time m_eifsNoDifs;

View File

@@ -55,6 +55,9 @@ private:
virtual void DoNotifyCollision (void) {
m_txop->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<const Packet> packet, WifiMacHeader const &hdr)
{

View File

@@ -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);

View File

@@ -603,6 +603,10 @@ InterferenceHelper::CalculateSnrPer (Ptr<InterferenceHelper::Event> event)
return snrPer;
}
void
InterferenceHelper::EraseEvents (void)
{
m_events.erase (m_events.begin (), m_events.end ());
}
} // namespace ns3

View File

@@ -95,6 +95,7 @@ public:
Time duration, double rxPower);
struct InterferenceHelper::SnrPer CalculateSnrPer (Ptr<InterferenceHelper::Event> event);
void EraseEvents (void);
private:
class NiChange {
public:

View File

@@ -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<WifiPhy> 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<WifiPhy> phy)
m_phy = phy;
m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this));
m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this));
SetupPhyMacLowListener(phy);
}
void
MacLow::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager)
@@ -488,6 +523,22 @@ MacLow::ReceiveError (Ptr<const Packet> 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> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble)
{

View File

@@ -356,6 +356,13 @@ public:
* the MAC layer that a packet was unsuccessfully received.
*/
void ReceiveError (Ptr<const Packet> 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<WifiPhy> phy);
Ptr<WifiPhy> m_phy;
Ptr<WifiRemoteStationManager> 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

View File

@@ -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<const Packet> 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> 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;

View File

@@ -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<const Packet> packet, WifiMode txMode, WifiPreamble preamble, uint8_t txPower);
void SwitchToSync (Time syncDuration);
void SwitchToChannelSwitching (Time switchingDuration);
void SwitchFromSyncEndOk (Ptr<Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble);
void SwitchFromSyncEndError (Ptr<const Packet> 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;

View File

@@ -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

View File

@@ -302,27 +302,53 @@ YansWifiPhy::SetChannel (Ptr<YansWifiChannel> 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> 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<const Packet> 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)

View File

@@ -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> packet, Ptr<InterferenceHelper::Event> event);
void DoSetChannelNumber(uint16_t id);
private:
double m_edThresholdW;
@@ -164,7 +164,7 @@ private:
uint32_t m_nTxPower;
Ptr<YansWifiChannel> m_channel;
uint16_t m_channelId;
uint16_t m_channelNumber;
Ptr<Object> m_device;
Ptr<Object> m_mobility;
Modes m_modes;