Skip to content

Instantly share code, notes, and snippets.

@emanuelegiona
Last active October 9, 2023 14:25
Show Gist options
  • Save emanuelegiona/81f3c8982e169916fcc3c3a6912b5a9c to your computer and use it in GitHub Desktop.
Save emanuelegiona/81f3c8982e169916fcc3c3a6912b5a9c to your computer and use it in GitHub Desktop.
Minimum Reproducible Example for "NetCDF: HDF error" in WOSS, as ns-3 simulation script
#include "ns3/core-module.h"
#include "ns3/uan-module.h"
#include "ns3/mobility-module.h"
#include "ns3/log.h"
#include "ns3/network-module.h"
// --- Just to allow intellisense reading definitions ---
#ifndef NS3_WOSS_SUPPORT
#define NS3_WOSS_SUPPORT
#endif
#ifndef WOSS_MULTITHREAD
#define WOSS_MULTITHREAD
#endif
// --- ----- ----- ---
#include "ns3/woss-helper.h"
#include "ns3/woss-channel.h"
#include "ns3/woss-prop-model.h"
namespace ns3 {
class PingHeader: public Header
{
public:
PingHeader();
virtual ~PingHeader();
static TypeId GetTypeId(void);
uint16_t GetPingId(void) const;
void SetPingId(uint16_t id);
// Inherited from Header
virtual uint32_t GetSerializedSize(void) const;
virtual void Serialize(Buffer::Iterator start) const;
virtual uint32_t Deserialize(Buffer::Iterator start);
virtual void Print(std::ostream &os) const;
virtual TypeId GetInstanceTypeId(void) const;
private:
uint16_t m_pingId;
};
class PongHeader: public Header
{
public:
PongHeader();
virtual ~PongHeader();
static TypeId GetTypeId(void);
uint16_t GetPingId(void) const;
uint32_t GetNodeId(void) const;
void SetPingId(uint16_t id);
void SetNodeId(uint32_t id);
// Inherited from Header
virtual uint32_t GetSerializedSize(void) const;
virtual void Serialize(Buffer::Iterator start) const;
virtual uint32_t Deserialize(Buffer::Iterator start);
virtual void Print(std::ostream &os) const;
virtual TypeId GetInstanceTypeId(void) const;
private:
uint16_t m_pingId;
uint32_t m_nodeId;
};
}; // namespace ns3
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("NetCDF_Error_MRE");
/** \brief Utility class for experiment setup. */
class Experiment
{
public:
// --- Reproducibility ---
uint64_t m_rngStream;
// --- Simulation params ---
double m_trafficCbr;
double m_deadline;
int m_fixWaypoint;
// --- WOSS params ---
bool m_wossDebug;
int m_wossRays;
int m_wossRuns;
std::string m_wossDbsPath;
bool m_wossHighMobility;
// --- Modulation params ---
uint32_t m_rateBps;
uint32_t m_freqHz;
uint32_t m_bandHz;
std::string m_modulationName;
// --- PHY params ---
double m_txPowerDb;
// --- ----- ----- ---
Experiment();
~Experiment();
void InitialSetup(void);
// Network setup
void CreateTopology(void);
void FinalizeSetup(void);
// Simulation setup
void StartApplication(Time start = Seconds(0));
void StopApplication(Time stop = Seconds(0));
private:
Ptr<WossHelper> m_wossHelper;
Ptr<UanPropModel> m_prop;
Ptr<UanNoiseModel> m_noise;
Ptr<Channel> m_channel;
NodeContainer m_roamingNode;
NodeContainer m_staticNodes;
NetDeviceContainer m_roamingDev;
NetDeviceContainer m_staticDevs;
std::map<uint32_t, uint16_t> m_phyNumber;
std::vector<Ptr<Socket>> m_roamingSock;
std::vector<Ptr<Socket>> m_staticSocks;
uint32_t m_sockId;
EventId m_genPing;
EventId m_pingDeadline;
Vector GetWossPosition(const Vector &pos);
Vector GetOriginalPosition(const Vector &wossPos);
// --- Roaming node ---
uint16_t m_pingId;
Time m_lastWpArrival;
void SendPing(void);
void PingDeadline(void);
void ReceivePong(Ptr<Socket> socket);
void WaypointCallback(Ptr<const MobilityModel> model);
// --- Static nodes ---
void ReceivePing(Ptr<Socket> socket);
void ReplyToPing(Ptr<Socket> socket, uint16_t pingId);
};
int
main(int argc, char *argv[])
{
Experiment exp;
uint32_t verboseLvl = 0;
uint32_t seed = 1;
uint32_t run = 0;
CommandLine cmd(__FILE__);
cmd.AddValue("verbose", "Verbosity level (0: Performance results only, 1: APP (logic), 2: APP (debug), 3: Socket+, 4: MAC+, 5: PHY+, 6: Channel+, 7: WOSS+)", verboseLvl);
cmd.AddValue("seed", "RNG seed value for reproducibility purposes", seed);
cmd.AddValue("run", "RNG independent run value for reproducibility purposes", run);
// --- Simulation params ---
cmd.AddValue("traffic", "Constant bitrate traffic for ping packet generation as interval between two consecutive pings, in seconds", exp.m_trafficCbr);
cmd.AddValue("deadline", "Ping deadline, in seconds", exp.m_deadline);
cmd.AddValue("fixWaypoint", "Waypoint number to override roaming node's trajectory and keep its position fixed (if -1, no overriding is performed)", exp.m_fixWaypoint);
// --- WOSS params ---
cmd.AddValue("wossRays", "Number of rays to use during Bellhop execution through WOSS (0 = auto)", exp.m_wossRays);
cmd.AddValue("wossRuns", "Number of WOSS runs to perform", exp.m_wossRuns);
cmd.AddValue("wossDbsPath", "Path to the main directory for WOSS databases", exp.m_wossDbsPath);
cmd.AddValue("wossHighMobility", "Flag indicating whether to setup WOSS for 'high-mobility' scenarios or not", exp.m_wossHighMobility);
// --- Modulation params ---
cmd.AddValue("datarate", "Modulation datarate in bits per second (bps)", exp.m_rateBps);
cmd.AddValue("frequency", "Modulation center frequency in Hertz (Hz)", exp.m_freqHz);
cmd.AddValue("bandwidth", "Modulation bandwidth in Hertz (Hz)", exp.m_bandHz);
cmd.AddValue("modeName", "Modulation name", exp.m_modulationName);
// --- PHY params ---
cmd.AddValue("txPower", "PHY transmission power in decibel (dB)", exp.m_txPowerDb);
cmd.Parse(argc, argv);
std::cout << "=== SIMULATION START ===\n";
std::cout << "Parameters:";
std::cout << "\n\t- seed: " << seed;
std::cout << "\n\t- run: " << run;
std::cout << "\n\t- ping traffic CBR (s): " << exp.m_trafficCbr;
std::cout << "\n\t- ping deadline (s): " << exp.m_deadline;
std::cout << "\n\t- Roaming node fix waypoint: " << exp.m_fixWaypoint << " (" << (exp.m_fixWaypoint == -1 ? "OFF" : "ON") << ")";
std::cout << "\n\t- WOSS rays: " << exp.m_wossRays << (exp.m_wossRays == 0 ? " (auto)" : "");
std::cout << "\n\t- WOSS runs: " << exp.m_wossRuns;
std::cout << "\n\t- WOSS databases path: " << exp.m_wossDbsPath;
std::cout << "\n\t- WOSS high-mobility setup: " << (exp.m_wossHighMobility ? "ON" : "OFF");
std::cout << "\n\t- PHY datarate (bps): " << exp.m_rateBps;
std::cout << "\n\t- PHY center frequency (Hz): " << exp.m_freqHz;
std::cout << "\n\t- PHY bandwidth (Hz): " << exp.m_bandHz;
std::cout << "\n\t- PHY transmission power (dB): " << exp.m_txPowerDb;
std::cout << "\n=== ===== ===== ===" << std::endl;
switch(verboseLvl)
{
case 7:
{
exp.m_wossDebug = true;
}
case 6:
{
LogComponentEnable("UanChannel", LOG_LEVEL_ALL);
}
case 5:
{
LogComponentEnable("UanPhyGen", LOG_LEVEL_ALL);
}
case 4:
{
LogComponentEnable("UanMacAloha", LOG_LEVEL_ALL);
}
case 3:
{
LogComponentEnable("Socket", LOG_LEVEL_ALL);
}
case 2:
{
LogComponentEnable("NetCDF_Error_MRE", LOG_LEVEL_ALL);
break;
}
case 1:
{
LogComponentEnable("NetCDF_Error_MRE", LOG_LEVEL_DEBUG);
break;
}
case 0:
default:
{
break;
}
}
// Reproducibility
RngSeedManager::SetSeed(seed);
RngSeedManager::SetRun(run);
exp.m_rngStream = RngSeedManager::GetNextStreamIndex();
// Setup experiment
exp.InitialSetup();
exp.CreateTopology();
exp.FinalizeSetup();
// Run simulation
Simulator::ScheduleNow(&Experiment::StartApplication, &exp, Seconds(0));
Simulator::Run();
std::cout << "=== SIMULATION END ===\n";
std::cout << "=== ===== ===== ===" << std::endl;
Simulator::Destroy();
return 0;
}
Experiment::Experiment()
: // Reproducibility
m_rngStream(0),
// Simulation params
m_trafficCbr(2),
m_deadline(1),
m_fixWaypoint(-1),
// WOSS params
m_wossDebug(false),
m_wossRays(0),
m_wossRuns(1),
m_wossDbsPath(""),
m_wossHighMobility(false),
// Modulation params
m_rateBps(500),
m_freqHz(17000),
m_bandHz(5000),
m_modulationName("QPSK"),
// PHY params
m_txPowerDb(190),
// Internal variables
m_wossHelper(0),
m_prop(0),
m_noise(0),
m_channel(0),
m_phyNumber(),
m_roamingSock(),
m_staticSocks(),
m_sockId(0),
// Roaming node
m_pingId(0),
m_lastWpArrival(Seconds(0))
{
}
Experiment::~Experiment()
{
if(m_channel)
{
m_channel = 0;
}
if(m_wossHelper)
{
m_wossHelper = 0;
}
if(m_prop)
{
m_prop = 0;
}
if(m_noise)
{
m_noise = 0;
}
m_phyNumber.clear();
for(auto sockIt = m_roamingSock.begin(); sockIt != m_roamingSock.end(); sockIt++)
{
auto sock = *sockIt;
if(sock)
{
sock->Dispose();
}
}
m_roamingSock.clear();
for(auto sockIt = m_staticSocks.begin(); sockIt != m_staticSocks.end(); sockIt++)
{
auto sock = *sockIt;
if(sock)
{
sock->Dispose();
}
}
m_staticSocks.clear();
m_genPing.Cancel();
m_pingDeadline.Cancel();
}
void
Experiment::InitialSetup(void)
{
m_noise = CreateObject<UanNoiseModelDefault>();
if(!m_wossHighMobility)
{
m_prop = CreateObject<WossPropModel>();
}
else
{
m_prop = CreateObjectWithAttributes<WossPropModel>("MemoryOptimization", BooleanValue(true)); // enable in case of "HIGH mobility"
}
m_wossHelper = CreateObject<WossHelper>();
m_wossHelper->SetAttribute("WossRandomGenStream", IntegerValue(m_rngStream++));
m_wossHelper->SetAttribute("WossTotalRays", IntegerValue(m_wossRays));
m_wossHelper->SetAttribute("WossTotalRuns", IntegerValue(m_wossRuns));
m_wossHelper->SetAttribute("ResDbUseBinary", BooleanValue (false));
m_wossHelper->SetAttribute("ResDbUseTimeArr", BooleanValue (true));
if(!m_wossHighMobility)
{
m_wossHelper->SetAttribute("ResDbFilePath", StringValue ("./netcdf_error_mre/res-db/")); // disable in case of "HIGH mobility"
m_wossHelper->SetAttribute("ResDbFileName", StringValue ("netcdf_error_mre-results.dat")); // disable in case of "HIGH mobility"
}
m_wossHelper->SetAttribute("WossCleanWorkDir", BooleanValue (false));
m_wossHelper->SetAttribute("WossWorkDirPath", StringValue ("./netcdf_error_mre/work-dir/"));
m_wossHelper->SetAttribute("WossSimTime", StringValue ("1|10|2012|0|1|1|1|10|2012|0|1|1"));
m_wossHelper->SetAttribute("WossBellhopArrSyntax", IntegerValue (2));
m_wossHelper->SetAttribute("WossBellhopShdSyntax", IntegerValue (1));
m_wossHelper->SetAttribute("WossManagerTimeEvoActive", BooleanValue (true));
m_wossHelper->SetAttribute("WossManagerTotalThreads", IntegerValue (4));
m_wossHelper->SetAttribute("WossManagerUseMultithread", BooleanValue (true));
m_wossHelper->SetAttribute("SedimDbCoordFilePath", StringValue (m_wossDbsPath + "/seafloor_sediment/DECK41_V2_coordinates.nc"));
m_wossHelper->SetAttribute("SedimDbMarsdenFilePath", StringValue (m_wossDbsPath + "/seafloor_sediment/DECK41_V2_marsden_square.nc"));
m_wossHelper->SetAttribute("SedimDbMarsdenOneFilePath", StringValue (m_wossDbsPath + "/seafloor_sediment/DECK41_V2_marsden_one_degree.nc"));
m_wossHelper->SetAttribute("BathyDbGebcoFormat", IntegerValue (4)); // 15 seconds, 2D netcdf format
m_wossHelper->SetAttribute("BathyDbCoordFilePath", StringValue (m_wossDbsPath + "/bathymetry/GEBCO_2020.nc"));
m_wossHelper->SetAttribute("SspDbWoaDbType", IntegerValue (1)); // 2013 WOA DB Format
m_wossHelper->SetAttribute("SspDbCoordFilePath", StringValue (m_wossDbsPath + "/ssp/WOA2018/WOA2018_SSP_April.nc"));
m_wossHelper->SetAttribute("SedimentDbDeck41DbType", IntegerValue (1)); // DECK41 V2 database data format
if(m_wossDebug)
{
m_wossHelper->SetAttribute("ResDbCreatorDebug", BooleanValue(true));
m_wossHelper->SetAttribute("ResDbDebug", BooleanValue(true));
m_wossHelper->SetAttribute("SedimentDbCreatorDebug", BooleanValue(true));
m_wossHelper->SetAttribute("SedimentDbDebug", BooleanValue(true));
m_wossHelper->SetAttribute("SspDbCreatorDebug", BooleanValue(true));
m_wossHelper->SetAttribute("SspDbDebug", BooleanValue(true));
m_wossHelper->SetAttribute("BathyDbCreatorDebug", BooleanValue(true));
m_wossHelper->SetAttribute("BathyDbDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossDbManagerDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossCreatorDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossManagerDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossTransHandlerDebug", BooleanValue(true));
m_wossHelper->SetAttribute("WossControllerDebug", BooleanValue(true));
}
m_wossHelper->Initialize(DynamicCast<WossPropModel>(m_prop));
m_channel = CreateObjectWithAttributes<WossChannel>("PropagationModel", PointerValue(DynamicCast<WossPropModel>(m_prop)),
"NoiseModel", PointerValue(m_noise));
}
void
Experiment::CreateTopology(void)
{
m_roamingNode.Create(1);
// Static nodes
std::vector<Vector> fixedPos;
fixedPos.emplace_back(Vector(43.8291, 9.56412, 0.00791293));
fixedPos.emplace_back(Vector(43.8289, 9.56461, 0.00978492));
fixedPos.emplace_back(Vector(43.829, 9.56498, 0.0115909));
fixedPos.emplace_back(Vector(43.8289, 9.56476, 0));
MobilityHelper mobility;
m_staticNodes.Create(fixedPos.size());
mobility.SetMobilityModel("ns3::WossWaypointMobilityModel");
mobility.Install(m_staticNodes);
for(uint32_t i=0; i<m_staticNodes.GetN(); i++)
{
auto waypointModel = DynamicCast<WaypointMobilityModel>(m_staticNodes.Get(i)->GetObject<MobilityModel>());
waypointModel->AddWaypoint(Waypoint(Seconds(0), GetWossPosition(fixedPos[i])));
}
// Roaming node mobility according to waypoints from file: replaced with hard-coded list
std::vector<Waypoint> roamingNodeWaypoints;
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(0), Vector(43.8289, 9.56476, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(5.09995), Vector(43.829, 9.56476, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(10.1001), Vector(43.829, 9.56475, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(15.1995), Vector(43.829, 9.56474, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(20.2994), Vector(43.829, 9.56473, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(25.2998), Vector(43.829, 9.56473, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(30.3991), Vector(43.829, 9.56472, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(35.3996), Vector(43.829, 9.56471, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(40.4995), Vector(43.829, 9.5647, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(45.5006), Vector(43.829, 9.56469, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(50.6004), Vector(43.829, 9.56469, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(55.7002), Vector(43.829, 9.56468, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(60.7997), Vector(43.8291, 9.56467, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(65.8001), Vector(43.8291, 9.56466, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(70.8995), Vector(43.8291, 9.56465, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(75.8998), Vector(43.8291, 9.56465, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(80.8999), Vector(43.8291, 9.56464, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(85.9994), Vector(43.8291, 9.56463, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(91.0005), Vector(43.8291, 9.56462, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(96.0993), Vector(43.8291, 9.56461, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(101.2), Vector(43.8291, 9.5646, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(106.3), Vector(43.8291, 9.56459, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(111.4), Vector(43.8291, 9.56458, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(116.4), Vector(43.8291, 9.56457, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(121.5), Vector(43.8291, 9.56456, 0)));
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(126.701), Vector(43.8291, 9.56455, 0)));
// If enabled, ignore roaming node's trajectory and keep its position fixed throughout the simulation
if(m_fixWaypoint > -1)
{
if(((uint32_t) m_fixWaypoint) >= roamingNodeWaypoints.size())
{
NS_FATAL_ERROR("Experiment::CreateTopology: unexpected roaming node fixed position index (" << m_fixWaypoint << ") while there are just " << roamingNodeWaypoints.size() << " waypoints");
return;
}
auto wpTmp = roamingNodeWaypoints[(uint32_t) m_fixWaypoint];
auto lastAdded = roamingNodeWaypoints[roamingNodeWaypoints.size() - 1].time;
NS_LOG_INFO(Now().As(Time::S) << " Experiment::CreateTopology: roaming node fixed position enabled at waypoint #" << m_fixWaypoint << ", position = " << wpTmp.position);
roamingNodeWaypoints.clear();
roamingNodeWaypoints.emplace_back(Waypoint(Seconds(0), wpTmp.position));
roamingNodeWaypoints.emplace_back(Waypoint(lastAdded, wpTmp.position));
}
mobility.Install(m_roamingNode);
auto waypointModel = DynamicCast<WaypointMobilityModel>(m_roamingNode.Get(0)->GetObject<MobilityModel>());
for(auto waypointIt = roamingNodeWaypoints.begin(); waypointIt != roamingNodeWaypoints.end(); waypointIt++)
{
auto wpTmp = *waypointIt;
waypointModel->AddWaypoint(Waypoint(wpTmp.time, GetWossPosition(wpTmp.position)));
}
auto wpModel = DynamicCast<WaypointMobilityModel>(m_roamingNode.Get(0)->GetObject<MobilityModel>());
wpModel->TraceConnectWithoutContext("CourseChange", MakeCallback(&Experiment::WaypointCallback, this));
m_rngStream += waypointModel->AssignStreams(m_rngStream);
}
void
Experiment::FinalizeSetup(void)
{
// Modulation setup
UanTxModeFactory::CreateMode(UanTxMode::PSK, m_rateBps, m_rateBps, m_freqHz, m_bandHz, 4, m_modulationName);
// General stack setup
Ptr<UanPhyPer> per = CreateObject<UanPhyPerCommonModes>();
Ptr<UanPhyCalcSinrDefault> sinr = CreateObject<UanPhyCalcSinrDefault>();
UanTxMode mode = UanTxModeFactory::GetMode(m_modulationName);
UanModesList modulations;
modulations.AppendMode(mode);
UanHelper uanHelper;
uanHelper.SetTransducer("ns3::UanTransducerHd");
uanHelper.SetPhy("ns3::UanPhyGen",
"PerModel", PointerValue(per),
"SinrModel", PointerValue(sinr),
"SupportedModes", UanModesListValue(modulations),
"TxPower", DoubleValue(m_txPowerDb));
uanHelper.SetMac("ns3::UanMacAloha");
Ptr<UanChannel> uanCh = DynamicCast<UanChannel>(m_channel);
m_roamingDev = uanHelper.Install(m_roamingNode, uanCh);
m_staticDevs = uanHelper.Install(m_staticNodes, uanCh);
// Socket creation
PacketSocketHelper sockHelper;
sockHelper.Install(m_roamingNode);
sockHelper.Install(m_staticNodes);
TypeId fTid = PacketSocketFactory::GetTypeId();
// Roaming node sends to everyone
for(auto nodeIt = m_roamingNode.Begin(); nodeIt != m_roamingNode.End(); nodeIt++)
{
auto sock = Socket::CreateSocket(*nodeIt, fTid);
sock->SetAllowBroadcast(true);
sock->Bind();
m_roamingSock.push_back(sock);
}
PacketSocketAddress sockAddr;
sockAddr.SetSingleDevice(m_roamingDev.Get(0)->GetIfIndex());
sockAddr.SetPhysicalAddress(m_roamingDev.Get(0)->GetAddress());
sockAddr.SetProtocol(0);
// Static nodes only send to roaming node
for(auto nodeIt = m_staticNodes.Begin(); nodeIt != m_staticNodes.End(); nodeIt++)
{
auto sock = Socket::CreateSocket(*nodeIt, fTid);
sock->SetAllowBroadcast(true);
sock->Bind();
sock->Connect(sockAddr);
m_staticSocks.push_back(sock);
}
// --- Roaming node ---
m_roamingSock[0]->SetRecvCallback(MakeCallback(&Experiment::ReceivePong, this));
// --- Static nodes ---
for(auto sockIt = m_staticSocks.begin(); sockIt != m_staticSocks.end(); sockIt++)
{
auto sock = *sockIt;
sock->SetRecvCallback(MakeCallback(&Experiment::ReceivePing, this));
}
// Reproducibility
m_rngStream += uanHelper.AssignStreams(m_roamingDev, m_rngStream);
m_rngStream += uanHelper.AssignStreams(m_staticDevs, m_rngStream);
}
void
Experiment::StartApplication(Time start)
{
// Start generating packets
m_genPing = Simulator::Schedule(start + MilliSeconds(100), &Experiment::SendPing, this);
}
void
Experiment::StopApplication(Time stop)
{
// Stop generating packets
if(m_genPing.IsRunning())
{
m_genPing.Cancel();
}
if(m_pingDeadline.IsRunning())
{
m_pingDeadline.Cancel();
}
// Schedule simulation stop after arbitrary time, if specified
if(stop.IsStrictlyPositive())
{
Simulator::Stop(stop);
}
// Close sockets
for(auto sockIt = m_roamingSock.begin(); sockIt != m_roamingSock.end(); sockIt++)
{
auto sock = *sockIt;
sock->Close();
}
for(auto sockIt = m_staticSocks.begin(); sockIt != m_staticSocks.end(); sockIt++)
{
auto sock = *sockIt;
sock->Close();
}
}
Vector
Experiment::GetWossPosition(const Vector &pos)
{
auto geoPos = woss::CoordZ(pos.x, pos.y, pos.z);
geoPos.setDepth(pos.z);
// Convert to cartesian coordinates via WOSS helper function
auto wossPos = CreateVectorFromCoordZ(geoPos);
NS_LOG_INFO(Now().As(Time::S) << " Experiment::GetWossPosition: geodesic coordinates " << geoPos.getLatitude() << ":" << geoPos.getLongitude() << ":" << geoPos.getDepth() << " --> WOSS cartesian coordinates " << wossPos);
return wossPos;
}
Vector
Experiment::GetOriginalPosition(const Vector &wossPos)
{
// Convert from WOSS helper function to geodesic coordinates
auto geoPos = CreateCoordZFromVector(wossPos);
double approxDepth = geoPos.getDepth() < 0.001 ? 0 : geoPos.getDepth();
Vector convPos{geoPos.getLatitude(), geoPos.getLongitude(), approxDepth};
NS_LOG_INFO(Now().As(Time::S) << " Experiment::GetOriginalPosition: WOSS cartesian coordinates " << wossPos << " --> geodesic coordinates " << convPos);
return convPos;
}
PingHeader::PingHeader()
: Header(),
m_pingId(0)
{
}
PingHeader::~PingHeader()
{
}
TypeId
PingHeader::GetTypeId(void)
{
static TypeId tid = TypeId("ns3::PingHeader")
.SetParent<Header>()
.AddConstructor<PingHeader>()
;
return tid;
}
uint16_t
PingHeader::GetPingId(void) const
{
return m_pingId;
}
void
PingHeader::SetPingId(uint16_t id)
{
m_pingId = id;
}
uint32_t
PingHeader::GetSerializedSize(void) const
{
return 2;
}
void
PingHeader::Serialize(Buffer::Iterator start) const
{
start.WriteU16(m_pingId);
}
uint32_t
PingHeader::Deserialize(Buffer::Iterator start)
{
Buffer::Iterator rbuf = start;
m_pingId = rbuf.ReadU16();
return rbuf.GetDistanceFrom(start);
}
void
PingHeader::Print(std::ostream &os) const
{
os << " [PING | Id: " << +m_pingId << "] ";
}
TypeId
PingHeader::GetInstanceTypeId(void) const
{
return GetTypeId();
}
PongHeader::PongHeader()
: Header(),
m_pingId(0),
m_nodeId(0)
{
}
PongHeader::~PongHeader()
{
}
TypeId
PongHeader::GetTypeId(void)
{
static TypeId tid = TypeId("ns3::PongHeader")
.SetParent<Header>()
.AddConstructor<PongHeader>()
;
return tid;
}
uint16_t
PongHeader::GetPingId(void) const
{
return m_pingId;
}
uint32_t
PongHeader::GetNodeId(void) const
{
return m_nodeId;
}
void
PongHeader::SetPingId(uint16_t id)
{
m_pingId = id;
}
void
PongHeader::SetNodeId(uint32_t id)
{
m_nodeId = id;
}
uint32_t
PongHeader::GetSerializedSize(void) const
{
return 2 + 4;
}
void
PongHeader::Serialize(Buffer::Iterator start) const
{
start.WriteU16(m_pingId);
start.WriteU32(m_nodeId);
}
uint32_t
PongHeader::Deserialize(Buffer::Iterator start)
{
Buffer::Iterator rbuf = start;
m_pingId = rbuf.ReadU16();
m_nodeId = rbuf.ReadU32();
return rbuf.GetDistanceFrom(start);
}
void
PongHeader::Print(std::ostream &os) const
{
os << " [PONG | Ping Id: " << +m_pingId << ", Node Id: " << m_nodeId << "] ";
}
TypeId
PongHeader::GetInstanceTypeId(void) const
{
return GetTypeId();
}
// --- Roaming node ---
void
Experiment::SendPing(void)
{
Ptr<Packet> pkt = Create<Packet>(0);
PingHeader pingH;
pingH.SetPingId(m_pingId++);
pkt->AddHeader(pingH);
// Inquiry a specific static node for PING-PONG exchange
Address sockAddr = m_staticDevs.Get(m_sockId)->GetAddress();
m_roamingDev.Get(0)->Send(pkt->Copy(), sockAddr, 0);
auto currPos = GetOriginalPosition(m_roamingSock[0]->GetNode()->GetObject<MobilityModel>()->GetPosition());
NS_LOG_DEBUG(Now().As(Time::S) << " Experiment::SendPing: packet " << pkt->GetUid() << " (PING #" << +pingH.GetPingId() << ") sent by roaming node to static node " << m_sockId << " (from position: " << currPos << ")");
if(m_pingDeadline.IsExpired())
{
m_pingDeadline = Simulator::Schedule(Seconds(m_deadline), &Experiment::PingDeadline, this);
}
}
void
Experiment::PingDeadline(void)
{
if(m_lastWpArrival.IsZero() || (Now() + Seconds(m_trafficCbr) < m_lastWpArrival))
{
m_sockId++;
m_sockId = m_sockId % m_staticNodes.GetN();
m_genPing = Simulator::Schedule(Seconds(m_trafficCbr), &Experiment::SendPing, this);
}
}
void
Experiment::ReceivePong(Ptr<Socket> socket)
{
Ptr<Node> node = socket->GetNode();
uint32_t nodeId = node->GetId();
Ptr<Packet> pkt;
while((pkt = socket->Recv()))
{
PongHeader pongH;
pkt->PeekHeader(pongH);
uint16_t pingId = pongH.GetPingId();
uint32_t sNodeId = pongH.GetNodeId();
auto currPos = GetOriginalPosition(node->GetObject<MobilityModel>()->GetPosition());
NS_LOG_DEBUG(Now().As(Time::S) << " Experiment::ReceivePong: packet " << pkt->GetUid() << " (PONG for PING #" << +pingId << ", static node " << sNodeId << ") received at roaming node (Position: " << currPos << ")");
}
// Generate new ping according to traffic interval
m_pingDeadline.Cancel();
if(m_lastWpArrival.IsZero() || (Now() + Seconds(m_trafficCbr) < m_lastWpArrival))
{
m_sockId++;
m_sockId = m_sockId % m_staticNodes.GetN();
m_genPing = Simulator::ScheduleNow(&Experiment::SendPing, this);
}
}
void
Experiment::WaypointCallback(Ptr<const MobilityModel> model)
{
UintegerValue numWaypointsLeft;
model->GetAttribute("WaypointsLeft", numWaypointsLeft);
if(numWaypointsLeft.Get() == 0)
{
WaypointValue lastWaypoint;
model->GetAttribute("NextWaypoint", lastWaypoint);
m_lastWpArrival = lastWaypoint.Get().time;
Simulator::Stop(m_lastWpArrival + Seconds(10));
}
}
// --- Static nodes ---
void
Experiment::ReceivePing(Ptr<Socket> socket)
{
Ptr<Node> node = socket->GetNode();
uint32_t nodeId = node->GetId();
Ptr<Packet> pkt;
while((pkt = socket->Recv()))
{
PingHeader pingH;
pkt->PeekHeader(pingH);
NS_LOG_DEBUG(Now().As(Time::S) << " Experiment::ReceivePing: packet " << pkt->GetUid() << " (PING #" << +pingH.GetPingId() << ") received at static node " << nodeId);
// Reply to this ping immediately
Simulator::ScheduleNow(&Experiment::ReplyToPing, this, socket, pingH.GetPingId());
}
}
void
Experiment::ReplyToPing(Ptr<Socket> socket, uint16_t pingId)
{
uint32_t nodeId = socket->GetNode()->GetId();
Ptr<Packet> pkt = Create<Packet>(0);
PongHeader pongH;
pongH.SetPingId(pingId);
pongH.SetNodeId(nodeId);
pkt->AddHeader(pongH);
NS_LOG_DEBUG(Now().As(Time::S) << " Experiment::ReplyToPing: packet " << pkt->GetUid() << " (PONG for PING #" << pingId << ") from static node " << nodeId);
socket->Send(pkt->Copy());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment