Last active
October 9, 2023 14:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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