RV battery model and WiFi energy example
authorHe Wu <mdzz@u.washington.edu>
Mon, 20 Dec 2010 15:49:12 -0800
changeset 6699 d8909a1fd0ff
parent 6698 bc947fbfac80
child 6700 1b4afd56648f
RV battery model and WiFi energy example
CHANGES.html
RELEASE_NOTES
examples/energy/energy-model-example.cc
examples/energy/waf
examples/energy/wscript
src/contrib/energy/helper/energy-model-helper.cc
src/contrib/energy/helper/energy-source-container.cc
src/contrib/energy/helper/rv-battery-model-helper.cc
src/contrib/energy/helper/rv-battery-model-helper.h
src/contrib/energy/helper/wifi-radio-energy-model-helper.cc
src/contrib/energy/model/basic-energy-source.cc
src/contrib/energy/model/basic-energy-source.h
src/contrib/energy/model/device-energy-model.h
src/contrib/energy/model/energy-source.cc
src/contrib/energy/model/energy-source.h
src/contrib/energy/model/rv-battery-model.cc
src/contrib/energy/model/rv-battery-model.h
src/contrib/energy/model/wifi-radio-energy-model.cc
src/contrib/energy/model/wifi-radio-energy-model.h
src/contrib/energy/test/basic-energy-model-test.cc
src/contrib/energy/test/rv-battery-model-test.cc
src/contrib/energy/wscript
test.py
--- a/CHANGES.html	Mon Dec 20 15:19:11 2010 -0800
+++ b/CHANGES.html	Mon Dec 20 15:49:12 2010 -0800
@@ -94,6 +94,10 @@
 for example TCP sockets and not UDP sockets. A helper class exists to 
 facilitate creating BulkSendApplications. The API for the helper class 
 is similar to existing application helper classes, for example, OnOff.
+</p></li>
+
+<li><b>Rakhmatov Vrudhula non-linear battery model</b>
+<p>New class and helper for this battery model. </p></li>
 
 </ul>
 
--- a/RELEASE_NOTES	Mon Dec 20 15:19:11 2010 -0800
+++ b/RELEASE_NOTES	Mon Dec 20 15:49:12 2010 -0800
@@ -71,6 +71,12 @@
      application only works with SOCK_STREAM and SOCK_SEQPACKET 
      sockets, for example TCP sockets and not UDP sockets.
 
+   - Extensions to the energy models:  1) a new Rakhmatov Vrudhula 
+     non-linear battery model, 2) additional support for modeling 
+     energy consumption in WiFi devices, 3) an example for how to add 
+     energy models to a WiFi-based simulation (in examples/energy/ 
+     directory).
+
 Bugs fixed
 ----------
 The following lists many of the bugs fixed or small feature additions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/energy/energy-model-example.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,262 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/common-module.h"
+#include "ns3/node-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/contrib-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/energy-module.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+
+NS_LOG_COMPONENT_DEFINE ("EnergyExample");
+
+using namespace ns3;
+
+/**
+ * \param socket Pointer to socket.
+ *
+ * Packet receiving sink.
+ */
+void
+ReceivePacket (Ptr<Socket> socket)
+{
+  Ptr<Packet> packet;
+  Address from;
+  while (packet = socket->RecvFrom (from))
+    {
+      if (packet->GetSize () > 0)
+        {
+          InetSocketAddress iaddr = InetSocketAddress::ConvertFrom (from);
+          NS_LOG_UNCOND ("--\nReceived one packet! Socket: "<< iaddr.GetIpv4 ()
+                         << " port: " << iaddr.GetPort () << " at time = " <<
+                         Simulator::Now ().GetSeconds () << "\n--");
+        }
+    }
+}
+
+/**
+ * \param socket Pointer to socket.
+ * \param pktSize Packet size.
+ * \param n Pointer to node.
+ * \param pktCount Number of packets to generate.
+ * \param pktInterval Packet sending interval.
+ *
+ * Traffic generator.
+ */
+static void
+GenerateTraffic (Ptr<Socket> socket, uint32_t pktSize, Ptr<Node> n,
+    uint32_t pktCount, Time pktInterval)
+{
+  if (pktCount > 0)
+    {
+      socket->Send (Create<Packet> (pktSize));
+      Simulator::Schedule (pktInterval, &GenerateTraffic, socket, pktSize, n,
+          pktCount - 1, pktInterval);
+    }
+  else
+    {
+      socket->Close ();
+    }
+}
+
+/// Trace function for remaining energy at node.
+void
+RemainingEnergy (double oldValue, double remainingEnergy)
+{
+  NS_LOG_UNCOND (Simulator::Now ().GetSeconds ()
+      << "s Current remaining energy = " << remainingEnergy << "J");
+}
+
+/// Trace function for total energy consumption at node.
+void
+TotalEnergy (double oldValue, double totalEnergy)
+{
+  NS_LOG_UNCOND (Simulator::Now ().GetSeconds ()
+      << "s Total energy consumed by radio = " << totalEnergy << "J");
+}
+
+int
+main (int argc, char *argv[])
+{
+  /*
+  LogComponentEnable ("EnergySource", LOG_LEVEL_DEBUG);
+  LogComponentEnable ("BasicEnergySource", LOG_LEVEL_DEBUG);
+  LogComponentEnable ("DeviceEnergyModel", LOG_LEVEL_DEBUG);
+  LogComponentEnable ("WifiRadioEnergyModel", LOG_LEVEL_DEBUG);
+   */
+
+  std::string phyMode ("DsssRate1Mbps");
+  double Prss = -80;            // dBm
+  uint32_t PpacketSize = 200;   // bytes
+  bool verbose = false;
+
+  // simulation parameters
+  uint32_t numPackets = 10000;  // number of packets to send
+  double interval = 1;          // seconds
+  double startTime = 0.0;       // seconds
+  double distanceToRx = 100.0;  // meters
+  /*
+   * This is a magic number used to set the transmit power, based on other
+   * configuration.
+   */
+  double offset = 81;
+
+  CommandLine cmd;
+  cmd.AddValue ("phyMode", "Wifi Phy mode", phyMode);
+  cmd.AddValue ("Prss", "Intended primary RSS (dBm)", Prss);
+  cmd.AddValue ("PpacketSize", "size of application packet sent", PpacketSize);
+  cmd.AddValue ("numPackets", "Total number of packets to send", numPackets);
+  cmd.AddValue ("startTime", "Simulation start time", startTime);
+  cmd.AddValue ("distanceToRx", "X-Axis distance between nodes", distanceToRx);
+  cmd.AddValue ("verbose", "Turn on all device log components", verbose);
+  cmd.Parse (argc, argv);
+
+  // Convert to time object
+  Time interPacketInterval = Seconds (interval);
+
+  // disable fragmentation for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold",
+                      StringValue ("2200"));
+  // turn off RTS/CTS for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold",
+                      StringValue ("2200"));
+  // Fix non-unicast data rate to be the same as that of unicast
+  Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode",
+                      StringValue (phyMode));
+
+  NodeContainer c;
+  c.Create (2);     // create 2 nodes
+  NodeContainer networkNodes;
+  networkNodes.Add (c.Get (0));
+  networkNodes.Add (c.Get (1));
+
+  // The below set of helpers will help us to put together the wifi NICs we want
+  WifiHelper wifi;
+  if (verbose)
+    {
+      wifi.EnableLogComponents ();
+    }
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
+
+  /** Wifi PHY **/
+  /***************************************************************************/
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  wifiPhy.Set ("RxGain", DoubleValue (-10));
+  wifiPhy.Set ("TxGain", DoubleValue (offset + Prss));
+  wifiPhy.Set ("CcaMode1Threshold", DoubleValue (0.0));
+  /***************************************************************************/
+
+  /** wifi channel **/
+  YansWifiChannelHelper wifiChannel;
+  wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
+  wifiChannel.AddPropagationLoss ("ns3::FriisPropagationLossModel");
+  // create wifi channel
+  Ptr<YansWifiChannel> wifiChannelPtr = wifiChannel.Create ();
+  wifiPhy.SetChannel (wifiChannelPtr);
+
+  /** MAC layer **/
+  // Add a non-QoS upper MAC, and disable rate control
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode",
+                                StringValue (phyMode), "ControlMode",
+                                StringValue (phyMode));
+  // Set it to ad-hoc mode
+  wifiMac.SetType ("ns3::AdhocWifiMac");
+
+  /** install PHY + MAC **/
+  NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, networkNodes);
+
+  /** mobility **/
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  positionAlloc->Add (Vector (0.0, 0.0, 0.0));
+  positionAlloc->Add (Vector (2 * distanceToRx, 0.0, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (c);
+
+  /** Energy Model **/
+  /***************************************************************************/
+  /* energy source */
+  BasicEnergySourceHelper basicSourceHelper;
+  // configure energy source
+  basicSourceHelper.Set ("BasicEnergySourceInitialEnergyJ", DoubleValue (0.1));
+  // install source
+  EnergySourceContainer sources = basicSourceHelper.Install (c);
+  /* device energy model */
+  WifiRadioEnergyModelHelper radioEnergyHelper;
+  // configure radio energy model
+  radioEnergyHelper.Set ("TxCurrentA", DoubleValue (0.0174));
+  // install device model
+  DeviceEnergyModelContainer deviceModels = radioEnergyHelper.Install (devices, sources);
+  /***************************************************************************/
+
+  /** Internet stack **/
+  InternetStackHelper internet;
+  internet.Install (networkNodes);
+
+  Ipv4AddressHelper ipv4;
+  NS_LOG_INFO ("Assign IP Addresses.");
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer i = ipv4.Assign (devices);
+
+  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
+  Ptr<Socket> recvSink = Socket::CreateSocket (networkNodes.Get (1), tid);  // node 1, receiver
+  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+  recvSink->Bind (local);
+  recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
+
+  Ptr<Socket> source = Socket::CreateSocket (networkNodes.Get (0), tid);    // node 0, sender
+  InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetBroadcast (), 80);
+  source->SetAllowBroadcast (true);
+  source->Connect (remote);
+
+  /** connect trace sources **/
+  /***************************************************************************/
+  // all sources are connected to node 1
+  // energy source
+  Ptr<BasicEnergySource> basicSourcePtr = DynamicCast<BasicEnergySource> (sources.Get (1));
+  basicSourcePtr->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback (&RemainingEnergy));
+  // device energy model
+  Ptr<DeviceEnergyModel> basicRadioModelPtr =
+    basicSourcePtr->FindDeviceEnergyModels ("ns3::WifiRadioEnergyModel").Get (0);
+  NS_ASSERT (basicRadioModelPtr != NULL);
+  basicRadioModelPtr->TraceConnectWithoutContext ("TotalEnergyConsumption", MakeCallback (&TotalEnergy));
+  /***************************************************************************/
+
+
+  /** simulation setup **/
+  // start traffic
+  Simulator::Schedule (Seconds (startTime), &GenerateTraffic, source, PpacketSize,
+                       networkNodes.Get (0), numPackets, interPacketInterval);
+
+  Simulator::Stop (Seconds (10.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/energy/waf	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/energy/wscript	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,5 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('energy-model-example', ['core', 'simulator', 'mobility', 'wifi', 'energy', 'internet-stack'])
+    obj.source = 'energy-model-example.cc'
\ No newline at end of file
--- a/src/contrib/energy/helper/energy-model-helper.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/helper/energy-model-helper.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -93,6 +93,7 @@
 {
   NS_ASSERT (device != NULL);
   NS_ASSERT (source != NULL);
+  // check to make sure source and net device are on the same node
   NS_ASSERT (device->GetNode () == source->GetNode ());
   DeviceEnergyModelContainer container (DoInstall (device, source));
   return container;
@@ -108,6 +109,7 @@
   EnergySourceContainer::Iterator src = sourceContainer.Begin ();
   while (dev != deviceContainer.End ())
     {
+      // check to make sure source and net device are on the same node
       NS_ASSERT ((*dev)->GetNode () == (*src)->GetNode ());
       Ptr<DeviceEnergyModel> model = DoInstall (*dev, *src);
       container.Add (model);
--- a/src/contrib/energy/helper/energy-source-container.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/helper/energy-source-container.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -118,6 +118,13 @@
 void
 EnergySourceContainer::DoDispose (void)
 {
+  // call Object::Dispose for all EnergySource objects
+  for (std::vector< Ptr<EnergySource> >::iterator i = m_sources.begin ();
+       i != m_sources.end (); i++)
+    {
+      (*i)->DisposeDeviceModels ();
+      (*i)->Dispose ();
+    }
   m_sources.clear ();
 }
 
@@ -126,9 +133,10 @@
 {
   // call Object::Start for all EnergySource objects
   for (std::vector< Ptr<EnergySource> >::iterator i = m_sources.begin ();
-      i != m_sources.end (); i++)
+       i != m_sources.end (); i++)
     {
       (*i)->Start ();
+      (*i)->StartDeviceModels ();
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/energy/helper/rv-battery-model-helper.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,57 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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
+ *
+ * Authors: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+ */
+
+#include "rv-battery-model-helper.h"
+#include "ns3/energy-source.h"
+
+namespace ns3 {
+
+RvBatteryModelHelper::RvBatteryModelHelper ()
+{
+  m_rvBatteryModel.SetTypeId ("ns3::RvBatteryModel");
+}
+
+RvBatteryModelHelper::~RvBatteryModelHelper ()
+{
+}
+
+void
+RvBatteryModelHelper::Set (std::string name, const AttributeValue &v)
+{
+  m_rvBatteryModel.Set (name, v);
+}
+
+Ptr<EnergySource>
+RvBatteryModelHelper::DoInstall (Ptr<Node> node) const
+{
+  NS_ASSERT (node != NULL);
+  // check if energy source already exists
+  Ptr<EnergySource> source = node->GetObject<EnergySource> ();
+  if (source != NULL)
+    {
+      NS_FATAL_ERROR ("Energy source already installed!");
+    }
+  source = m_rvBatteryModel.Create<EnergySource> ();
+  NS_ASSERT (source != NULL);
+  source->SetNode (node);
+  return source;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/energy/helper/rv-battery-model-helper.h	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,50 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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
+ *
+ * Authors: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+ */
+
+#ifndef RV_BATTERY_MODEL_HELPER_H
+#define RV_BATTERY_MODEL_HELPER_H
+
+#include "energy-model-helper.h"
+#include "ns3/node.h"
+
+namespace ns3 {
+
+/**
+ * \brief Creates a RvBatteryModel object.
+ */
+class RvBatteryModelHelper : public EnergySourceHelper
+{
+public:
+  RvBatteryModelHelper ();
+  ~RvBatteryModelHelper ();
+
+  void Set (std::string name, const AttributeValue &v);
+
+private:
+  virtual Ptr<EnergySource> DoInstall (Ptr<Node> node) const;
+
+private:
+  ObjectFactory m_rvBatteryModel;
+
+};
+
+} // namespace ns3
+
+#endif  /* RV_BATTERY_MODEL_HELPER_H */
--- a/src/contrib/energy/helper/wifi-radio-energy-model-helper.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/helper/wifi-radio-energy-model-helper.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -67,23 +67,18 @@
       NS_FATAL_ERROR ("NetDevice type is not WifiNetDevice!");
     }
   Ptr<Node> node = device->GetNode ();
-  Ptr<WifiRadioEnergyModel> model = m_radioEnergy.Create ()->
-    GetObject<WifiRadioEnergyModel> ();
+  Ptr<WifiRadioEnergyModel> model = m_radioEnergy.Create ()->GetObject<WifiRadioEnergyModel> ();
   NS_ASSERT (model != NULL);
-  // set node pointer
-  model->SetNode (node);
   // set energy source pointer
   model->SetEnergySource (source);
   // set energy depletion callback
   model->SetEnergyDepletionCallback (m_depletionCallback);
   // add model to device model list in energy source
   source->AppendDeviceEnergyModel (model);
-  // create and install energy model callback
+  // create and register energy model phy listener
   Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
   Ptr<WifiPhy> wifiPhy = wifiDevice->GetPhy ();
-  DeviceEnergyModel::ChangeStateCallback callback;
-  callback = MakeCallback (&DeviceEnergyModel::ChangeState, model);
-  //wifiPhy->SetEnergyModelCallback (callback);
+  wifiPhy->RegisterListener (model->GetPhyListener ());
   return model;
 }
 
--- a/src/contrib/energy/model/basic-energy-source.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/basic-energy-source.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -90,28 +90,25 @@
 void
 BasicEnergySource::SetEnergyUpdateInterval (Time interval)
 {
-  NS_LOG_FUNCTION (this);
+  NS_LOG_FUNCTION (this << interval);
   m_energyUpdateInterval = interval;
 }
 
 Time
 BasicEnergySource::GetEnergyUpdateInterval (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_energyUpdateInterval;
 }
 
 double
 BasicEnergySource::GetSupplyVoltage (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_supplyVoltageV;
 }
 
 double
 BasicEnergySource::GetInitialEnergy (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_initialEnergyJ;
 }
 
@@ -134,32 +131,10 @@
 }
 
 void
-BasicEnergySource::DecreaseRemainingEnergy (double energyJ)
-{
-  NS_LOG_FUNCTION (this << energyJ);
-  NS_ASSERT (energyJ >= 0);
-  m_remainingEnergyJ -= energyJ;
-  // check if remaining energy is 0
-  if (m_remainingEnergyJ <= 0)
-    {
-      HandleEnergyDrainedEvent ();
-    }
-}
-
-void
-BasicEnergySource::IncreaseRemainingEnergy (double energyJ)
-{
-  NS_LOG_FUNCTION (this << energyJ);
-  NS_ASSERT (energyJ >= 0);
-  m_remainingEnergyJ += energyJ;
-}
-
-void
 BasicEnergySource::UpdateEnergySource (void)
 {
   NS_LOG_FUNCTION (this);
-  NS_LOG_DEBUG ("BasicEnergySource:Updating remaining energy at node #" <<
-                GetNode ()->GetId ());
+  NS_LOG_DEBUG ("BasicEnergySource:Updating remaining energy.");
 
   // do not update if simulation has finished
   if (Simulator::IsFinished ())
@@ -208,8 +183,7 @@
 BasicEnergySource::HandleEnergyDrainedEvent (void)
 {
   NS_LOG_FUNCTION (this);
-  NS_LOG_DEBUG ("BasicEnergySource:Energy depleted at node #" <<
-                GetNode ()->GetId ());
+  NS_LOG_DEBUG ("BasicEnergySource:Energy depleted!");
   NotifyEnergyDrained (); // notify DeviceEnergyModel objects
   m_remainingEnergyJ = 0; // energy never goes below 0
 }
--- a/src/contrib/energy/model/basic-energy-source.h	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/basic-energy-source.h	Mon Dec 20 15:49:12 2010 -0800
@@ -68,20 +68,6 @@
   virtual double GetEnergyFraction (void);
 
   /**
-   * \param energyJ Amount of energy (in Joules) to decrease from energy source.
-   *
-   * Implements DecreaseRemainingEnergy.
-   */
-  virtual void DecreaseRemainingEnergy (double energyJ);
-
-  /**
-   * \param energyJ Amount of energy (in Joules) to increase from energy source.
-   *
-   * Implements IncreaseRemainingEnergy.
-   */
-  virtual void IncreaseRemainingEnergy (double energyJ);
-
-  /**
    * Implements UpdateEnergySource.
    */
   virtual void UpdateEnergySource (void);
@@ -116,7 +102,10 @@
 
 
 private:
+  /// Defined in ns3::Object
   void DoStart (void);
+
+  /// Defined in ns3::Object
   void DoDispose (void);
 
   /**
--- a/src/contrib/energy/model/device-energy-model.h	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/device-energy-model.h	Mon Dec 20 15:49:12 2010 -0800
@@ -53,20 +53,6 @@
   virtual ~DeviceEnergyModel ();
 
   /**
-   * \brief Sets pointer to node containing this EnergySource.
-   *
-   * \param node Pointer to node containing this EnergySource.
-   */
-  virtual void SetNode (Ptr<Node> node) = 0;
-
-  /**
-   * \brief Gets pointer to node containing this EnergySource.
-   *
-   * \returns Pointer to node containing this EnergySource.
-   */
-  virtual Ptr<Node> GetNode (void) const = 0;
-
-  /**
    * \param source Pointer to energy source installed on node.
    *
    * This function sets the pointer to energy source installed on node. Should
--- a/src/contrib/energy/model/energy-source.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/energy-source.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -47,7 +47,6 @@
 void
 EnergySource::SetNode (Ptr<Node> node)
 {
-  NS_LOG_FUNCTION (this << node);
   NS_ASSERT (node != NULL);
   m_node = node;
 }
@@ -55,7 +54,6 @@
 Ptr<Node>
 EnergySource::GetNode (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_node;
 }
 
@@ -99,6 +97,34 @@
   return container;
 }
 
+void
+EnergySource::StartDeviceModels (void)
+{
+  /*
+   * Device models are not aggregated to the node, hence we have to manually
+   * call dispose method here.
+   */
+  DeviceEnergyModelContainer::Iterator i;
+  for (i = m_models.Begin (); i != m_models.End (); i++)
+    {
+      (*i)->Start ();
+    }
+}
+
+void
+EnergySource::DisposeDeviceModels (void)
+{
+  /*
+   * Device models are not aggregated to the node, hence we have to manually
+   * call dispose method here.
+   */
+  DeviceEnergyModelContainer::Iterator i;
+  for (i = m_models.Begin (); i != m_models.End (); i++)
+    {
+      (*i)->Dispose ();
+    }
+}
+
 /*
  * Private function starts here.
  */
@@ -107,7 +133,7 @@
 EnergySource::DoDispose (void)
 {
   NS_LOG_FUNCTION (this);
-  m_models.Clear ();
+  BreakDeviceEnergyModelRefCycle ();
 }
 
 /*
--- a/src/contrib/energy/model/energy-source.h	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/energy-source.h	Mon Dec 20 15:49:12 2010 -0800
@@ -97,22 +97,6 @@
   virtual double GetEnergyFraction (void) = 0;
 
   /**
-   * \param energyJ Amount of energy to decrease (in Joules)
-   *
-   * This function decreases the remaining energy in the energy source by the
-   * specified amount. Provides linear interface for direct energy deduction.
-   */
-  virtual void DecreaseRemainingEnergy (double energyJ) = 0;
-
-  /**
-   * \param energyJ Amount of energy to increase (in Joules)
-   *
-   * This function increases the remaining energy in the energy source by the
-   * specified amount. Provides linear interface for direct energy increase.
-   */
-  virtual void IncreaseRemainingEnergy (double energyJ) = 0;
-
-  /**
    * This function goes through the list of DeviceEnergyModels to obtain total
    * current draw at the energy source and updates remaining energy. Called by
    * DeviceEnergyModels to inform EnergySource of a state change.
@@ -154,11 +138,27 @@
    */
   DeviceEnergyModelContainer FindDeviceEnergyModels (std::string name);
 
+  /**
+   * Calls Start () method of the device energy models. Device energy models are
+   * not aggregated to the node, therefore we need to manually start them here.
+   * Called by EnergySourceContainer, which is aggregated to the node.
+   */
+  void StartDeviceModels (void);
+
+  /**
+   * Calls Dispose () method of the device energy models. Device energy models
+   * are not aggregated to the node, therefore we need to manually start them
+   * here. Called by EnergySourceContainer, which is aggregated to the node.
+   */
+  void DisposeDeviceModels (void);
+
 
 private:
   /**
    * All child's implementation must call BreakDeviceEnergyModelRefCycle to
    * ensure reference cycles to DeviceEnergyModel objects are broken.
+   *
+   * Defined in ns3::Object
    */
   virtual void DoDispose (void);
 
@@ -169,7 +169,8 @@
   DeviceEnergyModelContainer m_models;
 
   /**
-   * Pointer to node containing this EnergySource.
+   * Pointer to node containing this EnergySource. Used by helper class to make
+   * sure device models are installed onto the corresponding node.
    */
   Ptr<Node> m_node;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/energy/model/rv-battery-model.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,367 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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
+ *
+ * Authors: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+ */
+
+#include "rv-battery-model.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/double.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/simulator.h"
+#include <math.h>
+
+NS_LOG_COMPONENT_DEFINE ("RvBatteryModel");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (RvBatteryModel);
+
+TypeId
+RvBatteryModel::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::RvBatteryModel")
+    .SetParent<EnergySource> ()
+    .AddConstructor<RvBatteryModel> ()
+    .AddAttribute ("RvBatteryModelPeriodicEnergyUpdateInterval",
+                   "RV battery model sampling interval.",
+                   TimeValue (Seconds (1.0)),
+                   MakeTimeAccessor (&RvBatteryModel::SetSamplingInterval,
+                                     &RvBatteryModel::GetSamplingInterval),
+                   MakeTimeChecker ())
+    .AddAttribute ("RvBatteryModelOpenCircuitVoltage",
+                   "RV battery model open circuit voltage.",
+                   DoubleValue (4.1),
+                   MakeDoubleAccessor (&RvBatteryModel::SetOpenCircuitVoltage,
+                                       &RvBatteryModel::GetOpenCircuitVoltage),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("RvBatteryModelCutoffVoltage",
+                   "RV battery model cutoff voltage.",
+                   DoubleValue (3.0),
+                   MakeDoubleAccessor (&RvBatteryModel::SetCutoffVoltage,
+                                       &RvBatteryModel::GetCutoffVoltage),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("RvBatteryModelAlphaValue",
+                   "RV battery model alpha value.",
+                   DoubleValue (35220.0),
+                   MakeDoubleAccessor (&RvBatteryModel::SetAlpha,
+                                       &RvBatteryModel::GetAlpha),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("RvBatteryModelBetaValue",
+                   "RV battery model beta value.",
+                   DoubleValue (0.637),
+                   MakeDoubleAccessor (&RvBatteryModel::SetBeta,
+                                       &RvBatteryModel::GetBeta),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("RvBatteryModelNumOfTerms",
+                   "The number of terms of the infinite sum for estimating battery level.",
+                   IntegerValue (10),   // value used in paper
+                   MakeIntegerAccessor (&RvBatteryModel::SetNumOfTerms,
+                                        &RvBatteryModel::GetNumOfTerms),
+                   MakeIntegerChecker<int> ())
+    .AddTraceSource ("RvBatteryModelBatteryLevel",
+                     "RV battery model battery level.",
+                     MakeTraceSourceAccessor (&RvBatteryModel::m_batteryLevel))
+    .AddTraceSource ("RvBatteryModelBatteryLifetime",
+                     "RV battery model battery lifetime.",
+                     MakeTraceSourceAccessor (&RvBatteryModel::m_lifetime))
+  ;
+  return tid;
+}
+
+RvBatteryModel::RvBatteryModel ()
+{
+  m_lastSampleTime = Seconds (0.0);
+  m_previousLoad = 0.0;
+  m_batteryLevel = 1; // fully charged
+  m_lifetime = Seconds (0.0);
+}
+
+RvBatteryModel::~RvBatteryModel ()
+{
+}
+
+double
+RvBatteryModel::GetInitialEnergy (void) const
+{
+  return m_alpha * GetSupplyVoltage ();
+}
+
+double
+RvBatteryModel::GetSupplyVoltage (void) const
+{
+  // average of Voc and Vcutoff
+  return (m_openCircuitVoltage - m_cutoffVoltage) / 2 + m_cutoffVoltage;
+}
+
+double
+RvBatteryModel::GetRemainingEnergy (void)
+{
+  NS_LOG_FUNCTION (this);
+  UpdateEnergySource ();
+  return m_alpha * GetSupplyVoltage () * m_batteryLevel;
+}
+
+double
+RvBatteryModel::GetEnergyFraction (void)
+{
+  return GetBatteryLevel ();
+}
+
+void
+RvBatteryModel::UpdateEnergySource (void)
+{
+  NS_LOG_FUNCTION (this);
+
+  // do not update if battery is already dead
+  if (m_batteryLevel <= 0)
+    {
+      NS_LOG_DEBUG ("RvBatteryModel:Battery is dead!");
+      return;
+    }
+
+  // do not update if simulation has finished
+  if (Simulator::IsFinished ())
+    {
+      return;
+    }
+
+  NS_LOG_DEBUG ("RvBatteryModel:Updating remaining energy!");
+
+  m_currentSampleEvent.Cancel ();
+
+  double currentLoad = CalculateTotalCurrent () * 1000; // must be in mA
+  double calculatedAlpha = Discharge (currentLoad, Simulator::Now ());
+
+  NS_LOG_DEBUG ("RvBatteryModel:Calculated alpha = " << calculatedAlpha <<
+                " time = " << Simulator::Now ().GetSeconds ());
+
+  // calculate battery level
+  m_batteryLevel = 1 - (calculatedAlpha / m_alpha);
+  if (m_batteryLevel < 0)
+    {
+      m_batteryLevel = 0;
+    }
+
+  // check if battery is dead.
+  if (calculatedAlpha >= m_alpha)
+    {
+      m_lifetime = Simulator::Now ();
+      NS_LOG_DEBUG ("RvBatteryModel:Battery is dead!");
+      HandleEnergyDrainedEvent ();
+      return; // stop periodic sampling
+    }
+
+  m_previousLoad = currentLoad;
+  m_lastSampleTime = Simulator::Now ();
+  m_currentSampleEvent = Simulator::Schedule (m_samplingInterval,
+                                              &RvBatteryModel::UpdateEnergySource,
+                                              this);
+}
+
+void
+RvBatteryModel::SetSamplingInterval (Time interval)
+{
+  NS_LOG_FUNCTION (this << interval);
+  m_samplingInterval = interval;
+}
+
+Time
+RvBatteryModel::GetSamplingInterval (void) const
+{
+  return m_samplingInterval;
+}
+
+void
+RvBatteryModel::SetOpenCircuitVoltage (double voltage)
+{
+  NS_LOG_FUNCTION (this << voltage);
+  NS_ASSERT (voltage >= 0);
+  m_openCircuitVoltage = voltage;
+}
+
+double
+RvBatteryModel::GetOpenCircuitVoltage (void) const
+{
+  return m_openCircuitVoltage;
+}
+
+void
+RvBatteryModel::SetCutoffVoltage (double voltage)
+{
+  NS_LOG_FUNCTION (this << voltage);
+  NS_ASSERT (voltage <= m_openCircuitVoltage);
+  m_cutoffVoltage = voltage;
+}
+
+double
+RvBatteryModel::GetCutoffVoltage (void) const
+{
+  return m_cutoffVoltage;
+}
+
+void
+RvBatteryModel::SetAlpha (double alpha)
+{
+  NS_LOG_FUNCTION (this << alpha);
+  NS_ASSERT (alpha >= 0);
+  m_alpha = alpha;
+}
+
+double
+RvBatteryModel::GetAlpha (void) const
+{
+  return m_alpha;
+}
+
+void
+RvBatteryModel::SetBeta (double beta)
+{
+  NS_LOG_FUNCTION (this << beta);
+  NS_ASSERT (beta >= 0);
+  m_beta = beta;
+}
+
+double
+RvBatteryModel::GetBeta (void) const
+{
+  return m_beta;
+}
+
+double
+RvBatteryModel::GetBatteryLevel (void)
+{
+  NS_LOG_FUNCTION (this);
+  UpdateEnergySource ();
+  return m_batteryLevel;
+}
+
+Time
+RvBatteryModel::GetLifetime (void) const
+{
+  return m_lifetime;
+}
+
+void
+RvBatteryModel::SetNumOfTerms (int num)
+{
+  NS_LOG_FUNCTION (this << num);
+  m_numOfTerms = num;
+}
+
+int
+RvBatteryModel::GetNumOfTerms (void) const
+{
+  return m_numOfTerms;
+}
+
+/*
+ * Private functions start here.
+ */
+
+void
+RvBatteryModel::DoStart (void)
+{
+  NS_LOG_DEBUG ("RvBatteryModel:Starting battery level update!");
+  UpdateEnergySource ();  // start periodic sampling of load (total current)
+}
+
+void
+RvBatteryModel::DoDispose (void)
+{
+  BreakDeviceEnergyModelRefCycle ();  // break reference cycle
+}
+
+void
+RvBatteryModel::HandleEnergyDrainedEvent (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("RvBatteryModel:Energy depleted!");
+  NotifyEnergyDrained (); // notify DeviceEnergyModel objects
+}
+
+double
+RvBatteryModel::Discharge (double load, Time t)
+{
+  NS_LOG_FUNCTION (this << load << t);
+
+  // record only when load changes
+  if (load != m_previousLoad)
+    {
+      m_load.push_back (load);
+      m_previousLoad = load;
+      if (t != Seconds (0.0))
+        {
+          m_timeStamps[m_timeStamps.size () - 1] = m_lastSampleTime;
+        }
+      else
+        {
+          m_timeStamps.push_back (Seconds (0.0));
+        }
+      m_timeStamps.push_back (t);
+    }
+  else
+    {
+      m_timeStamps[m_timeStamps.size () - 1] = t;
+    }
+
+  m_lastSampleTime = t;
+
+  // calculate alpha for new t
+  NS_ASSERT (m_load.size () == m_timeStamps.size () - 1); // size must be equal
+  double calculatedAlpha = 0.0;
+  if (m_timeStamps.size () == 1)
+    {
+      // constant load
+      calculatedAlpha = m_load[0] * RvModelAFunction (t, t, Seconds(0.0),
+                                                          m_beta);
+    }
+  else
+    {
+      // changing load
+      for (uint64_t i = 1; i < m_timeStamps.size (); i++)
+        {
+          calculatedAlpha += m_load[i - 1] * RvModelAFunction (t, m_timeStamps[i],
+                                                               m_timeStamps[i - 1],
+                                                               m_beta);
+        }
+    }
+
+  return calculatedAlpha;
+}
+
+double
+RvBatteryModel::RvModelAFunction (Time t, Time sk, Time sk_1, double beta)
+{
+  NS_LOG_FUNCTION (this << t << sk << sk_1 << beta);
+
+  // everything is in minutes
+  double firstDelta = (t.GetSeconds () - sk.GetSeconds ()) / 60;
+  double secondDelta = (t.GetSeconds () - sk_1.GetSeconds ()) / 60;
+  double delta = (sk.GetSeconds () - sk_1.GetSeconds ()) / 60;
+
+  double sum = 0.0;
+  for (int m = 1; m <= m_numOfTerms; m++)
+    {
+      double square = beta * beta * m * m;
+      sum += (exp (- square * (firstDelta)) - exp (- square * (secondDelta))) / square;
+    }
+  return delta + 2 * sum;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/energy/model/rv-battery-model.h	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,259 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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
+ *
+ * Authors: Sidharth Nabar <snabar@uw.edu>, He Wu <mdzz@u.washington.edu>
+ */
+
+#ifndef RV_BATTERY_MODEL_H
+#define RV_BATTERY_MODEL_H
+
+#include "ns3/traced-value.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include "energy-source.h"
+
+namespace ns3 {
+
+/**
+ * \brief Rakhmatov Vrudhula non-linear battery model.
+ *
+ * This (energy source) model implements an analytical non-linear battery model.
+ * It is capable of capturing load capacity and recovery effects of batteries.
+ * Batteries are characterized by 2 parameters, alpha and beta, which can both
+ * be obtained from the discharge curve of the batteries.
+ *
+ * The model is developed by Daler Rakhmatov & Sarma Vrudhula in: "Battery
+ * Lifetime Prediction for Energy-Aware Computing" and "An Analytical High-Level
+ * Battery Model for Use in Energy Management of Portable Electronic Systems".
+ *
+ * The real-time algorithm is developed by Matthias Handy & Dirk Timmermann in:
+ * "Simulation of Mobile Wireless Networks with Accurate Modeling of non-linear
+ * battery effects". The real-time algorithm is modified by the authors of this
+ * code for improved accuracy and reduced computation (sampling) overhead.
+ */
+class RvBatteryModel : public EnergySource
+{
+public:
+  static TypeId GetTypeId (void);
+  RvBatteryModel ();
+  virtual ~RvBatteryModel ();
+
+  /**
+   * \return Initial energy stored (theoretical capacity) in the battery.
+   *
+   * Implements GetInitialEnergy.
+   */
+  virtual double GetInitialEnergy (void) const;
+
+  /**
+   * \returns Supply voltage at the energy source.
+   *
+   * Implements GetSupplyVoltage.
+   */
+  virtual double GetSupplyVoltage (void) const;
+
+  /**
+   * \return Remaining energy in energy source, in Joules
+   *
+   * Implements GetRemainingEnergy.
+   */
+  virtual double GetRemainingEnergy (void);
+
+  /**
+   * \returns Energy fraction.
+   *
+   * Implements GetEnergyFraction. For the RV battery model, energy fraction is
+   * equivalent to battery level.
+   */
+  virtual double GetEnergyFraction (void);
+
+  /**
+   * Implements UpdateEnergySource. This function samples the total load (total
+   * current) from all devices to discharge the battery.
+   */
+  virtual void UpdateEnergySource (void);
+
+  /**
+   * \param interval Energy update interval.
+   *
+   * This function sets the interval between each energy update.
+   */
+  void SetSamplingInterval (Time interval);
+
+  /**
+   * \returns The interval between each energy update.
+   */
+  Time GetSamplingInterval (void) const;
+
+  /**
+   * \brief Sets open circuit voltage of battery.
+   *
+   * \param voltage Open circuit voltage.
+   */
+  void SetOpenCircuitVoltage (double voltage);
+
+  /**
+   * \return Open circuit voltage of battery.
+   */
+  double GetOpenCircuitVoltage (void) const;
+
+  /**
+   * \brief Sets cutoff voltage of battery.
+   *
+   * \param voltage Cutoff voltage.
+   */
+  void SetCutoffVoltage (double voltage);
+
+  /**
+   * \returns Cutoff voltage of battery.
+   */
+  double GetCutoffVoltage (void) const;
+
+  /**
+   * \brief Sets the alpha value for the battery model.
+   *
+   * \param alpha Alpha.
+   */
+  void SetAlpha (double alpha);
+
+  /**
+   * \returns The alpha value used by the battery model.
+   */
+  double GetAlpha (void) const;
+
+  /**
+   * \brief Sets the beta value for the battery model.
+   *
+   * \param beta Beta.
+   */
+  void SetBeta (double beta);
+
+  /**
+   * \returns The beta value used by the battery model.
+   */
+  double GetBeta (void) const;
+
+  /**
+   * \returns Battery level [0, 1].
+   */
+  double GetBatteryLevel (void);
+
+  /**
+   * \returns Lifetime of the battery.
+   */
+  Time GetLifetime (void) const;
+
+  /**
+   * \brief Sets the number of terms of the infinite sum for estimating battery
+   * level.
+   *
+   * \param num Number of terms.
+   */
+  void SetNumOfTerms (int num);
+
+  /**
+   * \returns The number of terms of the infinite sum for estimating battery
+   * level.
+   */
+  int GetNumOfTerms (void) const;
+
+private:
+  /// Defined in ns3::Object
+  virtual void DoStart (void);
+
+  /// Defined in ns3::Object
+  virtual void DoDispose (void);
+
+  /**
+   * Handles the remaining energy going to zero event. This function notifies
+   * all the energy models aggregated to the node about the energy being
+   * depleted. Each energy model is then responsible for its own handler.
+   */
+  void HandleEnergyDrainedEvent (void);
+
+  /**
+   * \brief Discharges the battery.
+   *
+   * \param load Load value (total current form devices, in mA).
+   * \param t Time stamp of the load value.
+   * \returns Calculated alpha value.
+   *
+   * Discharge function calculates a value which is then compared to the alpha
+   * value to determine if the battery is dead. It will also update the battery
+   * level.
+   *
+   * Note that the load value passed to Discharge has to be in mA.
+   */
+  double Discharge (double load, Time t);
+
+  /**
+   * \brief RV model A function.
+   *
+   * \param t Current time.
+   * \param sk Time stamp in array position k
+   * \param sk_1 Time stamp in array position k-1
+   * \param beta Beta value used by the battery model.
+   * \returns Result of A function.
+   *
+   * This function computes alpha value using the recorded load profile.
+   */
+  double RvModelAFunction (Time t, Time sk, Time sk_1, double beta);
+
+private:
+  double m_openCircuitVoltage;
+  double m_cutoffVoltage;
+  double m_alpha; // alpha value of RV model, in Coulomb
+  double m_beta;  // beta value of RV model, in second^-1
+
+  double m_previousLoad;  // load value (total current) of previous sampling
+  std::vector<double> m_load;     // load profile
+  std::vector<Time> m_timeStamps; // time stamps of load profile
+  Time m_lastSampleTime;
+  uint64_t m_counter;
+
+  int m_numOfTerms; // # of terms for infinite sum in battery level estimation
+
+  /**
+   * Battery level is defined as: output of Discharge function / alpha value
+   *
+   * The output of Discharge function is an estimated charge consumption of the
+   * battery.
+   *
+   * The alpha value is the amount of charges stored in the battery, or battery
+   * capacity (in Coulomb).
+   *
+   * When the battery is fully charged (no charge is consumed from the battery)
+   * the battery level is 1. When the battery is fully discharged, the battery
+   * level is 0.
+   *
+   * NOTE Note that the definition in Timmermann's paper is the inverse of this
+   * definition. In the paper, battery level = 1 when the battery is drained.
+   */
+  TracedValue<double> m_batteryLevel;
+
+  /**
+   * (1 / sampling interval) = sampling frequency
+   */
+  Time m_samplingInterval;
+  EventId m_currentSampleEvent;
+
+  TracedValue<Time> m_lifetime;   // time of death of the battery
+};
+
+} // namespace ns3
+
+#endif  /* RV_BATTERY_MODEL_H */
--- a/src/contrib/energy/model/wifi-radio-energy-model.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/wifi-radio-energy-model.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -37,6 +37,18 @@
   static TypeId tid = TypeId ("ns3::WifiRadioEnergyModel")
     .SetParent<DeviceEnergyModel> ()
     .AddConstructor<WifiRadioEnergyModel> ()
+    .AddAttribute ("IdleCurrentA",
+                   "The default radio Idle current in Ampere.",
+                   DoubleValue (0.000426),  // idle mode = 426uA
+                   MakeDoubleAccessor (&WifiRadioEnergyModel::SetIdleCurrentA,
+                                       &WifiRadioEnergyModel::GetIdleCurrentA),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("CcaBusyCurrentA",
+                   "The default radio CCA Busy State current in Ampere.",
+                   DoubleValue (0.000426),  // default to be the same as idle mode
+                   MakeDoubleAccessor (&WifiRadioEnergyModel::SetCcaBusyCurrentA,
+                                       &WifiRadioEnergyModel::GetCcaBusyCurrentA),
+                   MakeDoubleChecker<double> ())
     .AddAttribute ("TxCurrentA",
                    "The radio Tx current in Ampere.",
                    DoubleValue (0.0174),    // transmit at 0dBm = 17.4mA
@@ -49,17 +61,11 @@
                    MakeDoubleAccessor (&WifiRadioEnergyModel::SetRxCurrentA,
                                        &WifiRadioEnergyModel::GetRxCurrentA),
                    MakeDoubleChecker<double> ())
-    .AddAttribute ("IdleCurrentA",
-                   "The default radio Idle current in Ampere.",
-                   DoubleValue (0.000426),  // idle mode = 426uA
-                   MakeDoubleAccessor (&WifiRadioEnergyModel::SetIdleCurrentA,
-                                       &WifiRadioEnergyModel::GetIdleCurrentA),
-                   MakeDoubleChecker<double> ())
-    .AddAttribute ("SleepCurrentA",
-                   "The default radio Sleep current in Ampere.",
-                   DoubleValue (0.00002),   // power down mode = 20uA
-                   MakeDoubleAccessor (&WifiRadioEnergyModel::SetSleepCurrentA,
-                                       &WifiRadioEnergyModel::GetSleepCurrentA),
+    .AddAttribute ("SwitchingCurrentA",
+                   "The default radio Channel Switch current in Ampere.",
+                   DoubleValue (0.000426),  // default to be the same as idle mode
+                   MakeDoubleAccessor (&WifiRadioEnergyModel::SetSwitchingCurrentA,
+                                       &WifiRadioEnergyModel::GetSwitchingCurrentA),
                    MakeDoubleChecker<double> ())
     .AddTraceSource ("TotalEnergyConsumption",
                      "Total energy consumption of the radio device.",
@@ -71,29 +77,18 @@
 WifiRadioEnergyModel::WifiRadioEnergyModel ()
 {
   NS_LOG_FUNCTION (this);
-  m_currentState = IDLE;  // initially IDLE
+  m_currentState = WifiPhy::IDLE;  // initially IDLE
   m_lastUpdateTime = Seconds (0.0);
   m_energyDepletionCallback.Nullify ();
-  m_node = NULL;
   m_source = NULL;
+  // set callback for WifiPhy listener
+  m_listener = new WifiRadioEnergyModelPhyListener;
+  m_listener->SetChangeStateCallback (MakeCallback (&DeviceEnergyModel::ChangeState, this));
 }
 
 WifiRadioEnergyModel::~WifiRadioEnergyModel ()
 {
-}
-
-void
-WifiRadioEnergyModel::SetNode (Ptr<Node> node)
-{
-  NS_LOG_FUNCTION (this << node);
-  NS_ASSERT (node != NULL);
-  m_node = node;
-}
-
-Ptr<Node>
-WifiRadioEnergyModel::GetNode (void) const
-{
-  return m_node;
+  delete m_listener;
 }
 
 void
@@ -107,14 +102,38 @@
 double
 WifiRadioEnergyModel::GetTotalEnergyConsumption (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_totalEnergyConsumption;
 }
 
 double
+WifiRadioEnergyModel::GetIdleCurrentA (void) const
+{
+  return m_idleCurrentA;
+}
+
+void
+WifiRadioEnergyModel::SetIdleCurrentA (double idleCurrentA)
+{
+  NS_LOG_FUNCTION (this << idleCurrentA);
+  m_idleCurrentA = idleCurrentA;
+}
+
+double
+WifiRadioEnergyModel::GetCcaBusyCurrentA (void) const
+{
+  return m_ccaBusyCurrentA;
+}
+
+void
+WifiRadioEnergyModel::SetCcaBusyCurrentA (double CcaBusyCurrentA)
+{
+  NS_LOG_FUNCTION (this << CcaBusyCurrentA);
+  m_ccaBusyCurrentA = CcaBusyCurrentA;
+}
+
+double
 WifiRadioEnergyModel::GetTxCurrentA (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_txCurrentA;
 }
 
@@ -128,7 +147,6 @@
 double
 WifiRadioEnergyModel::GetRxCurrentA (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_rxCurrentA;
 }
 
@@ -140,37 +158,22 @@
 }
 
 double
-WifiRadioEnergyModel::GetIdleCurrentA (void) const
+WifiRadioEnergyModel::GetSwitchingCurrentA (void) const
 {
-  NS_LOG_FUNCTION (this);
-  return m_idleCurrentA;
+  return m_switchingCurrentA;
 }
 
 void
-WifiRadioEnergyModel::SetIdleCurrentA (double idleCurrentA)
+WifiRadioEnergyModel::SetSwitchingCurrentA (double switchingCurrentA)
 {
-  NS_LOG_FUNCTION (this << idleCurrentA);
-  m_idleCurrentA = idleCurrentA;
+  NS_LOG_FUNCTION (this << switchingCurrentA);
+  m_switchingCurrentA = switchingCurrentA;
 }
 
-double
-WifiRadioEnergyModel::GetSleepCurrentA (void) const
-{
-  NS_LOG_FUNCTION (this);
-  return m_sleepCurrentA;
-}
 
-void
-WifiRadioEnergyModel::SetSleepCurrentA (double sleepCurrentA)
-{
-  NS_LOG_FUNCTION (this << sleepCurrentA);
-  m_sleepCurrentA = sleepCurrentA;
-}
-
-WifiRadioEnergyModel::WifiRadioState
+WifiPhy::State
 WifiRadioEnergyModel::GetCurrentState (void) const
 {
-  NS_LOG_FUNCTION (this);
   return m_currentState;
 }
 
@@ -190,7 +193,6 @@
 WifiRadioEnergyModel::ChangeState (int newState)
 {
   NS_LOG_FUNCTION (this << newState);
-  NS_ASSERT (IsStateTransitionValid ((WifiRadioState) newState));
 
   Time duration = Simulator::Now () - m_lastUpdateTime;
   NS_ASSERT (duration.GetNanoSeconds () >= 0); // check if duration is valid
@@ -200,20 +202,23 @@
   double supplyVoltage = m_source->GetSupplyVoltage ();
   switch (m_currentState)
     {
-    case TX:
+    case WifiPhy::IDLE:
+      energyToDecrease = duration.GetSeconds () * m_idleCurrentA * supplyVoltage;
+      break;
+    case WifiPhy::CCA_BUSY:
+      energyToDecrease = duration.GetSeconds () * m_ccaBusyCurrentA * supplyVoltage;
+      break;
+    case WifiPhy::TX:
       energyToDecrease = duration.GetSeconds () * m_txCurrentA * supplyVoltage;
       break;
-    case RX:
+    case WifiPhy::RX:
       energyToDecrease = duration.GetSeconds () * m_rxCurrentA * supplyVoltage;
       break;
-    case IDLE:
-      energyToDecrease = duration.GetSeconds () * m_idleCurrentA * supplyVoltage;
-      break;
-    case SLEEP:
-      energyToDecrease = duration.GetSeconds () * m_sleepCurrentA * supplyVoltage;
+    case WifiPhy::SWITCHING:
+      energyToDecrease = duration.GetSeconds () * m_switchingCurrentA * supplyVoltage;
       break;
     default:
-      NS_FATAL_ERROR ("WifiRadioEnergyModel:Undefined radio state!");
+      NS_FATAL_ERROR ("WifiRadioEnergyModel:Undefined radio state: " << m_currentState);
     }
 
   // update total energy consumption
@@ -226,19 +231,17 @@
   m_source->UpdateEnergySource ();
 
   // update current state & last update time stamp
-  SetWifiRadioState ((WifiRadioState) newState);
+  SetWifiRadioState ((WifiPhy::State) newState);
 
   // some debug message
-  NS_LOG_DEBUG ("WifiRadioEnergyModel:Total energy consumption at node #"
-      << m_node->GetId () << " is " << m_totalEnergyConsumption << "J");
+  NS_LOG_DEBUG ("WifiRadioEnergyModel:Total energy consumption is " <<
+                m_totalEnergyConsumption << "J");
 }
 
 void
 WifiRadioEnergyModel::HandleEnergyDepletion (void)
 {
-  NS_LOG_FUNCTION (this);
-  NS_LOG_DEBUG ("WifiRadioEnergyModel:Energy is depleted at node #" <<
-                m_node->GetId ());
+  NS_LOG_DEBUG ("WifiRadioEnergyModel:Energy is depleted!");
   // invoke energy depletion callback, if set.
   if (!m_energyDepletionCallback.IsNull ())
     {
@@ -246,6 +249,12 @@
     }
 }
 
+WifiRadioEnergyModelPhyListener *
+WifiRadioEnergyModel::GetPhyListener (void)
+{
+  return m_listener;
+}
+
 /*
  * Private functions start here.
  */
@@ -253,8 +262,6 @@
 void
 WifiRadioEnergyModel::DoDispose (void)
 {
-  NS_LOG_FUNCTION (this);
-  m_node = NULL;
   m_source = NULL;
   m_energyDepletionCallback.Nullify ();
 }
@@ -262,67 +269,151 @@
 double
 WifiRadioEnergyModel::DoGetCurrentA (void) const
 {
-  NS_LOG_FUNCTION (this);
   switch (m_currentState)
     {
-    case TX:
+    case WifiPhy::IDLE:
+      return m_idleCurrentA;
+    case WifiPhy::CCA_BUSY:
+      return m_ccaBusyCurrentA;
+    case WifiPhy::TX:
       return m_txCurrentA;
-    case RX:
+    case WifiPhy::RX:
       return m_rxCurrentA;
-    case IDLE:
-      return m_idleCurrentA;
-    case SLEEP:
-      return m_sleepCurrentA;
+    case WifiPhy::SWITCHING:
+      return m_switchingCurrentA;
     default:
-      NS_FATAL_ERROR ("WifiRadioEnergyModel:Undefined radio state!");
+      NS_FATAL_ERROR ("WifiRadioEnergyModel:Undefined radio state:" << m_currentState);
     }
 }
 
-bool
-WifiRadioEnergyModel::IsStateTransitionValid (const WifiRadioState destState)
+void
+WifiRadioEnergyModel::SetWifiRadioState (const WifiPhy::State state)
 {
-  NS_LOG_FUNCTION (this << destState);
+  NS_LOG_FUNCTION (this << state);
+  m_currentState = state;
+  std::string stateName;
+  switch (state)
+    {
+    case WifiPhy::IDLE:
+      stateName = "IDLE";
+      break;
+    case WifiPhy::CCA_BUSY:
+      stateName = "CCA_BUSY";
+      break;
+    case WifiPhy::TX:
+      stateName = "TX";
+      break;
+    case WifiPhy::RX:
+      stateName = "RX";
+      break;
+    case WifiPhy::SWITCHING:
+      stateName = "SWITCHING";
+      break;
+    }
+  NS_LOG_DEBUG ("WifiRadioEnergyModel:Switching to state: " << stateName <<
+                " at time = " << Simulator::Now ());
+}
 
-  /*
-   * This is a placeholder function to specify if some of the radio state
-   * transitions are prohibited. For example, if transition TX -> RX is not
-   * allowed, and must go through IDLE as TX -> IDLE -> RX, then this method
-   * can be used to raise an ns3 error.
-   */
+// -------------------------------------------------------------------------- //
+
+WifiRadioEnergyModelPhyListener::WifiRadioEnergyModelPhyListener ()
+{
+  m_changeStateCallback.Nullify ();
+}
 
-  return true;
+WifiRadioEnergyModelPhyListener::~WifiRadioEnergyModelPhyListener ()
+{
+}
+
+void
+WifiRadioEnergyModelPhyListener::SetChangeStateCallback (DeviceEnergyModel::ChangeStateCallback callback)
+{
+  NS_ASSERT (!callback.IsNull ());
+  m_changeStateCallback = callback;
 }
 
 void
-WifiRadioEnergyModel::SetWifiRadioState (const WifiRadioState state)
+WifiRadioEnergyModelPhyListener::NotifyRxStart (Time duration)
+{
+  if (m_changeStateCallback.IsNull ())
+    {
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
+    }
+  m_changeStateCallback (WifiPhy::RX);
+  m_switchToIdleEvent.Cancel ();
+}
+
+void
+WifiRadioEnergyModelPhyListener::NotifyRxEndOk (void)
 {
-  NS_LOG_FUNCTION (this);
-  if (IsStateTransitionValid (state))
+  if (m_changeStateCallback.IsNull ())
+    {
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
+    }
+  m_changeStateCallback (WifiPhy::IDLE);
+}
+
+void
+WifiRadioEnergyModelPhyListener::NotifyRxEndError (void)
+{
+  if (m_changeStateCallback.IsNull ())
+    {
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
+    }
+  m_changeStateCallback (WifiPhy::IDLE);
+}
+
+void
+WifiRadioEnergyModelPhyListener::NotifyTxStart (Time duration)
+{
+  if (m_changeStateCallback.IsNull ())
     {
-      m_currentState = state;
-      std::string stateName;
-      switch (state)
-        {
-        case TX:
-          stateName = "TX";
-          break;
-        case RX:
-          stateName = "RX";
-          break;
-        case IDLE:
-          stateName = "IDLE";
-          break;
-        case SLEEP:
-          stateName = "SLEEP";
-          break;
-        }
-      NS_LOG_DEBUG ("WifiRadioEnergyModel:Switching to state: " << stateName <<
-                    " at time = " << Simulator::Now ());
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
+    }
+  m_changeStateCallback (WifiPhy::TX);
+  // schedule changing state back to IDLE after TX duration
+  m_switchToIdleEvent.Cancel ();
+  m_switchToIdleEvent = Simulator::Schedule (duration, &WifiRadioEnergyModelPhyListener::SwitchToIdle, this);
+}
+
+void
+WifiRadioEnergyModelPhyListener::NotifyMaybeCcaBusyStart (Time duration)
+{
+  if (m_changeStateCallback.IsNull ())
+    {
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-  else
+  m_changeStateCallback (WifiPhy::CCA_BUSY);
+  // schedule changing state back to IDLE after CCA_BUSY duration
+  m_switchToIdleEvent.Cancel ();
+  m_switchToIdleEvent = Simulator::Schedule (duration, &WifiRadioEnergyModelPhyListener::SwitchToIdle, this);
+}
+
+void
+WifiRadioEnergyModelPhyListener::NotifySwitchingStart (Time duration)
+{
+  if (m_changeStateCallback.IsNull ())
     {
-      NS_FATAL_ERROR ("WifiRadioEnergyModel:Invalid state transition!");
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
+  m_changeStateCallback (WifiPhy::SWITCHING);
+  // schedule changing state back to IDLE after CCA_BUSY duration
+  m_switchToIdleEvent.Cancel ();
+  m_switchToIdleEvent = Simulator::Schedule (duration, &WifiRadioEnergyModelPhyListener::SwitchToIdle, this);
+}
+
+/*
+ * Private function state here.
+ */
+
+void
+WifiRadioEnergyModelPhyListener::SwitchToIdle (void)
+{
+  if (m_changeStateCallback.IsNull ())
+    {
+      NS_FATAL_ERROR ("WifiRadioEnergyModelPhyListener:Change state callback not set!");
+    }
+  m_changeStateCallback (WifiPhy::IDLE);
 }
 
 } // namespace ns3
--- a/src/contrib/energy/model/wifi-radio-energy-model.h	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/model/wifi-radio-energy-model.h	Mon Dec 20 15:49:12 2010 -0800
@@ -25,10 +25,99 @@
 #include "ns3/nstime.h"
 #include "ns3/event-id.h"
 #include "ns3/traced-value.h"
+#include "ns3/wifi-phy.h"
 
 namespace ns3 {
 
 /**
+ * A WifiPhy listener class for notifying the WifiRadioEnergyModel of Wifi radio
+ * state change.
+ */
+class WifiRadioEnergyModelPhyListener : public WifiPhyListener
+{
+public:
+  WifiRadioEnergyModelPhyListener ();
+  virtual ~WifiRadioEnergyModelPhyListener ();
+
+  /**
+   * \brief Sets the change state callback. Used by helper class.
+   *
+   * \param callback Change state callback.
+   */
+  void SetChangeStateCallback (DeviceEnergyModel::ChangeStateCallback callback);
+
+  /**
+   * \brief Switches the WifiRadioEnergyModel to RX state.
+   *
+   * \param duration the expected duration of the packet reception.
+   *
+   * Defined in ns3::WifiPhyListener
+   */
+  virtual void NotifyRxStart (Time duration);
+
+  /**
+   * \brief Switches the WifiRadioEnergyModel back to IDLE state.
+   *
+   * Defined in ns3::WifiPhyListener
+   *
+   * Note that for the WifiRadioEnergyModel, the behavior of the function is the
+   * same as NotifyRxEndError.
+   */
+  virtual void NotifyRxEndOk (void);
+
+  /**
+   * \brief Switches the WifiRadioEnergyModel back to IDLE state.
+   *
+   * Defined in ns3::WifiPhyListener
+   *
+   * Note that for the WifiRadioEnergyModel, the behavior of the function is the
+   * same as NotifyRxEndOk.
+   */
+  virtual void NotifyRxEndError (void);
+
+  /**
+   * \brief Switches the WifiRadioEnergyModel to TX state and switches back to
+   * IDLE after TX duration.
+   *
+   * \param duration the expected transmission duration.
+   *
+   * Defined in ns3::WifiPhyListener
+   */
+  virtual void NotifyTxStart (Time duration);
+
+  /**
+   * \param duration the expected busy duration.
+   *
+   * Defined in ns3::WifiPhyListener
+   */
+  virtual void NotifyMaybeCcaBusyStart (Time duration);
+
+  /**
+   * \param duration the expected channel switching duration.
+   *
+   * Defined in ns3::WifiPhyListener
+   */
+  virtual void NotifySwitchingStart (Time duration);
+
+private:
+  /**
+   * A helper function that makes scheduling m_changeStateCallback possible.
+   */
+  void SwitchToIdle (void);
+
+private:
+  /**
+   * Change state callback used to notify the WifiRadioEnergyModel of a state
+   * change.
+   */
+  DeviceEnergyModel::ChangeStateCallback m_changeStateCallback;
+
+  EventId m_switchToIdleEvent;
+};
+
+// -------------------------------------------------------------------------- //
+
+/**
  * \brief A WiFi radio energy model.
  * 
  * 4 states are defined for the radio: TX, RX, IDLE, SLEEP. Default state is
@@ -54,29 +143,6 @@
 {
 public:
   /**
-   * Wifi radio states.
-   */
-  enum WifiRadioState
-  {
-    /**
-     * Radio is transmitting.
-     */
-    TX = 0,
-    /**
-     * Radio is receiving.
-     */
-    RX,
-    /**
-     * Radio is idling.
-     */
-    IDLE,
-    /**
-     * Radio is asleep.
-     */
-    SLEEP
-  };
-
-  /**
    * Callback type for energy depletion handling.
    */
   typedef Callback<void> WifiRadioEnergyDepletionCallback;
@@ -87,24 +153,6 @@
   virtual ~WifiRadioEnergyModel ();
 
   /**
-   * \brief Sets pointer to node.
-   *
-   * \param node Pointer to node.
-   *
-   * Implements DeviceEnergyModel::SetNode.
-   */
-  virtual void SetNode (Ptr<Node> node);
-
-  /**
-   * \brief Gets pointer to node.
-   *
-   * \returns Pointer to node.
-   *
-   * Implements DeviceEnergyModel::GetNode.
-   */
-  virtual Ptr<Node> GetNode (void) const;
-
-  /**
    * \brief Sets pointer to EnergySouce installed on node.
    *
    * \param source Pointer to EnergySource installed on node.
@@ -121,19 +169,21 @@
   virtual double GetTotalEnergyConsumption (void) const;
 
   // Setter & getters for state power consumption.
+  double GetIdleCurrentA (void) const;
+  void SetIdleCurrentA (double idleCurrentA);
+  double GetCcaBusyCurrentA (void) const;
+  void SetCcaBusyCurrentA (double ccaBusyCurrentA);
   double GetTxCurrentA (void) const;
   void SetTxCurrentA (double txCurrentA);
   double GetRxCurrentA (void) const;
   void SetRxCurrentA (double rxCurrentA);
-  double GetIdleCurrentA (void) const;
-  void SetIdleCurrentA (double idleCurrentA);
-  double GetSleepCurrentA (void) const;
-  void SetSleepCurrentA (double sleepCurrentA);
+  double GetSwitchingCurrentA (void) const;
+  void SetSwitchingCurrentA (double switchingCurrentA);
 
   /**
    * \returns Current state.
    */
-  WifiRadioState GetCurrentState (void) const;
+  WifiPhy::State GetCurrentState (void) const;
 
   /**
    * \param callback Callback function.
@@ -158,6 +208,11 @@
    */
   virtual void HandleEnergyDepletion (void);
 
+  /**
+   * \returns Pointer to the PHY listener.
+   */
+  WifiRadioEnergyModelPhyListener * GetPhyListener (void);
+
 
 private:
   void DoDispose (void);
@@ -170,40 +225,35 @@
   virtual double DoGetCurrentA (void) const;
 
   /**
-   * \param destState Radio state to switch to.
-   * \return True if the transition is allowed.
-   *
-   * This function checks if a given radio state transition is allowed.
-   */
-  bool IsStateTransitionValid (const WifiRadioState destState);
-
-  /**
    * \param currentState New state the radio device is currently in.
    *
    * Sets current state. This function is private so that only the energy model
    * can change its own state.
    */
-  void SetWifiRadioState (const WifiRadioState state);
+  void SetWifiRadioState (const WifiPhy::State state);
 
 private:
-  Ptr<Node> m_node;
   Ptr<EnergySource> m_source;
 
   // Member variables for current draw in different radio modes.
   double m_txCurrentA;
   double m_rxCurrentA;
   double m_idleCurrentA;
-  double m_sleepCurrentA;
+  double m_ccaBusyCurrentA;
+  double m_switchingCurrentA;
 
   // This variable keeps track of the total energy consumed by this model.
   TracedValue<double> m_totalEnergyConsumption;
 
   // State variables.
-  WifiRadioState m_currentState;  // current state the radio is in
+  WifiPhy::State m_currentState;  // current state the radio is in
   Time m_lastUpdateTime;          // time stamp of previous energy update
 
-  // energy depletion callback
+  // Energy depletion callback
   WifiRadioEnergyDepletionCallback m_energyDepletionCallback;
+
+  // WifiPhy listener
+  WifiRadioEnergyModelPhyListener *m_listener;
 };
 
 } // namespace ns3
--- a/src/contrib/energy/test/basic-energy-model-test.cc	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/test/basic-energy-model-test.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -15,7 +15,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Authors: He Wu <mdzz@u.washington.edu>
+ * Author: He Wu <mdzz@u.washington.edu>
  */
 
 #include "ns3/basic-energy-source.h"
@@ -59,7 +59,7 @@
    * Runs simulation for a while, check if final state & remaining energy is
    * correctly updated.
    */
-  bool StateSwitchTest (WifiRadioEnergyModel::WifiRadioState state);
+  bool StateSwitchTest (WifiPhy::State state);
 
 private:
   double m_timeS;     // in seconds
@@ -88,19 +88,23 @@
   m_deviceEnergyModel.SetTypeId ("ns3::WifiRadioEnergyModel");
 
   // run state switch tests
-  if (StateSwitchTest (WifiRadioEnergyModel::TX))
+  if (StateSwitchTest (WifiPhy::IDLE))
+    {
+      return true;
+    }
+  if (StateSwitchTest (WifiPhy::CCA_BUSY))
     {
       return true;
     }
-  if (StateSwitchTest (WifiRadioEnergyModel::RX))
+  if (StateSwitchTest (WifiPhy::TX))
     {
       return true;
     }
-  if (StateSwitchTest (WifiRadioEnergyModel::IDLE))
+  if (StateSwitchTest (WifiPhy::RX))
     {
       return true;
     }
-  if (StateSwitchTest (WifiRadioEnergyModel::SLEEP))
+  if (StateSwitchTest (WifiPhy::SWITCHING))
     {
       return true;
     }
@@ -110,8 +114,7 @@
 }
 
 bool
-BasicEnergyUpdateTest::StateSwitchTest (
-    WifiRadioEnergyModel::WifiRadioState state)
+BasicEnergyUpdateTest::StateSwitchTest (WifiPhy::State state)
 {
   // create node
   Ptr<Node> node = CreateObject<Node> ();
@@ -120,8 +123,6 @@
   Ptr<BasicEnergySource> source = m_energySource.Create<BasicEnergySource> ();
   // aggregate energy source to node
   node->AggregateObject (source);
-  // set update interval in source
-  source->SetEnergyUpdateInterval (Seconds (1.0));
 
   // create device energy model
   Ptr<WifiRadioEnergyModel> model =
@@ -176,17 +177,20 @@
   double current = 0.0;
   switch (state)
     {
-    case WifiRadioEnergyModel::TX:
+    case WifiPhy::IDLE:
+      current = devModel->GetIdleCurrentA ();
+      break;
+    case WifiPhy::CCA_BUSY:
+      current = devModel->GetCcaBusyCurrentA ();
+      break;
+    case WifiPhy::TX:
       current = devModel->GetTxCurrentA ();
       break;
-    case WifiRadioEnergyModel::RX:
+    case WifiPhy::RX:
       current = devModel->GetRxCurrentA ();
       break;
-    case WifiRadioEnergyModel::IDLE:
-      current = devModel->GetIdleCurrentA ();
-      break;
-    case WifiRadioEnergyModel::SLEEP:
-      current = devModel->GetSleepCurrentA ();
+    case WifiPhy::SWITCHING:
+      current = devModel->GetSwitchingCurrentA ();
       break;
     default:
       NS_FATAL_ERROR ("Undefined radio state: " << state);
@@ -204,7 +208,7 @@
                              "Incorrect remaining energy!");
 
   // obtain radio state
-  WifiRadioEnergyModel::WifiRadioState endState = devModel->GetCurrentState ();
+  WifiPhy::State endState = devModel->GetCurrentState ();
   NS_LOG_UNCOND ("Radio state is " << endState);
   // check end state
   NS_TEST_ASSERT_MSG_EQ (endState, state,  "Incorrect end state!");
@@ -362,8 +366,7 @@
     MakeCallback (&BasicEnergyDepletionTest::DepletionHandler, this);
   radioEnergyHelper.SetDepletionCallback (callback);
   // install on node
-  DeviceEnergyModelContainer deviceModels = radioEnergyHelper.Install (devices,
-                                                                       sources);
+  DeviceEnergyModelContainer deviceModels = radioEnergyHelper.Install (devices, sources);
 
   // run simulation
   Simulator::Stop (Seconds (simTimeS));
@@ -376,8 +379,7 @@
   NS_LOG_UNCOND ("Actual callback count is " << m_callbackCount);
 
   // check result, call back should only be invoked once
-  NS_TEST_ASSERT_MSG_EQ (m_numOfNodes, m_callbackCount,
-                         "Not all callbacks are invoked!");
+  NS_TEST_ASSERT_MSG_EQ (m_numOfNodes, m_callbackCount, "Not all callbacks are invoked!");
 
   return false;
 }
@@ -399,7 +401,7 @@
   : TestSuite ("basic-energy-model", UNIT)
 {
   AddTestCase (new BasicEnergyUpdateTest);
-  //AddTestCase (new BasicEnergyDepletionTest);
+  AddTestCase (new BasicEnergyDepletionTest);
 }
 
 // create an instance of the test suite
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/energy/test/rv-battery-model-test.cc	Mon Dec 20 15:49:12 2010 -0800
@@ -0,0 +1,906 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Network Security Lab, University of Washington, Seattle.
+ *
+ * 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: He Wu <mdzz@u.washington.edu>
+ */
+
+#include "ns3/rv-battery-model.h"
+#include "ns3/wifi-radio-energy-model.h"
+#include "ns3/rv-battery-model-helper.h"
+#include "ns3/wifi-radio-energy-model-helper.h"
+#include "ns3/energy-source-container.h"
+#include "ns3/device-energy-model-container.h"
+#include "ns3/log.h"
+#include "ns3/test.h"
+#include "ns3/node.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/config.h"
+#include "ns3/string.h"
+#include "ns3/yans-wifi-helper.h"
+#include "ns3/nqos-wifi-mac-helper.h"
+#include <math.h>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("RvBatteryModelTestSuite");
+
+/**
+ * Test case of update remaining energy for RvBatteryModel and
+ * WifiRadioEnergyModel.
+ */
+class BatteryLifetimeTest : public TestCase
+{
+public:
+  BatteryLifetimeTest ();
+  virtual ~BatteryLifetimeTest ();
+
+private:
+  /**
+   * Creates load profiles according to "Battery Lifetime Prediction for Energy-
+   * Aware Computing" paper.
+   */
+  void CreateLoadProfiles (void);
+
+  /**
+   * \returns False if no error occurs.
+   *
+   * Runs test.
+   */
+  bool DoRun (void);
+
+  /**
+   * \param load Load value, in Amperes (A).
+   * \param expLifetime Expected lifetime.
+   * \return False if no error occurs.
+   *
+   * Runs simulation with constant load and checks the battery lifetime with
+   * known results.
+   */
+  bool ConstantLoadTest (double load, Time expLifetime);
+
+  /**
+   * \param loads Load profile.
+   * \param timeStamps Time stamps.
+   * \param expLifeTime Expected lifetime.
+   * \returns False if no error occurs.
+   *
+   * Runs simulation with variable load and checks the battery lifetime with
+   * known results.
+   */
+  bool VariableLoadTest (std::vector<double> loads,
+                         std::vector<Time> timeStamps,
+                         Time expLifetime);
+
+private:
+  typedef struct LoadProfile
+  {
+    std::vector<double> loads;
+    std::vector<Time> timeStamps;
+    Time itsyLifetime;
+    Time dualFoilLifeTime;
+  } LoadProfile;
+
+private:
+  std::vector<LoadProfile> m_loadProfiles;
+  double m_alpha;
+  double m_beta;
+};
+
+BatteryLifetimeTest::BatteryLifetimeTest ()
+  : TestCase ("RV battery model battery lifetime test case.")
+{
+  // Itsy battery
+  m_alpha = 35220;
+  m_beta = 0.637;
+}
+
+BatteryLifetimeTest::~BatteryLifetimeTest ()
+{
+}
+
+void
+BatteryLifetimeTest::CreateLoadProfiles (void)
+{
+  // create set of load profiles
+  LoadProfile profile;
+
+  std::vector<double> loads;
+  std::vector<Time> timeStamps;
+
+  // C1
+  loads.push_back (0.628);
+  loads.push_back (0);
+  loads.push_back (0.628);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (19.5 * 60));
+  timeStamps.push_back (Seconds (26.0 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (55.0 * 60);     // 55.0 minutes
+  profile.dualFoilLifeTime = Seconds (36.2 * 60); // 36.2 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C2
+  loads.push_back (0.4947);
+  loads.push_back (0);
+  loads.push_back (0.4947);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (31.0 * 60));
+  timeStamps.push_back (Seconds (41.3 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (73.9 * 60);     // 73.9 minutes
+  profile.dualFoilLifeTime = Seconds (55.8 * 60); // 55.8 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C3
+  loads.push_back (0.4256);
+  loads.push_back (0);
+  loads.push_back (0.4256);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (41.0 * 60));
+  timeStamps.push_back (Seconds (54.6 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (88.8 * 60);     // 88.8 minutes
+  profile.dualFoilLifeTime = Seconds (71.8 * 60); // 71.8 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C4
+  loads.push_back (0.2923);
+  loads.push_back (0);
+  loads.push_back (0.2923);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (74.6 * 60));
+  timeStamps.push_back (Seconds (99.5 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (137.8 * 60);      // 137.8 minutes
+  profile.dualFoilLifeTime = Seconds (124.9 * 60);  // 124.9 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C5
+  loads.push_back (0.2227);
+  loads.push_back (0);
+  loads.push_back (0.2227);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (105.7 * 60));
+  timeStamps.push_back (Seconds (140.9 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (185.8 * 60);      // 185.8 minutes
+  profile.dualFoilLifeTime = Seconds (176.7 * 60);  // 176.7 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C6
+  loads.push_back (0.628);
+  loads.push_back (0);
+  loads.push_back (0.628);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (19.5 * 60));
+  timeStamps.push_back (Seconds (29.9 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (58.9 * 60);     // 58.9 minutes
+  profile.dualFoilLifeTime = Seconds (41.0 * 60); // 41.0 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C7
+  loads.push_back (0.628);
+  loads.push_back (0);
+  loads.push_back (0.628);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (19.5 * 60));
+  timeStamps.push_back (Seconds (22.1 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (51.1 * 60);     // 51.1 minutes
+  profile.dualFoilLifeTime = Seconds (30.8 * 60); // 30.8 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C8
+  loads.push_back (0.628);
+  loads.push_back (0);
+  loads.push_back (0.628);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (23.4 * 60));
+  timeStamps.push_back (Seconds (29.9 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (55.0 * 60);     // 55.0 minutes
+  profile.dualFoilLifeTime = Seconds (37.4 * 60); // 37.4 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C9
+  loads.push_back (0.628);
+  loads.push_back (0);
+  loads.push_back (0.628);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (15.6 * 60));
+  timeStamps.push_back (Seconds (22.1 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (55.0 * 60);     // 55.0 minutes
+  profile.dualFoilLifeTime = Seconds (35.2 * 60); // 35.2 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C10
+  loads.push_back (0.300);
+  loads.push_back (0.628);
+  loads.push_back (0.4947);
+  loads.push_back (0.2523);
+  loads.push_back (0.2341);
+  loads.push_back (0.1379);
+  loads.push_back (0.1139);
+  loads.push_back (0.2656);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (0.5 * 60));
+  timeStamps.push_back (Seconds (5.5 * 60));
+  timeStamps.push_back (Seconds (10.5 * 60));
+  timeStamps.push_back (Seconds (35.5 * 60));
+  timeStamps.push_back (Seconds (60.5 * 60));
+  timeStamps.push_back (Seconds (85.5 * 60));
+  timeStamps.push_back (Seconds (110.5 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (144.3 * 60);      // 144.3 minutes
+  profile.dualFoilLifeTime = Seconds (132.6 * 60);  // 132.6 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C11
+  loads.push_back (0.300);
+  loads.push_back (0.1139);
+  loads.push_back (0.1379);
+  loads.push_back (0.2341);
+  loads.push_back (0.2523);
+  loads.push_back (0.4947);
+  loads.push_back (0.628);
+  loads.push_back (0.2656);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (0.5 * 60));
+  timeStamps.push_back (Seconds (25.5 * 60));
+  timeStamps.push_back (Seconds (50.5 * 60));
+  timeStamps.push_back (Seconds (75.5 * 60));
+  timeStamps.push_back (Seconds (100.5 * 60));
+  timeStamps.push_back (Seconds (105.5 * 60));
+  timeStamps.push_back (Seconds (110.5 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (144.3 * 60);      // 144.3 minutes
+  profile.dualFoilLifeTime = Seconds (107.4 * 60);  // 107.4 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C12
+  loads.push_back (0.300);
+  loads.push_back (0.1139);
+  loads.push_back (0.1379);
+  loads.push_back (0.2341);
+  loads.push_back (0.2523);
+  loads.push_back (0.4947);
+  loads.push_back (0.0);
+  loads.push_back (0.300);
+  loads.push_back (0.628);
+  loads.push_back (0.2656);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (0.5 * 60));
+  timeStamps.push_back (Seconds (25.5 * 60));
+  timeStamps.push_back (Seconds (50.5 * 60));
+  timeStamps.push_back (Seconds (75.5 * 60));
+  timeStamps.push_back (Seconds (100.5 * 60));
+  timeStamps.push_back (Seconds (105.5 * 60));
+  timeStamps.push_back (Seconds (130.5 * 60));
+  timeStamps.push_back (Seconds (131.0 * 60));
+  timeStamps.push_back (Seconds (136.0 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (169.3 * 60);      // 169.3 minutes
+  profile.dualFoilLifeTime = Seconds (155.4 * 60);  // 155.4 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C13
+  loads.push_back (0.300);
+  timeStamps.push_back (Seconds (0));
+
+  for (int i = 0; i < 5; i++)
+    {
+      loads.push_back (0.628);
+      loads.push_back (0.4947);
+      loads.push_back (0.2523);
+      loads.push_back (0.2341);
+      loads.push_back (0.1379);
+      loads.push_back (0.1139);
+
+      timeStamps.push_back (Seconds ((0.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((1.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((2.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((7.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((12.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((17.5 + i * 22.5) * 60));
+    }
+
+  loads.push_back (0.2656);
+  timeStamps.push_back (Seconds (110.5 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (144.3 * 60);      // 144.3 minutes
+  profile.dualFoilLifeTime = Seconds (131.7 * 60);  // 131.7 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C14, time stamp calculation in paper is off, using our own estimated value
+  loads.push_back (0.300);
+  timeStamps.push_back (Seconds (0));
+
+  for (int i = 0; i < 5; i++)
+    {
+      loads.push_back (0.1139);
+      loads.push_back (0.1379);
+      loads.push_back (0.2341);
+      loads.push_back (0.2523);
+      loads.push_back (0.4947);
+      loads.push_back (0.628);
+
+      timeStamps.push_back (Seconds ((0.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((5.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((10.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((15.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((20.5 + i * 22.5) * 60));
+      timeStamps.push_back (Seconds ((21.5 + i * 22.5) * 60));
+    }
+
+  loads.push_back (0.2656);
+  timeStamps.push_back (Seconds (112.5 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (141.5 * 60);      // 141.5 minutes
+  profile.dualFoilLifeTime = Seconds (126.3 * 60);  // 126.3 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C15
+  loads.push_back (0.2227);
+  loads.push_back (0.2045);
+  loads.push_back (0.1083);
+  loads.push_back (0.0843);
+  loads.push_back (0.2227);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (50.0 * 60));
+  timeStamps.push_back (Seconds (100.0 * 60));
+  timeStamps.push_back (Seconds (150.0 * 60));
+  timeStamps.push_back (Seconds (200.0 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (211.4 * 60);      // 211.4 minutes
+  profile.dualFoilLifeTime = Seconds (209.2 * 60);  // 209.2 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C16
+  loads.push_back (0.0843);
+  loads.push_back (0.1083);
+  loads.push_back (0.2045);
+  loads.push_back (0.2227);
+  loads.push_back (0.2227);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (50.0 * 60));
+  timeStamps.push_back (Seconds (100.0 * 60));
+  timeStamps.push_back (Seconds (150.0 * 60));
+  timeStamps.push_back (Seconds (200.0 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (211.4 * 60);      // 211.4 minutes
+  profile.dualFoilLifeTime = Seconds (200.7 * 60);  // 200.7 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C17
+  loads.push_back (0.0843);
+  loads.push_back (0.1083);
+  loads.push_back (0.2045);
+  loads.push_back (0.0);
+  loads.push_back (0.2227);
+  loads.push_back (0.2227);
+
+  timeStamps.push_back (Seconds (0));
+  timeStamps.push_back (Seconds (50.0 * 60));
+  timeStamps.push_back (Seconds (100.0 * 60));
+  timeStamps.push_back (Seconds (150.0 * 60));
+  timeStamps.push_back (Seconds (200.0 * 60));
+  timeStamps.push_back (Seconds (250.0 * 60));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (261.4 * 60);      // 261.4 minutes
+  profile.dualFoilLifeTime = Seconds (251.2 * 60);  // 251.2 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C18
+  for (int i = 0; i < 10; i++)
+    {
+      loads.push_back (0.0843);
+      loads.push_back (0.1083);
+      loads.push_back (0.2045);
+      loads.push_back (0.2227);
+
+      timeStamps.push_back (Seconds ((0.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((5.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((10.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((15.0 + i * 20.0) * 60));
+    }
+
+  loads.push_back (0.2227);
+  timeStamps.push_back (Seconds (200.0));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (211.4 * 60);      // 211.4 minutes
+  profile.dualFoilLifeTime = Seconds (204.6 * 60);  // 204.6 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C19
+  for (int i = 0; i < 10; i++)
+    {
+      loads.push_back (0.0755);
+      loads.push_back (0.0949);
+      loads.push_back (0.2045);
+      loads.push_back (0.2227);
+
+      timeStamps.push_back (Seconds ((0.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((5.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((10.0 + i * 20.0) * 60));
+      timeStamps.push_back (Seconds ((15.0 + i * 20.0) * 60));
+    }
+
+  loads.push_back (0.2227);
+  timeStamps.push_back (Seconds (200.0));
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (216.4 * 60);      // 216.4 minutes
+  profile.dualFoilLifeTime = Seconds (208.7 * 60);  // 208.7 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C20
+  for (int i = 0; i < 50; i++)
+    {
+      loads.push_back (0.4947);
+      loads.push_back (0.628);
+
+      timeStamps.push_back (Seconds ((0.0 + i * 2.0) * 60));
+      timeStamps.push_back (Seconds ((1.0 + i * 2.0) * 60));
+    }
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (55.3 * 60);       // 55.3 minutes
+  profile.dualFoilLifeTime = Seconds (33.2 * 60);   // 33.2 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C21
+  for (int i = 0; i < 50; i++)
+    {
+      loads.push_back (0.4947);
+      loads.push_back (0.628);
+      loads.push_back (0.0576);
+
+      timeStamps.push_back (Seconds ((0.0 + i * 3.0) * 60));
+      timeStamps.push_back (Seconds ((1.0 + i * 3.0) * 60));
+      timeStamps.push_back (Seconds ((2.0 + i * 3.0) * 60));
+    }
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (79.6 * 60);       // 79.6 minutes
+  profile.dualFoilLifeTime = Seconds (55.9 * 60);   // 55.9 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+
+  // C22
+  for (int i = 0; i < 150; i++)
+    {
+      loads.push_back (0.005 + 0.005 * i);
+      timeStamps.push_back (Seconds ((0.0 + i * 1.0) * 60));
+    }
+
+  profile.loads = loads;
+  profile.timeStamps = timeStamps;
+  profile.itsyLifetime = Seconds (112.2 * 60);      // 112.2 minutes
+  profile.dualFoilLifeTime = Seconds (94.5 * 60);   // 94.5 minutes
+
+  m_loadProfiles.push_back (profile);
+
+  loads.clear ();
+  timeStamps.clear ();
+}
+
+bool
+BatteryLifetimeTest::DoRun (void)
+{
+  NS_LOG_UNCOND ("Constant load run.");
+  // 640mA
+  if (ConstantLoadTest (0.640, Seconds (2844.0)))
+    {
+      return true;
+    }
+  // 320mA
+  if (ConstantLoadTest (0.320, Seconds (6146.0)))
+    {
+      return true;
+    }
+  // 128mA
+  if (ConstantLoadTest (0.128, Seconds (16052.0)))
+    {
+      return true;
+    }
+  // 64mA
+  if (ConstantLoadTest (0.064, Seconds (32561.0)))
+    {
+      return true;
+    }
+  // 32mA
+  if (ConstantLoadTest (0.032, Seconds (65580.0)))
+    {
+      return true;
+    }
+
+  // create load profiles for variable load test
+  CreateLoadProfiles ();
+
+  // variable load with Itsy battery
+  NS_LOG_UNCOND ("\n\nItsy");
+  m_alpha = 35220;
+  m_beta = 0.637;
+  for (uint32_t i = 0; i < m_loadProfiles.size (); i++)
+    {
+      NS_LOG_UNCOND ("========");
+      NS_LOG_UNCOND ("Variable load profile C" << i + 1);
+      if (VariableLoadTest (m_loadProfiles[i].loads,
+                            m_loadProfiles[i].timeStamps,
+                            m_loadProfiles[i].itsyLifetime))
+        {
+          return false;
+        }
+    }
+
+  // variable load with DUALFOIL battery
+  NS_LOG_UNCOND ("\n\nDUALFOIL");
+  m_alpha = 40027;
+  m_beta = 0.276;
+  for (uint32_t i = 0; i < m_loadProfiles.size (); i++)
+    {
+      NS_LOG_UNCOND ("========");
+      NS_LOG_UNCOND ("Variable load profile C" << i + 1);
+      if (VariableLoadTest (m_loadProfiles[i].loads,
+                            m_loadProfiles[i].timeStamps,
+                            m_loadProfiles[i].dualFoilLifeTime))
+        {
+          return false;
+        }
+    }
+
+  return false; // error free
+}
+
+bool
+BatteryLifetimeTest::ConstantLoadTest (double load, Time expLifetime)
+{
+  // create single node
+  NodeContainer c;
+  c.Create (1);
+
+  std::string phyMode ("DsssRate1Mbps");
+
+  // disable fragmentation for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold",
+                      StringValue ("2200"));
+  // turn off RTS/CTS for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold",
+                      StringValue ("2200"));
+  // Fix non-unicast data rate to be the same as that of unicast
+  Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode",
+                      StringValue (phyMode));
+
+  // install YansWifiPhy
+  WifiHelper wifi;
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
+
+  YansWifiPhyHelper wifiPhy =  YansWifiPhyHelper::Default ();
+  /*
+   * This is one parameter that matters when using FixedRssLossModel, set it to
+   * zero; otherwise, gain will be added.
+   */
+  wifiPhy.Set ("RxGain", DoubleValue (0));
+  // ns-3 supports RadioTap and Prism tracing extensions for 802.11b
+  wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
+
+  YansWifiChannelHelper wifiChannel ;
+  wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
+  wifiPhy.SetChannel (wifiChannel.Create ());
+
+  // Add a non-QoS upper MAC, and disable rate control
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
+                                "DataMode", StringValue(phyMode),
+                                "ControlMode", StringValue(phyMode));
+  // Set it to ad-hoc mode
+  wifiMac.SetType ("ns3::AdhocWifiMac");
+  NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, c);
+
+  // Create and install battery model and device models
+  // RV battery model
+  RvBatteryModelHelper rvModelHelper;
+  // Set alpha & beta values
+  rvModelHelper.Set ("RvBatteryModelAlphaValue", DoubleValue (m_alpha));
+  rvModelHelper.Set ("RvBatteryModelBetaValue", DoubleValue (m_beta));
+  // install source
+  EnergySourceContainer sources = rvModelHelper.Install (c);
+  // device energy model
+  WifiRadioEnergyModelHelper radioEnergyHelper;
+  // set VariableLoadTestIDLE current, which will be the constant load
+  radioEnergyHelper.Set ("IdleCurrentA", DoubleValue (load));
+  // install on node
+  DeviceEnergyModelContainer deviceModels = radioEnergyHelper.Install (devices, sources);
+
+  // run simulation
+  Simulator::Stop (Seconds (70000.0));
+  Simulator::Run ();
+
+  Time actualLifetime;
+  Ptr<RvBatteryModel> srcPtr = DynamicCast<RvBatteryModel> (sources.Get (0));
+  actualLifetime = srcPtr->GetLifetime ();
+
+  NS_LOG_UNCOND ("Expected lifetime = " << expLifetime.GetSeconds () << "s");
+  NS_LOG_UNCOND ("Actual lifetime = " << actualLifetime.GetSeconds () << "s");
+
+  NS_TEST_ASSERT_MSG_EQ (actualLifetime, expLifetime, "Incorrect lifetime!");
+  /*
+  NS_TEST_ASSERT_MSG_EQ_TOL (actualLifetime.GetSeconds () / 60,
+                             expLifetime.GetSeconds () / 60, 0.1,
+                             "Incorrect lifetime!");
+   */
+
+  Simulator::Destroy ();
+
+  return false; // error free
+}
+
+bool
+BatteryLifetimeTest::VariableLoadTest (std::vector<double> loads,
+                                       std::vector<Time> timeStamps,
+                                       Time expLifetime)
+{
+  NS_ASSERT (loads.size () == timeStamps.size ());
+
+  // create single node
+    NodeContainer c;
+    c.Create (1);
+
+    std::string phyMode ("DsssRate1Mbps");
+
+    // disable fragmentation for frames below 2200 bytes
+    Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold",
+                        StringValue ("2200"));
+    // turn off RTS/CTS for frames below 2200 bytes
+    Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold",
+                        StringValue ("2200"));
+    // Fix non-unicast data rate to be the same as that of unicast
+    Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode",
+                        StringValue (phyMode));
+
+    // install YansWifiPhy
+    WifiHelper wifi;
+    wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
+
+    YansWifiPhyHelper wifiPhy =  YansWifiPhyHelper::Default ();
+    /*
+     * This is one parameter that matters when using FixedRssLossModel, set it to
+     * zero; otherwise, gain will be added.
+     */
+    wifiPhy.Set ("RxGain", DoubleValue (0));
+    // ns-3 supports RadioTap and Prism tracing extensions for 802.11b
+    wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
+
+    YansWifiChannelHelper wifiChannel ;
+    wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
+    wifiPhy.SetChannel (wifiChannel.Create ());
+
+    // Add a non-QoS upper MAC, and disable rate control
+    NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+    wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
+                                  "DataMode", StringValue(phyMode),
+                                  "ControlMode", StringValue(phyMode));
+    // Set it to ad-hoc mode
+    wifiMac.SetType ("ns3::AdhocWifiMac");
+    NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, c);
+
+    // Create and install battery model and device models
+    // RV battery model
+    RvBatteryModelHelper rvModelHelper;
+    // Set alpha & beta values
+    rvModelHelper.Set ("RvBatteryModelAlphaValue", DoubleValue (m_alpha));
+    rvModelHelper.Set ("RvBatteryModelBetaValue", DoubleValue (m_beta));
+    // install source
+    EnergySourceContainer sources = rvModelHelper.Install (c);
+    // device energy model
+    WifiRadioEnergyModelHelper radioEnergyHelper;
+    // set VariableLoadTestIDLE current, which will be the constant load
+    radioEnergyHelper.Set ("IdleCurrentA", DoubleValue (loads[0]));
+    // install on node
+    DeviceEnergyModelContainer deviceModels = radioEnergyHelper.Install (devices, sources);
+
+
+    Ptr<WifiRadioEnergyModel> wifiDevicePtr = DynamicCast<WifiRadioEnergyModel> (deviceModels.Get (0));
+    // schedule load change events
+    for (uint32_t i = 1; i < loads.size (); i++)
+      {
+        Simulator::Schedule (timeStamps[i], &WifiRadioEnergyModel::SetIdleCurrentA,
+                             wifiDevicePtr, loads[i]);
+      }
+
+    // run simulation
+    Simulator::Stop (Seconds (70000.0));
+    Simulator::Run ();
+
+    Time actualLifetime;
+    Ptr<RvBatteryModel> srcPtr = DynamicCast<RvBatteryModel> (sources.Get (0));
+    actualLifetime = srcPtr->GetLifetime ();
+
+    NS_LOG_UNCOND ("Expected lifetime = " << expLifetime.GetSeconds () << "s");
+    NS_LOG_UNCOND ("Actual lifetime = " << actualLifetime.GetSeconds () << "s");
+    NS_LOG_UNCOND ("Difference = " << expLifetime.GetSeconds () - actualLifetime.GetSeconds () << "s");
+
+    //NS_TEST_ASSERT_MSG_EQ (actualLifetime, expLifetime, "Incorrect lifetime!");
+    NS_TEST_ASSERT_MSG_EQ_TOL (actualLifetime.GetSeconds (), expLifetime.GetSeconds (),
+                               120, // error tolerance = 120s
+                               "Incorrect lifetime!");
+
+    Simulator::Destroy ();
+
+    return false; // error free
+}
+
+// -------------------------------------------------------------------------- //
+
+/**
+ * Unit test suite for energy model. Although the test suite involves 2 modules
+ * it is still considered a unit test. Because a DeviceEnergyModel cannot live
+ * without an EnergySource.
+ */
+class RvBatteryModelTestSuite : public TestSuite
+{
+public:
+  RvBatteryModelTestSuite ();
+};
+
+RvBatteryModelTestSuite::RvBatteryModelTestSuite ()
+  : TestSuite ("rv-battery-model", SYSTEM)
+{
+  AddTestCase (new BatteryLifetimeTest);
+}
+
+// create an instance of the test suite
+RvBatteryModelTestSuite g_rvBatteryModelTestSuite;
--- a/src/contrib/energy/wscript	Mon Dec 20 15:19:11 2010 -0800
+++ b/src/contrib/energy/wscript	Mon Dec 20 15:49:12 2010 -0800
@@ -6,13 +6,16 @@
         'model/wifi-radio-energy-model.cc',
         'model/energy-source.cc',
         'model/basic-energy-source.cc',
+        'model/rv-battery-model.cc',
         'model/device-energy-model.cc',
         'model/device-energy-model-container.cc',
         'helper/energy-source-container.cc',
         'helper/energy-model-helper.cc',
         'helper/basic-energy-source-helper.cc',
         'helper/wifi-radio-energy-model-helper.cc',
+        'helper/rv-battery-model-helper.cc',
         'test/basic-energy-model-test.cc',
+        'test/rv-battery-model-test.cc',
         ]
     headers = bld.new_task_gen('ns3header')
     headers.module = 'energy'
@@ -20,10 +23,12 @@
         'model/wifi-radio-energy-model.h',
         'model/energy-source.h',
         'model/basic-energy-source.h',
+        'model/rv-battery-model.h',
         'model/device-energy-model.h',
         'model/device-energy-model-container.h',
         'helper/energy-source-container.h',
         'helper/energy-model-helper.h',
         'helper/basic-energy-source-helper.h',
         'helper/wifi-radio-energy-model-helper.h',
+        'helper/rv-battery-model-helper.h',
         ]
--- a/test.py	Mon Dec 20 15:19:11 2010 -0800
+++ b/test.py	Mon Dec 20 15:49:12 2010 -0800
@@ -102,6 +102,8 @@
     ("examples/emulation/emu-ping", "False", "True"),
     ("examples/emulation/emu-udp-echo", "False", "True"),
 
+    ("examples/energy/energy-model-example", "True", "True"),
+
     ("examples/error-model/simple-error-model", "True", "True"),
 
     ("examples/ipv6/icmpv6-redirect", "True", "True"),