From c7a5c8ac6fcb84507c0bccf1242f495c96898137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deronne?= Date: Sun, 27 Nov 2016 19:27:15 +0100 Subject: [PATCH] wifi: (fixes #2552) Remove remaining code duplication between Yans and Spectrum --- RELEASE_NOTES | 1 + src/wifi/model/spectrum-wifi-phy.cc | 523 +---------------------- src/wifi/model/spectrum-wifi-phy.h | 58 +-- src/wifi/model/wifi-phy.cc | 525 ++++++++++++++++++++++-- src/wifi/model/wifi-phy.h | 114 ++--- src/wifi/model/wifi-utils.cc | 52 +++ src/wifi/model/wifi-utils.h | 61 +++ src/wifi/model/yans-wifi-channel.cc | 3 +- src/wifi/model/yans-wifi-phy.cc | 502 +--------------------- src/wifi/model/yans-wifi-phy.h | 47 +-- src/wifi/test/spectrum-wifi-phy-test.cc | 14 +- src/wifi/wscript | 2 + 12 files changed, 719 insertions(+), 1183 deletions(-) create mode 100644 src/wifi/model/wifi-utils.cc create mode 100644 src/wifi/model/wifi-utils.h diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 89766efd3..c6a4fb329 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -46,6 +46,7 @@ Bugs fixed - Bug 2545 - Optimized build fails for flow-monitor - Bug 2547 - dead assignments on various tcp congestion controls - Bug 2551 - wifi preamble should be part of TXVECTOR +- Bug 2552 - Remove code duplication between Yans and Spectrum Known issues ------------ diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index d4f26b90f..f77b7be37 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -33,11 +33,9 @@ #include "ns3/log.h" #include "ns3/double.h" #include "ns3/boolean.h" -#include "ampdu-tag.h" #include "wifi-spectrum-signal-parameters.h" -#include "wifi-phy-tag.h" #include "ns3/antenna-model.h" -#include +#include "wifi-utils.h" namespace ns3 { @@ -98,112 +96,6 @@ SpectrumWifiPhy::DoInitialize (void) } } -bool -SpectrumWifiPhy::DoChannelSwitch (uint16_t nch) -{ - if (IsInitialized () == false) - { - //this is not channel switch, this is initialization - NS_LOG_DEBUG ("start at channel " << nch); - return true; - } - - NS_ASSERT (!IsStateSwitching ()); - switch (m_state->GetState ()) - { - case SpectrumWifiPhy::RX: - NS_LOG_DEBUG ("drop packet because of channel switching while reception"); - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - goto switchChannel; - break; - case SpectrumWifiPhy::TX: - NS_LOG_DEBUG ("channel switching postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetChannelNumber, this, nch); - break; - case SpectrumWifiPhy::CCA_BUSY: - case SpectrumWifiPhy::IDLE: - goto switchChannel; - break; - case SpectrumWifiPhy::SLEEP: - NS_LOG_DEBUG ("channel switching ignored in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } - - return false; - -switchChannel: - - NS_LOG_DEBUG ("switching channel " << GetChannelNumber () << " -> " << nch); - m_rxSpectrumModel = WifiSpectrumValueHelper::GetSpectrumModel (GetFrequency (), GetChannelWidth ()); - m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); - 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. - */ - return true; -} - -bool -SpectrumWifiPhy::DoFrequencySwitch (uint32_t frequency) -{ - if (IsInitialized () == false) - { - //this is not channel switch, this is initialization - NS_LOG_DEBUG ("start at frequency " << frequency); - return true; - } - - NS_ASSERT (!IsStateSwitching ()); - switch (m_state->GetState ()) - { - case SpectrumWifiPhy::RX: - NS_LOG_DEBUG ("drop packet because of channel/frequency switching while reception"); - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - goto switchFrequency; - break; - case SpectrumWifiPhy::TX: - NS_LOG_DEBUG ("channel/frequency switching postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetFrequency, this, frequency); - break; - case SpectrumWifiPhy::CCA_BUSY: - case SpectrumWifiPhy::IDLE: - goto switchFrequency; - break; - case SpectrumWifiPhy::SLEEP: - NS_LOG_DEBUG ("frequency switching ignored in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } - - return false; - -switchFrequency: - - NS_LOG_DEBUG ("switching frequency " << GetFrequency () << " -> " << frequency); - m_rxSpectrumModel = WifiSpectrumValueHelper::GetSpectrumModel (GetFrequency (), GetChannelWidth ()); - m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); - 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. - */ - return true; -} - Ptr SpectrumWifiPhy::GetRxSpectrumModel () const { @@ -240,12 +132,6 @@ SpectrumWifiPhy::SetChannel (Ptr channel) m_channel = channel; } -void -SpectrumWifiPhy::SetPacketReceivedCallback (RxCallback callback) -{ - m_rxCallback = callback; -} - void SpectrumWifiPhy::AddOperationalChannel (uint16_t channelNumber) { @@ -273,80 +159,6 @@ SpectrumWifiPhy::ClearOperationalChannelList () m_operationalChannelList.clear (); } -void -SpectrumWifiPhy::SetSleepMode (void) -{ - NS_LOG_FUNCTION (this); - switch (m_state->GetState ()) - { - case SpectrumWifiPhy::TX: - NS_LOG_DEBUG ("setting sleep mode postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &SpectrumWifiPhy::SetSleepMode, this); - break; - case SpectrumWifiPhy::RX: - NS_LOG_DEBUG ("setting sleep mode postponed until end of current reception"); - Simulator::Schedule (GetDelayUntilIdle (), &SpectrumWifiPhy::SetSleepMode, this); - break; - case SpectrumWifiPhy::SWITCHING: - NS_LOG_DEBUG ("setting sleep mode postponed until end of channel switching"); - Simulator::Schedule (GetDelayUntilIdle (), &SpectrumWifiPhy::SetSleepMode, this); - break; - case SpectrumWifiPhy::CCA_BUSY: - case SpectrumWifiPhy::IDLE: - NS_LOG_DEBUG ("setting sleep mode"); - m_state->SwitchToSleep (); - break; - case SpectrumWifiPhy::SLEEP: - NS_LOG_DEBUG ("already in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } -} - -void -SpectrumWifiPhy::ResumeFromSleep (void) -{ - NS_LOG_FUNCTION (this); - switch (m_state->GetState ()) - { - case SpectrumWifiPhy::TX: - case SpectrumWifiPhy::RX: - case SpectrumWifiPhy::IDLE: - case SpectrumWifiPhy::CCA_BUSY: - case SpectrumWifiPhy::SWITCHING: - { - NS_LOG_DEBUG ("not in sleep mode, there is nothing to resume"); - break; - } - case SpectrumWifiPhy::SLEEP: - { - NS_LOG_DEBUG ("resuming from sleep mode"); - Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); - m_state->SwitchFromSleep (delayUntilCcaEnd); - break; - } - default: - { - NS_ASSERT (false); - break; - } - } -} - -void -SpectrumWifiPhy::SetReceiveOkCallback (RxOkCallback callback) -{ - m_state->SetReceiveOkCallback (callback); -} - -void -SpectrumWifiPhy::SetReceiveErrorCallback (RxErrorCallback callback) -{ - m_state->SetReceiveErrorCallback (callback); -} - void SpectrumWifiPhy::StartRx (Ptr rxParams) { @@ -391,207 +203,7 @@ SpectrumWifiPhy::StartRx (Ptr rxParams) NS_LOG_INFO ("Received Wi-Fi signal"); Ptr packet = wifiRxParams->packet->Copy (); - WifiPhyTag tag; - bool found = packet->PeekPacketTag (tag); - if (!found) - { - NS_FATAL_ERROR ("Received Wi-Fi Spectrum Signal with no WifiPhyTag"); - return; - } - - WifiTxVector txVector = tag.GetWifiTxVector (); - - if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT - && (txVector.GetNss () != (1 + (txVector.GetMode ().GetMcsValue () / 8)))) - { - NS_FATAL_ERROR ("MCS value does not match NSS value: MCS = " << (uint16_t)txVector.GetMode ().GetMcsValue () << ", NSS = " << (uint16_t)txVector.GetNss ()); - } - - if (txVector.GetNss () > GetMaxSupportedRxSpatialStreams ()) - { - NS_FATAL_ERROR ("Reception ends in failure because of an unsupported number of spatial streams"); - } - - WifiPreamble preamble = txVector.GetPreambleType (); - MpduType mpdutype = tag.GetMpduType (); - - // At this point forward, processing parallels that of - // YansWifiPhy::StartReceivePreambleAndHeader () - - AmpduTag ampduTag; - Time endRx = Simulator::Now () + rxDuration; - Time preambleAndHeaderDuration = CalculatePlcpPreambleAndHeaderDuration (txVector); - - Ptr event; - event = m_interference.Add (packet->GetSize (), - txVector, - rxDuration, - rxPowerW); - - switch (m_state->GetState ()) - { - case SpectrumWifiPhy::SWITCHING: - NS_LOG_DEBUG ("drop packet because of channel switching"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - /* - * 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. - SwitchMaybeToCcaBusy (); - return; - } - break; - case SpectrumWifiPhy::RX: - NS_LOG_DEBUG ("drop packet because already in Rx (power=" << - rxPowerW << "W)"); - NotifyRxDrop (packet); - if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) - { - //that packet will be noise _after_ the reception of the - //currently-received packet. - SwitchMaybeToCcaBusy (); - return; - } - break; - case SpectrumWifiPhy::TX: - NS_LOG_DEBUG ("drop packet because already in Tx (power=" << - rxPowerW << "W)"); - NotifyRxDrop (packet); - if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) - { - //that packet will be noise _after_ the transmission of the - //currently-transmitted packet. - SwitchMaybeToCcaBusy (); - return; - } - break; - case SpectrumWifiPhy::CCA_BUSY: - case SpectrumWifiPhy::IDLE: - if (rxPowerW > GetEdThresholdW ()) //checked here, no need to check in the payload reception (current implementation assumes constant rx power over the packet duration) - { - if (preamble == WIFI_PREAMBLE_NONE && m_mpdusNum == 0) - { - NS_LOG_DEBUG ("drop packet because no preamble has been received"); - NotifyRxDrop (packet); - SwitchMaybeToCcaBusy (); - return; - } - else if (preamble == WIFI_PREAMBLE_NONE && m_plcpSuccess == false) //A-MPDU reception fails - { - NS_LOG_DEBUG ("Drop MPDU because no plcp has been received"); - NotifyRxDrop (packet); - SwitchMaybeToCcaBusy (); - return; - } - else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0) - { - //received the first MPDU in an MPDU - m_mpdusNum = ampduTag.GetRemainingNbOfMpdus () - 1; - m_rxMpduReferenceNumber++; - } - else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) - { - //received the other MPDUs that are part of the A-MPDU - if (ampduTag.GetRemainingNbOfMpdus () < m_mpdusNum) - { - NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetRemainingNbOfMpdus ()); - m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); - } - else - { - m_mpdusNum--; - } - } - else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 ) - { - NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum); - m_mpdusNum = 0; - } - - NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)"); - //sync to signal - m_state->SwitchToRx (rxDuration); - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - NotifyRxBegin (packet); - m_interference.NotifyRxStart (); - - if (preamble != WIFI_PREAMBLE_NONE) - { - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, &SpectrumWifiPhy::StartReceivePacket, this, - packet, txVector, mpdutype, event); - } - - NS_ASSERT (m_endRxEvent.IsExpired ()); - m_endRxEvent = Simulator::Schedule (rxDuration, &SpectrumWifiPhy::EndReceive, this, - packet, preamble, mpdutype, event); - } - else - { - NS_LOG_DEBUG ("drop packet because signal power too Small (" << - rxPowerW << "<" << GetEdThresholdW () << ")"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - SwitchMaybeToCcaBusy (); - return; - } - break; - case SpectrumWifiPhy::SLEEP: - NS_LOG_DEBUG ("drop packet because in sleep mode"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - break; - } - - return; -} - -void -SpectrumWifiPhy::StartReceivePacket (Ptr packet, - WifiTxVector txVector, - MpduType mpdutype, - Ptr event) -{ - NS_LOG_FUNCTION (this << packet << txVector.GetMode () << txVector.GetPreambleType () << (uint32_t)mpdutype); - NS_ASSERT (IsStateRx ()); - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - AmpduTag ampduTag; - WifiMode txMode = txVector.GetMode (); - - InterferenceHelper::SnrPer snrPer; - snrPer = m_interference.CalculatePlcpHeaderSnrPer (event); - - NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); - - if (m_random->GetValue () > snrPer.per) //plcp reception succeeded - { - if (IsModeSupported (txMode) || IsMcsSupported (txMode)) - { - NS_LOG_DEBUG ("receiving plcp payload"); //endReceive is already scheduled - m_plcpSuccess = true; - } - else //mode is not allowed - { - NS_LOG_DEBUG ("drop packet because it was sent using an unsupported mode (" << txMode << ")"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - } - } - else //plcp reception failed - { - NS_LOG_DEBUG ("drop packet because plcp preamble/header reception failed"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - } + StartReceivePreambleAndHeader (packet, rxPowerW, rxDuration); } Ptr @@ -652,65 +264,10 @@ SpectrumWifiPhy::GetTxPowerSpectralDensity (uint32_t centerFrequency, uint32_t c } void -SpectrumWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype) +SpectrumWifiPhy::StartTx (Ptr packet, WifiTxVector txVector, Time txDuration) { - NS_LOG_FUNCTION (this << packet << txVector.GetMode () - << txVector.GetMode ().GetDataRate (txVector) - << txVector.GetPreambleType () - << (uint32_t)txVector.GetTxPowerLevel () - << (uint32_t)mpdutype); - /* Transmission can happen if: - * - we are syncing on a packet. It is the responsability of the - * MAC layer to avoid doing this but the PHY does nothing to - * prevent it. - * - we are idle - */ - NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ()); - - if (txVector.GetNss () > GetMaxSupportedTxSpatialStreams ()) - { - NS_FATAL_ERROR ("Unsupported number of spatial streams!"); - } - - if (m_state->IsStateSleep ()) - { - NS_LOG_DEBUG ("Dropping packet because in sleep mode"); - NotifyTxDrop (packet); - return; - } - - Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, GetFrequency (), mpdutype, 1); - NS_ASSERT (txDuration > NanoSeconds (0)); - - if (m_state->IsStateRx ()) - { - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - m_interference.NotifyRxEnd (); - } - NotifyTxBegin (packet); - if ((mpdutype == MPDU_IN_AGGREGATE) && (txVector.GetPreambleType () != WIFI_PREAMBLE_NONE)) - { - //send the first MPDU in an MPDU - m_txMpduReferenceNumber++; - } - MpduInfo aMpdu; - aMpdu.type = mpdutype; - aMpdu.mpduRefNumber = m_txMpduReferenceNumber; - NotifyMonitorSniffTx (packet, (uint16_t) GetFrequency (), GetChannelNumber (), txVector, aMpdu); - m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel ()), txVector); - // - // Spectrum elements added here - // - Ptr newPacket = packet->Copy (); // obtain non-const Packet - WifiPhyTag oldtag; - newPacket->RemovePacketTag (oldtag); - WifiPhyTag tag (txVector, mpdutype); - newPacket->AddPacketTag (tag); - - NS_LOG_DEBUG ("Transmission signal power before antenna gain: " << GetPowerDbm (txVector.GetTxPowerLevel ()) << " dBm"); + NS_LOG_DEBUG ("Start transmission: signal power before antenna gain=" << GetPowerDbm (txVector.GetTxPowerLevel ()) << "dBm"); double txPowerWatts = DbmToW (GetPowerDbm (txVector.GetTxPowerLevel ()) + GetTxGain ()); - Ptr txPowerSpectrum = GetTxPowerSpectralDensity (GetFrequency (), GetChannelWidth (), txPowerWatts); Ptr txParams = Create (); txParams->duration = txDuration; @@ -718,80 +275,10 @@ SpectrumWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, Mp NS_ASSERT_MSG (m_wifiSpectrumPhyInterface, "SpectrumPhy() is not set; maybe forgot to call CreateWifiSpectrumPhyInterface?"); txParams->txPhy = m_wifiSpectrumPhyInterface->GetObject (); txParams->txAntenna = m_antenna; - txParams->packet = newPacket; + txParams->packet = packet; NS_LOG_DEBUG ("Starting transmission with power " << WToDbm (txPowerWatts) << " dBm on channel " << GetChannelNumber ()); NS_LOG_DEBUG ("Starting transmission with integrated spectrum power " << WToDbm (Integral (*txPowerSpectrum)) << " dBm; spectrum model Uid: " << txPowerSpectrum->GetSpectrumModel ()->GetUid ()); m_channel->StartTx (txParams); } -void -SpectrumWifiPhy::RegisterListener (WifiPhyListener *listener) -{ - m_state->RegisterListener (listener); -} - -void -SpectrumWifiPhy::UnregisterListener (WifiPhyListener *listener) -{ - m_state->UnregisterListener (listener); -} - -void -SpectrumWifiPhy::EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event) -{ - NS_LOG_FUNCTION (this << packet << event); - NS_ASSERT (IsStateRx ()); - NS_ASSERT (event->GetEndTime () == Simulator::Now ()); - - InterferenceHelper::SnrPer snrPer; - snrPer = m_interference.CalculatePlcpPayloadSnrPer (event); - m_interference.NotifyRxEnd (); - bool rxSucceeded; - - if (m_plcpSuccess == true) - { - NS_LOG_DEBUG ("mode=" << (event->GetPayloadMode ().GetDataRate (event->GetTxVector ())) << - ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << packet->GetSize ()); - - if (m_random->GetValue () > snrPer.per) - { - NotifyRxEnd (packet); - SignalNoiseDbm signalNoise; - signalNoise.signal = RatioToDb (event->GetRxPowerW ()) + 30; - signalNoise.noise = RatioToDb (event->GetRxPowerW () / snrPer.snr) - GetRxNoiseFigure () + 30; - MpduInfo aMpdu; - aMpdu.type = mpdutype; - aMpdu.mpduRefNumber = m_rxMpduReferenceNumber; - NotifyMonitorSniffRx (packet, (uint16_t) GetFrequency (), GetChannelNumber (), event->GetTxVector (), aMpdu, signalNoise); - m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector ()); - rxSucceeded = true; - } - else - { - /* failure. */ - NotifyRxDrop (packet); - m_state->SwitchFromRxEndError (packet, snrPer.snr); - rxSucceeded = false; - } - if (!m_rxCallback.IsNull ()) - { - m_rxCallback (rxSucceeded); - } - } - else - { - m_state->SwitchFromRxEndError (packet, snrPer.snr); - if (!m_rxCallback.IsNull ()) - { - m_rxCallback (false); - } - } - - if (preamble == WIFI_PREAMBLE_NONE && mpdutype == LAST_MPDU_IN_AGGREGATE) - { - m_plcpSuccess = false; - } - -} - } //namespace ns3 diff --git a/src/wifi/model/spectrum-wifi-phy.h b/src/wifi/model/spectrum-wifi-phy.h index ba508d33d..35e1cfc66 100644 --- a/src/wifi/model/spectrum-wifi-phy.h +++ b/src/wifi/model/spectrum-wifi-phy.h @@ -80,19 +80,6 @@ public: */ void ClearOperationalChannelList (void); - /** - * Starting receiving the payload of a packet (i.e. the first bit of the packet has arrived). - * - * \param packet the arriving packet - * \param txVector the TXVECTOR of the arriving packet - * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. - * \param event the corresponding event of the first time the packet arrives - */ - void StartReceivePacket (Ptr packet, - WifiTxVector txVector, - MpduType mpdutype, - Ptr event); - /** * Input method for delivering a signal from the spectrum channel * and low-level Phy interface to this SpectrumWifiPhy instance. @@ -100,6 +87,16 @@ public: * \param rxParams Input signal parameters */ void StartRx (Ptr rxParams); + + /** + * \param packet the packet to send + * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send + * this packet, and txPowerLevel, a power level to use to send this packet. The real transmission + * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels + * \param txDuration duration of the transmission. + */ + void StartTx (Ptr packet, WifiTxVector txVector, Time txDuration); + /** * Method to encapsulate the creation of the WifiSpectrumPhyInterface * object (used to bind the WifiSpectrumPhy to a SpectrumChannel) and @@ -136,19 +133,6 @@ public: * returned, it means that any model will be accepted. */ Ptr GetRxSpectrumModel () const; - /** - * Callback invoked at the end of a frame reception, to notify whether - * the frame was received successfully (true) or not (false) - */ - typedef Callback RxCallback; - /** - * Set the packet received callback (invoked at the end of a frame - * reception), to notify whether the frame was received successfully - * or not. - * - * \param callback the function to hook to the callback - */ - void SetPacketReceivedCallback (RxCallback callback); /** * Callback invoked when the Phy model starts to process a signal @@ -160,33 +144,16 @@ public: */ typedef void (* SignalArrivalCallback) (bool signalType, uint32_t senderNodeId, double rxPower, Time duration); - virtual void SetReceiveOkCallback (WifiPhy::RxOkCallback callback); - virtual void SetReceiveErrorCallback (WifiPhy::RxErrorCallback callback); - virtual void SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype = NORMAL_MPDU); - virtual void RegisterListener (WifiPhyListener *listener); - virtual void UnregisterListener (WifiPhyListener *listener); - virtual void SetSleepMode (void); - virtual void ResumeFromSleep (void); virtual Ptr GetChannel (void) const; + protected: // Inherited virtual void DoDispose (void); virtual void DoInitialize (void); - virtual bool DoChannelSwitch (uint16_t id); - virtual bool DoFrequencySwitch (uint32_t frequency); + private: - /** - * The last bit of the packet has arrived. - * - * \param packet the packet that the last bit has arrived - * \param preamble the preamble of the arriving packet - * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. - * \param event the corresponding event of the first time the packet arrives - */ - void EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event); - /** * \param centerFrequency center frequency (MHz) * \param channelWidth channel width (MHz) of the channel @@ -204,7 +171,6 @@ private: Ptr m_wifiSpectrumPhyInterface; Ptr m_antenna; mutable Ptr m_rxSpectrumModel; - RxCallback m_rxCallback; bool m_disableWifiReception; //!< forces this Phy to fail to sync on any signal TracedCallback m_signalCb; diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index cd2c685ff..6576e9b59 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -34,7 +34,9 @@ #include "ns3/pointer.h" #include "ns3/trace-source-accessor.h" #include "ns3/fatal-error.h" -#include +#include "wifi-phy-tag.h" +#include "ampdu-tag.h" +#include "wifi-utils.h" namespace ns3 { @@ -415,6 +417,30 @@ WifiPhy::DoInitialize (void) InitializeFrequencyChannelNumber (); } +void +WifiPhy::SetReceiveOkCallback (RxOkCallback callback) +{ + m_state->SetReceiveOkCallback (callback); +} + +void +WifiPhy::SetReceiveErrorCallback (RxErrorCallback callback) +{ + m_state->SetReceiveErrorCallback (callback); +} + +void +WifiPhy::RegisterListener (WifiPhyListener *listener) +{ + m_state->RegisterListener (listener); +} + +void +WifiPhy::UnregisterListener (WifiPhyListener *listener) +{ + m_state->UnregisterListener (listener); +} + void WifiPhy::InitializeFrequencyChannelNumber (void) { @@ -1364,15 +1390,169 @@ WifiPhy::GetChannelNumber (void) const bool WifiPhy::DoChannelSwitch (uint16_t nch) { + if (!IsInitialized ()) + { + //this is not channel switch, this is initialization + NS_LOG_DEBUG ("initialize to channel " << nch); + return true; + } + + NS_ASSERT (!IsStateSwitching ()); + switch (m_state->GetState ()) + { + case WifiPhy::RX: + NS_LOG_DEBUG ("drop packet because of channel switching while reception"); + m_endPlcpRxEvent.Cancel (); + m_endRxEvent.Cancel (); + goto switchChannel; + break; + case WifiPhy::TX: + NS_LOG_DEBUG ("channel switching postponed until end of current transmission"); + Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetChannelNumber, this, nch); + break; + case WifiPhy::CCA_BUSY: + case WifiPhy::IDLE: + goto switchChannel; + break; + case WifiPhy::SLEEP: + NS_LOG_DEBUG ("channel switching ignored in sleep mode"); + break; + default: + NS_ASSERT (false); + break; + } + + return false; + +switchChannel: + + NS_LOG_DEBUG ("switching channel " << GetChannelNumber () << " -> " << nch); + m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); + 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. + */ return true; } bool WifiPhy::DoFrequencySwitch (uint32_t frequency) { + if (!IsInitialized ()) + { + //this is not channel switch, this is initialization + NS_LOG_DEBUG ("start at frequency " << frequency); + return true; + } + + NS_ASSERT (!IsStateSwitching ()); + switch (m_state->GetState ()) + { + case WifiPhy::RX: + NS_LOG_DEBUG ("drop packet because of channel/frequency switching while reception"); + m_endPlcpRxEvent.Cancel (); + m_endRxEvent.Cancel (); + goto switchFrequency; + break; + case WifiPhy::TX: + NS_LOG_DEBUG ("channel/frequency switching postponed until end of current transmission"); + Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetFrequency, this, frequency); + break; + case WifiPhy::CCA_BUSY: + case WifiPhy::IDLE: + goto switchFrequency; + break; + case WifiPhy::SLEEP: + NS_LOG_DEBUG ("frequency switching ignored in sleep mode"); + break; + default: + NS_ASSERT (false); + break; + } + + return false; + +switchFrequency: + + NS_LOG_DEBUG ("switching frequency " << GetFrequency () << " -> " << frequency); + m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); + 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. + */ return true; } +void +WifiPhy::SetSleepMode (void) +{ + NS_LOG_FUNCTION (this); + switch (m_state->GetState ()) + { + case WifiPhy::TX: + NS_LOG_DEBUG ("setting sleep mode postponed until end of current transmission"); + Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetSleepMode, this); + break; + case WifiPhy::RX: + NS_LOG_DEBUG ("setting sleep mode postponed until end of current reception"); + Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetSleepMode, this); + break; + case WifiPhy::SWITCHING: + NS_LOG_DEBUG ("setting sleep mode postponed until end of channel switching"); + Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetSleepMode, this); + break; + case WifiPhy::CCA_BUSY: + case WifiPhy::IDLE: + NS_LOG_DEBUG ("setting sleep mode"); + m_state->SwitchToSleep (); + break; + case WifiPhy::SLEEP: + NS_LOG_DEBUG ("already in sleep mode"); + break; + default: + NS_ASSERT (false); + break; + } +} + +void +WifiPhy::ResumeFromSleep (void) +{ + NS_LOG_FUNCTION (this); + switch (m_state->GetState ()) + { + case WifiPhy::TX: + case WifiPhy::RX: + case WifiPhy::IDLE: + case WifiPhy::CCA_BUSY: + case WifiPhy::SWITCHING: + { + NS_LOG_DEBUG ("not in sleep mode, there is nothing to resume"); + break; + } + case WifiPhy::SLEEP: + { + NS_LOG_DEBUG ("resuming from sleep mode"); + Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); + m_state->SwitchFromSleep (delayUntilCcaEnd); + break; + } + default: + { + NS_ASSERT (false); + break; + } + } +} + WifiMode WifiPhy::GetHtPlcpHeaderMode (WifiMode payloadMode) { @@ -2026,6 +2206,323 @@ WifiPhy::NotifyMonitorSniffTx (Ptr packet, uint16_t channelFreqMhz m_phyMonitorSniffTxTrace (packet, channelFreqMhz, channelNumber, txVector, aMpdu); } +void +WifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype) +{ + NS_LOG_FUNCTION (this << packet << txVector.GetMode () + << txVector.GetMode ().GetDataRate (txVector) + << txVector.GetPreambleType () + << (uint32_t)txVector.GetTxPowerLevel () + << (uint32_t)mpdutype); + /* Transmission can happen if: + * - we are syncing on a packet. It is the responsability of the + * MAC layer to avoid doing this but the PHY does nothing to + * prevent it. + * - we are idle + */ + NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ()); + + if (txVector.GetNss () > GetMaxSupportedTxSpatialStreams ()) + { + NS_FATAL_ERROR ("Unsupported number of spatial streams!"); + } + + if (m_state->IsStateSleep ()) + { + NS_LOG_DEBUG ("Dropping packet because in sleep mode"); + NotifyTxDrop (packet); + return; + } + + Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, GetFrequency (), mpdutype, 1); + NS_ASSERT (txDuration > NanoSeconds (0)); + + if (m_state->IsStateRx ()) + { + m_endPlcpRxEvent.Cancel (); + m_endRxEvent.Cancel (); + m_interference.NotifyRxEnd (); + } + NotifyTxBegin (packet); + if ((mpdutype == MPDU_IN_AGGREGATE) && (txVector.GetPreambleType () != WIFI_PREAMBLE_NONE)) + { + //send the first MPDU in an MPDU + m_txMpduReferenceNumber++; + } + MpduInfo aMpdu; + aMpdu.type = mpdutype; + aMpdu.mpduRefNumber = m_txMpduReferenceNumber; + NotifyMonitorSniffTx (packet, (uint16_t) GetFrequency (), GetChannelNumber (), txVector, aMpdu); + m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel ()), txVector); + + Ptr newPacket = packet->Copy (); // obtain non-const Packet + WifiPhyTag oldtag; + newPacket->RemovePacketTag (oldtag); + WifiPhyTag tag (txVector, mpdutype); + newPacket->AddPacketTag (tag); + + StartTx (newPacket, txVector, txDuration); +} + +void +WifiPhy::StartReceivePreambleAndHeader (Ptr packet, double rxPowerW, Time rxDuration) +{ + //This function should be later split to check separately whether plcp preamble and plcp header can be successfully received. + //Note: plcp preamble reception is not yet modeled. + NS_LOG_FUNCTION (this << packet << WToDbm (rxPowerW) << rxDuration); + AmpduTag ampduTag; + Time endRx = Simulator::Now () + rxDuration; + + WifiPhyTag tag; + bool found = packet->RemovePacketTag (tag); + if (!found) + { + NS_FATAL_ERROR ("Received Wi-Fi Signal with no WifiPhyTag"); + return; + } + + WifiTxVector txVector = tag.GetWifiTxVector (); + + if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT + && (txVector.GetNss () != (1 + (txVector.GetMode ().GetMcsValue () / 8)))) + { + NS_FATAL_ERROR ("MCS value does not match NSS value: MCS = " << (uint16_t)txVector.GetMode ().GetMcsValue () << ", NSS = " << (uint16_t)txVector.GetNss ()); + } + + if (txVector.GetNss () > GetMaxSupportedRxSpatialStreams ()) + { + NS_FATAL_ERROR ("Reception ends in failure because of an unsupported number of spatial streams"); + } + + WifiPreamble preamble = txVector.GetPreambleType (); + MpduType mpdutype = tag.GetMpduType (); + Time preambleAndHeaderDuration = CalculatePlcpPreambleAndHeaderDuration (txVector); + + Ptr event; + event = m_interference.Add (packet->GetSize (), + txVector, + rxDuration, + rxPowerW); + + switch (m_state->GetState ()) + { + case WifiPhy::SWITCHING: + NS_LOG_DEBUG ("drop packet because of channel switching"); + NotifyRxDrop (packet); + m_plcpSuccess = false; + /* + * 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 WifiPhy::RX: + NS_LOG_DEBUG ("drop packet because already in Rx (power=" << + rxPowerW << "W)"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + //that packet will be noise _after_ the reception of the + //currently-received packet. + goto maybeCcaBusy; + } + break; + case WifiPhy::TX: + NS_LOG_DEBUG ("drop packet because already in Tx (power=" << + rxPowerW << "W)"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + //that packet will be noise _after_ the transmission of the + //currently-transmitted packet. + goto maybeCcaBusy; + } + break; + case WifiPhy::CCA_BUSY: + case WifiPhy::IDLE: + if (rxPowerW > GetEdThresholdW ()) //checked here, no need to check in the payload reception (current implementation assumes constant rx power over the packet duration) + { + if (preamble == WIFI_PREAMBLE_NONE && (m_mpdusNum == 0 || m_plcpSuccess == false)) + { + m_plcpSuccess = false; + m_mpdusNum = 0; + NS_LOG_DEBUG ("drop packet because no PLCP preamble/header has been received"); + NotifyRxDrop (packet); + goto maybeCcaBusy; + } + else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0) + { + //received the first MPDU in an MPDU + m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); + m_rxMpduReferenceNumber++; + } + else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) + { + //received the other MPDUs that are part of the A-MPDU + if (ampduTag.GetRemainingNbOfMpdus () < (m_mpdusNum - 1)) + { + NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetRemainingNbOfMpdus ()); + m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); + } + else + { + m_mpdusNum--; + } + } + else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) + { + NS_LOG_DEBUG ("New A-MPDU started while " << m_mpdusNum << " MPDUs from previous are lost"); + m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); + } + else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 ) + { + NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum); + m_mpdusNum = 0; + } + + NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)"); + //sync to signal + m_state->SwitchToRx (rxDuration); + NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); + NotifyRxBegin (packet); + m_interference.NotifyRxStart (); + + if (preamble != WIFI_PREAMBLE_NONE) + { + NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); + m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, &WifiPhy::StartReceivePacket, this, + packet, txVector, mpdutype, event); + } + + NS_ASSERT (m_endRxEvent.IsExpired ()); + m_endRxEvent = Simulator::Schedule (rxDuration, &WifiPhy::EndReceive, this, + packet, preamble, mpdutype, event); + } + else + { + NS_LOG_DEBUG ("drop packet because signal power too Small (" << + rxPowerW << "<" << GetEdThresholdW () << ")"); + NotifyRxDrop (packet); + m_plcpSuccess = false; + goto maybeCcaBusy; + } + break; + case WifiPhy::SLEEP: + NS_LOG_DEBUG ("drop packet because in sleep mode"); + NotifyRxDrop (packet); + m_plcpSuccess = false; + break; + } + + return; + +maybeCcaBusy: + //We are here because we have received the first bit of a packet and we are + //not going to be able to synchronize on it + //In this model, CCA becomes busy when the aggregation of all signals as + //tracked by the InterferenceHelper class is higher than the CcaBusyThreshold + + Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); + if (!delayUntilCcaEnd.IsZero ()) + { + m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd); + } +} + +void +WifiPhy::StartReceivePacket (Ptr packet, + WifiTxVector txVector, + MpduType mpdutype, + Ptr event) +{ + NS_LOG_FUNCTION (this << packet << txVector.GetMode () << txVector.GetPreambleType () << (uint32_t)mpdutype); + NS_ASSERT (IsStateRx ()); + NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); + WifiMode txMode = txVector.GetMode (); + + InterferenceHelper::SnrPer snrPer; + snrPer = m_interference.CalculatePlcpHeaderSnrPer (event); + + NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); + + if (m_random->GetValue () > snrPer.per) //plcp reception succeeded + { + if (IsModeSupported (txMode) || IsMcsSupported (txMode)) + { + NS_LOG_DEBUG ("receiving plcp payload"); //endReceive is already scheduled + m_plcpSuccess = true; + } + else //mode is not allowed + { + NS_LOG_DEBUG ("drop packet because it was sent using an unsupported mode (" << txMode << ")"); + NotifyRxDrop (packet); + m_plcpSuccess = false; + } + } + else //plcp reception failed + { + NS_LOG_DEBUG ("drop packet because plcp preamble/header reception failed"); + NotifyRxDrop (packet); + m_plcpSuccess = false; + } +} + +void +WifiPhy::EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event) +{ + NS_LOG_FUNCTION (this << packet << event); + NS_ASSERT (IsStateRx ()); + NS_ASSERT (event->GetEndTime () == Simulator::Now ()); + + InterferenceHelper::SnrPer snrPer; + snrPer = m_interference.CalculatePlcpPayloadSnrPer (event); + m_interference.NotifyRxEnd (); + + if (m_plcpSuccess == true) + { + NS_LOG_DEBUG ("mode=" << (event->GetPayloadMode ().GetDataRate (event->GetTxVector ())) << + ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << packet->GetSize ()); + + if (m_random->GetValue () > snrPer.per) + { + NotifyRxEnd (packet); + SignalNoiseDbm signalNoise; + signalNoise.signal = RatioToDb (event->GetRxPowerW ()) + 30; + signalNoise.noise = RatioToDb (event->GetRxPowerW () / snrPer.snr) - GetRxNoiseFigure () + 30; + MpduInfo aMpdu; + aMpdu.type = mpdutype; + aMpdu.mpduRefNumber = m_rxMpduReferenceNumber; + NotifyMonitorSniffRx (packet, (uint16_t) GetFrequency (), GetChannelNumber (), event->GetTxVector (), aMpdu, signalNoise); + m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector ()); + } + else + { + /* failure. */ + NotifyRxDrop (packet); + m_state->SwitchFromRxEndError (packet, snrPer.snr); + } + } + else + { + m_state->SwitchFromRxEndError (packet, snrPer.snr); + } + + if (preamble == WIFI_PREAMBLE_NONE && mpdutype == LAST_MPDU_IN_AGGREGATE) + { + m_plcpSuccess = false; + } + +} + // Clause 15 rates (DSSS) @@ -2904,32 +3401,6 @@ WifiPhy::GetMcs (uint8_t mcs) const return m_deviceMcsSet[mcs]; } -double -WifiPhy::DbToRatio (double dB) const -{ - double ratio = std::pow (10.0, dB / 10.0); - return ratio; -} - -double -WifiPhy::DbmToW (double dBm) const -{ - double mW = std::pow (10.0, dBm / 10.0); - return mW / 1000.0; -} - -double -WifiPhy::WToDbm (double w) const -{ - return 10.0 * std::log10 (w * 1000.0); -} - -double -WifiPhy::RatioToDb (double ratio) const -{ - return 10.0 * std::log10 (ratio); -} - bool WifiPhy::IsStateCcaBusy (void) { diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 7ced529dc..5c6b80dd5 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -215,13 +215,62 @@ public: * \param callback the callback to invoke * upon successful packet reception. */ - virtual void SetReceiveOkCallback (RxOkCallback callback) = 0; + void SetReceiveOkCallback (RxOkCallback callback); /** * \param callback the callback to invoke * upon erroneous packet reception. */ - virtual void SetReceiveErrorCallback (RxErrorCallback callback) = 0; - + void SetReceiveErrorCallback (RxErrorCallback callback); + + /** + * \param listener the new listener + * + * Add the input listener to the list of objects to be notified of + * PHY-level events. + */ + void RegisterListener (WifiPhyListener *listener); + /** + * \param listener the listener to be unregistered + * + * Remove the input listener from the list of objects to be notified of + * PHY-level events. + */ + void UnregisterListener (WifiPhyListener *listener); + + /** + * Starting receiving the plcp of a packet (i.e. the first bit of the preamble has arrived). + * + * \param packet the arriving packet + * \param rxPowerW the receive power in W + * \param rxDuration the duration needed for the reception of the packet + */ + void StartReceivePreambleAndHeader (Ptr packet, + double rxPowerW, + Time rxDuration); + + /** + * Starting receiving the payload of a packet (i.e. the first bit of the packet has arrived). + * + * \param packet the arriving packet + * \param txVector the TXVECTOR of the arriving packet + * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. + * \param event the corresponding event of the first time the packet arrives + */ + void StartReceivePacket (Ptr packet, + WifiTxVector txVector, + MpduType mpdutype, + Ptr event); + + /** + * The last bit of the packet has arrived. + * + * \param packet the packet that the last bit has arrived + * \param preamble the preamble of the arriving packet + * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. + * \param event the corresponding event of the first time the packet arrives + */ + void EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event); + /** * \param packet the packet to send * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send @@ -229,31 +278,25 @@ public: * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. */ - virtual void SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype = NORMAL_MPDU) = 0; - + void SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype = NORMAL_MPDU); + /** - * \param listener the new listener - * - * Add the input listener to the list of objects to be notified of - * PHY-level events. + * \param packet the packet to send + * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send + * this packet, and txPowerLevel, a power level to use to send this packet. The real transmission + * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels + * \param txDuration duration of the transmission. */ - virtual void RegisterListener (WifiPhyListener *listener) = 0; - /** - * \param listener the listener to be unregistered - * - * Remove the input listener from the list of objects to be notified of - * PHY-level events. - */ - virtual void UnregisterListener (WifiPhyListener *listener) = 0; + virtual void StartTx (Ptr packet, WifiTxVector txVector, Time txDuration) = 0; /** * Put in sleep mode. */ - virtual void SetSleepMode (void) = 0; + virtual void SetSleepMode (void); /** * Resume from sleep mode. */ - virtual void ResumeFromSleep (void) = 0; + virtual void ResumeFromSleep (void); /** * \return true of the current state of the PHY layer is WifiPhy::IDLE, false otherwise. @@ -1490,38 +1533,7 @@ public: * \return a vector containing the supported channel widths, values in MHz */ virtual std::vector GetSupportedChannelWidthSet (void) const; - /** - * Convert from dBm to Watts. - * - * \param dbm the power in dBm - * - * \return the equivalent Watts for the given dBm - */ - double DbmToW (double dbm) const; - /** - * Convert from dB to ratio. - * - * \param db - * - * \return ratio - */ - double DbToRatio (double db) const; - /** - * Convert from Watts to dBm. - * - * \param w the power in Watts - * - * \return the equivalent dBm for the given Watts - */ - double WToDbm (double w) const; - /** - * Convert from ratio to dB. - * - * \param ratio - * - * \return dB - */ - double RatioToDb (double ratio) const; + protected: // Inherited diff --git a/src/wifi/model/wifi-utils.cc b/src/wifi/model/wifi-utils.cc new file mode 100644 index 000000000..1edd4c224 --- /dev/null +++ b/src/wifi/model/wifi-utils.cc @@ -0,0 +1,52 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#include "wifi-utils.h" +#include + +namespace ns3 { + +double +DbToRatio (double dB) +{ + double ratio = std::pow (10.0, dB / 10.0); + return ratio; +} + +double +DbmToW (double dBm) +{ + double mW = std::pow (10.0, dBm / 10.0); + return mW / 1000.0; +} + +double +WToDbm (double w) +{ + return 10.0 * std::log10 (w * 1000.0); +} + +double +RatioToDb (double ratio) +{ + return 10.0 * std::log10 (ratio); +} + +} //namespace ns3 diff --git a/src/wifi/model/wifi-utils.h b/src/wifi/model/wifi-utils.h new file mode 100644 index 000000000..a4613616a --- /dev/null +++ b/src/wifi/model/wifi-utils.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#ifndef WIFI_UTILS_H +#define WIFI_UTILS_H + +namespace ns3 { + + /** + * Convert from dBm to Watts. + * + * \param dbm the power in dBm + * + * \return the equivalent Watts for the given dBm + */ + double DbmToW (double dbm); + /** + * Convert from dB to ratio. + * + * \param db + * + * \return ratio + */ + double DbToRatio (double db); + /** + * Convert from Watts to dBm. + * + * \param w the power in Watts + * + * \return the equivalent dBm for the given Watts + */ + double WToDbm (double w); + /** + * Convert from ratio to dB. + * + * \param ratio + * + * \return dB + */ + double RatioToDb (double ratio); + +} // namespace ns3 + +#endif /* WIFI_UTILS_H */ diff --git a/src/wifi/model/yans-wifi-channel.cc b/src/wifi/model/yans-wifi-channel.cc index 6e2a8b566..5cf541112 100644 --- a/src/wifi/model/yans-wifi-channel.cc +++ b/src/wifi/model/yans-wifi-channel.cc @@ -29,6 +29,7 @@ #include "yans-wifi-channel.h" #include "ns3/propagation-loss-model.h" #include "ns3/propagation-delay-model.h" +#include "wifi-utils.h" namespace ns3 { @@ -120,7 +121,7 @@ YansWifiChannel::Send (Ptr sender, Ptr packet, double void YansWifiChannel::Receive (uint32_t i, Ptr packet, double rxPowerDbm, Time duration) const { - m_phyList[i]->StartReceivePreambleAndHeader (packet, rxPowerDbm, duration); + m_phyList[i]->StartReceivePreambleAndHeader (packet, DbmToW (rxPowerDbm + m_phyList[i]->GetRxGain ()), duration); } uint32_t diff --git a/src/wifi/model/yans-wifi-phy.cc b/src/wifi/model/yans-wifi-phy.cc index 57938db0d..2ac109109 100644 --- a/src/wifi/model/yans-wifi-phy.cc +++ b/src/wifi/model/yans-wifi-phy.cc @@ -28,9 +28,7 @@ #include "ns3/assert.h" #include "ns3/log.h" #include "ns3/double.h" -#include "ampdu-tag.h" -#include "wifi-phy-tag.h" -#include +#include "wifi-utils.h" namespace ns3 { @@ -66,110 +64,6 @@ YansWifiPhy::DoDispose (void) m_channel = 0; } -bool -YansWifiPhy::DoChannelSwitch (uint16_t nch) -{ - if (!IsInitialized ()) - { - //this is not channel switch, this is initialization - NS_LOG_DEBUG ("initialize to channel " << nch); - return true; - } - - NS_ASSERT (!IsStateSwitching ()); - switch (m_state->GetState ()) - { - case YansWifiPhy::RX: - NS_LOG_DEBUG ("drop packet because of channel switching while reception"); - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - goto switchChannel; - break; - case YansWifiPhy::TX: - NS_LOG_DEBUG ("channel switching postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetChannelNumber, this, nch); - break; - case YansWifiPhy::CCA_BUSY: - case YansWifiPhy::IDLE: - goto switchChannel; - break; - case YansWifiPhy::SLEEP: - NS_LOG_DEBUG ("channel switching ignored in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } - - return false; - -switchChannel: - - NS_LOG_DEBUG ("switching channel " << GetChannelNumber () << " -> " << nch); - m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); - 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. - */ - return true; -} - -bool -YansWifiPhy::DoFrequencySwitch (uint32_t frequency) -{ - if (!IsInitialized ()) - { - //this is not channel switch, this is initialization - NS_LOG_DEBUG ("start at frequency " << frequency); - return true; - } - - NS_ASSERT (!IsStateSwitching ()); - switch (m_state->GetState ()) - { - case YansWifiPhy::RX: - NS_LOG_DEBUG ("drop packet because of channel/frequency switching while reception"); - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - goto switchFrequency; - break; - case YansWifiPhy::TX: - NS_LOG_DEBUG ("channel/frequency switching postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &WifiPhy::SetFrequency, this, frequency); - break; - case YansWifiPhy::CCA_BUSY: - case YansWifiPhy::IDLE: - goto switchFrequency; - break; - case YansWifiPhy::SLEEP: - NS_LOG_DEBUG ("frequency switching ignored in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } - - return false; - -switchFrequency: - - NS_LOG_DEBUG ("switching frequency " << GetFrequency () << " -> " << frequency); - m_state->SwitchToChannelSwitching (GetChannelSwitchDelay ()); - 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. - */ - return true; -} - Ptr YansWifiPhy::GetChannel (void) const { @@ -184,398 +78,10 @@ YansWifiPhy::SetChannel (Ptr channel) } void -YansWifiPhy::SetSleepMode (void) +YansWifiPhy::StartTx (Ptr packet, WifiTxVector txVector, Time txDuration) { - NS_LOG_FUNCTION (this); - switch (m_state->GetState ()) - { - case YansWifiPhy::TX: - NS_LOG_DEBUG ("setting sleep mode postponed until end of current transmission"); - Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this); - break; - case YansWifiPhy::RX: - NS_LOG_DEBUG ("setting sleep mode postponed until end of current reception"); - Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this); - break; - case YansWifiPhy::SWITCHING: - NS_LOG_DEBUG ("setting sleep mode postponed until end of channel switching"); - Simulator::Schedule (GetDelayUntilIdle (), &YansWifiPhy::SetSleepMode, this); - break; - case YansWifiPhy::CCA_BUSY: - case YansWifiPhy::IDLE: - NS_LOG_DEBUG ("setting sleep mode"); - m_state->SwitchToSleep (); - break; - case YansWifiPhy::SLEEP: - NS_LOG_DEBUG ("already in sleep mode"); - break; - default: - NS_ASSERT (false); - break; - } -} - -void -YansWifiPhy::ResumeFromSleep (void) -{ - NS_LOG_FUNCTION (this); - switch (m_state->GetState ()) - { - case YansWifiPhy::TX: - case YansWifiPhy::RX: - case YansWifiPhy::IDLE: - case YansWifiPhy::CCA_BUSY: - case YansWifiPhy::SWITCHING: - { - NS_LOG_DEBUG ("not in sleep mode, there is nothing to resume"); - break; - } - case YansWifiPhy::SLEEP: - { - NS_LOG_DEBUG ("resuming from sleep mode"); - Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); - m_state->SwitchFromSleep (delayUntilCcaEnd); - break; - } - default: - { - NS_ASSERT (false); - break; - } - } -} - -void -YansWifiPhy::SetReceiveOkCallback (RxOkCallback callback) -{ - m_state->SetReceiveOkCallback (callback); -} - -void -YansWifiPhy::SetReceiveErrorCallback (RxErrorCallback callback) -{ - m_state->SetReceiveErrorCallback (callback); -} - -void -YansWifiPhy::StartReceivePreambleAndHeader (Ptr packet, double rxPowerDbm, Time rxDuration) -{ - //This function should be later split to check separately whether plcp preamble and plcp header can be successfully received. - //Note: plcp preamble reception is not yet modeled. - NS_LOG_FUNCTION (this << packet << rxPowerDbm << rxDuration); - AmpduTag ampduTag; - rxPowerDbm += GetRxGain (); - double rxPowerW = DbmToW (rxPowerDbm); - Time endRx = Simulator::Now () + rxDuration; - - WifiPhyTag tag; - packet->RemovePacketTag (tag); - WifiTxVector txVector = tag.GetWifiTxVector (); - - if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT - && (txVector.GetNss () != (1 + (txVector.GetMode ().GetMcsValue () / 8)))) - { - NS_FATAL_ERROR ("MCS value does not match NSS value: MCS = " << (uint16_t)txVector.GetMode ().GetMcsValue () << ", NSS = " << (uint16_t)txVector.GetNss ()); - } - - if (txVector.GetNss () > GetMaxSupportedRxSpatialStreams ()) - { - NS_FATAL_ERROR ("Reception ends in failure because of an unsupported number of spatial streams"); - } - - WifiPreamble preamble = txVector.GetPreambleType (); - MpduType mpdutype = tag.GetMpduType (); - Time preambleAndHeaderDuration = CalculatePlcpPreambleAndHeaderDuration (txVector); - - Ptr event; - event = m_interference.Add (packet->GetSize (), - txVector, - rxDuration, - rxPowerW); - - switch (m_state->GetState ()) - { - case YansWifiPhy::SWITCHING: - NS_LOG_DEBUG ("drop packet because of channel switching"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - /* - * 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::RX: - NS_LOG_DEBUG ("drop packet because already in Rx (power=" << - rxPowerW << "W)"); - NotifyRxDrop (packet); - if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) - { - //that packet will be noise _after_ the reception of the - //currently-received packet. - goto maybeCcaBusy; - } - break; - case YansWifiPhy::TX: - NS_LOG_DEBUG ("drop packet because already in Tx (power=" << - rxPowerW << "W)"); - NotifyRxDrop (packet); - if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) - { - //that packet will be noise _after_ the transmission of the - //currently-transmitted packet. - goto maybeCcaBusy; - } - break; - case YansWifiPhy::CCA_BUSY: - case YansWifiPhy::IDLE: - if (rxPowerW > GetEdThresholdW ()) //checked here, no need to check in the payload reception (current implementation assumes constant rx power over the packet duration) - { - if (preamble == WIFI_PREAMBLE_NONE && (m_mpdusNum == 0 || m_plcpSuccess == false)) - { - m_plcpSuccess = false; - m_mpdusNum = 0; - NS_LOG_DEBUG ("drop packet because no PLCP preamble/header has been received"); - NotifyRxDrop (packet); - goto maybeCcaBusy; - } - else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0) - { - //received the first MPDU in an MPDU - m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); - m_rxMpduReferenceNumber++; - } - else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) - { - //received the other MPDUs that are part of the A-MPDU - if (ampduTag.GetRemainingNbOfMpdus () < (m_mpdusNum - 1)) - { - NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetRemainingNbOfMpdus ()); - m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); - } - else - { - m_mpdusNum--; - } - } - else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) - { - NS_LOG_DEBUG ("New A-MPDU started while " << m_mpdusNum << " MPDUs from previous are lost"); - m_mpdusNum = ampduTag.GetRemainingNbOfMpdus (); - } - else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 ) - { - NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum); - m_mpdusNum = 0; - } - - NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)"); - //sync to signal - m_state->SwitchToRx (rxDuration); - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - NotifyRxBegin (packet); - m_interference.NotifyRxStart (); - - if (preamble != WIFI_PREAMBLE_NONE) - { - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, &YansWifiPhy::StartReceivePacket, this, - packet, txVector, mpdutype, event); - } - - NS_ASSERT (m_endRxEvent.IsExpired ()); - m_endRxEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndReceive, this, - packet, preamble, mpdutype, event); - } - else - { - NS_LOG_DEBUG ("drop packet because signal power too Small (" << - rxPowerW << "<" << GetEdThresholdW () << ")"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - goto maybeCcaBusy; - } - break; - case YansWifiPhy::SLEEP: - NS_LOG_DEBUG ("drop packet because in sleep mode"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - break; - } - - return; - -maybeCcaBusy: - //We are here because we have received the first bit of a packet and we are - //not going to be able to synchronize on it - //In this model, CCA becomes busy when the aggregation of all signals as - //tracked by the InterferenceHelper class is higher than the CcaBusyThreshold - - Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); - if (!delayUntilCcaEnd.IsZero ()) - { - m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd); - } -} - -void -YansWifiPhy::StartReceivePacket (Ptr packet, - WifiTxVector txVector, - MpduType mpdutype, - Ptr event) -{ - NS_LOG_FUNCTION (this << packet << txVector.GetMode () << txVector.GetPreambleType () << (uint32_t)mpdutype); - NS_ASSERT (IsStateRx ()); - NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); - WifiMode txMode = txVector.GetMode (); - - InterferenceHelper::SnrPer snrPer; - snrPer = m_interference.CalculatePlcpHeaderSnrPer (event); - - NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); - - if (m_random->GetValue () > snrPer.per) //plcp reception succeeded - { - if (IsModeSupported (txMode) || IsMcsSupported (txMode)) - { - NS_LOG_DEBUG ("receiving plcp payload"); //endReceive is already scheduled - m_plcpSuccess = true; - } - else //mode is not allowed - { - NS_LOG_DEBUG ("drop packet because it was sent using an unsupported mode (" << txMode << ")"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - } - } - else //plcp reception failed - { - NS_LOG_DEBUG ("drop packet because plcp preamble/header reception failed"); - NotifyRxDrop (packet); - m_plcpSuccess = false; - } -} - -void -YansWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype) -{ - NS_LOG_FUNCTION (this << packet << txVector.GetMode () - << txVector.GetMode ().GetDataRate (txVector) << txVector.GetPreambleType () - << (uint32_t)txVector.GetTxPowerLevel () << (uint32_t)mpdutype); - /* Transmission can happen if: - * - we are syncing on a packet. It is the responsability of the - * MAC layer to avoid doing this but the PHY does nothing to - * prevent it. - * - we are idle - */ - NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ()); - - if (txVector.GetNss () > GetMaxSupportedTxSpatialStreams ()) - { - NS_FATAL_ERROR ("Unsupported number of spatial streams!"); - } - - if (m_state->IsStateSleep ()) - { - NS_LOG_DEBUG ("Dropping packet because in sleep mode"); - NotifyTxDrop (packet); - return; - } - - Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, GetFrequency (), mpdutype, 1); - NS_ASSERT (txDuration > NanoSeconds (0)); - - if (m_state->IsStateRx ()) - { - m_endPlcpRxEvent.Cancel (); - m_endRxEvent.Cancel (); - m_interference.NotifyRxEnd (); - } - NotifyTxBegin (packet); - if ((mpdutype == MPDU_IN_AGGREGATE) && (txVector.GetPreambleType () != WIFI_PREAMBLE_NONE)) - { - //send the first MPDU in an MPDU - m_txMpduReferenceNumber++; - } - MpduInfo aMpdu; - aMpdu.type = mpdutype; - aMpdu.mpduRefNumber = m_txMpduReferenceNumber; - NotifyMonitorSniffTx (packet, (uint16_t)GetFrequency (), GetChannelNumber (), txVector, aMpdu); - m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel ()), txVector); - - Ptr newPacket = packet->Copy (); // obtain non-const Packet - WifiPhyTag oldtag; - newPacket->RemovePacketTag (oldtag); - WifiPhyTag tag (txVector, mpdutype); - newPacket->AddPacketTag (tag); - m_channel->Send (this, newPacket, GetPowerDbm (txVector.GetTxPowerLevel ()) + GetTxGain (), txDuration); -} - -void -YansWifiPhy::RegisterListener (WifiPhyListener *listener) -{ - m_state->RegisterListener (listener); -} - -void -YansWifiPhy::UnregisterListener (WifiPhyListener *listener) -{ - m_state->UnregisterListener (listener); -} - -void -YansWifiPhy::EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event) -{ - NS_LOG_FUNCTION (this << packet << event); - NS_ASSERT (IsStateRx ()); - NS_ASSERT (event->GetEndTime () == Simulator::Now ()); - - InterferenceHelper::SnrPer snrPer; - snrPer = m_interference.CalculatePlcpPayloadSnrPer (event); - m_interference.NotifyRxEnd (); - - if (m_plcpSuccess == true) - { - NS_LOG_DEBUG ("mode=" << (event->GetPayloadMode ().GetDataRate (event->GetTxVector ())) << - ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << packet->GetSize ()); - - if (m_random->GetValue () > snrPer.per) - { - NotifyRxEnd (packet); - SignalNoiseDbm signalNoise; - signalNoise.signal = RatioToDb (event->GetRxPowerW ()) + 30; - signalNoise.noise = RatioToDb (event->GetRxPowerW () / snrPer.snr) - GetRxNoiseFigure () + 30; - MpduInfo aMpdu; - aMpdu.type = mpdutype; - aMpdu.mpduRefNumber = m_rxMpduReferenceNumber; - NotifyMonitorSniffRx (packet, (uint16_t)GetFrequency (), GetChannelNumber (), event->GetTxVector (), aMpdu, signalNoise); - m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector ()); - } - else - { - /* failure. */ - NotifyRxDrop (packet); - m_state->SwitchFromRxEndError (packet, snrPer.snr); - } - } - else - { - m_state->SwitchFromRxEndError (packet, snrPer.snr); - } - - if (preamble == WIFI_PREAMBLE_NONE && mpdutype == LAST_MPDU_IN_AGGREGATE) - { - m_plcpSuccess = false; - } + NS_LOG_DEBUG ("Start transmission: signal power before antenna gain=" << GetPowerDbm (txVector.GetTxPowerLevel ()) << "dBm"); + m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel ()) + GetTxGain (), txDuration); } } //namespace ns3 diff --git a/src/wifi/model/yans-wifi-phy.h b/src/wifi/model/yans-wifi-phy.h index 47ea5bcba..fed72ff91 100644 --- a/src/wifi/model/yans-wifi-phy.h +++ b/src/wifi/model/yans-wifi-phy.h @@ -60,54 +60,23 @@ public: void SetChannel (Ptr channel); /** - * Starting receiving the plcp of a packet (i.e. the first bit of the preamble has arrived). - * - * \param packet the arriving packet - * \param rxPowerDbm the receive power in dBm - * \param rxDuration the duration needed for the reception of the packet + * \param packet the packet to send + * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send + * this packet, and txPowerLevel, a power level to use to send this packet. The real transmission + * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels + * \param txDuration duration of the transmission. */ - void StartReceivePreambleAndHeader (Ptr packet, - double rxPowerDbm, - Time rxDuration); - /** - * Starting receiving the payload of a packet (i.e. the first bit of the packet has arrived). - * - * \param packet the arriving packet - * \param txVector the TXVECTOR of the arriving packet - * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. - * \param event the corresponding event of the first time the packet arrives - */ - void StartReceivePacket (Ptr packet, - WifiTxVector txVector, - MpduType mpdutype, - Ptr event); + void StartTx (Ptr packet, WifiTxVector txVector, Time txDuration); - virtual void SetReceiveOkCallback (WifiPhy::RxOkCallback callback); - virtual void SetReceiveErrorCallback (WifiPhy::RxErrorCallback callback); - virtual void SendPacket (Ptr packet, WifiTxVector txVector, MpduType mpdutype = NORMAL_MPDU); - virtual void RegisterListener (WifiPhyListener *listener); - virtual void UnregisterListener (WifiPhyListener *listener); - virtual void SetSleepMode (void); - virtual void ResumeFromSleep (void); virtual Ptr GetChannel (void) const; + protected: // Inherited virtual void DoDispose (void); - virtual bool DoChannelSwitch (uint16_t id); - virtual bool DoFrequencySwitch (uint32_t frequency); + private: - /** - * The last bit of the packet has arrived. - * - * \param packet the packet that the last bit has arrived - * \param preamble the preamble of the arriving packet - * \param mpdutype the type of the MPDU as defined in WifiPhy::MpduType. - * \param event the corresponding event of the first time the packet arrives - */ - void EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutype, Ptr event); - Ptr m_channel; //!< YansWifiChannel that this YansWifiPhy is connected to }; diff --git a/src/wifi/test/spectrum-wifi-phy-test.cc b/src/wifi/test/spectrum-wifi-phy-test.cc index 4737dc149..0abe45abb 100644 --- a/src/wifi/test/spectrum-wifi-phy-test.cc +++ b/src/wifi/test/spectrum-wifi-phy-test.cc @@ -48,7 +48,8 @@ protected: Ptr m_phy; Ptr MakeSignal (double txPowerWatts); void SendSignal (double txPowerWatts); - void SpectrumWifiPhyReceiver (bool rxSucceeded); + void SpectrumWifiPhyRxSuccess (Ptr p, double snr, WifiTxVector txVector); + void SpectrumWifiPhyRxFailure (Ptr p, double snr); uint32_t m_count; private: virtual void DoRun (void); @@ -104,7 +105,13 @@ SpectrumWifiPhyBasicTest::SendSignal (double txPowerWatts) } void -SpectrumWifiPhyBasicTest::SpectrumWifiPhyReceiver (bool rxSucceeded) +SpectrumWifiPhyBasicTest::SpectrumWifiPhyRxSuccess (Ptr p, double snr, WifiTxVector txVector) +{ + m_count++; +} + +void +SpectrumWifiPhyBasicTest::SpectrumWifiPhyRxFailure (Ptr p, double snr) { m_count++; } @@ -124,7 +131,8 @@ SpectrumWifiPhyBasicTest::DoSetup (void) m_phy->SetErrorRateModel (error); m_phy->SetChannelNumber (CHANNEL_NUMBER); m_phy->SetFrequency (FREQUENCY); - m_phy->SetPacketReceivedCallback (MakeCallback (&SpectrumWifiPhyBasicTest::SpectrumWifiPhyReceiver, this)); + m_phy->SetReceiveOkCallback (MakeCallback (&SpectrumWifiPhyBasicTest::SpectrumWifiPhyRxSuccess, this)); + m_phy->SetReceiveErrorCallback (MakeCallback (&SpectrumWifiPhyBasicTest::SpectrumWifiPhyRxFailure, this)); //Bug 2460: CcaMode1Threshold default should be set to -62 dBm when using Spectrum m_phy->SetCcaMode1Threshold (-62.0); } diff --git a/src/wifi/wscript b/src/wifi/wscript index 0ba3c191e..3b07f7733 100644 --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -3,6 +3,7 @@ def build(bld): obj = bld.create_ns3_module('wifi', ['network', 'propagation', 'energy', 'spectrum', 'antenna', 'mobility']) obj.source = [ + 'model/wifi-utils.cc', 'model/wifi-information-element.cc', 'model/wifi-information-element-vector.cc', 'model/wifi-channel.cc', @@ -107,6 +108,7 @@ def build(bld): headers = bld(features='ns3header') headers.module = 'wifi' headers.source = [ + 'model/wifi-utils.h', 'model/wifi-information-element.h', 'model/wifi-information-element-vector.h', 'model/wifi-net-device.h',