From c2d69b4d03fcdeedad737e12f981ef1f0c94ed37 Mon Sep 17 00:00:00 2001
From: Tim Schubert <tim.schubert@tu-bs.de>
Date: Thu, 16 Jul 2020 22:37:18 +0200
Subject: [PATCH] Add sat and gnd node helpers

---
 data/empty                               |   0
 helper/ground-node-helper.cc             |  55 +++++++++++++
 helper/ground-node-helper.h              |  48 +++++++++++
 helper/satellite-node-helper.cc          |  55 +++++++++++++
 helper/satellite-node-helper.h           |  51 ++++++++++++
 model/satellite-node.h                   |   6 ++
 test/ground-node-helper-test-suite.cc    |  96 ++++++++++++++++++++++
 test/leo-test-suite.cc                   |  21 +++--
 test/satellite-node-helper-test-suite.cc | 100 +++++++++++++++++++++++
 utils/leo-input-fstream-container.cc     |   4 +-
 wscript                                  |  26 +++---
 11 files changed, 442 insertions(+), 20 deletions(-)
 delete mode 100644 data/empty
 create mode 100644 helper/ground-node-helper.cc
 create mode 100644 helper/ground-node-helper.h
 create mode 100644 helper/satellite-node-helper.cc
 create mode 100644 helper/satellite-node-helper.h
 create mode 100644 model/satellite-node.h
 create mode 100644 test/ground-node-helper-test-suite.cc
 create mode 100644 test/satellite-node-helper-test-suite.cc

diff --git a/data/empty b/data/empty
deleted file mode 100644
index e69de29..0000000
diff --git a/helper/ground-node-helper.cc b/helper/ground-node-helper.cc
new file mode 100644
index 0000000..4e80030
--- /dev/null
+++ b/helper/ground-node-helper.cc
@@ -0,0 +1,55 @@
+#include <fstream>
+
+#include "ns3/log.h"
+#include "ns3/config.h"
+#include "ns3/waypoint.h"
+
+#include "ground-node-helper.h"
+
+using namespace std;
+
+namespace ns3
+{
+NS_LOG_COMPONENT_DEFINE ("LeoGndNodeHelper");
+
+LeoGndNodeHelper::LeoGndNodeHelper ()
+{
+  m_gndNodeFactory.SetTypeId ("ns3::Node");
+}
+
+LeoGndNodeHelper::~LeoGndNodeHelper ()
+{
+}
+
+void
+LeoGndNodeHelper::SetAttribute (string name, const AttributeValue &value)
+{
+  m_gndNodeFactory.Set (name, value);
+}
+
+NodeContainer
+LeoGndNodeHelper::Install (const std::string &wpFile)
+{
+  NS_LOG_FUNCTION (wpFile);
+
+  NodeContainer nodes;
+  ifstream waypoints;
+  waypoints.open (wpFile, ifstream::in);
+  Vector pos;
+  while ((waypoints >> pos))
+    {
+      Ptr<ConstantPositionMobilityModel> mob = CreateObject<ConstantPositionMobilityModel> ();
+      mob->SetPosition (pos);
+      Ptr<Node> node = m_gndNodeFactory.Create<Node> ();
+      node->AggregateObject (mob);
+      nodes.Add (node);
+      NS_LOG_INFO ("Added ground node at " << pos);
+    }
+  waypoints.close ();
+
+  NS_LOG_INFO ("Added " << nodes.GetN () << " ground nodes");
+
+  return nodes;
+}
+
+}; // namespace ns3
diff --git a/helper/ground-node-helper.h b/helper/ground-node-helper.h
new file mode 100644
index 0000000..922fdca
--- /dev/null
+++ b/helper/ground-node-helper.h
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#ifndef LEO_GND_NODE_HELPER_H
+#define LEO_GND_NODE_HELPER_H
+
+#include <string>
+
+#include "ns3/object-factory.h"
+#include "ns3/node-container.h"
+#include "ns3/constant-position-mobility-model.h"
+
+/**
+ * \brief Builds a node container of nodes with constant positions
+ *
+ * Adds waypoints from file for each node.
+ */
+
+namespace ns3
+{
+
+class LeoGndNodeHelper
+{
+public:
+  LeoGndNodeHelper ();
+  virtual ~LeoGndNodeHelper ();
+
+  /**
+   *
+   * \param wpFile path to waypoint file
+   * \returns a node container containing nodes using the specified attributes
+   */
+  NodeContainer Install (const std::string &wpFile);
+
+  /**
+   * Set an attribute for each node
+   *
+   * \param name name of the attribute
+   * \param value value of the attribute
+   */
+  void SetAttribute (std::string name, const AttributeValue &value);
+
+private:
+  ObjectFactory m_gndNodeFactory;
+};
+
+}; // namespace ns3
+
+#endif
diff --git a/helper/satellite-node-helper.cc b/helper/satellite-node-helper.cc
new file mode 100644
index 0000000..16a6f96
--- /dev/null
+++ b/helper/satellite-node-helper.cc
@@ -0,0 +1,55 @@
+#include "ns3/log.h"
+#include "ns3/config.h"
+#include "ns3/waypoint-mobility-model.h"
+
+#include "satellite-node-helper.h"
+
+using namespace std;
+
+namespace ns3
+{
+NS_LOG_COMPONENT_DEFINE ("LeoSatNodeHelper");
+
+LeoSatNodeHelper::LeoSatNodeHelper ()
+{
+  m_satNodeFactory.SetTypeId ("ns3::Node");
+}
+
+LeoSatNodeHelper::~LeoSatNodeHelper ()
+{
+}
+
+void
+LeoSatNodeHelper::SetAttribute (string name, const AttributeValue &value)
+{
+  m_satNodeFactory.Set (name, value);
+}
+
+NodeContainer
+LeoSatNodeHelper::Install (vector<string> &wpFiles)
+{
+  NS_LOG_FUNCTION (wpFiles);
+
+  NodeContainer nodes;
+  for (size_t i = 0; i < wpFiles.size (); i ++)
+    {
+      Ptr<WaypointMobilityModel> mob = CreateObject<WaypointMobilityModel> ();
+      string fileName = wpFiles[i];
+      m_fileStreamContainer.SetFile (fileName);
+      Waypoint wp;
+      while (m_fileStreamContainer.GetNextSample (wp))
+      	{
+      	  mob->AddWaypoint (wp);
+          NS_LOG_DEBUG ("Added waypoint " << wp);
+      	}
+      Ptr<Node> node = m_satNodeFactory.Create<Node> ();
+      node->AggregateObject (mob);
+
+      nodes.Add (node);
+      NS_LOG_INFO ("Added satellite node " << node->GetId ());
+    }
+
+  return nodes;
+}
+
+}; // namespace ns3
diff --git a/helper/satellite-node-helper.h b/helper/satellite-node-helper.h
new file mode 100644
index 0000000..b2581e1
--- /dev/null
+++ b/helper/satellite-node-helper.h
@@ -0,0 +1,51 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#ifndef SAT_NODE_HELPER_H
+#define SAT_NODE_HELPER_H
+
+#include <string>
+
+#include "ns3/object-factory.h"
+#include "ns3/node-container.h"
+
+#include "ns3/leo-input-fstream-container.h"
+
+/**
+ * \brief Builds a node container with a waypoint mobility model
+ *
+ * Adds waypoints from file for each node.
+ * The node satId must must correspond to the NORAD id from Celestrack.
+ */
+
+namespace ns3
+{
+
+class LeoSatNodeHelper
+{
+public:
+  LeoSatNodeHelper ();
+  virtual ~LeoSatNodeHelper ();
+
+  /**
+   *
+   * \param nodeIds paths to satellite to waypoint files
+   * \returns a node container containing nodes using the specified attributes
+   */
+  NodeContainer Install (std::vector<std::string> &wpFiles);
+
+  /**
+   * Set an attribute for each node
+   *
+   * \param name name of the attribute
+   * \param value value of the attribute
+   */
+  void SetAttribute (std::string name, const AttributeValue &value);
+
+private:
+  ObjectFactory m_satNodeFactory;
+  LeoWaypointInputFileStreamContainer m_fileStreamContainer;
+};
+
+}; // namespace ns3
+
+#endif
diff --git a/model/satellite-node.h b/model/satellite-node.h
new file mode 100644
index 0000000..7f645d7
--- /dev/null
+++ b/model/satellite-node.h
@@ -0,0 +1,6 @@
+
+    .AddAttribute ("MobilityModel", "The mobility model of the device",
+                   PointerValue (),
+                   MakePointerAccessor (&MockNetDevice::SetMobilityModel,
+                     &MockNetDevice::GetMobilityModel),
+                   MakePointerChecker<MobilityModel> ())
diff --git a/test/ground-node-helper-test-suite.cc b/test/ground-node-helper-test-suite.cc
new file mode 100644
index 0000000..bf9e4f2
--- /dev/null
+++ b/test/ground-node-helper-test-suite.cc
@@ -0,0 +1,96 @@
+
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/node-container.h"
+#include "ns3/core-module.h"
+
+#include "ns3/leo-module.h"
+#include "ns3/test.h"
+
+using namespace ns3;
+
+class EmptyGndNodeHelperTestCase : public TestCase
+{
+public:
+  EmptyGndNodeHelperTestCase ();
+  virtual ~EmptyGndNodeHelperTestCase ();
+
+private:
+  virtual void DoRun (void);
+};
+
+EmptyGndNodeHelperTestCase::EmptyGndNodeHelperTestCase ()
+  : TestCase ("Empty list of positions")
+{
+}
+
+EmptyGndNodeHelperTestCase::~EmptyGndNodeHelperTestCase ()
+{
+  Simulator::Destroy ();
+}
+
+void
+EmptyGndNodeHelperTestCase::DoRun (void)
+{
+  std::vector<std::string> gndWps = {};
+
+  LeoGndNodeHelper gndHelper;
+  NodeContainer nodes = gndHelper.Install ("contrib/leo/data/test/empty");
+
+  NS_ASSERT_MSG (nodes.GetN () == 0, "Empty position file produces non-empty node container");
+}
+
+// ------------------------------------------------------------------------- //
+
+class SomeGndNodeHelperTestCase : public TestCase
+{
+public:
+  SomeGndNodeHelperTestCase ();
+  virtual ~SomeGndNodeHelperTestCase ();
+
+private:
+  virtual void DoRun (void);
+};
+
+SomeGndNodeHelperTestCase::SomeGndNodeHelperTestCase ()
+  : TestCase ("Some ground stations")
+{
+}
+
+SomeGndNodeHelperTestCase::~SomeGndNodeHelperTestCase ()
+{
+  Simulator::Destroy ();
+}
+
+void
+SomeGndNodeHelperTestCase::DoRun (void)
+{
+  LeoGndNodeHelper gndHelper;
+  NodeContainer nodes = gndHelper.Install ("contrib/leo/data/test/ground-stations.txt");
+
+  NS_ASSERT_MSG (nodes.GetN () > 1, "No ground stations");
+
+  Ptr<MobilityModel> mob = nodes.Get (0)->GetObject<MobilityModel> ();
+  NS_ASSERT_MSG (mob != Ptr<MobilityModel> (), "Mobility model is valid");
+}
+
+class GndNodeHelperTestSuite : public TestSuite
+{
+public:
+  GndNodeHelperTestSuite ();
+};
+
+GndNodeHelperTestSuite::GndNodeHelperTestSuite ()
+  : TestSuite ("gnd-node-helper", UNIT)
+{
+  // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
+  AddTestCase (new EmptyGndNodeHelperTestCase, TestCase::QUICK);
+  AddTestCase (new SomeGndNodeHelperTestCase, TestCase::QUICK);
+}
+
+// Do not forget to allocate an instance of this TestSuite
+static GndNodeHelperTestSuite gndNodeHelperTestSuite;
diff --git a/test/leo-test-suite.cc b/test/leo-test-suite.cc
index d78179c..792ca32 100644
--- a/test/leo-test-suite.cc
+++ b/test/leo-test-suite.cc
@@ -8,7 +8,6 @@
 #include "ns3/core-module.h"
 
 #include "ns3/leo-module.h"
-
 #include "ns3/test.h"
 
 using namespace ns3;
@@ -38,17 +37,23 @@ LeoTestCase1::DoRun (void)
 {
   Time::SetResolution (Time::NS);
 
-  NodeContainer satellites;
-  satellites.Create (100);
-  NodeContainer gateways;
-  gateways.Create (10);
-  NodeContainer terminals;
-  terminals.Create (20);
+  std::vector<std::string> satWps =
+    {
+      "../contrib/leo/data/starlink/45212.waypoints",
+      "../contrib/leo/data/starlink/45213.waypoints",
+      "../contrib/leo/data/starlink/45214.waypoints",
+      "../contrib/leo/data/starlink/45215.waypoints",
+    };
+
+  LeoSatNodeHelper satHelper;
+  NodeContainer satellites = satHelper.Install (satWps);
+  LeoGndNodeHelper gndHelper;
+  NodeContainer gateways = gndHelper.Install ("../contrib/leo/data/gateways");
+  NodeContainer terminals = gndHelper.Install ("../contrib/leo/data/terminals");
 
   LeoHelper leo;
   leo.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
   leo.SetChannelAttribute ("PropagationDelay", StringValue ("ns3::ConstantSpeedPropagationDelayModel"));
-  leo.SetDeviceAttribute ("MobilityModel", StringValue ("ns3::WaypointMobilityModel"));
 
   NetDeviceContainer allDevices = leo.Install (satellites, gateways, terminals);
 
diff --git a/test/satellite-node-helper-test-suite.cc b/test/satellite-node-helper-test-suite.cc
new file mode 100644
index 0000000..506da25
--- /dev/null
+++ b/test/satellite-node-helper-test-suite.cc
@@ -0,0 +1,100 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/node-container.h"
+#include "ns3/core-module.h"
+
+#include "ns3/leo-module.h"
+#include "ns3/test.h"
+
+using namespace ns3;
+
+class EmptySatNodeHelperTestCase : public TestCase
+{
+public:
+  EmptySatNodeHelperTestCase ();
+  virtual ~EmptySatNodeHelperTestCase ();
+
+private:
+  virtual void DoRun (void);
+};
+
+EmptySatNodeHelperTestCase::EmptySatNodeHelperTestCase ()
+  : TestCase ("Empty list of waypoint files")
+{
+}
+
+EmptySatNodeHelperTestCase::~EmptySatNodeHelperTestCase ()
+{
+  Simulator::Destroy ();
+}
+
+void
+EmptySatNodeHelperTestCase::DoRun (void)
+{
+  std::vector<std::string> satWps = {};
+
+  LeoSatNodeHelper satHelper;
+  NodeContainer satellites = satHelper.Install (satWps);
+
+  NS_ASSERT_MSG (satellites.GetN () == 0, "Empty list of waypoint files produces non-empty node container");
+}
+
+// ------------------------------------------------------------------------- //
+
+class SingleSatNodeHelperTestCase : public TestCase
+{
+public:
+  SingleSatNodeHelperTestCase ();
+  virtual ~SingleSatNodeHelperTestCase ();
+
+private:
+  virtual void DoRun (void);
+};
+
+SingleSatNodeHelperTestCase::SingleSatNodeHelperTestCase ()
+  : TestCase ("Single waypoint file")
+{
+}
+
+SingleSatNodeHelperTestCase::~SingleSatNodeHelperTestCase ()
+{
+  Simulator::Destroy ();
+}
+
+void
+SingleSatNodeHelperTestCase::DoRun (void)
+{
+  std::vector<std::string> satWps =
+    {
+      "contrib/leo/data/test/waypoints.txt"
+    };
+
+  LeoSatNodeHelper satHelper;
+  NodeContainer satellites = satHelper.Install (satWps);
+
+  NS_ASSERT_MSG (satellites.GetN () == 1, "No satellite nodes");
+
+  Ptr<MobilityModel> mob = satellites.Get (0)->GetObject<MobilityModel> ();
+  NS_ASSERT_MSG (mob != Ptr<MobilityModel> (), "Mobility model is valid");
+}
+
+class SatNodeHelperTestSuite : public TestSuite
+{
+public:
+  SatNodeHelperTestSuite ();
+};
+
+SatNodeHelperTestSuite::SatNodeHelperTestSuite ()
+  : TestSuite ("sat-node-helper", UNIT)
+{
+  // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
+  AddTestCase (new EmptySatNodeHelperTestCase, TestCase::QUICK);
+  AddTestCase (new SingleSatNodeHelperTestCase, TestCase::QUICK);
+}
+
+// Do not forget to allocate an instance of this TestSuite
+static SatNodeHelperTestSuite satNodeHelperTestSuite;
diff --git a/utils/leo-input-fstream-container.cc b/utils/leo-input-fstream-container.cc
index 616147c..d92b12c 100644
--- a/utils/leo-input-fstream-container.cc
+++ b/utils/leo-input-fstream-container.cc
@@ -30,7 +30,7 @@ LeoWaypointInputFileStreamContainer::GetTypeId (void)
 
 LeoWaypointInputFileStreamContainer::LeoWaypointInputFileStreamContainer () :
   m_filePath (),
-  m_input ()
+  m_lastTime (0)
 {
 }
 
@@ -66,7 +66,7 @@ LeoWaypointInputFileStreamContainer::GetNextSample (Waypoint &sample)
   sample.time = Time (0);
   sample.position = Vector (0.0, 0.0, 0.0);
   bool updated = false;
-  while (sample.time < m_lastTime && (m_input >> sample))
+  while (sample.time <= m_lastTime && (m_input >> sample))
     {
       updated = true;
     }
diff --git a/wscript b/wscript
index d605332..90d06c4 100644
--- a/wscript
+++ b/wscript
@@ -9,18 +9,20 @@
 def build(bld):
     module = bld.create_ns3_module('leo', ['core','internet', 'propagation', 'stats', 'traffic', 'flow-monitor', 'applications'])
     module.source = [
-        'model/isl-mock-channel.cc',
-        'model/isl-propagation-loss-model.cc',
         'helper/isl-helper.cc',
-        'model/leo.cc',
         'helper/leo-channel-helper.cc',
+        'helper/leo-helper.cc',
+        'helper/nd-cache-helper.cc',
+        'helper/ground-node-helper.cc',
+        'helper/satellite-node-helper.cc',
+        'model/leo.cc',
         'model/leo-mock-channel.cc',
         'model/leo-mock-net-device.cc',
-        'helper/leo-helper.cc',
         'model/leo-propagation-loss-model.cc',
         'model/mock-net-device.cc',
         'model/mock-channel.cc',
-        'helper/nd-cache-helper.cc',
+        'model/isl-mock-channel.cc',
+        'model/isl-propagation-loss-model.cc',
         'utils/leo-input-fstream-container.cc',
         ]
 
@@ -32,23 +34,27 @@ def build(bld):
         'test/leo-mock-channel-test-suite.cc',
         'test/leo-input-fstream-container-test-suite.cc',
         'test/leo-mobility-test-suite.cc',
+        'test/satellite-node-helper-test-suite.cc',
+        'test/ground-node-helper-test-suite.cc',
         ]
 
     headers = bld(features='ns3header')
     headers.module = 'leo'
     headers.source = [
-        'model/isl-mock-channel.h',
-        'model/isl-propagation-loss-model.h',
         'helper/isl-helper.h',
-        'model/leo.h',
         'helper/leo-channel-helper.h',
+        'helper/leo-helper.h',
+        'helper/nd-cache-helper.h',
+        'helper/ground-node-helper.h',
+        'helper/satellite-node-helper.h',
+        'model/leo.h',
         'model/leo-mock-channel.h',
         'model/leo-mock-net-device.h',
-        'helper/leo-helper.h',
         'model/leo-propagation-loss-model.h',
         'model/mock-net-device.h',
         'model/mock-channel.h',
-        'helper/nd-cache-helper.h',
+        'model/isl-mock-channel.h',
+        'model/isl-propagation-loss-model.h',
         'utils/leo-input-fstream-container.h',
         ]