wifi: (fixes #2809) Stop wifi devices when energy is depleted

This commit is contained in:
Sébastien Deronne
2018-01-10 17:43:54 +01:00
parent ee8f90a664
commit 1b7dd60567
17 changed files with 280 additions and 51 deletions

View File

@@ -39,6 +39,7 @@ Bugs fixed
- Bug 2766 - core: Modify logging for int64x64 to avoid stack overflow
- Bug 2768 - lte: LteUeNetDevice has a null MAC address
- Bug 2807 - energy: GetTotalEnergyConsumption is not updated correctly
- Bug 2809 - wifi: Wifi doesn't fully stop when energy is depleted
- Bug 2820 - wifi: segmentation fault when Rrpaa wifi manager is used
- Bug 2824 - ICMP opcode fr fragment timeout drop is wrong
- Bug 2828 - OLSR simple P2P example produces wrong results

View File

@@ -162,6 +162,7 @@ BasicEnergySource::UpdateEnergySource (void)
m_energyUpdateEvent.Cancel ();
double remainingEnergy = m_remainingEnergyJ;
CalculateRemainingEnergy ();
m_lastUpdateTime = Simulator::Now ();
@@ -171,12 +172,15 @@ BasicEnergySource::UpdateEnergySource (void)
m_depleted = true;
HandleEnergyDrainedEvent ();
}
if (m_depleted && m_remainingEnergyJ > m_highBatteryTh * m_initialEnergyJ)
else if (m_depleted && m_remainingEnergyJ > m_highBatteryTh * m_initialEnergyJ)
{
m_depleted = false;
HandleEnergyRechargedEvent ();
}
else if (m_remainingEnergyJ != remainingEnergy)
{
NotifyEnergyChanged ();
}
m_energyUpdateEvent = Simulator::Schedule (m_energyUpdateInterval,
&BasicEnergySource::UpdateEnergySource,
@@ -223,19 +227,11 @@ BasicEnergySource::CalculateRemainingEnergy (void)
NS_LOG_FUNCTION (this);
double totalCurrentA = CalculateTotalCurrent ();
Time duration = Simulator::Now () - m_lastUpdateTime;
NS_ASSERT (duration.GetSeconds () >= 0);
NS_ASSERT (duration.IsPositive ());
// energy = current * voltage * time
double energyToDecreaseJ = totalCurrentA * m_supplyVoltageV * duration.GetSeconds ();
if (m_remainingEnergyJ < energyToDecreaseJ)
{
m_remainingEnergyJ = 0; // energy never goes below 0
}
else
{
m_remainingEnergyJ -= energyToDecreaseJ;
}
double energyToDecreaseJ = (totalCurrentA * m_supplyVoltageV * duration.GetNanoSeconds ()) / 1e9;
NS_ASSERT (m_remainingEnergyJ >= energyToDecreaseJ);
m_remainingEnergyJ -= energyToDecreaseJ;
NS_LOG_DEBUG ("BasicEnergySource:Remaining energy = " << m_remainingEnergyJ);
}

View File

@@ -99,6 +99,12 @@ public:
*/
virtual void HandleEnergyRecharged (void) = 0;
/**
* This function is called by the EnergySource object when energy stored in
* the energy source is changed. Should be implemented by child classes.
*/
virtual void HandleEnergyChanged (void) = 0;
private:
/**

View File

@@ -212,6 +212,18 @@ EnergySource::NotifyEnergyRecharged (void)
}
}
void
EnergySource::NotifyEnergyChanged (void)
{
NS_LOG_FUNCTION (this);
// notify all device energy models installed on node
DeviceEnergyModelContainer::Iterator i;
for (i = m_models.Begin (); i != m_models.End (); i++)
{
(*i)->HandleEnergyChanged ();
}
}
void
EnergySource::BreakDeviceEnergyModelRefCycle (void)
{

View File

@@ -228,6 +228,12 @@ protected:
*/
void NotifyEnergyRecharged (void);
/**
* This function notifies all DeviceEnergyModel of energy changed event. It
* is called by the child EnergySource class when energy source is changed.
*/
void NotifyEnergyChanged (void);
/**
* This function is called to break reference cycle between EnergySource and
* DeviceEnergyModel. Child of the EnergySource base class must call this

View File

@@ -103,6 +103,15 @@ public:
{
}
/**
* \brief Handles energy changed.
*
* Not implemented
*/
virtual void HandleEnergyChanged (void)
{
}
/**
* \param current the current draw of device.
*

View File

@@ -288,6 +288,14 @@ AcousticModemEnergyModel::HandleEnergyRecharged (void)
SetMicroModemState(UanPhy::IDLE);
}
void
AcousticModemEnergyModel::HandleEnergyChanged (void)
{
NS_LOG_FUNCTION (this);
//Not implemented
}
/*
* Private functions start here.
*/

View File

@@ -175,16 +175,21 @@ public:
virtual void ChangeState (int newState);
/**
* Handles energy depletion.
* \brief Handles energy depletion.
*/
virtual void HandleEnergyDepletion (void);
/**
* \brief Handles energy recharged.
*/
virtual void HandleEnergyRecharged (void);
/**
* \brief Handles energy changed.
*
* Not implemented
*/
virtual void HandleEnergyRecharged (void);
virtual void HandleEnergyChanged (void);
private:

View File

@@ -99,32 +99,32 @@ WifiRadioEnergyModelHelper::DoInstall (Ptr<NetDevice> device,
Ptr<Node> node = device->GetNode ();
Ptr<WifiRadioEnergyModel> model = m_radioEnergy.Create ()->GetObject<WifiRadioEnergyModel> ();
NS_ASSERT (model != NULL);
// set energy source pointer
model->SetEnergySource (source);
// set energy depletion callback
// if none is specified, make a callback to WifiPhy::SetSleepMode
// if none is specified, make a callback to WifiPhy::SetOffMode
Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
Ptr<WifiPhy> wifiPhy = wifiDevice->GetPhy ();
wifiPhy->SetWifiRadioEnergyModel (model);
if (m_depletionCallback.IsNull ())
{
model->SetEnergyDepletionCallback (MakeCallback (&WifiPhy::SetSleepMode, wifiPhy));
model->SetEnergyDepletionCallback (MakeCallback (&WifiPhy::SetOffMode, wifiPhy));
}
else
{
model->SetEnergyDepletionCallback (m_depletionCallback);
}
// set energy recharged callback
// if none is specified, make a callback to WifiPhy::ResumeFromSleep
if (m_rechargedCallback.IsNull ())
{
model->SetEnergyRechargedCallback (MakeCallback (&WifiPhy::ResumeFromSleep, wifiPhy));
}
else
// if none is specified, make a callback to WifiPhy::ResumeFromOff
//TODO: ResumeFromOff not supported yet
//model->SetEnergyRechargedCallback (MakeCallback (&WifiPhy::ResumeFromOff, wifiPhy));
if (!m_rechargedCallback.IsNull ())
{
model->SetEnergyRechargedCallback (m_rechargedCallback);
}
// add model to device model list in energy source
source->AppendDeviceEnergyModel (model);
// set energy source pointer
model->SetEnergySource (source);
// create and register energy model phy listener
wifiPhy->RegisterListener (model->GetPhyListener ());
//

View File

@@ -460,6 +460,12 @@ MacLow::StartTransmission (Ptr<const Packet> packet,
MacLowTransmissionParameters params,
Ptr<DcaTxop> dca)
{
if (m_phy->IsStateOff ())
{
NS_LOG_DEBUG ("Cannot start TX because device is OFF");
return;
}
NS_LOG_FUNCTION (this << packet << hdr << params << dca);
/* m_currentPacket is not NULL because someone started
* a transmission and was interrupted before one of:
@@ -572,8 +578,8 @@ MacLow::StartTransmission (Ptr<const Packet> packet,
}
}
/* When this method completes, we have taken ownership of the medium. */
NS_ASSERT (m_phy->IsStateTx ());
/* When this method completes, either we have taken ownership of the medium or the device switched off in the meantime. */
NS_ASSERT (m_phy->IsStateTx () || m_phy->IsStateOff ());
}
bool

View File

@@ -40,7 +40,7 @@ WifiPhyTag::GetInstanceTypeId (void) const
uint32_t
WifiPhyTag::GetSerializedSize (void) const
{
return (sizeof (WifiTxVector) + 2);
return (sizeof (WifiTxVector) + 2 + 1);
}
void
@@ -48,6 +48,7 @@ WifiPhyTag::Serialize (TagBuffer i) const
{
i.Write ((uint8_t *)&m_wifiTxVector, sizeof (WifiTxVector));
i.WriteU16 (m_mpduType);
i.WriteU8 (m_frameComplete);
}
void
@@ -55,20 +56,22 @@ WifiPhyTag::Deserialize (TagBuffer i)
{
i.Read ((uint8_t *)&m_wifiTxVector, sizeof (WifiTxVector));
m_mpduType = static_cast<MpduType> (i.ReadU16 ());
m_frameComplete = i.ReadU8 ();
}
void
WifiPhyTag::Print (std::ostream &os) const
{
os << m_wifiTxVector << " " << m_mpduType;
os << m_wifiTxVector << " " << m_mpduType << " " << m_frameComplete;
}
WifiPhyTag::WifiPhyTag ()
{
}
WifiPhyTag::WifiPhyTag (WifiTxVector txVector, MpduType mpdutype)
WifiPhyTag::WifiPhyTag (WifiTxVector txVector, MpduType mpdutype, uint8_t frameComplete)
: m_wifiTxVector (txVector),
m_mpduType (mpdutype)
m_mpduType (mpdutype),
m_frameComplete (frameComplete)
{
}
@@ -84,4 +87,10 @@ WifiPhyTag::GetMpduType (void) const
return m_mpduType;
}
uint8_t
WifiPhyTag::GetFrameComplete (void) const
{
return m_frameComplete;
}
} // namespace ns3

View File

@@ -50,8 +50,9 @@ public:
* Constructor
* \param txVector the WifiTxVector
* \param mpdutype the mpduType
* \param frameComplete the frameComplete
*/
WifiPhyTag (WifiTxVector txVector, MpduType mpdutype);
WifiPhyTag (WifiTxVector txVector, MpduType mpdutype, uint8_t frameComplete);
/**
* Getter for WifiTxVector parameter
* \return the WifiTxVector
@@ -62,6 +63,11 @@ public:
* \return mpduType the mpduType
*/
MpduType GetMpduType (void) const;
/**
* Getter for frameComplete parameter
* \return the frameComplete parameter, i.e. 0 if the frame is not complete, 1 otherwise.
*/
uint8_t GetFrameComplete (void) const;
// From class Tag
uint32_t GetSerializedSize (void) const;
@@ -73,6 +79,7 @@ public:
private:
WifiTxVector m_wifiTxVector; ///< wifi transmit vector
MpduType m_mpduType; ///< MPDU type
uint8_t m_frameComplete; ///< Used to indicate that TX stopped sending before the end of the frame
};
} // namespace ns3

View File

@@ -31,6 +31,7 @@
#include "ampdu-tag.h"
#include "wifi-utils.h"
#include "frame-capture-model.h"
#include "wifi-radio-energy-model.h"
namespace ns3 {
@@ -372,7 +373,8 @@ WifiPhy::WifiPhy ()
m_initialChannelNumber (0),
m_totalAmpduSize (0),
m_totalAmpduNumSymbols (0),
m_currentEvent (0)
m_currentEvent (0),
m_wifiRadioEnergyModel (0)
{
NS_LOG_FUNCTION (this);
m_random = CreateObject<UniformRandomVariable> ();
@@ -705,6 +707,12 @@ WifiPhy::GetFrameCaptureModel (void) const
{
return m_frameCaptureModel;
}
void
WifiPhy::SetWifiRadioEnergyModel (const Ptr<WifiRadioEnergyModel> wifiRadioEnergyModel)
{
m_wifiRadioEnergyModel = wifiRadioEnergyModel;
}
double
WifiPhy::GetPowerDbm (uint8_t power) const
@@ -1598,6 +1606,28 @@ WifiPhy::SetSleepMode (void)
}
}
void
WifiPhy::SetOffMode (void)
{
NS_LOG_FUNCTION (this);
switch (m_state->GetState ())
{
case WifiPhy::RX:
m_endPlcpRxEvent.Cancel ();
m_endRxEvent.Cancel ();
case WifiPhy::TX:
case WifiPhy::SWITCHING:
case WifiPhy::CCA_BUSY:
case WifiPhy::IDLE:
case WifiPhy::SLEEP:
m_state->SwitchToOff ();
break;
default:
NS_ASSERT (false);
break;
}
}
void
WifiPhy::ResumeFromSleep (void)
{
@@ -2328,7 +2358,17 @@ WifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, MpduType m
Ptr<Packet> newPacket = packet->Copy (); // obtain non-const Packet
WifiPhyTag oldtag;
newPacket->RemovePacketTag (oldtag);
WifiPhyTag tag (txVector, mpdutype);
if (m_state->GetState () == WifiPhy::OFF)
{
NS_LOG_DEBUG ("Transmission canceled because device is OFF");
return;
}
uint8_t isFrameComplete = 1;
if (m_wifiRadioEnergyModel != 0 && m_wifiRadioEnergyModel->GetMaximumTimeInState (WifiPhy::TX) < txDuration)
{
isFrameComplete = 0;
}
WifiPhyTag tag (txVector, mpdutype, isFrameComplete);
newPacket->AddPacketTag (tag);
StartTx (newPacket, txVector, txDuration);
@@ -2339,6 +2379,12 @@ WifiPhy::StartReceivePreambleAndHeader (Ptr<Packet> packet, double rxPowerW, Tim
{
//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.
if (m_state->GetState () == WifiPhy::OFF)
{
NS_LOG_DEBUG ("Cannot start RX because device is OFF");
return;
}
NS_LOG_FUNCTION (this << packet << WToDbm (rxPowerW) << rxDuration);
Time endRx = Simulator::Now () + rxDuration;
@@ -2350,6 +2396,14 @@ WifiPhy::StartReceivePreambleAndHeader (Ptr<Packet> packet, double rxPowerW, Tim
return;
}
if (tag.GetFrameComplete () == 0)
{
NS_LOG_DEBUG ("drop packet because of incomplete frame");
NotifyRxDrop (packet);
m_plcpSuccess = false;
return;
}
WifiTxVector txVector = tag.GetWifiTxVector ();
if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT
@@ -3493,47 +3547,53 @@ WifiPhy::GetMcs (uint8_t mcs) const
}
bool
WifiPhy::IsStateCcaBusy (void)
WifiPhy::IsStateCcaBusy (void) const
{
return m_state->IsStateCcaBusy ();
}
bool
WifiPhy::IsStateIdle (void)
WifiPhy::IsStateIdle (void) const
{
return m_state->IsStateIdle ();
}
bool
WifiPhy::IsStateBusy (void)
WifiPhy::IsStateBusy (void) const
{
return m_state->IsStateBusy ();
}
bool
WifiPhy::IsStateRx (void)
WifiPhy::IsStateRx (void) const
{
return m_state->IsStateRx ();
}
bool
WifiPhy::IsStateTx (void)
WifiPhy::IsStateTx (void) const
{
return m_state->IsStateTx ();
}
bool
WifiPhy::IsStateSwitching (void)
WifiPhy::IsStateSwitching (void) const
{
return m_state->IsStateSwitching ();
}
bool
WifiPhy::IsStateSleep (void)
WifiPhy::IsStateSleep (void) const
{
return m_state->IsStateSleep ();
}
bool
WifiPhy::IsStateOff (void) const
{
return m_state->IsStateOff ();
}
Time
WifiPhy::GetStateDuration (void)
{

View File

@@ -49,6 +49,11 @@ class WifiPhyStateHelper;
*/
class FrameCaptureModel;
/**
* WifiRadioEnergyModel class
*/
class WifiRadioEnergyModel;
/**
* This enumeration defines the type of an MPDU.
*/
@@ -312,35 +317,44 @@ public:
* Resume from sleep mode.
*/
void ResumeFromSleep (void);
/**
* Put in off mode.
*/
void SetOffMode (void);
/**
* \return true of the current state of the PHY layer is WifiPhy::IDLE, false otherwise.
*/
bool IsStateIdle (void);
bool IsStateIdle (void) const;
/**
* \return true of the current state of the PHY layer is WifiPhy::CCA_BUSY, false otherwise.
*/
bool IsStateCcaBusy (void);
bool IsStateCcaBusy (void) const;
/**
* \return true of the current state of the PHY layer is not WifiPhy::IDLE, false otherwise.
*/
bool IsStateBusy (void);
bool IsStateBusy (void) const;
/**
* \return true of the current state of the PHY layer is WifiPhy::RX, false otherwise.
*/
bool IsStateRx (void);
bool IsStateRx (void) const;
/**
* \return true of the current state of the PHY layer is WifiPhy::TX, false otherwise.
*/
bool IsStateTx (void);
bool IsStateTx (void) const;
/**
* \return true of the current state of the PHY layer is WifiPhy::SWITCHING, false otherwise.
*/
bool IsStateSwitching (void);
bool IsStateSwitching (void) const;
/**
* \return true if the current state of the PHY layer is WifiPhy::SLEEP, false otherwise.
*/
bool IsStateSleep (void);
bool IsStateSleep (void) const;
/**
* \return true if the current state of the PHY layer is WifiPhy::OFF, false otherwise.
*/
bool IsStateOff (void) const ;
/**
* \return the amount of time since the current state has started.
*/
@@ -1609,6 +1623,13 @@ public:
*/
Ptr<FrameCaptureModel> GetFrameCaptureModel (void) const;
/**
* Sets the wifi radio energy model.
*
* \param wifiRadioEnergyModel the wifi radio energy model
*/
void SetWifiRadioEnergyModel (const Ptr<WifiRadioEnergyModel> wifiRadioEnergyModel);
/**
* \return the channel width
*/
@@ -1965,6 +1986,7 @@ private:
Ptr<InterferenceHelper::Event> m_currentEvent; //!< Hold the current event
Ptr<FrameCaptureModel> m_frameCaptureModel; //!< Frame capture model
Ptr<WifiRadioEnergyModel> m_wifiRadioEnergyModel; //!< Wifi radio energy model
};
/**

View File

@@ -113,6 +113,9 @@ WifiRadioEnergyModel::SetEnergySource (const Ptr<EnergySource> source)
NS_LOG_FUNCTION (this << source);
NS_ASSERT (source != NULL);
m_source = source;
m_switchToOffEvent.Cancel ();
Time durationToOff = GetMaximumTimeInState (m_currentState);
m_switchToOffEvent = Simulator::Schedule (durationToOff, &WifiRadioEnergyModel::ChangeState, this, WifiPhy::OFF);
}
double
@@ -146,6 +149,9 @@ WifiRadioEnergyModel::GetTotalEnergyConsumption (void) const
case WifiPhy::SLEEP:
energyToDecrease = duration.GetSeconds () * m_sleepCurrentA * supplyVoltage;
break;
case WifiPhy::OFF:
energyToDecrease = 0;
break;
default:
NS_FATAL_ERROR ("WifiRadioEnergyModel:Undefined radio state: " << m_currentState);
}
@@ -286,6 +292,38 @@ WifiRadioEnergyModel::SetTxCurrentFromModel (double txPowerDbm)
}
}
Time
WifiRadioEnergyModel::GetMaximumTimeInState (int state) const
{
Time remainingTime;
double remainingEnergy = m_source->GetRemainingEnergy();
double supplyVoltage = m_source->GetSupplyVoltage ();
switch (state)
{
case WifiPhy::IDLE:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_idleCurrentA * supplyVoltage)));
break;
case WifiPhy::CCA_BUSY:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_ccaBusyCurrentA * supplyVoltage)));
break;
case WifiPhy::TX:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_txCurrentA * supplyVoltage)));
break;
case WifiPhy::RX:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_rxCurrentA * supplyVoltage)));
break;
case WifiPhy::SWITCHING:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_switchingCurrentA * supplyVoltage)));
break;
case WifiPhy::SLEEP:
remainingTime = NanoSeconds (1e9 * (remainingEnergy / (m_sleepCurrentA * supplyVoltage)));
break;
default:
NS_FATAL_ERROR ("WifiRadioEnergyModel: undefined radio state " << state);
}
return remainingTime;
}
void
WifiRadioEnergyModel::ChangeState (int newState)
{
@@ -293,6 +331,20 @@ WifiRadioEnergyModel::ChangeState (int newState)
m_nPendingChangeState++;
if (m_nPendingChangeState > 1 && newState == WifiPhy::OFF)
{
SetWifiRadioState ((WifiPhy::State) newState);
m_nPendingChangeState--;
return;
}
if (newState != WifiPhy::OFF)
{
m_switchToOffEvent.Cancel ();
Time durationToOff = GetMaximumTimeInState (newState);
m_switchToOffEvent = Simulator::Schedule (durationToOff, &WifiRadioEnergyModel::ChangeState, this, WifiPhy::OFF);
}
Time duration = Simulator::Now () - m_lastUpdateTime;
NS_ASSERT (duration.IsPositive ()); // check if duration is valid
@@ -328,6 +380,7 @@ WifiRadioEnergyModel::ChangeState (int newState)
// update total energy consumption
m_totalEnergyConsumption += energyToDecrease;
NS_ASSERT (m_totalEnergyConsumption <= m_source->GetInitialEnergy ());
// update last update time stamp
m_lastUpdateTime = Simulator::Now ();
@@ -342,7 +395,7 @@ WifiRadioEnergyModel::ChangeState (int newState)
// by the previous instance is erroneously the final state stored in m_currentState. The check below
// ensures that previous instances do not change m_currentState.
if (m_nPendingChangeState <= 1)
if (m_nPendingChangeState <= 1 && m_currentState != WifiPhy::OFF)
{
// update current state & last update time stamp
SetWifiRadioState ((WifiPhy::State) newState);
@@ -379,6 +432,19 @@ WifiRadioEnergyModel::HandleEnergyRecharged (void)
}
}
void
WifiRadioEnergyModel::HandleEnergyChanged (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("WifiRadioEnergyModel:Energy is changed!");
if (m_currentState != WifiPhy::OFF)
{
m_switchToOffEvent.Cancel ();
Time durationToOff = GetMaximumTimeInState (m_currentState);
m_switchToOffEvent = Simulator::Schedule (durationToOff, &WifiRadioEnergyModel::ChangeState, this, WifiPhy::OFF);
}
}
WifiRadioEnergyModelPhyListener *
WifiRadioEnergyModel::GetPhyListener (void)
{

View File

@@ -354,6 +354,13 @@ public:
*/
void ChangeState (int newState);
/**
* \param state the wifi state
*
* \returns the time the radio can stay in that state based on the remaining energy.
*/
Time GetMaximumTimeInState (int state) const;
/**
* \brief Handles energy depletion.
*
@@ -368,6 +375,13 @@ public:
*/
void HandleEnergyRecharged (void);
/**
* \brief Handles energy changed.
*
* Implements DeviceEnergyModel::HandleEnergyChanged
*/
void HandleEnergyChanged (void);
/**
* \returns Pointer to the PHY listener.
*/
@@ -420,6 +434,8 @@ private:
/// WifiPhy listener
WifiRadioEnergyModelPhyListener *m_listener;
EventId m_switchToOffEvent; ///< switch to off event
};
} // namespace ns3

View File

@@ -113,7 +113,7 @@ SpectrumWifiPhyBasicTest::MakeSignal (double txPowerWatts)
pkt->AddHeader (hdr);
pkt->AddTrailer (trailer);
WifiPhyTag tag (txVector, mpdutype);
WifiPhyTag tag (txVector, mpdutype, 1);
pkt->AddPacketTag (tag);
Ptr<SpectrumValue> txPowerSpectrum = WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity (FREQUENCY, CHANNEL_WIDTH, txPowerWatts, GUARD_WIDTH);
Ptr<WifiSpectrumSignalParameters> txParams = Create<WifiSpectrumSignalParameters> ();