diff --git a/examples/adr-example.cc b/examples/adr-example.cc index 2e4167cf58..6d99a02299 100644 --- a/examples/adr-example.cc +++ b/examples/adr-example.cc @@ -73,7 +73,7 @@ main(int argc, char* argv[]) double mobileNodeProbability = 0; double sideLengthMeters = 10000; int gatewayDistanceMeters = 5000; - double maxRandomLossDB = 10; + double maxRandomLossDb = 10; double minSpeedMetersPerSecond = 2; double maxSpeedMetersPerSecond = 16; std::string adrType = "ns3::AdrComponent"; @@ -98,7 +98,7 @@ main(int argc, char* argv[]) sideLengthMeters); cmd.AddValue("maxRandomLoss", "Maximum amount (dB) of the random loss component", - maxRandomLossDB); + maxRandomLossDb); cmd.AddValue("gatewayDistance", "Distance (m) between gateways", gatewayDistanceMeters); cmd.AddValue("initializeSF", "Whether to initialize the SFs", initializeSF); cmd.AddValue("MinSpeed", "Minimum speed (m/s) for mobile devices", minSpeedMetersPerSecond); @@ -132,7 +132,7 @@ main(int argc, char* argv[]) // Set the end devices to allow data rate control (i.e. adaptive data rate) from the network // server - Config::SetDefault("ns3::EndDeviceLorawanMac::DRControl", BooleanValue(true)); + Config::SetDefault("ns3::EndDeviceLorawanMac::ADR", BooleanValue(true)); // Create a simple wireless channel /////////////////////////////////// @@ -143,7 +143,7 @@ main(int argc, char* argv[]) Ptr x = CreateObject(); x->SetAttribute("Min", DoubleValue(0.0)); - x->SetAttribute("Max", DoubleValue(maxRandomLossDB)); + x->SetAttribute("Max", DoubleValue(maxRandomLossDb)); Ptr randomLoss = CreateObject(); randomLoss->SetAttribute("Variable", PointerValue(x)); diff --git a/examples/aloha-throughput.cc b/examples/aloha-throughput.cc index 4bf7a5957f..7d4a7cac31 100644 --- a/examples/aloha-throughput.cc +++ b/examples/aloha-throughput.cc @@ -258,7 +258,7 @@ main(int argc, char* argv[]) appHelper.SetPacketSize(packetSize); ApplicationContainer appContainer = appHelper.Install(endDevices); - appContainer.Start(Seconds(0)); + appContainer.Start(Time(0)); appContainer.Stop(appStopTime); std::ofstream outputFile; diff --git a/examples/complete-network-example.cc b/examples/complete-network-example.cc index be2a2686db..633e16bd2d 100644 --- a/examples/complete-network-example.cc +++ b/examples/complete-network-example.cc @@ -305,7 +305,7 @@ main(int argc, char* argv[]) DoubleValue(10)); ApplicationContainer appContainer = appHelper.Install(endDevices); - appContainer.Start(Seconds(0)); + appContainer.Start(Time(0)); appContainer.Stop(appStopTime); /************************** @@ -353,7 +353,7 @@ main(int argc, char* argv[]) NS_LOG_INFO("Computing performance metrics..."); LoraPacketTracker& tracker = helper.GetPacketTracker(); - std::cout << tracker.CountMacPacketsGlobally(Seconds(0), appStopTime + Hours(1)) << std::endl; + std::cout << tracker.CountMacPacketsGlobally(Time(0), appStopTime + Hours(1)) << std::endl; return 0; } diff --git a/examples/frame-counter-update.cc b/examples/frame-counter-update.cc index 013c80acd1..73279e118e 100644 --- a/examples/frame-counter-update.cc +++ b/examples/frame-counter-update.cc @@ -239,14 +239,14 @@ main(int argc, char* argv[]) Time appStopTime = Seconds(simulationTimeSeconds); OneShotSenderHelper appHelper = OneShotSenderHelper(); - appHelper.SetSendTime(Seconds(0)); + appHelper.SetSendTime(Time(0)); ApplicationContainer appContainer = appHelper.Install(endDevices); appHelper.SetSendTime(Seconds(100)); appContainer.Add(appHelper.Install(endDevices)); appHelper.SetSendTime(Seconds(200)); appContainer.Add(appHelper.Install(endDevices)); - appContainer.Start(Seconds(0)); + appContainer.Start(Time(0)); appContainer.Stop(appStopTime); Simulator::Schedule(Seconds(110), &ChangeEndDevicePosition, endDevices.Get(0), true); @@ -298,7 +298,7 @@ main(int argc, char* argv[]) LoraPacketTracker& tracker = helper.GetPacketTracker(); NS_LOG_INFO("Printing total sent MAC-layer packets and successful MAC-layer packets"); - std::cout << tracker.CountMacPacketsGlobally(Seconds(0), appStopTime + Hours(1)) << std::endl; + std::cout << tracker.CountMacPacketsGlobally(Time(0), appStopTime + Hours(1)) << std::endl; return 0; } diff --git a/helper/lora-helper.cc b/helper/lora-helper.cc index ba691ed76b..de38ed7bf2 100644 --- a/helper/lora-helper.cc +++ b/helper/lora-helper.cc @@ -20,8 +20,8 @@ namespace lorawan NS_LOG_COMPONENT_DEFINE("LoraHelper"); LoraHelper::LoraHelper() - : m_lastPhyPerformanceUpdate(Seconds(0)), - m_lastGlobalPerformanceUpdate(Seconds(0)) + : m_lastPhyPerformanceUpdate(Time(0)), + m_lastGlobalPerformanceUpdate(Time(0)) { } @@ -47,7 +47,7 @@ LoraHelper::Install(const LoraPhyHelper& phyHelper, Ptr device = CreateObject(); // Create the PHY - Ptr phy = phyHelper.Create(node, device); + Ptr phy = phyHelper.Install(node, device); NS_ASSERT(phy); device->SetPhy(phy); NS_LOG_DEBUG("Done creating the PHY"); @@ -85,7 +85,7 @@ LoraHelper::Install(const LoraPhyHelper& phyHelper, } // Create the MAC - Ptr mac = macHelper.Create(node, device); + Ptr mac = macHelper.Install(node, device); NS_ASSERT(mac); mac->SetPhy(phy); NS_LOG_DEBUG("Done creating the MAC"); @@ -151,7 +151,7 @@ void LoraHelper::EnableSimulationTimePrinting(Time interval) { m_oldtime = std::time(nullptr); - Simulator::Schedule(Seconds(0), &LoraHelper::DoPrintSimulationTime, this, interval); + Simulator::Schedule(Time(0), &LoraHelper::DoPrintSimulationTime, this, interval); } void @@ -181,7 +181,7 @@ LoraHelper::DoPrintDeviceStatus(NodeContainer endDevices, { const char* c = filename.c_str(); std::ofstream outputFile; - if (Simulator::Now() == Seconds(0)) + if (Now().IsZero()) { // Delete contents of the file as it is opened outputFile.open(c, std::ofstream::out | std::ofstream::trunc); @@ -192,7 +192,7 @@ LoraHelper::DoPrintDeviceStatus(NodeContainer endDevices, outputFile.open(c, std::ofstream::out | std::ofstream::app); } - Time currentTime = Simulator::Now(); + Time currentTime = Now(); for (auto j = endDevices.Begin(); j != endDevices.End(); ++j) { Ptr object = *j; @@ -204,9 +204,9 @@ LoraHelper::DoPrintDeviceStatus(NodeContainer endDevices, Ptr mac = DynamicCast(loraNetDevice->GetMac()); int dr = int(mac->GetDataRate()); - double txPower = mac->GetTransmissionPower(); + double txPower = mac->GetTransmissionPowerDbm(); Vector pos = position->GetPosition(); - outputFile << currentTime.GetSeconds() << " " << object->GetId() << " " << pos.x << " " + outputFile << currentTime.As(Time::S) << " " << object->GetId() << " " << pos.x << " " << pos.y << " " << dr << " " << unsigned(txPower) << std::endl; } // for (NodeContainer::Iterator j = gateways.Begin (); j != gateways.End (); ++j) @@ -245,7 +245,7 @@ LoraHelper::DoPrintPhyPerformance(NodeContainer gateways, std::string filename) const char* c = filename.c_str(); std::ofstream outputFile; - if (Simulator::Now() == Seconds(0)) + if (Now().IsZero()) { // Delete contents of the file as it is opened outputFile.open(c, std::ofstream::out | std::ofstream::trunc); @@ -259,14 +259,14 @@ LoraHelper::DoPrintPhyPerformance(NodeContainer gateways, std::string filename) for (auto it = gateways.Begin(); it != gateways.End(); ++it) { int systemId = (*it)->GetId(); - outputFile << Simulator::Now().GetSeconds() << " " << std::to_string(systemId) << " " + outputFile << Now().As(Time::S) << " " << std::to_string(systemId) << " " << m_packetTracker->PrintPhyPacketsPerGw(m_lastPhyPerformanceUpdate, - Simulator::Now(), + Now(), systemId) << std::endl; } - m_lastPhyPerformanceUpdate = Simulator::Now(); + m_lastPhyPerformanceUpdate = Now(); outputFile.close(); } @@ -292,7 +292,7 @@ LoraHelper::DoPrintGlobalPerformance(std::string filename) const char* c = filename.c_str(); std::ofstream outputFile; - if (Simulator::Now() == Seconds(0)) + if (Now().IsZero()) { // Delete contents of the file as it is opened outputFile.open(c, std::ofstream::out | std::ofstream::trunc); @@ -303,12 +303,11 @@ LoraHelper::DoPrintGlobalPerformance(std::string filename) outputFile.open(c, std::ofstream::out | std::ofstream::app); } - outputFile << Simulator::Now().GetSeconds() << " " - << m_packetTracker->CountMacPacketsGlobally(m_lastGlobalPerformanceUpdate, - Simulator::Now()) + outputFile << Now().As(Time::S) << " " + << m_packetTracker->CountMacPacketsGlobally(m_lastGlobalPerformanceUpdate, Now()) << std::endl; - m_lastGlobalPerformanceUpdate = Simulator::Now(); + m_lastGlobalPerformanceUpdate = Now(); outputFile.close(); } @@ -316,8 +315,8 @@ LoraHelper::DoPrintGlobalPerformance(std::string filename) void LoraHelper::DoPrintSimulationTime(Time interval) { - // NS_LOG_INFO ("Time: " << Simulator::Now().GetHours()); - std::cout << "Simulated time: " << Simulator::Now().GetHours() << " hours" << std::endl; + // NS_LOG_INFO ("Time: " << Now().As(Time::H)); + std::cout << "Simulated time: " << Now().As(Time::H) << std::endl; std::cout << "Real time from last call: " << std::time(nullptr) - m_oldtime << " seconds" << std::endl; m_oldtime = std::time(nullptr); diff --git a/helper/lora-packet-tracker.cc b/helper/lora-packet-tracker.cc index 534a404254..5c1290cae0 100644 --- a/helper/lora-packet-tracker.cc +++ b/helper/lora-packet-tracker.cc @@ -44,7 +44,7 @@ LoraPacketTracker::MacTransmissionCallback(Ptr packet) MacPacketStatus status; status.packet = packet; - status.sendTime = Simulator::Now(); + status.sendTime = Now(); status.senderId = Simulator::GetContext(); status.receivedTime = Time::Max(); @@ -60,11 +60,11 @@ LoraPacketTracker::RequiredTransmissionsCallback(uint8_t reqTx, { NS_LOG_INFO("Finished retransmission attempts for a packet"); NS_LOG_DEBUG("Packet: " << packet << "ReqTx " << unsigned(reqTx) << ", succ: " << success - << ", firstAttempt: " << firstAttempt.GetSeconds()); + << ", firstAttempt: " << firstAttempt.As(Time::S)); RetransmissionStatus entry; entry.firstAttempt = firstAttempt; - entry.finishTime = Simulator::Now(); + entry.finishTime = Now(); entry.reTxAttempts = reqTx; entry.successful = success; @@ -84,7 +84,7 @@ LoraPacketTracker::MacGwReceptionCallback(Ptr packet) if (it != m_macPacketTracker.end()) { (*it).second.receptionTimes.insert( - std::pair(Simulator::GetContext(), Simulator::Now())); + std::pair(Simulator::GetContext(), Now())); } else { @@ -106,7 +106,7 @@ LoraPacketTracker::TransmissionCallback(Ptr packet, uint32_t edId) // Create a packetStatus PacketStatus status; status.packet = packet; - status.sendTime = Simulator::Now(); + status.sendTime = Now(); status.senderId = edId; m_packetTracker.insert(std::pair, PacketStatus>(packet, status)); diff --git a/helper/lora-phy-helper.cc b/helper/lora-phy-helper.cc index 51ff87bd3d..86f81514ac 100644 --- a/helper/lora-phy-helper.cc +++ b/helper/lora-phy-helper.cc @@ -60,7 +60,7 @@ LoraPhyHelper::Set(std::string name, const AttributeValue& v) } Ptr -LoraPhyHelper::Create(Ptr node, Ptr device) const +LoraPhyHelper::Install(Ptr node, Ptr device) const { NS_LOG_FUNCTION(this << node->GetId() << device); diff --git a/helper/lora-phy-helper.h b/helper/lora-phy-helper.h index 249f32f5ab..845e9cbd5e 100644 --- a/helper/lora-phy-helper.h +++ b/helper/lora-phy-helper.h @@ -80,7 +80,7 @@ class LoraPhyHelper * \param device The device within which this PHY will be created. * \return A newly-created PHY object. */ - Ptr Create(Ptr node, Ptr device) const; + Ptr Install(Ptr node, Ptr device) const; /** * Set the maximum number of gateway receive paths. diff --git a/helper/lorawan-mac-helper.cc b/helper/lorawan-mac-helper.cc index 4dbdf57d4e..c9b6a9f027 100644 --- a/helper/lorawan-mac-helper.cc +++ b/helper/lorawan-mac-helper.cc @@ -63,7 +63,7 @@ LorawanMacHelper::SetRegion(enum LorawanMacHelper::Regions region) } Ptr -LorawanMacHelper::Create(Ptr node, Ptr device) const +LorawanMacHelper::Install(Ptr node, Ptr device) const { Ptr mac = m_mac.Create(); mac->SetDevice(device); @@ -132,10 +132,10 @@ LorawanMacHelper::ConfigureForAlohaRegion(Ptr edMac) ApplyCommonAlohaConfigurations(edMac); - ///////////////////////////////////////////////////// - // TxPower -> Transmission power in dBm conversion // - ///////////////////////////////////////////////////// - edMac->SetTxDbmForTxPower(std::vector{16, 14, 12, 10, 8, 6, 4, 2}); + ///////////////////////////////////////////////////////// + // TxPower -> Transmission power in dBm ERP conversion // + ///////////////////////////////////////////////////////// + edMac->SetTxDbmForTxPower(std::vector{14, 12, 10, 8, 6, 4, 2, 0}); //////////////////////////////////////////////////////////// // Matrix to know which data rate the gateway will respond with // @@ -200,14 +200,14 @@ LorawanMacHelper::ApplyCommonAlohaConfigurations(Ptr lorawanMac) con // SubBands // ////////////// - Ptr channelHelper = CreateObject(); - channelHelper->AddSubBand(868, 868.6, 1, 14); + auto channelHelper = Create(1); + channelHelper->AddSubBand(Create(868, 868.6, 1, 14)); ////////////////////// // Default channels // ////////////////////// - Ptr lc1 = CreateObject(868.1, 0, 5); - channelHelper->AddChannel(lc1); + Ptr lc1 = Create(868.1, 0, 5); + channelHelper->SetChannel(0, lc1); lorawanMac->SetLogicalLoraChannelHelper(channelHelper); @@ -229,10 +229,10 @@ LorawanMacHelper::ConfigureForEuRegion(Ptr edMac) con ApplyCommonEuConfigurations(edMac); - ///////////////////////////////////////////////////// - // TxPower -> Transmission power in dBm conversion // - ///////////////////////////////////////////////////// - edMac->SetTxDbmForTxPower(std::vector{16, 14, 12, 10, 8, 6, 4, 2}); + ///////////////////////////////////////////////////////// + // TxPower -> Transmission power in dBm ERP conversion // + ///////////////////////////////////////////////////////// + edMac->SetTxDbmForTxPower(std::vector{14, 12, 10, 8, 6, 4, 2, 0}); //////////////////////////////////////////////////////////// // Matrix to know which data rate the gateway will respond with // @@ -306,20 +306,23 @@ LorawanMacHelper::ApplyCommonEuConfigurations(Ptr lorawanMac) const // SubBands // ////////////// - Ptr channelHelper = CreateObject(); - channelHelper->AddSubBand(868, 868.6, 0.01, 14); - channelHelper->AddSubBand(868.7, 869.2, 0.001, 14); - channelHelper->AddSubBand(869.4, 869.65, 0.1, 27); + auto channelHelper = Create(16); + channelHelper->AddSubBand(Create(863, 865, 0.001, 14)); + channelHelper->AddSubBand(Create(865, 868, 0.01, 14)); + channelHelper->AddSubBand(Create(868, 868.6, 0.01, 14)); + channelHelper->AddSubBand(Create(868.7, 869.2, 0.001, 14)); + channelHelper->AddSubBand(Create(869.4, 869.65, 0.1, 27)); + channelHelper->AddSubBand(Create(869.7, 870, 0.01, 14)); ////////////////////// // Default channels // ////////////////////// - Ptr lc1 = CreateObject(868.1, 0, 5); - Ptr lc2 = CreateObject(868.3, 0, 5); - Ptr lc3 = CreateObject(868.5, 0, 5); - channelHelper->AddChannel(lc1); - channelHelper->AddChannel(lc2); - channelHelper->AddChannel(lc3); + Ptr lc1 = Create(868.1, 0, 5); + Ptr lc2 = Create(868.3, 0, 5); + Ptr lc3 = Create(868.5, 0, 5); + channelHelper->SetChannel(0, lc1); + channelHelper->SetChannel(1, lc2); + channelHelper->SetChannel(2, lc3); lorawanMac->SetLogicalLoraChannelHelper(channelHelper); @@ -343,10 +346,10 @@ LorawanMacHelper::ConfigureForSingleChannelRegion(Ptr ApplyCommonSingleChannelConfigurations(edMac); - ///////////////////////////////////////////////////// - // TxPower -> Transmission power in dBm conversion // - ///////////////////////////////////////////////////// - edMac->SetTxDbmForTxPower(std::vector{16, 14, 12, 10, 8, 6, 4, 2}); + ///////////////////////////////////////////////////////// + // TxPower -> Transmission power in dBm ERP conversion // + ///////////////////////////////////////////////////////// + edMac->SetTxDbmForTxPower(std::vector{14, 12, 10, 8, 6, 4, 2, 0}); //////////////////////////////////////////////////////////// // Matrix to know which DataRate the gateway will respond with // @@ -418,16 +421,14 @@ LorawanMacHelper::ApplyCommonSingleChannelConfigurations(Ptr lorawan // SubBands // ////////////// - Ptr channelHelper = CreateObject(); - channelHelper->AddSubBand(868, 868.6, 0.01, 14); - channelHelper->AddSubBand(868.7, 869.2, 0.001, 14); - channelHelper->AddSubBand(869.4, 869.65, 0.1, 27); + auto channelHelper = Create(1); + channelHelper->AddSubBand(Create(868, 868.6, 0.01, 14)); ////////////////////// // Default channels // ////////////////////// - Ptr lc1 = CreateObject(868.1, 0, 5); - channelHelper->AddChannel(lc1); + Ptr lc1 = Create(868.1, 0, 5); + channelHelper->SetChannel(0, lc1); lorawanMac->SetLogicalLoraChannelHelper(channelHelper); diff --git a/helper/lorawan-mac-helper.h b/helper/lorawan-mac-helper.h index 44e5ac7d9b..9fe88d5e85 100644 --- a/helper/lorawan-mac-helper.h +++ b/helper/lorawan-mac-helper.h @@ -97,7 +97,7 @@ class LorawanMacHelper * \param device The device within which this MAC will be created. * \return A newly-created LorawanMac object. */ - Ptr Create(Ptr node, Ptr device) const; + Ptr Install(Ptr node, Ptr device) const; /** * Initialize the end devices' data rate parameter. diff --git a/helper/periodic-sender-helper.cc b/helper/periodic-sender-helper.cc index bab6fbbf48..8e77524d07 100644 --- a/helper/periodic-sender-helper.cc +++ b/helper/periodic-sender-helper.cc @@ -77,7 +77,7 @@ PeriodicSenderHelper::InstallPriv(Ptr node) const Ptr app = m_factory.Create(); Time interval; - if (m_period == Seconds(0)) + if (m_period.IsZero()) { double intervalProb = m_intervalProb->GetValue(); NS_LOG_DEBUG("IntervalProb = " << intervalProb); @@ -106,7 +106,7 @@ PeriodicSenderHelper::InstallPriv(Ptr node) const } app->SetInterval(interval); - NS_LOG_DEBUG("Created an application with interval = " << interval.GetHours() << " hours"); + NS_LOG_DEBUG("Created an application with interval = " << interval.As(Time::H)); app->SetInitialDelay(Seconds(m_initialDelay->GetValue(0, interval.GetSeconds()))); app->SetPacketSize(m_pktSize); diff --git a/model/adr-component.cc b/model/adr-component.cc index 7d2a86f2f3..157c05ebee 100644 --- a/model/adr-component.cc +++ b/model/adr-component.cc @@ -110,22 +110,22 @@ AdrComponent::BeforeSendingReply(Ptr status, Ptr uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor(); // Get the device transmission power (dBm) - uint8_t transmissionPower = status->GetMac()->GetTransmissionPower(); + double transmissionPowerDbm = status->GetMac()->GetTransmissionPowerDbm(); // New parameters for the end-device uint8_t newDataRate; - uint8_t newTxPower; + double newTxPowerDbm; // Adaptive Data Rate (ADR) Algorithm - AdrImplementation(&newDataRate, &newTxPower, status); + AdrImplementation(&newDataRate, &newTxPowerDbm, status); // Change the power back to the default if we don't want to change it if (!m_toggleTxPower) { - newTxPower = transmissionPower; + newTxPowerDbm = transmissionPowerDbm; } - if (newDataRate != SfToDr(spreadingFactor) || newTxPower != transmissionPower) + if (newDataRate != SfToDr(spreadingFactor) || newTxPowerDbm != transmissionPowerDbm) { // Create a list with mandatory channel indexes int channels[] = {0, 1, 2}; @@ -134,12 +134,11 @@ AdrComponent::BeforeSendingReply(Ptr status, Ptr // Repetitions Setting const int rep = 1; - NS_LOG_DEBUG("Sending LinkAdrReq with DR = " << (unsigned)newDataRate - << " and TP = " << (unsigned)newTxPower - << " dBm"); + NS_LOG_DEBUG("Sending LinkAdrReq with DR = " + << (unsigned)newDataRate << " and TP = " << newTxPowerDbm << "dBm"); status->m_reply.frameHeader.AddLinkAdrReq(newDataRate, - GetTxPowerIndex(newTxPower), + GetTxPowerIndex(newTxPowerDbm), enabledChannels, rep); status->m_reply.frameHeader.SetAsDownlink(); @@ -167,7 +166,7 @@ AdrComponent::OnFailedReply(Ptr status, Ptr netw void AdrComponent::AdrImplementation(uint8_t* newDataRate, - uint8_t* newTxPower, + double* newTxPower, Ptr status) { // Compute the maximum or median SNR, based on the boolean value historyAveraging @@ -197,7 +196,7 @@ AdrComponent::AdrImplementation(uint8_t* newDataRate, NS_LOG_DEBUG("Required SNR = " << req_SNR); // Get the device transmission power (dBm) - double transmissionPower = status->GetMac()->GetTransmissionPower(); + double transmissionPower = status->GetMac()->GetTransmissionPowerDbm(); NS_LOG_DEBUG("Transmission Power = " << transmissionPower); @@ -429,41 +428,12 @@ AdrComponent::GetAverageSNR(EndDeviceStatus::ReceivedPacketList packetList, int return average; } -int -AdrComponent::GetTxPowerIndex(int txPower) +uint8_t +AdrComponent::GetTxPowerIndex(double txPower) { - if (txPower >= 16) - { - return 0; - } - else if (txPower >= 14) - { - return 1; - } - else if (txPower >= 12) - { - return 2; - } - else if (txPower >= 10) - { - return 3; - } - else if (txPower >= 8) - { - return 4; - } - else if (txPower >= 6) - { - return 5; - } - else if (txPower >= 4) - { - return 6; - } - else - { - return 7; - } + NS_ASSERT_MSG(txPower <= 14 || txPower >= 0, "TxPower dBm value out of supported range"); + NS_ASSERT_MSG(fmod(txPower, 2) == 0, "Invalid TxPower value"); + return 7 - txPower / 2; } } // namespace lorawan } // namespace ns3 diff --git a/model/adr-component.h b/model/adr-component.h index 7f59b4c4c7..7bf256df69 100644 --- a/model/adr-component.h +++ b/model/adr-component.h @@ -65,10 +65,10 @@ class AdrComponent : public NetworkControllerComponent * https://doi.org/10.1109/NOMS.2018.8406255 . * * \param newDataRate [out] new data rate value selected for the end device. - * \param newTxPower [out] new tx power value selected for the end device. + * \param newTxPower [out] new tx power [dBm] value selected for the end device. * \param status State representation of the current end device. */ - void AdrImplementation(uint8_t* newDataRate, uint8_t* newTxPower, Ptr status); + void AdrImplementation(uint8_t* newDataRate, double* newTxPower, Ptr status); /** * Convert spreading factor values [7:12] to respective data rate values [0:5]. @@ -147,13 +147,12 @@ class AdrComponent : public NetworkControllerComponent double GetAverageSNR(EndDeviceStatus::ReceivedPacketList packetList, int historyRange); /** - * Get the LoRaWAN protocol TXPower configuration index from the Equivalent Isotropically - * Radiated Power (EIRP) in dBm. + * Get the LoRaWAN protocol TxPower parameter from the Equivalent Radiated Power (ERP) in dBm. * - * \param txPower Transission EIRP configuration. - * \return TXPower index as int. + * \param txPower Transission ERP configuration [dBm]. + * \return TxPower parameter value as uint8_t. */ - int GetTxPowerIndex(int txPower); + uint8_t GetTxPowerIndex(double txPower); enum CombiningMethod tpAveraging; //!< TX power from gateways policy int historyRange; //!< Number of previous packets to consider diff --git a/model/class-a-end-device-lorawan-mac.cc b/model/class-a-end-device-lorawan-mac.cc index e85c9db4c8..a40748b0c4 100644 --- a/model/class-a-end-device-lorawan-mac.cc +++ b/model/class-a-end-device-lorawan-mac.cc @@ -14,11 +14,10 @@ #include "end-device-lora-phy.h" #include "end-device-lorawan-mac.h" +#include "lora-tag.h" #include "ns3/log.h" -#include - namespace ns3 { namespace lorawan @@ -75,10 +74,10 @@ ClassAEndDeviceLorawanMac::SendToPhy(Ptr packetToSend) NS_LOG_DEBUG("PacketToSend: " << packetToSend); // Data rate adaptation as in LoRaWAN specification, V1.0.2 (2016) - if (m_enableDRAdapt && (m_dataRate > 0) && (m_retxParams.retxLeft < m_maxNumbTx) && + if (m_enableDRAdapt && (m_dataRate > 0) && (m_retxParams.retxLeft < m_nbTrans) && (m_retxParams.retxLeft % 2 == 0)) { - m_txPower = 14; // Reset transmission power + m_txPowerDbm = 14; // Reset transmission power m_dataRate = m_dataRate - 1; } @@ -97,7 +96,7 @@ ClassAEndDeviceLorawanMac::SendToPhy(Ptr packetToSend) Ptr txChannel = GetChannelForTx(); NS_LOG_DEBUG("PacketToSend: " << packetToSend); - m_phy->Send(packetToSend, params, txChannel->GetFrequency(), m_txPower); + m_phy->Send(packetToSend, params, txChannel->GetFrequency(), m_txPowerDbm); ////////////////////////////////////////////// // Register packet transmission for duty cycle @@ -166,6 +165,11 @@ ClassAEndDeviceLorawanMac::Receive(Ptr packet) // THIS WILL BE GetReceiveWindow() Simulator::Cancel(m_secondReceiveWindow); + LoraTag tag; + packet->PeekPacketTag(tag); + /// \see ns3::lorawan::AdrComponent::RxPowerToSNR + m_lastRxSnr = tag.GetReceivePower() + 174 - 10 * log10(125000) - 6; + // Parse the MAC commands ParseCommands(fHdr); @@ -187,7 +191,7 @@ ClassAEndDeviceLorawanMac::Receive(Ptr packet) { if (m_retxParams.retxLeft == 0) { - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, @@ -218,7 +222,7 @@ ClassAEndDeviceLorawanMac::Receive(Ptr packet) } else { - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs) << " transmissions."); @@ -249,7 +253,7 @@ ClassAEndDeviceLorawanMac::FailedReception(Ptr packet) } else { - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs) << " transmissions."); @@ -352,10 +356,10 @@ ClassAEndDeviceLorawanMac::OpenSecondReceiveWindow() DynamicCast(m_phy)->SwitchToStandby(); // Switch to appropriate channel and data rate - NS_LOG_INFO("Using parameters: " << m_secondReceiveWindowFrequency << "Hz, DR" + NS_LOG_INFO("Using parameters: " << m_secondReceiveWindowFrequencyMHz << "MHz, DR" << unsigned(m_secondReceiveWindowDataRate)); - DynamicCast(m_phy)->SetFrequency(m_secondReceiveWindowFrequency); + DynamicCast(m_phy)->SetFrequency(m_secondReceiveWindowFrequencyMHz); DynamicCast(m_phy)->SetSpreadingFactor( GetSfFromDataRate(m_secondReceiveWindowDataRate)); @@ -412,7 +416,7 @@ ClassAEndDeviceLorawanMac::CloseSecondReceiveWindow() else if (m_retxParams.retxLeft == 0 && DynamicCast(m_phy)->GetState() != EndDeviceLoraPhy::RX) { - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs) << " transmissions."); @@ -428,7 +432,7 @@ ClassAEndDeviceLorawanMac::CloseSecondReceiveWindow() } else { - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, true, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_INFO( "We have " << unsigned(m_retxParams.retxLeft) @@ -444,7 +448,7 @@ ClassAEndDeviceLorawanMac::CloseSecondReceiveWindow() ///////////////////////// Time -ClassAEndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitingTime) +ClassAEndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitTime) { NS_LOG_FUNCTION_NOARGS(); @@ -465,8 +469,8 @@ ClassAEndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitingTime) Seconds(m_receiveWindowDurationInSymbols * tSym); NS_LOG_DEBUG("Duration until endSecondRxWindow for new transmission:" - << (endSecondRxWindow - Simulator::Now()).GetSeconds()); - waitingTime = std::max(waitingTime, endSecondRxWindow - Simulator::Now()); + << (endSecondRxWindow - Now()).As(Time::S)); + waitTime = Max(waitTime, endSecondRxWindow - Now()); } } // This is a retransmitted packet, it can not be sent until the end of @@ -476,15 +480,15 @@ ClassAEndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitingTime) double ack_timeout = m_uniformRV->GetValue(1, 3); // Compute the duration until ACK_TIMEOUT (It may be a negative number, but it doesn't // matter.) - Time retransmitWaitingTime = - Time(m_secondReceiveWindow.GetTs()) - Simulator::Now() + Seconds(ack_timeout); + Time retransmitWaitTime = + Time(m_secondReceiveWindow.GetTs()) - Now() + Seconds(ack_timeout); - NS_LOG_DEBUG("ack_timeout:" << ack_timeout << " retransmitWaitingTime:" - << retransmitWaitingTime.GetSeconds()); - waitingTime = std::max(waitingTime, retransmitWaitingTime); + NS_LOG_DEBUG("ack_timeout:" << ack_timeout + << " retransmitWaitTime:" << retransmitWaitTime.As(Time::S)); + waitTime = Max(waitTime, retransmitWaitTime); } - return waitingTime; + return waitTime; } uint8_t @@ -508,13 +512,13 @@ ClassAEndDeviceLorawanMac::GetSecondReceiveWindowDataRate() const void ClassAEndDeviceLorawanMac::SetSecondReceiveWindowFrequency(double frequencyMHz) { - m_secondReceiveWindowFrequency = frequencyMHz; + m_secondReceiveWindowFrequencyMHz = frequencyMHz; } double ClassAEndDeviceLorawanMac::GetSecondReceiveWindowFrequency() const { - return m_secondReceiveWindowFrequency; + return m_secondReceiveWindowFrequencyMHz; } ///////////////////////// @@ -522,39 +526,48 @@ ClassAEndDeviceLorawanMac::GetSecondReceiveWindowFrequency() const ///////////////////////// void -ClassAEndDeviceLorawanMac::OnRxClassParamSetupReq(Ptr rxParamSetupReq) +ClassAEndDeviceLorawanMac::OnRxParamSetupReq(uint8_t rx1DrOffset, + uint8_t rx2DataRate, + double frequencyHz) { - NS_LOG_FUNCTION(this << rxParamSetupReq); + NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) + << uint32_t(frequencyHz)); - bool offsetOk = true; - bool dataRateOk = true; + // Adapted from: github.com/Lora-net/SWL2001.git v4.3.1 + // For the time being, this implementation is valid for the EU868 region - uint8_t rx1DrOffset = rxParamSetupReq->GetRx1DrOffset(); - uint8_t rx2DataRate = rxParamSetupReq->GetRx2DataRate(); - double frequency = rxParamSetupReq->GetFrequency(); + bool rx1DrOffsetAck = true; + bool rx2DataRateAck = true; + bool channelAck = true; - NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency); + if (rx1DrOffset >= m_replyDataRateMatrix.at(m_dataRate).size()) + { + NS_LOG_WARN("Invalid rx1DrOffset"); + rx1DrOffsetAck = false; + } - // Check that the desired offset is valid - if (!(0 <= rx1DrOffset && rx1DrOffset <= 5)) + if (!GetSfFromDataRate(rx2DataRate) || !GetBandwidthFromDataRate(rx2DataRate)) { - offsetOk = false; + NS_LOG_WARN("Invalid rx2DataRate"); + rx2DataRateAck = false; } - // Check that the desired data rate is valid - if (GetSfFromDataRate(rx2DataRate) == 0 || GetBandwidthFromDataRate(rx2DataRate) == 0) + if (!m_channelHelper->IsFrequencyValid(frequencyHz / 1e6)) { - dataRateOk = false; + NS_LOG_WARN("Invalid rx2 frequency"); + channelAck = false; } - // For now, don't check for validity of frequency - m_secondReceiveWindowDataRate = rx2DataRate; - m_rx1DrOffset = rx1DrOffset; - m_secondReceiveWindowFrequency = frequency; + if (rx1DrOffsetAck && rx2DataRateAck && channelAck) + { + m_rx1DrOffset = rx1DrOffset; + m_secondReceiveWindowDataRate = rx2DataRate; + m_secondReceiveWindowFrequencyMHz = frequencyHz / 1e6; + } - // Craft a RxParamSetupAns as response NS_LOG_INFO("Adding RxParamSetupAns reply"); - m_macCommandList.emplace_back(CreateObject(offsetOk, dataRateOk, true)); + m_macCommandList.emplace_back( + Create(rx1DrOffsetAck, rx2DataRateAck, channelAck)); } } /* namespace lorawan */ diff --git a/model/class-a-end-device-lorawan-mac.h b/model/class-a-end-device-lorawan-mac.h index d85c6422e8..e3d585ed58 100644 --- a/model/class-a-end-device-lorawan-mac.h +++ b/model/class-a-end-device-lorawan-mac.h @@ -67,8 +67,21 @@ class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac */ void Receive(Ptr packet) override; + /** + * Function called by lower layers to inform this layer that reception of a + * packet we were locked on failed. + * + * \param packet The packet we failed to receive. + */ void FailedReception(Ptr packet) override; + /** + * Perform the actions that are required after a packet send. + * + * This function handles opening of the first receive window. + * + * \param packet The packet that has just been transmitted. + */ void TxFinished(Ptr packet) override; /** @@ -96,14 +109,14 @@ class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac ///////////////////////// /** - * Find the minimum waiting time before the next possible transmission based + * Find the minimum wait time before the next possible transmission based * on end device's Class Type. * - * \param waitingTime The minimum waiting time that has to be respected, + * \param waitTime The minimum wait time that has to be respected, * irrespective of the class (e.g., because of duty cycle limitations). * \return The Time value. */ - Time GetNextClassTransmissionDelay(Time waitingTime) override; + Time GetNextClassTransmissionDelay(Time waitTime) override; /** * Get the data rate that will be used in the first receive window. @@ -144,16 +157,7 @@ class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac // MAC command methods // ///////////////////////// - /** - * Perform the actions that need to be taken when receiving a RxParamSetupReq - * command based on the Device's Class Type. - * - * \param rxParamSetupReq The Parameter Setup Request, which contains: - * - The offset to set. - * - The data rate to use for the second receive window. - * - The frequency to use for the second receive window. - */ - void OnRxClassParamSetupReq(Ptr rxParamSetupReq) override; + void OnRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz) override; private: Time m_receiveDelay1; //!< The interval between when a packet is done sending and when the first @@ -188,9 +192,9 @@ class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac EventId m_secondReceiveWindow; /** - * The frequency to listen on for the second receive window. + * The frequency [MHz] to listen on for the second receive window. */ - double m_secondReceiveWindowFrequency; + double m_secondReceiveWindowFrequencyMHz; /** * The data rate to listen for during the second downlink transmission. diff --git a/model/end-device-lora-phy.cc b/model/end-device-lora-phy.cc index fcc8c1d868..f54e0c286b 100644 --- a/model/end-device-lora-phy.cc +++ b/model/end-device-lora-phy.cc @@ -62,7 +62,7 @@ EndDeviceLoraPhy::GetTypeId() // These will then be changed by helpers. EndDeviceLoraPhy::EndDeviceLoraPhy() : m_state(SLEEP), - m_frequency(868.1), + m_frequencyMHz(868.1), m_sf(7) { } @@ -97,13 +97,13 @@ EndDeviceLoraPhy::IsTransmitting() bool EndDeviceLoraPhy::IsOnFrequency(double frequencyMHz) { - return m_frequency == frequencyMHz; + return m_frequencyMHz == frequencyMHz; } void EndDeviceLoraPhy::SetFrequency(double frequencyMHz) { - m_frequency = frequencyMHz; + m_frequencyMHz = frequencyMHz; } void diff --git a/model/end-device-lora-phy.h b/model/end-device-lora-phy.h index c55d460e58..65cbdf3524 100644 --- a/model/end-device-lora-phy.h +++ b/model/end-device-lora-phy.h @@ -263,7 +263,7 @@ class EndDeviceLoraPhy : public LoraPhy // static const double sensitivity[6]; //!< The sensitivity vector of this device to different // SFs - double m_frequency; //!< The frequency this device is listening on + double m_frequencyMHz; //!< The frequency [MHz] this device is listening on uint8_t m_sf; //!< The Spreading Factor this device is listening for diff --git a/model/end-device-lorawan-mac.cc b/model/end-device-lorawan-mac.cc index 449730ac1f..011a9e1822 100644 --- a/model/end-device-lorawan-mac.cc +++ b/model/end-device-lorawan-mac.cc @@ -14,10 +14,11 @@ #include "class-a-end-device-lorawan-mac.h" #include "end-device-lora-phy.h" +#include "ns3/energy-source-container.h" #include "ns3/log.h" #include "ns3/simulator.h" -#include +#include namespace ns3 { @@ -49,35 +50,36 @@ EndDeviceLorawanMac::GetTypeId() MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_dataRate), "ns3::TracedValueCallback::uint8_t") .AddAttribute( - "DRControl", - "Whether to request the network server to control this device's data rate", - BooleanValue(), - MakeBooleanAccessor(&EndDeviceLorawanMac::m_controlDataRate), + "ADR", + "Ensure to the network server that this device will accept data rate, transmission " + "power and number of retransmissions configurations received via LinkADRReq.", + BooleanValue(true), + MakeBooleanAccessor(&EndDeviceLorawanMac::m_adr), MakeBooleanChecker()) .AddTraceSource("TxPower", - "Transmission power currently employed by this end device", - MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_txPower), + "Transmission ERP [dBm] currently employed by this end device", + MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_txPowerDbm), "ns3::TracedValueCallback::Double") .AddTraceSource("LastKnownLinkMargin", "Last known demodulation margin in " "communications between this end device " "and a gateway", - MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_lastKnownLinkMargin), - "ns3::TracedValueCallback::Double") + MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_lastKnownLinkMarginDb), + "ns3::TracedValueCallback::uint8_t") .AddTraceSource("LastKnownGatewayCount", "Last known number of gateways able to " "listen to this end device", MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_lastKnownGatewayCount), - "ns3::TracedValueCallback::Int") + "ns3::TracedValueCallback::uint8_t") .AddTraceSource("AggregatedDutyCycle", "Aggregate duty cycle, in fraction form, " "this end device must respect", MakeTraceSourceAccessor(&EndDeviceLorawanMac::m_aggregatedDutyCycle), "ns3::TracedValueCallback::Double") .AddAttribute("MaxTransmissions", - "Maximum number of transmissions for a packet", - IntegerValue(8), - MakeIntegerAccessor(&EndDeviceLorawanMac::m_maxNumbTx), + "Maximum number of transmissions for a packet (NbTrans)", + IntegerValue(1), + MakeIntegerAccessor(&EndDeviceLorawanMac::m_nbTrans), MakeIntegerChecker()) .AddAttribute("EnableEDDataRateAdaptation", "Whether the end device should up its data rate " @@ -92,16 +94,15 @@ EndDeviceLorawanMac::GetTypeId() MakeEnumChecker(LorawanMacHeader::UNCONFIRMED_DATA_UP, "Unconfirmed", LorawanMacHeader::CONFIRMED_DATA_UP, - "Confirmed")) - .AddConstructor(); + "Confirmed")); return tid; } EndDeviceLorawanMac::EndDeviceLorawanMac() : m_enableDRAdapt(false), - m_maxNumbTx(8), + m_nbTrans(1), m_dataRate(0), - m_txPower(14), + m_txPowerDbm(14), m_codingRate(1), // LoraWAN default m_headerDisabled(false), @@ -109,9 +110,10 @@ EndDeviceLorawanMac::EndDeviceLorawanMac() m_address(LoraDeviceAddress(0)), // LoraWAN default m_receiveWindowDurationInSymbols(8), - // LoraWAN default - m_controlDataRate(false), - m_lastKnownLinkMargin(0), + // Max initial value + m_lastRxSnr(32), + m_adr(true), + m_lastKnownLinkMarginDb(0), m_lastKnownGatewayCount(0), m_aggregatedDutyCycle(1), m_mType(LorawanMacHeader::CONFIRMED_DATA_UP), @@ -129,7 +131,7 @@ EndDeviceLorawanMac::EndDeviceLorawanMac() // Initialize structure for retransmission parameters m_retxParams = EndDeviceLorawanMac::LoraRetxParameters(); - m_retxParams.retxLeft = m_maxNumbTx; + m_retxParams.retxLeft = m_nbTrans; } EndDeviceLorawanMac::~EndDeviceLorawanMac() @@ -150,7 +152,7 @@ EndDeviceLorawanMac::Send(Ptr packet) // or because we are receiving, schedule a tx/retx later Time netxTxDelay = GetNextTransmissionDelay(); - if (netxTxDelay != Seconds(0)) + if (netxTxDelay.IsStrictlyPositive()) { postponeTransmission(netxTxDelay, packet); return; @@ -175,7 +177,7 @@ EndDeviceLorawanMac::Send(Ptr packet) // retransmissions { // Make sure we can transmit at the current power on this channel - NS_ASSERT_MSG(m_txPower <= m_channelHelper->GetTxPowerForChannel(txChannel), + NS_ASSERT_MSG(m_txPowerDbm <= m_channelHelper->GetTxPowerForChannel(txChannel), " The selected power is too high to be supported by this channel."); DoSend(packet); } @@ -190,7 +192,7 @@ EndDeviceLorawanMac::postponeTransmission(Time netxTxDelay, Ptr packet) m_nextTx = Simulator::Schedule(netxTxDelay, &EndDeviceLorawanMac::DoSend, this, packet); NS_LOG_WARN("Attempting to send, but the aggregate duty cycle won't allow it. Scheduling a tx " "at a delay " - << netxTxDelay.GetSeconds() << "."); + << netxTxDelay.As(Time::S) << "."); } void @@ -210,7 +212,8 @@ EndDeviceLorawanMac::DoSend(Ptr packet) ApplyNecessaryOptions(frameHdr); packet->AddHeader(frameHdr); - NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes."); + auto fhdrSize = frameHdr.GetSerializedSize(); + NS_LOG_INFO("Added frame header of size " << fhdrSize << " bytes."); // Check that MACPayload length is below the allowed maximum if (packet->GetSize() > m_maxAppPayloadForDataRate.at(m_dataRate)) @@ -232,12 +235,12 @@ EndDeviceLorawanMac::DoSend(Ptr packet) if (m_retxParams.waitingAck) { // Call the callback to notify about the failure - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_DEBUG(" Received new packet from the application layer: stopping retransmission " "procedure. Used " << unsigned(txs) << " transmissions out of a maximum of " - << unsigned(m_maxNumbTx) << "."); + << unsigned(m_nbTrans) << "."); } // Reset retransmission parameters @@ -248,9 +251,9 @@ EndDeviceLorawanMac::DoSend(Ptr packet) if (m_mType == LorawanMacHeader::CONFIRMED_DATA_UP) { m_retxParams.packet = packet->Copy(); - m_retxParams.retxLeft = m_maxNumbTx; + m_retxParams.retxLeft = m_nbTrans; m_retxParams.waitingAck = true; - m_retxParams.firstAttempt = Simulator::Now(); + m_retxParams.firstAttempt = Now(); m_retxParams.retxLeft = m_retxParams.retxLeft - 1; // decreasing the number of retransmissions @@ -258,7 +261,8 @@ EndDeviceLorawanMac::DoSend(Ptr packet) NS_LOG_DEBUG("It is a confirmed packet. Setting retransmission parameters and " "decreasing the number of transmissions left."); - NS_LOG_INFO("Added MAC header of size " << macHdr.GetSerializedSize() << " bytes."); + auto mhdrSize = macHdr.GetSerializedSize(); + NS_LOG_INFO("Added MAC header of size " << mhdrSize << " bytes."); // Sent a new packet NS_LOG_DEBUG("Copied packet: " << m_retxParams.packet); @@ -290,7 +294,8 @@ EndDeviceLorawanMac::DoSend(Ptr packet) ApplyNecessaryOptions(frameHdr); packet->AddHeader(frameHdr); - NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes."); + auto fhdrSize = frameHdr.GetSerializedSize(); + NS_LOG_INFO("Added frame header of size " << fhdrSize << " bytes."); // Add the Lorawan Mac header to the packet macHdr = LorawanMacHeader(); @@ -339,7 +344,7 @@ EndDeviceLorawanMac::ParseCommands(LoraFrameHeader frameHeader) NS_LOG_DEBUG("Reset retransmission variables to default values and cancel " "retransmission if already scheduled."); - uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft); + uint8_t txs = m_nbTrans - (m_retxParams.retxLeft); m_requiredTxCallback(txs, true, m_retxParams.firstAttempt, m_retxParams.packet); NS_LOG_DEBUG("Received ACK packet after " << unsigned(txs) << " transmissions: stopping retransmission procedure. "); @@ -354,84 +359,55 @@ EndDeviceLorawanMac::ParseCommands(LoraFrameHeader frameHeader) } } - std::list> commands = frameHeader.GetCommands(); - std::list>::iterator it; - for (it = commands.begin(); it != commands.end(); it++) + for (const auto& c : frameHeader.GetCommands()) { NS_LOG_DEBUG("Iterating over the MAC commands..."); - enum MacCommandType type = (*it)->GetCommandType(); + enum MacCommandType type = (c)->GetCommandType(); switch (type) { case (LINK_CHECK_ANS): { NS_LOG_DEBUG("Detected a LinkCheckAns command."); - - // Cast the command - Ptr linkCheckAns = DynamicCast(*it); - - // Call the appropriate function to take action + auto linkCheckAns = DynamicCast(c); OnLinkCheckAns(linkCheckAns->GetMargin(), linkCheckAns->GetGwCnt()); - break; } case (LINK_ADR_REQ): { NS_LOG_DEBUG("Detected a LinkAdrReq command."); - - // Cast the command - Ptr linkAdrReq = DynamicCast(*it); - - // Call the appropriate function to take action + auto linkAdrReq = DynamicCast(c); OnLinkAdrReq(linkAdrReq->GetDataRate(), linkAdrReq->GetTxPower(), - linkAdrReq->GetEnabledChannelsList(), - linkAdrReq->GetRepetitions()); - + linkAdrReq->GetChMask(), + linkAdrReq->GetChMaskCntl(), + linkAdrReq->GetNbTrans()); break; } case (DUTY_CYCLE_REQ): { NS_LOG_DEBUG("Detected a DutyCycleReq command."); - - // Cast the command - Ptr dutyCycleReq = DynamicCast(*it); - - // Call the appropriate function to take action - OnDutyCycleReq(dutyCycleReq->GetMaximumAllowedDutyCycle()); - + auto dutyCycleReq = DynamicCast(c); + OnDutyCycleReq(dutyCycleReq->GetMaxDutyCycle()); break; } case (RX_PARAM_SETUP_REQ): { NS_LOG_DEBUG("Detected a RxParamSetupReq command."); - - // Cast the command - Ptr rxParamSetupReq = DynamicCast(*it); - - // Call the appropriate function to take action - OnRxParamSetupReq(rxParamSetupReq); - + auto rxParamSetupReq = DynamicCast(c); + OnRxParamSetupReq(rxParamSetupReq->GetRx1DrOffset(), + rxParamSetupReq->GetRx2DataRate(), + rxParamSetupReq->GetFrequency()); break; } case (DEV_STATUS_REQ): { NS_LOG_DEBUG("Detected a DevStatusReq command."); - - // Cast the command - Ptr devStatusReq = DynamicCast(*it); - - // Call the appropriate function to take action + auto devStatusReq = DynamicCast(c); OnDevStatusReq(); - break; } case (NEW_CHANNEL_REQ): { NS_LOG_DEBUG("Detected a NewChannelReq command."); - - // Cast the command - Ptr newChannelReq = DynamicCast(*it); - - // Call the appropriate function to take action + auto newChannelReq = DynamicCast(c); OnNewChannelReq(newChannelReq->GetChannelIndex(), newChannelReq->GetFrequency(), newChannelReq->GetMinDataRate(), newChannelReq->GetMaxDataRate()); - break; } case (RX_TIMING_SETUP_REQ): @@ -453,7 +429,7 @@ EndDeviceLorawanMac::ApplyNecessaryOptions(LoraFrameHeader& frameHeader) frameHeader.SetAsUplink(); frameHeader.SetFPort(1); // TODO Use an appropriate frame port based on the application frameHeader.SetAddress(m_address); - frameHeader.SetAdr(m_controlDataRate); + frameHeader.SetAdr(m_adr); frameHeader.SetAdrAckReq(false); // TODO Set ADRACKREQ if a member variable is true // FPending does not exist in uplink messages @@ -497,102 +473,66 @@ EndDeviceLorawanMac::TxFinished(Ptr packet) } Time -EndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitingTime) +EndDeviceLorawanMac::GetNextClassTransmissionDelay(Time waitTime) { NS_LOG_FUNCTION_NOARGS(); - return waitingTime; + return waitTime; } Time EndDeviceLorawanMac::GetNextTransmissionDelay() { - NS_LOG_FUNCTION_NOARGS(); - - // Check duty cycle // - - // Pick a random channel to transmit on - std::vector> logicalChannels; - logicalChannels = - m_channelHelper->GetEnabledChannelList(); // Use a separate list to do the shuffle - // logicalChannels = Shuffle (logicalChannels); - - Time waitingTime = Time::Max(); - - // Try every channel - std::vector>::iterator it; - for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it) + NS_LOG_FUNCTION(this); + // Check duty cycle + /// \todo possibly move to LogicalChannelHelper + auto waitTime = Time::Max(); + for (const auto& channel : m_channelHelper->GetRawChannelArray()) { - // Pointer to the current channel - Ptr logicalChannel = *it; - double frequency = logicalChannel->GetFrequency(); - - waitingTime = std::min(waitingTime, m_channelHelper->GetWaitingTime(logicalChannel)); - - NS_LOG_DEBUG("Waiting time before the next transmission in channel with frequency " - << frequency << " is = " << waitingTime.GetSeconds() << "."); + if (channel && channel->IsEnabledForUplink()) // Skip empty frequency channel slots + { + auto curr = m_channelHelper->GetWaitTime(channel); + if (curr < waitTime) + { + waitTime = curr; + } + NS_LOG_DEBUG("frequency=" << channel->GetFrequency() << "MHz," + << " waitTime=" << waitTime.As(Time::S)); + } } - - waitingTime = GetNextClassTransmissionDelay(waitingTime); - - return waitingTime; + return GetNextClassTransmissionDelay(waitTime); } Ptr EndDeviceLorawanMac::GetChannelForTx() { - NS_LOG_FUNCTION_NOARGS(); - - // Pick a random channel to transmit on - std::vector> logicalChannels; - logicalChannels = - m_channelHelper->GetEnabledChannelList(); // Use a separate list to do the shuffle - logicalChannels = Shuffle(logicalChannels); - - // Try every channel - std::vector>::iterator it; - for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it) + NS_LOG_FUNCTION(this); + /// \todo possibly move to LogicalChannelHelper + std::vector> candidates; + for (const auto& channel : m_channelHelper->GetRawChannelArray()) { - // Pointer to the current channel - Ptr logicalChannel = *it; - double frequency = logicalChannel->GetFrequency(); - - NS_LOG_DEBUG("Frequency of the current channel: " << frequency); - - // Verify that we can send the packet - Time waitingTime = m_channelHelper->GetWaitingTime(logicalChannel); - - NS_LOG_DEBUG("Waiting time for current channel = " << waitingTime.GetSeconds()); - - // Send immediately if we can - if (waitingTime == Seconds(0)) + if (channel && channel->IsEnabledForUplink()) // Skip empty frequency channel slots { - return *it; - } - else - { - NS_LOG_DEBUG("Packet cannot be immediately transmitted on " - << "the current channel because of duty cycle limitations."); + uint8_t minDr = channel->GetMinimumDataRate(); + uint8_t maxDr = channel->GetMaximumDataRate(); + Time waitTime = m_channelHelper->GetWaitTime(channel); + NS_LOG_DEBUG("Enabled channel: frequency=" + << channel->GetFrequency() << "MHz, minDr=" << unsigned(minDr) + << ", maxDr=" << unsigned(maxDr) << ", waitTime=" << waitTime.As(Time::S)); + if (m_dataRate >= minDr && m_dataRate <= maxDr && waitTime.IsZero()) + { + candidates.emplace_back(channel); + } } } - return nullptr; // In this case, no suitable channel was found -} - -std::vector> -EndDeviceLorawanMac::Shuffle(std::vector> vector) -{ - NS_LOG_FUNCTION_NOARGS(); - - int size = vector.size(); - - for (int i = 0; i < size; ++i) + if (candidates.empty()) { - uint16_t random = std::floor(m_uniformRV->GetValue(0, size)); - Ptr temp = vector.at(random); - vector.at(random) = vector.at(i); - vector.at(i) = temp; + NS_LOG_DEBUG("No suitable TX channel found"); + return nullptr; } - - return vector; + uint8_t i = m_uniformRV->GetInteger(0, candidates.size() - 1); + auto channel = candidates.at(i); + NS_LOG_DEBUG("Selected channel with frequency=" << channel->GetFrequency() << "MHz"); + return channel; } ///////////////////////// @@ -603,40 +543,41 @@ void EndDeviceLorawanMac::resetRetransmissionParameters() { m_retxParams.waitingAck = false; - m_retxParams.retxLeft = m_maxNumbTx; + m_retxParams.retxLeft = m_nbTrans; m_retxParams.packet = nullptr; - m_retxParams.firstAttempt = Seconds(0); + m_retxParams.firstAttempt = Time(0); // Cancel next retransmissions, if any Simulator::Cancel(m_nextTx); } void -EndDeviceLorawanMac::SetDataRateAdaptation(bool adapt) +EndDeviceLorawanMac::SetUplinkAdrBit(bool adr) { - NS_LOG_FUNCTION(this << adapt); - m_enableDRAdapt = adapt; + NS_LOG_FUNCTION(this << adr); + m_adr = adr; } bool -EndDeviceLorawanMac::GetDataRateAdaptation() const +EndDeviceLorawanMac::GetUplinkAdrBit() const { - return m_enableDRAdapt; + NS_LOG_FUNCTION(this); + return m_adr; } void -EndDeviceLorawanMac::SetMaxNumberOfTransmissions(uint8_t maxNumbTx) +EndDeviceLorawanMac::SetMaxNumberOfTransmissions(uint8_t nbTrans) { - NS_LOG_FUNCTION(this << unsigned(maxNumbTx)); - m_maxNumbTx = maxNumbTx; - m_retxParams.retxLeft = maxNumbTx; + NS_LOG_FUNCTION(this << unsigned(nbTrans)); + m_nbTrans = nbTrans; + m_retxParams.retxLeft = nbTrans; } uint8_t EndDeviceLorawanMac::GetMaxNumberOfTransmissions() { NS_LOG_FUNCTION(this); - return m_maxNumbTx; + return m_nbTrans; } void @@ -655,6 +596,20 @@ EndDeviceLorawanMac::GetDataRate() return m_dataRate; } +void +EndDeviceLorawanMac::SetTransmissionPowerDbm(double txPowerDbm) +{ + NS_LOG_FUNCTION(this << txPowerDbm); + m_txPowerDbm = txPowerDbm; +} + +double +EndDeviceLorawanMac::GetTransmissionPowerDbm() +{ + NS_LOG_FUNCTION(this); + return m_txPowerDbm; +} + void EndDeviceLorawanMac::SetDeviceAddress(LoraDeviceAddress address) { @@ -676,150 +631,201 @@ EndDeviceLorawanMac::OnLinkCheckAns(uint8_t margin, uint8_t gwCnt) { NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt)); - m_lastKnownLinkMargin = margin; + m_lastKnownLinkMarginDb = margin; m_lastKnownGatewayCount = gwCnt; } void EndDeviceLorawanMac::OnLinkAdrReq(uint8_t dataRate, uint8_t txPower, - std::list enabledChannels, - int repetitions) + uint16_t chMask, + uint8_t chMaskCntl, + uint8_t nbTrans) { - NS_LOG_FUNCTION(this << unsigned(dataRate) << unsigned(txPower) << repetitions); + NS_LOG_FUNCTION(this << unsigned(dataRate) << unsigned(txPower) << std::bitset<16>(chMask) + << unsigned(chMaskCntl) << unsigned(nbTrans)); + + // Adapted from: github.com/Lora-net/SWL2001.git v4.3.1 + // For the time being, this implementation is valid for the EU868 region + + NS_ASSERT_MSG(!(dataRate & 0xF0), "dataRate field > 4 bits"); + NS_ASSERT_MSG(!(txPower & 0xF0), "txPower field > 4 bits"); + NS_ASSERT_MSG(!(chMaskCntl & 0xF8), "chMaskCntl field > 3 bits"); + NS_ASSERT_MSG(!(nbTrans & 0xF0), "nbTrans field > 4 bits"); - // Three bools for three requirements before setting things up - bool channelMaskOk = true; - bool dataRateOk = true; - bool txPowerOk = true; + auto channels = m_channelHelper->GetRawChannelArray(); - // Check the channel mask - ///////////////////////// - // Check whether all specified channels exist on this device - auto channelList = m_channelHelper->GetChannelList(); - int channelListSize = channelList.size(); + bool channelMaskAck = true; + bool dataRateAck = true; + bool powerAck = true; - for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++) + NS_LOG_DEBUG("Channel mask = " << std::bitset<16>(chMask) + << ", ChMaskCtrl = " << unsigned(chMaskCntl)); + + // Check channel mask + switch (chMaskCntl) { - if ((*it) > channelListSize) + // Channels 0 to 15 + case 0: + // Check if all enabled channels have a valid frequency + for (size_t i = 0; i < channels.size(); ++i) { - channelMaskOk = false; - break; + if ((chMask & 0b1 << i) && !channels.at(i)) + { + NS_LOG_WARN("Invalid channel mask"); + channelMaskAck = false; + break; // break for loop + } } + break; + // All channels ON independently of the ChMask field value + case 6: + chMask = 0b0; + for (size_t i = 0; i < channels.size(); ++i) + { + if (channels.at(i)) + { + chMask |= 0b1 << i; + } + } + break; + default: + NS_LOG_WARN("Invalid channel mask ctrl field"); + channelMaskAck = false; + break; } - // Check the dataRate - ///////////////////// - // We need to know we can use it at all - // To assess this, we try and convert it to a spreading factor / bandwidth combination and check - // if those values are valid. Since GetSfFromDataRate and GetBandwidthFromDataRate return 0 if - // the dataRate is not recognized, we can check against this. - uint8_t sf = GetSfFromDataRate(dataRate); - double bw = GetBandwidthFromDataRate(dataRate); - NS_LOG_DEBUG("SF: " << unsigned(sf) << ", BW: " << bw); - if (sf == 0 || bw == 0) + // check if all channels are disabled + if (chMask == 0) { - dataRateOk = false; - NS_LOG_DEBUG("Data rate non valid"); + NS_LOG_WARN("Invalid channel mask"); + channelMaskAck = false; } - // We need to know we can use it in at least one of the enabled channels - // Cycle through available channels, stop when at least one is enabled for the - // specified dataRate. - if (dataRateOk && channelMaskOk) // If false, skip the check + // Temporary channel mask is built and validated + if (!m_adr) // ADR disabled, only consider channel mask conf. { - bool foundAvailableChannel = false; - for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++) + /// \remark Original code considers this to be mobile-mode + if (channelMaskAck) // valid channel mask { - NS_LOG_DEBUG("MinDR: " << unsigned(channelList.at(*it)->GetMinimumDataRate())); - NS_LOG_DEBUG("MaxDR: " << unsigned(channelList.at(*it)->GetMaximumDataRate())); - if (channelList.at(*it)->GetMinimumDataRate() <= dataRate && - channelList.at(*it)->GetMaximumDataRate() >= dataRate) + bool compatible = false; + // Look for enabled channel that supports current data rate. + for (size_t i = 0; i < channels.size(); ++i) { - foundAvailableChannel = true; - break; + if ((chMask & 0b1 << i) && m_dataRate >= channels.at(i)->GetMinimumDataRate() && + m_dataRate <= channels.at(i)->GetMaximumDataRate()) + { // Found compatible channel, break loop + compatible = true; + break; + } + } + if (!compatible) + { + NS_LOG_WARN("Invalid channel mask for current device data rate (ADR off)"); + channelMaskAck = dataRateAck = powerAck = false; // reject all configurations + } + else // apply channel mask configuration + { + for (size_t i = 0; i < channels.size(); ++i) + { + if (auto c = channels.at(i); c) + { + (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink(); + } + } + dataRateAck = powerAck = false; // only ack channel mask } } - - if (!foundAvailableChannel) + else // reject { - dataRateOk = false; - NS_LOG_DEBUG("Available channel not found"); + NS_LOG_WARN("Invalid channel mask"); + dataRateAck = powerAck = false; // reject all configurations } } - - // Check the txPower - //////////////////// - // Check whether we can use this transmission power - if (GetDbmForTxPower(txPower) == 0) - { - txPowerOk = false; - } - - NS_LOG_DEBUG("Finished checking. ChannelMaskOk: " << channelMaskOk << ", " - << "DataRateOk: " << dataRateOk << ", " - << "txPowerOk: " << txPowerOk); - - // If all checks are successful, set parameters up - ////////////////////////////////////////////////// - if (channelMaskOk && dataRateOk && txPowerOk) + else // Server-side ADR is enabled { - // Cycle over all channels in the list - for (uint32_t i = 0; i < m_channelHelper->GetChannelList().size(); i++) + if (dataRate != 0xF) // If value is 0xF, ignore config. { - if (std::find(enabledChannels.begin(), enabledChannels.end(), i) != - enabledChannels.end()) + bool compatible = false; + // Look for enabled channel that supports config. data rate. + for (size_t i = 0; i < channels.size(); ++i) { - m_channelHelper->GetChannelList().at(i)->SetEnabledForUplink(); - NS_LOG_DEBUG("Channel " << i << " enabled"); + if (chMask & 0b1 << i) // all enabled by chMask, even if it was invalid + { + if (const auto& c = channels.at(i); c) // exists + { + if (dataRate >= c->GetMinimumDataRate() && + dataRate <= c->GetMaximumDataRate()) + { // Found compatible channel, break loop + compatible = true; + break; + } + } + else // manages invalid case, checks with defaults + { + if (GetSfFromDataRate(dataRate) && GetBandwidthFromDataRate(dataRate)) + { // Found compatible (invalid) channel, break loop + compatible = true; + break; + } + } + } } - else + // Check if it is acceptable + if (!compatible) { - m_channelHelper->GetChannelList().at(i)->DisableForUplink(); - NS_LOG_DEBUG("Channel " << i << " disabled"); + NS_LOG_WARN("Invalid data rate"); + dataRateAck = false; } } - // Set the data rate - m_dataRate = dataRate; + if (txPower != 0xF) // If value is 0xF, ignore config. + { + // Check if it is acceptable + if (GetDbmForTxPower(txPower) < 0) + { + NS_LOG_WARN("Invalid tx power"); + powerAck = false; + } + } - // Set the transmission power - m_txPower = GetDbmForTxPower(txPower); + // If no error, apply configurations + if (channelMaskAck && dataRateAck && powerAck) + { + for (size_t i = 0; i < channels.size(); ++i) + { + if (auto c = channels.at(i); c) + { + (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink(); + } + } + if (txPower != 0xF) // If value is 0xF, ignore config. + { + m_txPowerDbm = GetDbmForTxPower(txPower); + } + m_nbTrans = (nbTrans == 0) ? 1 : nbTrans; + if (dataRate != 0xF) // If value is 0xF, ignore config. + { + m_dataRate = dataRate; + } + NS_LOG_DEBUG("MacTxDataRateAdr = " << unsigned(m_dataRate)); + NS_LOG_DEBUG("MacTxPower = " << unsigned(m_txPowerDbm) << "dBm"); + NS_LOG_DEBUG("MacNbTrans = " << unsigned(m_nbTrans)); + } } - // Craft a LinkAdrAns MAC command as a response - /////////////////////////////////////////////// - m_macCommandList.emplace_back(CreateObject(txPowerOk, dataRateOk, channelMaskOk)); + NS_LOG_INFO("Adding LinkAdrAns reply"); + m_macCommandList.emplace_back(Create(powerAck, dataRateAck, channelMaskAck)); } void -EndDeviceLorawanMac::OnDutyCycleReq(double dutyCycle) +EndDeviceLorawanMac::OnDutyCycleReq(uint8_t maxDutyCycle) { - NS_LOG_FUNCTION(this << dutyCycle); - - // Make sure we get a value that makes sense - NS_ASSERT(0 <= dutyCycle && dutyCycle < 1); - - // Set the new duty cycle value - m_aggregatedDutyCycle = dutyCycle; - - // Craft a DutyCycleAns as response + NS_LOG_FUNCTION(this << unsigned(maxDutyCycle)); + NS_ASSERT_MSG(!(maxDutyCycle & 0xF0), "maxDutyCycle > 4 bits"); + m_aggregatedDutyCycle = 1 / std::pow(2, maxDutyCycle); NS_LOG_INFO("Adding DutyCycleAns reply"); - m_macCommandList.emplace_back(CreateObject()); -} - -void -EndDeviceLorawanMac::OnRxClassParamSetupReq(Ptr rxParamSetupReq) -{ -} - -void -EndDeviceLorawanMac::OnRxParamSetupReq(Ptr rxParamSetupReq) -{ - NS_LOG_FUNCTION(this << rxParamSetupReq); - - // static_cast(this)->OnRxClassParamSetupReq (rxParamSetupReq); - OnRxClassParamSetupReq(rxParamSetupReq); + m_macCommandList.emplace_back(Create()); } void @@ -827,73 +833,106 @@ EndDeviceLorawanMac::OnDevStatusReq() { NS_LOG_FUNCTION(this); - uint8_t battery = 10; // XXX Fake battery level - uint8_t margin = 10; // XXX Fake margin + uint8_t battery = 255; // could not measure + if (m_device && m_device->GetNode()) + { + if (auto sc = m_device->GetNode()->GetObject(); + sc && sc->GetN() == 1) + { + battery = sc->Get(0)->GetEnergyFraction() * 253 + 1.5; // range 1-254 + } + } + else + { + battery = 0; // external power source + } + + // approximate to nearest integer + double snr = round(m_lastRxSnr); + // clamp value to boundaries + snr = snr < -32 ? -32 : snr > 31 ? 31 : snr; + // cast to 6-bit signed int and store in uint8_t + uint8_t margin = std::bitset<6>(snr).to_ulong(); - // Craft a RxParamSetupAns as response NS_LOG_INFO("Adding DevStatusAns reply"); - m_macCommandList.emplace_back(CreateObject(battery, margin)); + m_macCommandList.emplace_back(Create(battery, margin)); } void EndDeviceLorawanMac::OnNewChannelReq(uint8_t chIndex, - double frequency, + double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate) { - NS_LOG_FUNCTION(this); + NS_LOG_FUNCTION(this << unsigned(chIndex) << uint32_t(frequencyHz) << unsigned(minDataRate) + << unsigned(maxDataRate)); - bool dataRateRangeOk = true; // XXX Check whether the new data rate range is ok - bool channelFrequencyOk = true; // XXX Check whether the frequency is ok + NS_ASSERT_MSG(!(minDataRate & 0xF0), "minDataRate field > 4 bits"); + NS_ASSERT_MSG(!(maxDataRate & 0xF0), "maxDataRate field > 4 bits"); - // TODO Return false if one of the checks above failed - // TODO Create new channel in the LogicalLoraChannelHelper + // Adapted from: github.com/Lora-net/SWL2001.git v4.3.1 + // For the time being, this implementation is valid for the EU868 region - SetLogicalChannel(chIndex, frequency, minDataRate, maxDataRate); + bool dataRateRangeOk = true; + bool channelFrequencyOk = true; - NS_LOG_INFO("Adding NewChannelAns reply"); - m_macCommandList.emplace_back(CreateObject(dataRateRangeOk, channelFrequencyOk)); -} + // Valid Channel Index + if (chIndex < 3 || chIndex > m_channelHelper->GetRawChannelArray().size() - 1) + { + NS_LOG_WARN("[WARNING] Invalid channel index"); + dataRateRangeOk = channelFrequencyOk = false; + } -void -EndDeviceLorawanMac::AddLogicalChannel(double frequency) -{ - NS_LOG_FUNCTION(this << frequency); + // Valid Frequency + if (frequencyHz != 0 && !m_channelHelper->IsFrequencyValid(frequencyHz / 1e6)) + { + NS_LOG_WARN("[WARNING] Invalid frequency"); + channelFrequencyOk = false; + } - m_channelHelper->AddChannel(frequency); -} + // Valid DRMIN/MAX + if (!GetSfFromDataRate(minDataRate) || !GetBandwidthFromDataRate(minDataRate)) + { + NS_LOG_WARN("[WARNING] Invalid DR min"); + dataRateRangeOk = false; + } -void -EndDeviceLorawanMac::AddLogicalChannel(Ptr logicalChannel) -{ - NS_LOG_FUNCTION(this << logicalChannel); + if (!GetSfFromDataRate(maxDataRate) || !GetBandwidthFromDataRate(maxDataRate)) + { + NS_LOG_WARN("[WARNING] Invalid DR max"); + dataRateRangeOk = false; + } - m_channelHelper->AddChannel(logicalChannel); -} + if (maxDataRate < minDataRate) + { + NS_LOG_WARN("[WARNING] Invalid DR max < DR min"); + dataRateRangeOk = false; + } -void -EndDeviceLorawanMac::SetLogicalChannel(uint8_t chIndex, - double frequency, - uint8_t minDataRate, - uint8_t maxDataRate) -{ - NS_LOG_FUNCTION(this << unsigned(chIndex) << frequency << unsigned(minDataRate) - << unsigned(maxDataRate)); + if (dataRateRangeOk && channelFrequencyOk) + { + auto channel = Create(frequencyHz / 1e6, minDataRate, maxDataRate); + (frequencyHz == 0) ? channel->DisableForUplink() : channel->EnableForUplink(); + m_channelHelper->SetChannel(chIndex, channel); + NS_LOG_DEBUG("MacTxFrequency[" << unsigned(chIndex) << "]=" << uint32_t(frequencyHz) + << ", DrMin=" << unsigned(minDataRate) + << ", DrMax=" << unsigned(maxDataRate)); + } - m_channelHelper->SetChannel( - chIndex, - CreateObject(frequency, minDataRate, maxDataRate)); + NS_LOG_INFO("Adding NewChannelAns reply"); + m_macCommandList.emplace_back(Create(dataRateRangeOk, channelFrequencyOk)); } -void -EndDeviceLorawanMac::AddSubBand(double startFrequency, - double endFrequency, - double dutyCycle, - double maxTxPowerDbm) +uint8_t +EndDeviceLorawanMac::GetLastKnownLinkMarginDb() const { - NS_LOG_FUNCTION_NOARGS(); + return m_lastKnownLinkMarginDb; +} - m_channelHelper->AddSubBand(startFrequency, endFrequency, dutyCycle, maxTxPowerDbm); +uint8_t +EndDeviceLorawanMac::GetLastKnownGatewayCount() const +{ + return m_lastKnownGatewayCount; } double @@ -912,10 +951,5 @@ EndDeviceLorawanMac::AddMacCommand(Ptr macCommand) m_macCommandList.push_back(macCommand); } -uint8_t -EndDeviceLorawanMac::GetTransmissionPower() -{ - return m_txPower; -} } // namespace lorawan } // namespace ns3 diff --git a/model/end-device-lorawan-mac.h b/model/end-device-lorawan-mac.h index 5f588f68d9..c802d39810 100644 --- a/model/end-device-lorawan-mac.h +++ b/model/end-device-lorawan-mac.h @@ -83,25 +83,10 @@ class EndDeviceLorawanMac : public LorawanMac // Receiving methods // /////////////////////// - /** - * Receive a packet. - * - * This method is typically registered as a callback in the underlying PHY - * layer so that it's called when a packet is going up the stack. - * - * \param packet The received packet. - */ void Receive(Ptr packet) override; void FailedReception(Ptr packet) override; - /** - * Perform the actions that are required after a packet send. - * - * This function handles opening of the first receive window. - * - * \param packet The packet that has just been transmitted. - */ void TxFinished(Ptr packet) override; ///////////////////////// @@ -114,26 +99,30 @@ class EndDeviceLorawanMac : public LorawanMac virtual void resetRetransmissionParameters(); /** - * Enable data rate adaptation in the retransmitting procedure. + * Signals to the network server that this device will or may not comply with LinkADRReq + * settings (data rate, transmission power and number of retransmissions) received in downlink. * - * \param adapt If the data rate adaptation is enabled or not. + * \param adr The ADR bit. */ - void SetDataRateAdaptation(bool adapt); + void SetUplinkAdrBit(bool adr); /** - * Get if data rate adaptation is enabled or not. + * Get the current value of the device's uplink ADR bit of the LoRaWAN FHDR. * - * \return True if the data rate adaptation is enabled, false if disabled. + * \return true The device will comply with data rate, transmission power and number of + * retransmissions settings received from the network server via LikADRReq. + * \return false Signals to the network server that the device may not comply with the data + * rate, transmission power and number of retransmissions settings received via LikADRReq. */ - bool GetDataRateAdaptation() const; + bool GetUplinkAdrBit() const; /** * Set the max number of unacknowledged redundant transmissions of each packet. If, * after a transmission, any acknowledgement is received, no more are sent for that packet. * - * \param maxNumbTx The number of transmissions. + * \param nbTrans The number of transmissions. */ - void SetMaxNumberOfTransmissions(uint8_t maxNumbTx); + void SetMaxNumberOfTransmissions(uint8_t nbTrans); /** * Get the max number of unacknowledged redundant transmissions of each packet. If, @@ -162,9 +151,16 @@ class EndDeviceLorawanMac : public LorawanMac /** * Get the transmission power this end device is set to use. * - * \return The transmission power this device uses when transmitting. + * \return The transmission ERP [dBm] this device uses when transmitting. */ - virtual uint8_t GetTransmissionPower(); + double GetTransmissionPowerDbm(); + + /** + * Set the transmission power of this end device. + * + * \param txPowerDbm The transmission ERP [dBm] value. + */ + void SetTransmissionPowerDbm(double txPowerDbm); /** * Set the network address of this device. @@ -184,6 +180,26 @@ class EndDeviceLorawanMac : public LorawanMac // uint8_t GetRx1DrOffset (); + /** + * Get the last known link margin from the demodulation floor. + * + * This is intended for asynchronous polling by the Application layer of the device. For + * synchronous behavior provide a callback using the trace system. + * + * \return The last known link margin [dB] + */ + uint8_t GetLastKnownLinkMarginDb() const; + + /** + * Get the last known number of gateways concurrently receiving transmissions from the device. + * + * This is intended for asynchronous polling by the Application layer of the device. For + * synchronous behavior provide a callback using the trace system. + * + * \return The last known number of receiver gateways. + */ + uint8_t GetLastKnownGatewayCount() const; + /** * Get the aggregated duty cycle. * @@ -243,36 +259,34 @@ class EndDeviceLorawanMac : public LorawanMac * * \param dataRate The data rate value of the command. * \param txPower The transmission power value of the command. - * \param enabledChannels A list of the enabled channels. - * \param repetitions The number of repetitions prescribed by the command. + * \param chMask Mask of enabled channels of the command. + * \param chMaskCntl Indicator of the 16 channel bank to apply the chMask to. + * \param nbTrans The number of repetitions prescribed by the command. */ void OnLinkAdrReq(uint8_t dataRate, uint8_t txPower, - std::list enabledChannels, - int repetitions); + uint16_t chMask, + uint8_t chMaskCntl, + uint8_t nbTrans); /** * Perform the actions that need to be taken when receiving a DutyCycleReq command. * - * \param dutyCycle The aggregate duty cycle prescribed by the command, in - * fraction form. - */ - void OnDutyCycleReq(double dutyCycle); - - /** - * Perform the actions that need to be taken when receiving a RxParamSetupReq command. - * - * \param rxParamSetupReq The Parameter Setup Request. + * \param maxDutyCycle The aggregate duty cycle encoded by the command. */ - void OnRxParamSetupReq(Ptr rxParamSetupReq); + void OnDutyCycleReq(uint8_t maxDutyCycle); /** * Perform the actions that need to be taken when receiving a RxParamSetupReq * command based on the Device's Class Type. * - * \param rxParamSetupReq The Parameter Setup Request. + * \param rx1DrOffset The first reception window data rate offset to set. + * \param rx2DataRate The data rate to use for the second receive window. + * \param frequencyHz The frequency [Hz] to use for the second receive window. */ - virtual void OnRxClassParamSetupReq(Ptr rxParamSetupReq); + virtual void OnRxParamSetupReq(uint8_t rx1DrOffset, + uint8_t rx2DataRate, + double frequencyHz) = 0; /** * Perform the actions that need to be taken when receiving a DevStatusReq command. @@ -283,59 +297,15 @@ class EndDeviceLorawanMac : public LorawanMac * Perform the actions that need to be taken when receiving a NewChannelReq command. * * \param chIndex The ChIndex field of the received NewChannelReq command. - * \param frequency The Frequency field of the received NewChannelReq command. + * \param frequencyHz The Frequency [Hz] field of the received NewChannelReq command. * \param minDataRate The MinDR field of the received NewChannelReq command. * \param maxDataRate The MaxDR field of the received NewChannelReq command. */ void OnNewChannelReq(uint8_t chIndex, - double frequency, + double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate); - //////////////////////////////////// - // Logical channel administration // - //////////////////////////////////// - - /** - * Add a logical channel to the helper. - * - * \param frequency The channel's center frequency. - */ - void AddLogicalChannel(double frequency); - - /** - * Set a new logical channel in the helper. - * - * \param chIndex The channel's new index. - * \param frequency The channel's center frequency. - * \param minDataRate The minimum data rate allowed on the channel. - * \param maxDataRate The maximum data rate allowed on the channel. - */ - void SetLogicalChannel(uint8_t chIndex, - double frequency, - uint8_t minDataRate, - uint8_t maxDataRate); - - /** - * Add a logical channel to the helper. - * - * \param logicalChannel The logical channel to add. - */ - void AddLogicalChannel(Ptr logicalChannel); - - /** - * Add a subband to the logical channel helper. - * - * \param startFrequency The SubBand's lowest frequency. - * \param endFrequency The SubBand's highest frequency. - * \param dutyCycle The SubBand's duty cycle, in fraction form. - * \param maxTxPowerDbm The maximum transmission power allowed on the SubBand. - */ - void AddSubBand(double startFrequency, - double endFrequency, - double dutyCycle, - double maxTxPowerDbm); - /** * Add a MAC command to the list of those that will be sent out in the next * packet. @@ -359,23 +329,23 @@ class EndDeviceLorawanMac : public LorawanMac bool m_enableDRAdapt; //!< Enable data rate adaptation (ADR) during the retransmission procedure. - uint8_t - m_maxNumbTx; //!< Default number of unacknowledged redundant transmissions of each packet. + uint8_t m_nbTrans; //!< Default number of unacknowledged redundant transmissions of each packet. TracedValue m_dataRate; //!< The data rate this device is using to transmit. - TracedValue m_txPower; //!< The transmission power this device is using to transmit. - uint8_t m_codingRate; //!< The coding rate used by this device. + TracedValue + m_txPowerDbm; //!< The transmission ERP [dBm] this device is currently using. + uint8_t m_codingRate; //!< The coding rate used by this device. bool m_headerDisabled; //!< Whether or not the LoRa PHY header is disabled for communications by //!< this device. LoraDeviceAddress m_address; //!< The address of this device. /** - * Find the minimum waiting time before the next possible transmission based + * Find the minimum wait time before the next possible transmission based * on end device's Class Type. * - * \param waitingTime Currently known minimum waiting time, possibly raised by this function. - * \return The updated minimum waiting time in Time format. + * \param waitTime Currently known minimum wait time, possibly raised by this function. + * \return The updated minimum wait time in Time format. */ - virtual Time GetNextClassTransmissionDelay(Time waitingTime); + virtual Time GetNextClassTransmissionDelay(Time waitTime); /** * Find a suitable channel for transmission. The channel is chosen among the @@ -409,11 +379,15 @@ class EndDeviceLorawanMac : public LorawanMac struct LoraRetxParameters m_retxParams; /** - * An uniform random variable, used by the Shuffle method to randomly reorder - * the channel list. + * An uniform random variable, used to randomly pick from the channel list. */ Ptr m_uniformRV; + /** + * Used to record the last reception SNR measurement to be included in the DevStatusAns. + */ + double m_lastRxSnr; + ///////////////// // Callbacks // ///////////////// @@ -425,26 +399,17 @@ class EndDeviceLorawanMac : public LorawanMac private: /** - * Randomly shuffle a Ptr vector. - * - * Used to pick a random channel on which to send the packet. + * Find the base minimum wait time before the next possible transmission. * - * \param vector The vector of pointers to logical LoRa channels. - * \return The shuffled vector. - */ - std::vector> Shuffle(std::vector> vector); - - /** - * Find the base minimum waiting time before the next possible transmission. - * - * \return The base minimum waiting time. + * \return The base minimum wait time. */ Time GetNextTransmissionDelay(); - /** - * Whether this device's data rate should be controlled by the network server. - */ - bool m_controlDataRate; + bool m_adr; //!< Uplink ADR bit contained in the FCtrl field of the LoRaWAN FHDR. + //!< Controlled by the device, if set to false signals the network server + //!< that the device may not accept attempts to control the number of + //!< retransmissions, the data rate, or the TX power with downlink + //!< LinkADRReq commands. /** * The event of retransmitting a packet in a consecutive moment if an ACK is not received. @@ -464,12 +429,12 @@ class EndDeviceLorawanMac : public LorawanMac EventId m_nextRetx; /** - * The last known link margin. + * The last known link margin in dB from the demodulation floor. * * This value is obtained (and updated) when a LinkCheckAns Mac command is * received. */ - TracedValue m_lastKnownLinkMargin; + TracedValue m_lastKnownLinkMarginDb; /** * The last known gateway count (i.e., gateways that are in communication @@ -478,7 +443,7 @@ class EndDeviceLorawanMac : public LorawanMac * This value is obtained (and updated) when a LinkCheckAns Mac command is * received. */ - TracedValue m_lastKnownGatewayCount; + TracedValue m_lastKnownGatewayCount; /** * The aggregated duty cycle this device needs to respect across all sub-bands. diff --git a/model/end-device-status.cc b/model/end-device-status.cc index e0a327e838..0c237c26d2 100644 --- a/model/end-device-status.cc +++ b/model/end-device-status.cc @@ -184,10 +184,10 @@ EndDeviceStatus::SetFirstReceiveWindowSpreadingFactor(uint8_t sf) } void -EndDeviceStatus::SetFirstReceiveWindowFrequency(double frequency) +EndDeviceStatus::SetFirstReceiveWindowFrequency(double frequencyMHz) { NS_LOG_FUNCTION_NOARGS(); - m_firstReceiveWindowFrequency = frequency; + m_firstReceiveWindowFrequency = frequencyMHz; } void @@ -198,10 +198,10 @@ EndDeviceStatus::SetSecondReceiveWindowSpreadingFactor(uint8_t sf) } void -EndDeviceStatus::SetSecondReceiveWindowFrequency(double frequency) +EndDeviceStatus::SetSecondReceiveWindowFrequency(double frequencyMHz) { NS_LOG_FUNCTION_NOARGS(); - m_secondReceiveWindowFrequency = frequency; + m_secondReceiveWindowFrequency = frequencyMHz; } void @@ -254,7 +254,7 @@ EndDeviceStatus::InsertReceivedPacket(Ptr receivedPacket, const Ad // Update Information on the received packet ReceivedPacketInfo info; info.sf = tag.GetSpreadingFactor(); - info.frequency = tag.GetFrequency(); + info.frequencyMHz = tag.GetFrequency(); info.packet = receivedPacket; double rcvPower = tag.GetReceivePower(); @@ -288,7 +288,7 @@ EndDeviceStatus::InsertReceivedPacket(Ptr receivedPacket, const Ad GatewayList& gwList = it->second.gwList; PacketInfoPerGw gwInfo; - gwInfo.receivedTime = Simulator::Now(); + gwInfo.receivedTime = Now(); gwInfo.rxPower = rcvPower; gwInfo.gwAddress = gwAddress; gwList.insert(std::pair(gwAddress, gwInfo)); @@ -302,7 +302,7 @@ EndDeviceStatus::InsertReceivedPacket(Ptr receivedPacket, const Ad { NS_LOG_INFO("Packet was received for the first time"); PacketInfoPerGw gwInfo; - gwInfo.receivedTime = Simulator::Now(); + gwInfo.receivedTime = Now(); gwInfo.rxPower = rcvPower; gwInfo.gwAddress = gwAddress; info.gwList.insert(std::pair(gwAddress, gwInfo)); diff --git a/model/end-device-status.h b/model/end-device-status.h index d7b6f93e02..c5450ddba8 100644 --- a/model/end-device-status.h +++ b/model/end-device-status.h @@ -154,7 +154,7 @@ class EndDeviceStatus : public Object Ptr packet = nullptr; //!< The received packet GatewayList gwList; //!< List of gateways that received this packet uint8_t sf; //!< Spreading factor used to send this packet - double frequency; //!< Carrier frequency [MHz] used to send this packet + double frequencyMHz; //!< Carrier frequency [MHz] used to send this packet }; /** @@ -230,9 +230,9 @@ class EndDeviceStatus : public Object /** * Set the first window frequency of this device. * - * \param frequency The frequency [MHz]. + * \param frequencyMHz The frequency [MHz]. */ - void SetFirstReceiveWindowFrequency(double frequency); + void SetFirstReceiveWindowFrequency(double frequencyMHz); /** * Set the spreading factor this device is using in the second receive window. @@ -244,9 +244,9 @@ class EndDeviceStatus : public Object /** * Set the second window frequency of this device. * - * \param frequency The frequency [MHz]. + * \param frequencyMHz The frequency [MHz]. */ - void SetSecondReceiveWindowFrequency(double frequency); + void SetSecondReceiveWindowFrequency(double frequencyMHz); /** * Set the reply packet mac header. diff --git a/model/gateway-lorawan-mac.cc b/model/gateway-lorawan-mac.cc index 7dae8e43bc..89b4f0bcc5 100644 --- a/model/gateway-lorawan-mac.cc +++ b/model/gateway-lorawan-mac.cc @@ -52,15 +52,15 @@ GatewayLorawanMac::Send(Ptr packet) LoraTag tag; packet->RemovePacketTag(tag); uint8_t dataRate = tag.GetDataRate(); - double frequency = tag.GetFrequency(); + double frequencyMHz = tag.GetFrequency(); NS_LOG_DEBUG("DR: " << unsigned(dataRate)); NS_LOG_DEBUG("SF: " << unsigned(GetSfFromDataRate(dataRate))); NS_LOG_DEBUG("BW: " << GetBandwidthFromDataRate(dataRate)); - NS_LOG_DEBUG("Freq: " << frequency << " MHz"); + NS_LOG_DEBUG("Freq: " << frequencyMHz << " MHz"); packet->AddPacketTag(tag); // Make sure we can transmit this packet - if (m_channelHelper->GetWaitingTime(CreateObject(frequency)) > Time(0)) + if (GetWaitTime(frequencyMHz).IsStrictlyPositive()) { // We cannot send now! NS_LOG_WARN("Trying to send a packet but Duty Cycle won't allow it. Aborting."); @@ -79,17 +79,16 @@ GatewayLorawanMac::Send(Ptr packet) // Get the duration Time duration = LoraPhy::GetOnAirTime(packet, params); - NS_LOG_DEBUG("Duration: " << duration.GetSeconds()); + NS_LOG_DEBUG("Duration: " << duration.As(Time::S)); // Find the channel with the desired frequency - double sendingPower = - m_channelHelper->GetTxPowerForChannel(CreateObject(frequency)); + double sendingPower = m_channelHelper->GetTxPowerForChannel(frequencyMHz); // Add the event to the channelHelper to keep track of duty cycle - m_channelHelper->AddEvent(duration, CreateObject(frequency)); + m_channelHelper->AddEvent(duration, frequencyMHz); // Send the packet to the PHY layer to send it on the channel - m_phy->Send(packet, params, frequency, sendingPower); + m_phy->Send(packet, params, frequencyMHz, sendingPower); m_sentNewPacket(packet); } @@ -139,11 +138,11 @@ GatewayLorawanMac::TxFinished(Ptr packet) } Time -GatewayLorawanMac::GetWaitingTime(double frequency) +GatewayLorawanMac::GetWaitTime(double frequencyMHz) { NS_LOG_FUNCTION_NOARGS(); - return m_channelHelper->GetWaitingTime(CreateObject(frequency)); + return m_channelHelper->GetWaitTime(frequencyMHz); } } // namespace lorawan } // namespace ns3 diff --git a/model/gateway-lorawan-mac.h b/model/gateway-lorawan-mac.h index 30fcc29d47..c174c6dbd7 100644 --- a/model/gateway-lorawan-mac.h +++ b/model/gateway-lorawan-mac.h @@ -56,10 +56,10 @@ class GatewayLorawanMac : public LorawanMac /** * Return the next time at which we will be able to transmit on the specified frequency. * - * \param frequency The frequency value [MHz]. + * \param frequencyMHz The frequency value [MHz]. * \return The next transmission time. */ - Time GetWaitingTime(double frequency); + Time GetWaitTime(double frequencyMHz); private: protected: diff --git a/model/gateway-status.cc b/model/gateway-status.cc index ebbc69dfae..e6235d00d3 100644 --- a/model/gateway-status.cc +++ b/model/gateway-status.cc @@ -41,7 +41,7 @@ GatewayStatus::GatewayStatus(Address address, : m_address(address), m_netDevice(netDevice), m_gatewayMac(gwMac), - m_nextTransmissionTime(Seconds(0)) + m_nextTransmissionTime(Time(0)) { NS_LOG_FUNCTION(this); } @@ -81,12 +81,12 @@ GatewayStatus::GetGatewayMac() } bool -GatewayStatus::IsAvailableForTransmission(double frequency) +GatewayStatus::IsAvailableForTransmission(double frequencyMHz) { // We can't send multiple packets at once, see SX1301 V2.01 page 29 // Check that the gateway was not already "booked" - if (m_nextTransmissionTime > Simulator::Now() - MilliSeconds(1)) + if (m_nextTransmissionTime > Now() - MilliSeconds(1)) { NS_LOG_INFO("This gateway is already booked for a transmission"); return false; @@ -100,11 +100,11 @@ GatewayStatus::IsAvailableForTransmission(double frequency) } // Check that the gateway is not constrained by the duty cycle - Time waitingTime = m_gatewayMac->GetWaitingTime(frequency); - if (waitingTime > Seconds(0)) + Time waitTime = m_gatewayMac->GetWaitTime(frequencyMHz); + if (waitTime.IsStrictlyPositive()) { NS_LOG_INFO("Gateway cannot be used because of duty cycle"); - NS_LOG_INFO("Waiting time at current gateway: " << waitingTime.GetSeconds() << " seconds"); + NS_LOG_INFO("Wait time at current gateway: " << waitTime.As(Time::S)); return false; } diff --git a/model/gateway-status.h b/model/gateway-status.h index fa79d3decb..b8bfb543df 100644 --- a/model/gateway-status.h +++ b/model/gateway-status.h @@ -97,10 +97,11 @@ class GatewayStatus : public Object * Query whether or not this gateway is available for immediate transmission * on this frequency. * - * \param frequency The frequency at which the gateway's availability should be queried. + * \param frequencyMHz The frequency [MHz] at which the gateway's availability should be + * queried. * \return True if the gateway's available, false otherwise. */ - bool IsAvailableForTransmission(double frequency); + bool IsAvailableForTransmission(double frequencyMHz); /** * Set the time of the next scheduled transmission for the gateway. diff --git a/model/logical-lora-channel-helper.cc b/model/logical-lora-channel-helper.cc index a43f87be5e..e88c87af70 100644 --- a/model/logical-lora-channel-helper.cc +++ b/model/logical-lora-channel-helper.cc @@ -8,7 +8,6 @@ #include "logical-lora-channel-helper.h" -#include "ns3/log.h" #include "ns3/simulator.h" namespace ns3 @@ -18,19 +17,8 @@ namespace lorawan NS_LOG_COMPONENT_DEFINE("LogicalLoraChannelHelper"); -NS_OBJECT_ENSURE_REGISTERED(LogicalLoraChannelHelper); - -TypeId -LogicalLoraChannelHelper::GetTypeId() -{ - static TypeId tid = - TypeId("ns3::LogicalLoraChannelHelper").SetParent().SetGroupName("lorawan"); - return tid; -} - -LogicalLoraChannelHelper::LogicalLoraChannelHelper() - : m_nextAggregatedTransmissionTime(Seconds(0)), - m_aggregatedDutyCycle(1) +LogicalLoraChannelHelper::LogicalLoraChannelHelper(uint8_t size) + : m_channelVec(size) { NS_LOG_FUNCTION(this); } @@ -38,223 +26,107 @@ LogicalLoraChannelHelper::LogicalLoraChannelHelper() LogicalLoraChannelHelper::~LogicalLoraChannelHelper() { NS_LOG_FUNCTION(this); + m_subBandList.clear(); + m_channelVec.clear(); } std::vector> -LogicalLoraChannelHelper::GetChannelList() -{ - NS_LOG_FUNCTION(this); - - // Make a copy of the channel vector - std::vector> vector; - vector.reserve(m_channelList.size()); - std::copy(m_channelList.begin(), m_channelList.end(), std::back_inserter(vector)); - - return vector; -} - -std::vector> -LogicalLoraChannelHelper::GetEnabledChannelList() +LogicalLoraChannelHelper::GetRawChannelArray() const { NS_LOG_FUNCTION(this); - - // Make a copy of the channel vector - std::vector> vector; - vector.reserve(m_channelList.size()); - std::copy(m_channelList.begin(), - m_channelList.end(), - std::back_inserter(vector)); // Working on a copy - - std::vector> channels; - std::vector>::iterator it; - for (it = vector.begin(); it != vector.end(); it++) - { - if ((*it)->IsEnabledForUplink()) - { - channels.push_back(*it); - } - } - - return channels; -} - -Ptr -LogicalLoraChannelHelper::GetSubBandFromChannel(Ptr channel) -{ - return GetSubBandFromFrequency(channel->GetFrequency()); + return m_channelVec; } Ptr -LogicalLoraChannelHelper::GetSubBandFromFrequency(double frequency) +LogicalLoraChannelHelper::GetSubBandFromFrequency(double frequencyMHz) const { - // Get the SubBand this frequency belongs to - std::list>::iterator it; - for (it = m_subBandList.begin(); it != m_subBandList.end(); it++) + NS_LOG_FUNCTION(this << frequencyMHz); + for (const auto& sb : m_subBandList) { - if ((*it)->BelongsToSubBand(frequency)) + if (sb->Contains(frequencyMHz)) { - return *it; + return sb; } } - - NS_LOG_ERROR("Requested frequency: " << frequency); - NS_ABORT_MSG("Warning: frequency is outside any known SubBand."); - - return nullptr; // If no SubBand is found, return 0 -} - -void -LogicalLoraChannelHelper::AddChannel(double frequency) -{ - NS_LOG_FUNCTION(this << frequency); - - // Create the new channel and increment the counter - Ptr channel = Create(frequency); - - // Add it to the list - m_channelList.push_back(channel); - - NS_LOG_DEBUG("Added a channel. Current number of channels in list is " << m_channelList.size()); -} - -void -LogicalLoraChannelHelper::AddChannel(Ptr logicalChannel) -{ - NS_LOG_FUNCTION(this << logicalChannel); - - // Add it to the list - m_channelList.push_back(logicalChannel); + NS_LOG_ERROR("[ERROR] Requested frequency " << frequencyMHz << "MHz outside known sub-bands."); + return nullptr; // If no SubBand is found, return nullptr } void -LogicalLoraChannelHelper::SetChannel(uint8_t chIndex, Ptr logicalChannel) +LogicalLoraChannelHelper::SetChannel(uint8_t chIndex, Ptr channel) { - NS_LOG_FUNCTION(this << chIndex << logicalChannel); - - m_channelList.at(chIndex) = logicalChannel; -} - -void -LogicalLoraChannelHelper::AddSubBand(double firstFrequency, - double lastFrequency, - double dutyCycle, - double maxTxPowerDbm) -{ - NS_LOG_FUNCTION(this << firstFrequency << lastFrequency); - - Ptr subBand = Create(firstFrequency, lastFrequency, dutyCycle, maxTxPowerDbm); - - m_subBandList.push_back(subBand); + NS_LOG_FUNCTION(this << unsigned(chIndex) << channel); + NS_ASSERT_MSG(m_channelVec.size() > chIndex, "ChIndex > channel storage bounds"); + m_channelVec.at(chIndex) = channel; } void LogicalLoraChannelHelper::AddSubBand(Ptr subBand) { NS_LOG_FUNCTION(this << subBand); - - m_subBandList.push_back(subBand); + m_subBandList.emplace_back(subBand); } -void -LogicalLoraChannelHelper::RemoveChannel(Ptr logicalChannel) +Time +LogicalLoraChannelHelper::GetWaitTime(Ptr channel) const { - // Search and remove the channel from the list - std::vector>::iterator it; - for (it = m_channelList.begin(); it != m_channelList.end(); it++) - { - Ptr currentChannel = *it; - if (currentChannel == logicalChannel) - { - m_channelList.erase(it); - return; - } - } + NS_LOG_FUNCTION(this << channel); + return GetWaitTime(channel->GetFrequency()); } Time -LogicalLoraChannelHelper::GetAggregatedWaitingTime() +LogicalLoraChannelHelper::GetWaitTime(double frequencyMHz) const { - // Aggregate waiting time - Time aggregatedWaitingTime = m_nextAggregatedTransmissionTime - Simulator::Now(); - - // Handle case in which waiting time is negative - aggregatedWaitingTime = Seconds(std::max(aggregatedWaitingTime.GetSeconds(), double(0))); - - NS_LOG_DEBUG("Aggregated waiting time: " << aggregatedWaitingTime.GetSeconds()); - - return aggregatedWaitingTime; + NS_LOG_FUNCTION(this << frequencyMHz); + auto subBand = GetSubBandFromFrequency(frequencyMHz); + NS_ASSERT_MSG(subBand, "Input frequency is out-of-band"); + Time waitTime = subBand->GetNextTransmissionTime() - Now(); + waitTime = Max(waitTime, Time(0)); // Handle negative values + NS_LOG_DEBUG("waitTime=" << waitTime.As(Time::S)); + return waitTime; } -Time -LogicalLoraChannelHelper::GetWaitingTime(Ptr channel) +void +LogicalLoraChannelHelper::AddEvent(Time duration, Ptr channel) { NS_LOG_FUNCTION(this << channel); - - // SubBand waiting time - Time subBandWaitingTime = - GetSubBandFromChannel(channel)->GetNextTransmissionTime() - Simulator::Now(); - - // Handle case in which waiting time is negative - subBandWaitingTime = Seconds(std::max(subBandWaitingTime.GetSeconds(), double(0))); - - NS_LOG_DEBUG("Waiting time: " << subBandWaitingTime.GetSeconds()); - - return subBandWaitingTime; + AddEvent(duration, channel->GetFrequency()); } void -LogicalLoraChannelHelper::AddEvent(Time duration, Ptr channel) +LogicalLoraChannelHelper::AddEvent(Time duration, double frequencyMHz) { - NS_LOG_FUNCTION(this << duration << channel); - - Ptr subBand = GetSubBandFromChannel(channel); - - double dutyCycle = subBand->GetDutyCycle(); - double timeOnAir = duration.GetSeconds(); - - // Computation of necessary waiting time on this sub-band - subBand->SetNextTransmissionTime(Simulator::Now() + Seconds(timeOnAir / dutyCycle - timeOnAir)); - - // Computation of necessary aggregate waiting time - m_nextAggregatedTransmissionTime = - Simulator::Now() + Seconds(timeOnAir / m_aggregatedDutyCycle - timeOnAir); - - NS_LOG_DEBUG("Time on air: " << timeOnAir); - NS_LOG_DEBUG("m_aggregatedDutyCycle: " << m_aggregatedDutyCycle); - NS_LOG_DEBUG("Current time: " << Simulator::Now().GetSeconds()); - NS_LOG_DEBUG("Next transmission on this sub-band allowed at time: " - << (subBand->GetNextTransmissionTime()).GetSeconds()); - NS_LOG_DEBUG("Next aggregated transmission allowed at time " - << m_nextAggregatedTransmissionTime.GetSeconds()); + NS_LOG_FUNCTION(this << duration << frequencyMHz); + NS_LOG_DEBUG("frequency=" << frequencyMHz << "MHz, timeOnAir=" << duration.As(Time::S)); + auto subBand = GetSubBandFromFrequency(frequencyMHz); + NS_ASSERT_MSG(subBand, "Input frequency is out-of-band"); + Time nextTxTime = Now() + duration / subBand->GetDutyCycle(); + subBand->SetNextTransmissionTime(nextTxTime); + NS_LOG_DEBUG("now=" << Now().As(Time::S) << ", nextTxTime=" << nextTxTime.As(Time::S)); } double -LogicalLoraChannelHelper::GetTxPowerForChannel(Ptr logicalChannel) +LogicalLoraChannelHelper::GetTxPowerForChannel(Ptr channel) const { - NS_LOG_FUNCTION_NOARGS(); - - // Get the maxTxPowerDbm from the SubBand this channel is in - std::list>::iterator it; - for (it = m_subBandList.begin(); it != m_subBandList.end(); it++) - { - // Check whether this channel is in this SubBand - if ((*it)->BelongsToSubBand(logicalChannel->GetFrequency())) - { - return (*it)->GetMaxTxPowerDbm(); - } - } - NS_ABORT_MSG("Logical channel doesn't belong to a known SubBand"); - - return 0; + NS_LOG_FUNCTION(this << channel); + return GetTxPowerForChannel(channel->GetFrequency()); } -void -LogicalLoraChannelHelper::DisableChannel(int index) +double +LogicalLoraChannelHelper::GetTxPowerForChannel(double frequencyMHz) const { - NS_LOG_FUNCTION(this << index); + NS_LOG_FUNCTION(this << frequencyMHz); + auto subBand = GetSubBandFromFrequency(frequencyMHz); + NS_ASSERT_MSG(subBand, "Input frequency is out-of-band"); + return subBand->GetMaxTxPowerDbm(); +} - m_channelList.at(index)->DisableForUplink(); +bool +LogicalLoraChannelHelper::IsFrequencyValid(double frequencyMHz) const +{ + return (bool)(GetSubBandFromFrequency(frequencyMHz)); } + } // namespace lorawan } // namespace ns3 diff --git a/model/logical-lora-channel-helper.h b/model/logical-lora-channel-helper.h index 25dfbb5444..d6ea213ba1 100644 --- a/model/logical-lora-channel-helper.h +++ b/model/logical-lora-channel-helper.h @@ -13,11 +13,9 @@ #include "sub-band.h" #include "ns3/nstime.h" -#include "ns3/object.h" -#include "ns3/packet.h" +#include "ns3/ptr.h" +#include "ns3/simple-ref-count.h" -#include -#include #include namespace ns3 @@ -36,39 +34,36 @@ namespace lorawan * of SubBand objects and providing methods to query whether transmission on a * set channel is admissible or not. */ -class LogicalLoraChannelHelper : public Object +class LogicalLoraChannelHelper : public SimpleRefCount { public: /** - * Register this type. - * \return The object TypeId. + * Construct a LogicalLoraChannelHelper of a certain size. + * + * \param size The maximum number of transmission channels that can be installed on this device + * according to regional parameter specifications. */ - static TypeId GetTypeId(); + LogicalLoraChannelHelper(uint8_t size); - LogicalLoraChannelHelper(); //!< Default constructor - ~LogicalLoraChannelHelper() override; //!< Destructor + ~LogicalLoraChannelHelper(); //!< Destructor /** - * Get the time it is necessary to wait before transmitting again, according - * to the aggregate duty cycle timer. + * Get the time it is necessary to wait for before transmitting on a given channel. * - * \return The aggregate waiting time. + * \param channel A pointer to the channel we want to know the wait time for. + * \return A Time instance containing the wait time before transmission is allowed on the + * channel. */ - Time GetAggregatedWaitingTime(); + Time GetWaitTime(Ptr channel) const; /** - * Get the time it is necessary to wait for before transmitting on a given - * channel. - * - * \remark This function does not take into account aggregate waiting time. - * Check on this should be performed before calling this function. + * Get the time it is necessary to wait for before transmitting on a given channel. * - * \param channel A pointer to the channel we want to know the waiting time. - * for. - * \return A Time instance containing the waiting time before transmission is. - * allowed on the channel. + * \param frequencyMHz The channel frequency [MHz] we want to know the wait time of for. + * \return A Time instance containing the wait time before transmission is allowed on the + * channel. */ - Time GetWaitingTime(Ptr channel); + Time GetWaitTime(double frequencyMHz) const; /** * Register the transmission of a packet. @@ -79,55 +74,32 @@ class LogicalLoraChannelHelper : public Object void AddEvent(Time duration, Ptr channel); /** - * Get the list of LogicalLoraChannels currently registered on this helper. + * Register the transmission of a packet. * - * \return A list of the managed channels. + * \param duration The duration of the transmission event. + * \param frequencyMHz The carrier frequency the transmission was on. */ - std::vector> GetChannelList(); + void AddEvent(Time duration, double frequencyMHz); /** - * Get the list of LogicalLoraChannels currently registered on this helper - * that have been enabled for Uplink transmission with the channel mask. + * Get the frequency channel storage array of this device. * - * \return A list of the managed channels enabled for Uplink transmission. - */ - std::vector> GetEnabledChannelList(); - - /** - * Add a new channel to the list. + * By specifications, devices are required to hold an indexed structure + * of a certain size (region-dependent) for storing transmission channels. * - * \param frequency The frequency of the channel to create. - */ - void AddChannel(double frequency); - - /** - * Add a new channel to the list. + * \remark Empty index slots hold nullptr. * - * \param logicalChannel A pointer to the channel to add to the list. + * \return An indexed vector of pointers to LogicalLoraChannels. */ - void AddChannel(Ptr logicalChannel); + std::vector> GetRawChannelArray() const; /** * Set a new channel at a fixed index. * * \param chIndex The index of the channel to substitute. - * \param logicalChannel A pointer to the channel to add to the list. - */ - void SetChannel(uint8_t chIndex, Ptr logicalChannel); - - /** - * Add a new SubBand to this helper. - * - * \param firstFrequency The first frequency of the subband, in MHz. - * \param lastFrequency The last frequency of the subband, in MHz. - * \param dutyCycle The duty cycle that needs to be enforced on this subband. - * \param maxTxPowerDbm The maximum transmission power [dBm] that can be used. - * on this SubBand. + * \param channel A pointer to the channel to add to the list. */ - void AddSubBand(double firstFrequency, - double lastFrequency, - double dutyCycle, - double maxTxPowerDbm); + void SetChannel(uint8_t chIndex, Ptr channel); /** * Add a new SubBand. @@ -136,69 +108,54 @@ class LogicalLoraChannelHelper : public Object */ void AddSubBand(Ptr subBand); - /** - * Remove a channel. - * - * \param channel A pointer to the channel we want to remove. - */ - void RemoveChannel(Ptr channel); - /** * Returns the maximum transmission power [dBm] that is allowed on a channel. * - * \param logicalChannel The power for which to check the maximum allowed. - * transmission power. + * \param channel The channel in question. * \return The power in dBm. */ - double GetTxPowerForChannel(Ptr logicalChannel); + double GetTxPowerForChannel(Ptr channel) const; /** - * Get the SubBand a channel belongs to. + * Returns the maximum transmission power [dBm] that is allowed on a channel. * - * \param channel The channel whose SubBand we want to get. - * \return The SubBand the channel belongs to. + * \param frequencyMHz The carrier frequency of the channel in question. + * \return The power in dBm. */ - Ptr GetSubBandFromChannel(Ptr channel); + double GetTxPowerForChannel(double frequencyMHz) const; /** - * Get the SubBand a frequency belongs to. + * Check if a frequency is valid, that is, if it belongs to any of the sub-bands registered in + * this class. * - * \param frequency The frequency we want to check. - * \return The SubBand the frequency belongs to. + * \param frequencyMHz The frequency [MHz] to be evaluated. + * \return Whether the input frequency belongs to any of the registered sub-bands. */ - Ptr GetSubBandFromFrequency(double frequency); + bool IsFrequencyValid(double frequencyMHz) const; + private: /** - * Disable the channel at a specified index. + * Get the SubBand a frequency belongs to, also used to test validity of a frequency. * - * \param index The index of the channel to disable. + * \param frequencyMHz The frequency [MHz] we want to check. + * \return The SubBand the frequency belongs to, nullptr if none. */ - void DisableChannel(int index); + Ptr GetSubBandFromFrequency(double frequencyMHz) const; - private: /** - * A list of the SubBands that are currently registered within this helper. + * A vector of the SubBands that are currently registered within this helper. */ - std::list> m_subBandList; + std::vector> m_subBandList; /** * A vector of the LogicalLoraChannels that are currently registered within * this helper. This vector represents the node's channel mask. The first N * channels are the default ones for a fixed region. */ - std::vector> m_channelList; - - Time m_nextAggregatedTransmissionTime; //!< The next time at which - //! transmission will be possible - //! according to the aggregated - //! transmission timer - - double m_aggregatedDutyCycle; //!< The next time at which - //! transmission will be possible - //! according to the aggregated - //! transmission timer + std::vector> m_channelVec; }; -} // namespace lorawan +} // namespace lorawan } // namespace ns3 + #endif /* LOGICAL_LORA_CHANNEL_HELPER_H */ diff --git a/model/logical-lora-channel.cc b/model/logical-lora-channel.cc index f0ee4ada46..f4e9367680 100644 --- a/model/logical-lora-channel.cc +++ b/model/logical-lora-channel.cc @@ -8,6 +8,8 @@ #include "logical-lora-channel.h" +#include "sub-band.h" + #include "ns3/log.h" namespace ns3 @@ -17,39 +19,10 @@ namespace lorawan NS_LOG_COMPONENT_DEFINE("LogicalLoraChannel"); -NS_OBJECT_ENSURE_REGISTERED(LogicalLoraChannel); - -TypeId -LogicalLoraChannel::GetTypeId() -{ - static TypeId tid = - TypeId("ns3::LogicalLoraChannel").SetParent().SetGroupName("lorawan"); - return tid; -} - -LogicalLoraChannel::LogicalLoraChannel() - : m_frequency(0), - m_minDataRate(0), - m_maxDataRate(5), - m_enabledForUplink(true) -{ - NS_LOG_FUNCTION(this); -} - -LogicalLoraChannel::~LogicalLoraChannel() -{ - NS_LOG_FUNCTION(this); -} - -LogicalLoraChannel::LogicalLoraChannel(double frequency) - : m_frequency(frequency), - m_enabledForUplink(true) -{ - NS_LOG_FUNCTION(this); -} - -LogicalLoraChannel::LogicalLoraChannel(double frequency, uint8_t minDataRate, uint8_t maxDataRate) - : m_frequency(frequency), +LogicalLoraChannel::LogicalLoraChannel(double frequencyMHz, + uint8_t minDataRate, + uint8_t maxDataRate) + : m_frequencyMHz(frequencyMHz), m_minDataRate(minDataRate), m_maxDataRate(maxDataRate), m_enabledForUplink(true) @@ -60,19 +33,7 @@ LogicalLoraChannel::LogicalLoraChannel(double frequency, uint8_t minDataRate, ui double LogicalLoraChannel::GetFrequency() const { - return m_frequency; -} - -void -LogicalLoraChannel::SetMinimumDataRate(uint8_t minDataRate) -{ - m_minDataRate = minDataRate; -} - -void -LogicalLoraChannel::SetMaximumDataRate(uint8_t maxDataRate) -{ - m_maxDataRate = maxDataRate; + return m_frequencyMHz; } uint8_t @@ -88,7 +49,7 @@ LogicalLoraChannel::GetMaximumDataRate() const } void -LogicalLoraChannel::SetEnabledForUplink() +LogicalLoraChannel::EnableForUplink() { m_enabledForUplink = true; } @@ -123,5 +84,6 @@ operator!=(const Ptr& first, const Ptr& { return !(first == second); } + } // namespace lorawan } // namespace ns3 diff --git a/model/logical-lora-channel.h b/model/logical-lora-channel.h index 6f75e8629d..f95cb49c8c 100644 --- a/model/logical-lora-channel.h +++ b/model/logical-lora-channel.h @@ -9,17 +9,14 @@ #ifndef LOGICAL_LORA_CHANNEL_H #define LOGICAL_LORA_CHANNEL_H -#include "sub-band.h" - -#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/simple-ref-count.h" namespace ns3 { namespace lorawan { -class SubBand; - /** * \ingroup lorawan * @@ -31,33 +28,17 @@ class SubBand; * Furthermore, a LogicalLoraChannel can be marked as enabled or disabled for * uplink transmission. */ -class LogicalLoraChannel : public Object +class LogicalLoraChannel : public SimpleRefCount { public: - /** - * Register this type. - * \return The object TypeId. - */ - static TypeId GetTypeId(); - - LogicalLoraChannel(); //!< Default constructor - ~LogicalLoraChannel() override; //!< Destructor - - /** - * Construct a new LogicalLoraChannel object initializing the carrier frequency. - * - * \param frequency The carrier frequency [MHz]. - */ - LogicalLoraChannel(double frequency); - /** * Constructor providing initialization of frequency and data rate limits. * - * \param frequency This channel's frequency [MHz]. + * \param frequencyMHz This channel's frequency [MHz]. * \param minDataRate This channel's minimum data rate. * \param maxDataRate This channel's maximum data rate. */ - LogicalLoraChannel(double frequency, uint8_t minDataRate, uint8_t maxDataRate); + LogicalLoraChannel(double frequencyMHz, uint8_t minDataRate, uint8_t maxDataRate); /** * Get the frequency (MHz). @@ -66,22 +47,6 @@ class LogicalLoraChannel : public Object */ double GetFrequency() const; - // void SetFrequency (double frequencyMHz); - - /** - * Set the minimum data rate that is allowed on this channel. - * - * \param minDataRate The minimum data rate value. - */ - void SetMinimumDataRate(uint8_t minDataRate); - - /** - * Set the maximum data rate that is allowed on this channel. - * - * \param maxDataRate The maximum data rate value. - */ - void SetMaximumDataRate(uint8_t maxDataRate); - /** * Get the minimum data rate that is allowed on this channel. * @@ -99,7 +64,7 @@ class LogicalLoraChannel : public Object /** * Set this channel as enabled for uplink. */ - void SetEnabledForUplink(); + void EnableForUplink(); /** * Set this channel as disabled for uplink. @@ -114,7 +79,7 @@ class LogicalLoraChannel : public Object bool IsEnabledForUplink() const; private: - double m_frequency; //!< The central frequency of this channel, in MHz. + double m_frequencyMHz; //!< The central frequency of this channel, in MHz. uint8_t m_minDataRate; //!< The minimum data rate that is allowed on this channel. uint8_t m_maxDataRate; //!< The maximum data rate that is allowed on this channel. bool m_enabledForUplink; //!< Whether this channel can be used for uplink or not. diff --git a/model/lora-channel.cc b/model/lora-channel.cc index debb11819b..5301f1d6e3 100644 --- a/model/lora-channel.cc +++ b/model/lora-channel.cc @@ -202,7 +202,7 @@ std::ostream& operator<<(std::ostream& os, const LoraChannelParameters& params) { os << "(rxPowerDbm: " << params.rxPowerDbm << ", SF: " << unsigned(params.sf) - << ", durationSec: " << params.duration.GetSeconds() + << ", durationSec: " << params.duration.As(Time::S) << ", frequencyMHz: " << params.frequencyMHz << ")"; return os; } diff --git a/model/lora-frame-header.cc b/model/lora-frame-header.cc index f6d8c4a3ce..449007c9e3 100644 --- a/model/lora-frame-header.cc +++ b/model/lora-frame-header.cc @@ -53,21 +53,17 @@ LoraFrameHeader::GetInstanceTypeId() const uint32_t LoraFrameHeader::GetSerializedSize() const { - NS_LOG_FUNCTION_NOARGS(); - - // Sizes in bytes: + NS_LOG_FUNCTION(this); // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts uint32_t size = 8 + m_fOptsLen; - NS_LOG_INFO("LoraFrameHeader serialized size: " << size); - return size; } void LoraFrameHeader::Serialize(Buffer::Iterator start) const { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); // Device Address field start.WriteU32(m_address.Get()); @@ -88,29 +84,20 @@ LoraFrameHeader::Serialize(Buffer::Iterator start) const start.WriteU16(m_fCnt); // FOpts field - for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++) + for (const auto& c : m_macCommands) { NS_LOG_DEBUG("Serializing a MAC command"); - (*it)->Serialize(start); + c->Serialize(start); } // FPort start.WriteU8(m_fPort); - - NS_LOG_DEBUG("Serializing the following data: "); - NS_LOG_DEBUG("Address: " << m_address.Print()); - NS_LOG_DEBUG("ADR: " << unsigned(m_adr)); - NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq)); - NS_LOG_DEBUG("Ack: " << unsigned(m_ack)); - NS_LOG_DEBUG("fPending: " << unsigned(m_fPending)); - NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen)); - NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt)); } uint32_t LoraFrameHeader::Deserialize(Buffer::Iterator start) { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); // Empty the list of MAC commands m_macCommands.clear(); @@ -127,15 +114,6 @@ LoraFrameHeader::Deserialize(Buffer::Iterator start) m_fOptsLen = fCtrl & 0b1111; m_fCnt = start.ReadU16(); - NS_LOG_DEBUG("Deserialized data: "); - NS_LOG_DEBUG("Address: " << m_address.Print()); - NS_LOG_DEBUG("ADR: " << unsigned(m_adr)); - NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq)); - NS_LOG_DEBUG("Ack: " << unsigned(m_ack)); - NS_LOG_DEBUG("fPending: " << unsigned(m_fPending)); - NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen)); - NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt)); - // Deserialize MAC commands NS_LOG_DEBUG("Starting deserialization of MAC commands"); for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;) @@ -147,6 +125,7 @@ LoraFrameHeader::Deserialize(Buffer::Iterator start) // This needs to be done because they have the same CID, and the context // about where this message will be Serialized/Deserialized (i.e., at the // end device or at the network server) is umportant. + Ptr command; if (m_isUplink) { switch (cid) @@ -155,65 +134,47 @@ LoraFrameHeader::Deserialize(Buffer::Iterator start) // request for a link check case (0x02): { NS_LOG_DEBUG("Creating a LinkCheckReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x03): { NS_LOG_DEBUG("Creating a LinkAdrAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x04): { NS_LOG_DEBUG("Creating a DutyCycleAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x05): { NS_LOG_DEBUG("Creating a RxParamSetupAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x06): { NS_LOG_DEBUG("Creating a DevStatusAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x07): { NS_LOG_DEBUG("Creating a NewChannelAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x08): { NS_LOG_DEBUG("Creating a RxTimingSetupAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x09): { NS_LOG_DEBUG("Creating a TxParamSetupAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x0A): { NS_LOG_DEBUG("Creating a DlChannelAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } default: { @@ -229,58 +190,42 @@ LoraFrameHeader::Deserialize(Buffer::Iterator start) // answer to a link check case (0x02): { NS_LOG_DEBUG("Creating a LinkCheckAns command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x03): { NS_LOG_DEBUG("Creating a LinkAdrReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x04): { NS_LOG_DEBUG("Creating a DutyCycleReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x05): { NS_LOG_DEBUG("Creating a RxParamSetupReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x06): { NS_LOG_DEBUG("Creating a DevStatusReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x07): { NS_LOG_DEBUG("Creating a NewChannelReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x08): { NS_LOG_DEBUG("Creating a RxTimingSetupReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } case (0x09): { NS_LOG_DEBUG("Creating a TxParamSetupReq command"); - Ptr command = Create(); - byteNumber += command->Deserialize(start); - m_macCommands.emplace_back(command); + command = Create(); break; } default: { @@ -288,47 +233,42 @@ LoraFrameHeader::Deserialize(Buffer::Iterator start) } } } + byteNumber += command->Deserialize(start); + m_macCommands.emplace_back(command); } - - m_fPort = uint8_t(start.ReadU8()); - + m_fPort = start.ReadU8(); return 8 + m_fOptsLen; // the number of bytes consumed. } void LoraFrameHeader::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "Address=" << m_address.Print() << std::endl; - os << "ADR=" << m_adr << std::endl; - os << "ADRAckReq=" << m_adrAckReq << std::endl; - os << "ACK=" << m_ack << std::endl; - os << "FPending=" << m_fPending << std::endl; - os << "FOptsLen=" << unsigned(m_fOptsLen) << std::endl; - os << "FCnt=" << unsigned(m_fCnt) << std::endl; - - for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++) + os << "Address=" << m_address.Print(); + os << ", ADR=" << m_adr; + os << ", ADRAckReq=" << m_adrAckReq; + os << ", ACK=" << m_ack; + os << ", FPending=" << m_fPending; + os << ", FOptsLen=" << unsigned(m_fOptsLen); + os << ", FCnt=" << unsigned(m_fCnt); + for (const auto& c : m_macCommands) { - (*it)->Print(os); + os << ", "; + c->Print(os); } - - os << "FPort=" << unsigned(m_fPort) << std::endl; + os << ", FPort=" << unsigned(m_fPort); } void LoraFrameHeader::SetAsUplink() { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); m_isUplink = true; } void LoraFrameHeader::SetAsDownlink() { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); m_isUplink = false; } @@ -409,12 +349,10 @@ LoraFrameHeader::GetFPending() const uint8_t LoraFrameHeader::GetFOptsLen() const { - // Sum the serialized length of all commands in the list uint8_t fOptsLen = 0; - std::list>::const_iterator it; - for (it = m_macCommands.begin(); it != m_macCommands.end(); it++) + for (const auto& c : m_macCommands) { - fOptsLen = fOptsLen + (*it)->GetSerializedSize(); + fOptsLen += c->GetSerializedSize(); } return fOptsLen; } @@ -434,12 +372,9 @@ LoraFrameHeader::GetFCnt() const void LoraFrameHeader::AddLinkCheckReq() { - NS_LOG_FUNCTION_NOARGS(); - - Ptr command = Create(); + NS_LOG_FUNCTION(this); + auto command = Create(); m_macCommands.emplace_back(command); - - NS_LOG_DEBUG("Command SerializedSize: " << unsigned(command->GetSerializedSize())); m_fOptsLen += command->GetSerializedSize(); } @@ -447,10 +382,8 @@ void LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt) { NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt)); - - Ptr command = Create(margin, gwCnt); + auto command = Create(margin, gwCnt); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -461,23 +394,15 @@ LoraFrameHeader::AddLinkAdrReq(uint8_t dataRate, int repetitions) { NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions); - uint16_t channelMask = 0; - for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++) + for (const auto chId : enabledChannels) { - NS_ASSERT((*it) < 16 && (*it) > -1); - - channelMask |= 0b1 << (*it); + NS_ASSERT(chId < 16 && chId > -1); + channelMask |= 0b1 << chId; } - - // TODO Implement chMaskCntl field - - NS_LOG_DEBUG("Creating LinkAdrReq with: DR = " << unsigned(dataRate) - << " and txPower = " << unsigned(txPower)); - - Ptr command = Create(dataRate, txPower, channelMask, 0, repetitions); + /// \todo Implement chMaskCntl field + auto command = Create(dataRate, txPower, channelMask, 0, repetitions); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -485,10 +410,8 @@ void LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck) { NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck); - - Ptr command = Create(powerAck, dataRateAck, channelMaskAck); + auto command = Create(powerAck, dataRateAck, channelMaskAck); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -496,11 +419,8 @@ void LoraFrameHeader::AddDutyCycleReq(uint8_t dutyCycle) { NS_LOG_FUNCTION(this << unsigned(dutyCycle)); - - Ptr command = Create(dutyCycle); - + auto command = Create(dutyCycle); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -508,26 +428,20 @@ void LoraFrameHeader::AddDutyCycleAns() { NS_LOG_FUNCTION(this); - - Ptr command = Create(); - + auto command = Create(); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } void -LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency) +LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz) { - NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency); - + NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) + << uint32_t(frequencyHz)); // Evaluate whether to eliminate this assert in case new offsets can be defined. NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5); - - Ptr command = Create(rx1DrOffset, rx2DataRate, frequency); - + auto command = Create(rx1DrOffset, rx2DataRate, frequencyHz); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -535,11 +449,8 @@ void LoraFrameHeader::AddRxParamSetupAns() { NS_LOG_FUNCTION(this); - - Ptr command = Create(); - + auto command = Create(); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } @@ -547,35 +458,28 @@ void LoraFrameHeader::AddDevStatusReq() { NS_LOG_FUNCTION(this); - - Ptr command = Create(); - + auto command = Create(); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } void LoraFrameHeader::AddNewChannelReq(uint8_t chIndex, - double frequency, + double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate) { - NS_LOG_FUNCTION(this); - - Ptr command = - Create(chIndex, frequency, minDataRate, maxDataRate); - + NS_LOG_FUNCTION(this << unsigned(chIndex) << uint32_t(frequencyHz) << unsigned(minDataRate) + << unsigned(maxDataRate)); + auto command = Create(chIndex, frequencyHz, minDataRate, maxDataRate); m_macCommands.emplace_back(command); - m_fOptsLen += command->GetSerializedSize(); } -std::list> +std::vector> LoraFrameHeader::GetCommands() { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_macCommands; } @@ -583,8 +487,7 @@ void LoraFrameHeader::AddCommand(Ptr macCommand) { NS_LOG_FUNCTION(this << macCommand); - - m_macCommands.push_back(macCommand); + m_macCommands.emplace_back(macCommand); m_fOptsLen += macCommand->GetSerializedSize(); } diff --git a/model/lora-frame-header.h b/model/lora-frame-header.h index 8d32f1de1c..701d2ef92c 100644 --- a/model/lora-frame-header.h +++ b/model/lora-frame-header.h @@ -270,9 +270,9 @@ class LoraFrameHeader : public Header * * \param rx1DrOffset The requested data rate offset for the first receive window. * \param rx2DataRate The requested data rate for the second receive window. - * \param frequency The frequency at which to listen for the second receive window. + * \param frequencyHz The frequency [Hz] at which to listen for the second receive window. */ - void AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency); + void AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz); /** * Add a RxParamSetupAns command. @@ -288,24 +288,24 @@ class LoraFrameHeader : public Header * Add a NewChannelReq command with provided fields. * * \param chIndex The ChIndex field. - * \param frequency The Frequency field. + * \param frequencyHz The Frequency field in Hz. * \param minDataRate The MinDR field. * \param maxDataRate The MaxDR field. */ void AddNewChannelReq(uint8_t chIndex, - double frequency, + double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate); /** - * Return a list of pointers to all the MAC commands saved in this header. + * Return a vector of pointers to all the MAC commands saved in this header. * - * \return The list of pointers to MacCommand objects. + * \return The vector of pointers to MacCommand objects. */ - std::list> GetCommands(); + std::vector> GetCommands(); /** - * Add a predefined command to the list in this frame header. + * Add a predefined command to the vector in this frame header. * * \param macCommand A pointer to the MacCommand object to add. */ @@ -324,9 +324,9 @@ class LoraFrameHeader : public Header uint16_t m_fCnt; //!< The FCnt field - Buffer m_fOpts; //!< The FOpts field - std::list> m_macCommands; //!< List containing all the MacCommand instances that - //!< are contained in this LoraFrameHeader + Buffer m_fOpts; //!< The FOpts field + std::vector> m_macCommands; //!< Vector containing all the MacCommand instances + //!< that are contained in this LoraFrameHeader bool m_isUplink; //!< Whether this frame header is uplink or not }; @@ -336,15 +336,13 @@ Ptr LoraFrameHeader::GetMacCommand() { // Iterate on MAC commands and try casting - std::list>::const_iterator it; - for (it = m_macCommands.begin(); it != m_macCommands.end(); ++it) + for (const auto& cmd : m_macCommands) { - if (DynamicCast(*it)) + if (auto c = DynamicCast(cmd); c) { - return DynamicCast(*it); + return c; } } - // If no command was found, return 0 return nullptr; } diff --git a/model/lora-interference-helper.cc b/model/lora-interference-helper.cc index 647ade1b1a..f06f411595 100644 --- a/model/lora-interference-helper.cc +++ b/model/lora-interference-helper.cc @@ -30,7 +30,7 @@ LoraInterferenceHelper::Event::Event(Time duration, uint8_t spreadingFactor, Ptr packet, double frequencyMHz) - : m_startTime(Simulator::Now()), + : m_startTime(Now()), m_endTime(m_startTime + duration), m_sf(spreadingFactor), m_rxPowerdBm(rxPowerdBm), @@ -92,7 +92,7 @@ LoraInterferenceHelper::Event::GetFrequency() const void LoraInterferenceHelper::Event::Print(std::ostream& stream) const { - stream << "(" << m_startTime.GetSeconds() << " s - " << m_endTime.GetSeconds() << " s), SF" + stream << "(" << m_startTime.As(Time::S) << " - " << m_endTime.As(Time::S) << "), SF" << unsigned(m_sf) << ", " << m_rxPowerdBm << " dBm, " << m_frequencyMHz << " MHz"; } @@ -187,7 +187,7 @@ LoraInterferenceHelper::Add(Time duration, Ptr packet, double frequencyMHz) { - NS_LOG_FUNCTION(this << duration.GetSeconds() << rxPower << unsigned(spreadingFactor) << packet + NS_LOG_FUNCTION(this << duration << rxPower << unsigned(spreadingFactor) << packet << frequencyMHz); // Create an event based on the parameters @@ -218,7 +218,7 @@ LoraInterferenceHelper::CleanOldEvents() // Cycle the events, and clean up if an event is old. for (auto it = m_events.begin(); it != m_events.end();) { - if ((*it)->GetEndTime() + oldEventThreshold < Simulator::Now()) + if ((*it)->GetEndTime() + oldEventThreshold < Now()) { it = m_events.erase(it); } @@ -263,10 +263,10 @@ LoraInterferenceHelper::IsDestroyedByInterference(PtrGetRxPowerdBm(); uint8_t sf = event->GetSpreadingFactor(); - double frequency = event->GetFrequency(); + double frequencyMHz = event->GetFrequency(); // Handy information about the time frame when the packet was received - Time now = Simulator::Now(); + Time now = Now(); Time duration = event->GetDuration(); Time packetStartTime = now - duration; @@ -285,7 +285,7 @@ LoraInterferenceHelper::IsDestroyedByInterference(PtrGetFrequency() == frequency) || interferer == event) + if (!(interferer->GetFrequency() == frequencyMHz) || interferer == event) { NS_LOG_DEBUG("Different channel or same event"); it++; @@ -308,7 +308,7 @@ LoraInterferenceHelper::IsDestroyedByInterference(Ptr event1 // Non-overlapping events if (e1 <= s2 || e2 <= s1) { - overlap = Seconds(0); + overlap = Time(0); } // event1 before event2 else if (s1 < s2) diff --git a/model/lora-interference-helper.h b/model/lora-interference-helper.h index 6889a9a765..a050be7e7c 100644 --- a/model/lora-interference-helper.h +++ b/model/lora-interference-helper.h @@ -108,7 +108,7 @@ class LoraInterferenceHelper /** * Get the frequency this event was on. * - * \return The carrier frequency as a double. + * \return The carrier frequency [MHz] as a double. */ double GetFrequency() const; diff --git a/model/lora-net-device.cc b/model/lora-net-device.cc index 44f92794d1..866ed67840 100644 --- a/model/lora-net-device.cc +++ b/model/lora-net-device.cc @@ -188,7 +188,7 @@ LoraNetDevice::IsLinkUp() const { NS_LOG_FUNCTION(this); - return m_phy != nullptr; + return (bool)(m_phy); } void diff --git a/model/lora-phy.h b/model/lora-phy.h index 952d89db30..b56e242f2e 100644 --- a/model/lora-phy.h +++ b/model/lora-phy.h @@ -153,11 +153,11 @@ class LoraPhy : public Object /** * Whether this device is listening on the specified frequency or not. * - * \param frequency The frequency to query. + * \param frequencyMHz The frequency [MHz] to query. * \return True if the device is listening on that frequency, false * otherwise. */ - virtual bool IsOnFrequency(double frequency) = 0; + virtual bool IsOnFrequency(double frequencyMHz) = 0; /** * Set the callback to call upon successful reception of a packet. diff --git a/model/lora-radio-energy-model.cc b/model/lora-radio-energy-model.cc index 1bd1d91ccd..426c520262 100644 --- a/model/lora-radio-energy-model.cc +++ b/model/lora-radio-energy-model.cc @@ -210,8 +210,8 @@ LoraRadioEnergyModel::ChangeState(int newState) { NS_LOG_FUNCTION(this << newState); - Time duration = Simulator::Now() - m_lastUpdateTime; - NS_ASSERT(duration.GetNanoSeconds() >= 0); // check if duration is valid + Time duration = Now() - m_lastUpdateTime; + NS_ASSERT(duration.IsPositive()); // check if duration is valid // energy to decrease = current * voltage * time double energyToDecrease = 0.0; @@ -238,7 +238,7 @@ LoraRadioEnergyModel::ChangeState(int newState) m_totalEnergyConsumption += energyToDecrease; // update last update time stamp - m_lastUpdateTime = Simulator::Now(); + m_lastUpdateTime = Now(); m_nPendingChangeState++; @@ -357,8 +357,8 @@ LoraRadioEnergyModel::SetLoraRadioState(const EndDeviceLoraPhy::State state) stateName = "SLEEP"; break; } - NS_LOG_DEBUG("LoraRadioEnergyModel:Switching to state: " - << stateName << " at time = " << Simulator::Now().GetSeconds() << " s"); + NS_LOG_DEBUG("LoraRadioEnergyModel:Switching to state: " << stateName + << " at time = " << Now().As(Time::S)); } // -------------------------------------------------------------------------- // diff --git a/model/lora-tag.cc b/model/lora-tag.cc index b676b7a8aa..7ab330430d 100644 --- a/model/lora-tag.cc +++ b/model/lora-tag.cc @@ -37,7 +37,7 @@ LoraTag::LoraTag(uint8_t sf, uint8_t destroyedBy) m_destroyedBy(destroyedBy), m_receivePower(0), m_dataRate(0), - m_frequency(0) + m_frequencyMHz(0) { } @@ -60,7 +60,7 @@ LoraTag::Serialize(TagBuffer i) const i.WriteU8(m_destroyedBy); i.WriteDouble(m_receivePower); i.WriteU8(m_dataRate); - i.WriteDouble(m_frequency); + i.WriteDouble(m_frequencyMHz); } void @@ -70,7 +70,7 @@ LoraTag::Deserialize(TagBuffer i) m_destroyedBy = i.ReadU8(); m_receivePower = i.ReadDouble(); m_dataRate = i.ReadU8(); - m_frequency = i.ReadDouble(); + m_frequencyMHz = i.ReadDouble(); } void @@ -116,15 +116,15 @@ LoraTag::SetReceivePower(double receivePower) } void -LoraTag::SetFrequency(double frequency) +LoraTag::SetFrequency(double frequencyMHz) { - m_frequency = frequency; + m_frequencyMHz = frequencyMHz; } double LoraTag::GetFrequency() const { - return m_frequency; + return m_frequencyMHz; } uint8_t diff --git a/model/lora-tag.h b/model/lora-tag.h index d46b5d1e0d..5d6ad9d75b 100644 --- a/model/lora-tag.h +++ b/model/lora-tag.h @@ -98,9 +98,9 @@ class LoraTag : public Tag * - It is used by the network server to signal to the gateway the frequency of a downlink * packet. * - * \param frequency The frequency value [MHz]. + * \param frequencyMHz The frequency value [MHz]. */ - void SetFrequency(double frequency); + void SetFrequency(double frequencyMHz); /** * Get the frequency of the packet. @@ -134,7 +134,7 @@ class LoraTag : public Tag uint8_t m_destroyedBy; //!< The Spreading Factor that destroyed the packet. double m_receivePower; //!< The reception power of this packet. uint8_t m_dataRate; //!< The data rate that needs to be used to send this packet. - double m_frequency; //!< The frequency of this packet + double m_frequencyMHz; //!< The frequency [MHz] of this packet }; } // namespace lorawan } // namespace ns3 diff --git a/model/lorawan-mac-header.cc b/model/lorawan-mac-header.cc index b323b1ffdf..6f403d3834 100644 --- a/model/lorawan-mac-header.cc +++ b/model/lorawan-mac-header.cc @@ -94,8 +94,8 @@ LorawanMacHeader::Deserialize(Buffer::Iterator start) void LorawanMacHeader::Print(std::ostream& os) const { - os << "MessageType=" << unsigned(m_mtype) << std::endl; - os << "Major=" << unsigned(m_major) << std::endl; + os << "MessageType=" << unsigned(m_mtype); + os << ", Major=" << unsigned(m_major); } void diff --git a/model/lorawan-mac.cc b/model/lorawan-mac.cc index 829f6aa1b2..8fdc13c58a 100644 --- a/model/lorawan-mac.cc +++ b/model/lorawan-mac.cc @@ -129,9 +129,9 @@ LorawanMac::GetDbmForTxPower(uint8_t txPower) { NS_LOG_FUNCTION(this << unsigned(txPower)); - if (txPower > m_txDbmForTxPower.size()) + if (txPower > m_txDbmForTxPower.size() - 1) { - return 0; + return -1; } return m_txDbmForTxPower.at(txPower); diff --git a/model/lorawan-mac.h b/model/lorawan-mac.h index 6cb51abe6e..6eb273fa43 100644 --- a/model/lorawan-mac.h +++ b/model/lorawan-mac.h @@ -148,7 +148,7 @@ class LorawanMac : public Object * * \param txPower The 8-bit encoded txPower to convert. * - * \return The corresponding transmission power in dBm, or 0 if the encoded + * \return The corresponding transmission power in dBm ERP, or -1 if the encoded * power was not recognized as valid. */ double GetDbmForTxPower(uint8_t txPower); diff --git a/model/mac-command.cc b/model/mac-command.cc index 7696dd9a22..853ff4e226 100644 --- a/model/mac-command.cc +++ b/model/mac-command.cc @@ -42,16 +42,14 @@ MacCommand::~MacCommand() enum MacCommandType MacCommand::GetCommandType() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_commandType; } uint8_t MacCommand::GetSerializedSize() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_serializedSize; } @@ -59,7 +57,6 @@ uint8_t MacCommand::GetCIDFromMacCommand(enum MacCommandType commandType) { NS_LOG_FUNCTION_NOARGS(); - switch (commandType) { case (INVALID): { @@ -111,44 +108,31 @@ MacCommand::GetCIDFromMacCommand(enum MacCommandType commandType) LinkCheckReq::LinkCheckReq() { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); m_commandType = LINK_CHECK_REQ; m_serializedSize = 1; } -LinkCheckReq::~LinkCheckReq() -{ - NS_LOG_FUNCTION_NOARGS(); -} - void LinkCheckReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID and we're done - uint8_t cid = GetCIDFromMacCommand(m_commandType); - start.WriteU8(cid); - NS_LOG_DEBUG("Serialized LinkCheckReq: " << unsigned(cid)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t LinkCheckReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Read the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void LinkCheckReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "LinkCheckReq" << std::endl; + NS_LOG_FUNCTION(this); + os << "LinkCheckReq()"; } ////////////////// @@ -156,11 +140,8 @@ LinkCheckReq::Print(std::ostream& os) const ////////////////// LinkCheckAns::LinkCheckAns() - : m_margin(0), - m_gwCnt(0) { NS_LOG_FUNCTION(this); - m_commandType = LINK_CHECK_ANS; m_serializedSize = 3; } @@ -170,7 +151,6 @@ LinkCheckAns::LinkCheckAns(uint8_t margin, uint8_t gwCnt) m_gwCnt(gwCnt) { NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt)); - m_commandType = LINK_CHECK_ANS; m_serializedSize = 3; } @@ -178,23 +158,17 @@ LinkCheckAns::LinkCheckAns(uint8_t margin, uint8_t gwCnt) void LinkCheckAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - // Write the margin - start.WriteU8(m_margin); - // Write the gwCnt - start.WriteU8(m_gwCnt); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID + start.WriteU8(m_margin); // Write the margin + start.WriteU8(m_gwCnt); // Write the gwCnt } uint8_t LinkCheckAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID m_margin = start.ReadU8(); m_gwCnt = start.ReadU8(); return m_serializedSize; @@ -203,37 +177,20 @@ LinkCheckAns::Deserialize(Buffer::Iterator& start) void LinkCheckAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "LinkCheckAns" << std::endl; - os << "margin: " << unsigned(m_margin) << std::endl; - os << "gwCnt: " << unsigned(m_gwCnt) << std::endl; -} - -void -LinkCheckAns::SetMargin(uint8_t margin) -{ - NS_LOG_FUNCTION(this << unsigned(margin)); - - m_margin = margin; + NS_LOG_FUNCTION(this); + os << "LinkCheckAns("; + os << "Margin=" << unsigned(m_margin); + os << ", GwCnt=" << unsigned(m_gwCnt); + os << ")"; } uint8_t LinkCheckAns::GetMargin() const { NS_LOG_FUNCTION(this); - return m_margin; } -void -LinkCheckAns::SetGwCnt(uint8_t gwCnt) -{ - NS_LOG_FUNCTION(this << unsigned(gwCnt)); - - m_gwCnt = gwCnt; -} - uint8_t LinkCheckAns::GetGwCnt() const { @@ -242,14 +199,6 @@ LinkCheckAns::GetGwCnt() const return m_gwCnt; } -void -LinkCheckAns::IncrementGwCnt() -{ - NS_LOG_FUNCTION(this); - - m_gwCnt++; -} - //////////////// // LinkAdrReq // //////////////// @@ -257,24 +206,26 @@ LinkCheckAns::IncrementGwCnt() LinkAdrReq::LinkAdrReq() { NS_LOG_FUNCTION(this); - m_commandType = LINK_ADR_REQ; m_serializedSize = 5; } LinkAdrReq::LinkAdrReq(uint8_t dataRate, uint8_t txPower, - uint16_t channelMask, + uint16_t chMask, uint8_t chMaskCntl, - uint8_t nbRep) + uint8_t nbTrans) : m_dataRate(dataRate), m_txPower(txPower), - m_channelMask(channelMask), + m_chMask(chMask), m_chMaskCntl(chMaskCntl), - m_nbRep(nbRep) + m_nbTrans(nbTrans) { NS_LOG_FUNCTION(this); - + NS_ASSERT_MSG(!(dataRate & 0xF0), "dataRate field > 4 bits"); + NS_ASSERT_MSG(!(txPower & 0xF0), "txPower field > 4 bits"); + NS_ASSERT_MSG(!(chMaskCntl & 0xF8), "chMaskCntl field > 3 bits"); + NS_ASSERT_MSG(!(nbTrans & 0xF0), "nbTrans field > 4 bits"); m_commandType = LINK_ADR_REQ; m_serializedSize = 5; } @@ -282,86 +233,74 @@ LinkAdrReq::LinkAdrReq(uint8_t dataRate, void LinkAdrReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8(m_dataRate << 4 | (m_txPower & 0b1111)); - start.WriteU16(m_channelMask); - start.WriteU8(m_chMaskCntl << 4 | (m_nbRep & 0b1111)); + start.WriteU16(m_chMask); + start.WriteU8(m_chMaskCntl << 4 | (m_nbTrans & 0b1111)); } uint8_t LinkAdrReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID uint8_t firstByte = start.ReadU8(); m_dataRate = firstByte >> 4; m_txPower = firstByte & 0b1111; - m_channelMask = start.ReadU16(); + m_chMask = start.ReadU16(); uint8_t fourthByte = start.ReadU8(); m_chMaskCntl = fourthByte >> 4; - m_nbRep = fourthByte & 0b1111; - + m_nbTrans = fourthByte & 0b1111; return m_serializedSize; } void LinkAdrReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "LinkAdrReq" << std::endl; - os << "dataRate: " << unsigned(m_dataRate) << std::endl; - os << "txPower: " << unsigned(m_txPower) << std::endl; - os << "channelMask: " << std::bitset<16>(m_channelMask) << std::endl; - os << "chMaskCntl: " << unsigned(m_chMaskCntl) << std::endl; - os << "nbRep: " << unsigned(m_nbRep) << std::endl; + NS_LOG_FUNCTION(this); + os << "LinkAdrReq("; + os << "DataRate=" << unsigned(m_dataRate); + os << ", TXPower=" << unsigned(m_txPower); + os << ", ChMask=" << std::bitset<16>(m_chMask); + os << ", ChMaskCntl=" << unsigned(m_chMaskCntl); + os << ", NbTrans=" << unsigned(m_nbTrans); + os << ")"; } uint8_t -LinkAdrReq::GetDataRate() +LinkAdrReq::GetDataRate() const { NS_LOG_FUNCTION(this); - return m_dataRate; } uint8_t -LinkAdrReq::GetTxPower() +LinkAdrReq::GetTxPower() const { NS_LOG_FUNCTION(this); - return m_txPower; } -std::list -LinkAdrReq::GetEnabledChannelsList() +uint16_t +LinkAdrReq::GetChMask() const { NS_LOG_FUNCTION(this); - - std::list channelIndices; - for (int i = 0; i < 16; i++) - { - if (m_channelMask & (0b1 << i)) // Take channel mask's i-th bit - { - NS_LOG_DEBUG("Adding channel index " << i); - channelIndices.push_back(i); - } - } - - return channelIndices; + return m_chMask; } -int -LinkAdrReq::GetRepetitions() +uint8_t +LinkAdrReq::GetChMaskCntl() const { NS_LOG_FUNCTION(this); + return m_chMaskCntl; +} - return m_nbRep; +uint8_t +LinkAdrReq::GetNbTrans() const +{ + NS_LOG_FUNCTION(this); + return m_nbTrans; } //////////////// @@ -371,7 +310,6 @@ LinkAdrReq::GetRepetitions() LinkAdrAns::LinkAdrAns() { NS_LOG_FUNCTION(this); - m_commandType = LINK_ADR_ANS; m_serializedSize = 2; } @@ -382,7 +320,6 @@ LinkAdrAns::LinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck) m_channelMaskAck(channelMaskAck) { NS_LOG_FUNCTION(this); - m_commandType = LINK_ADR_ANS; m_serializedSize = 2; } @@ -390,12 +327,8 @@ LinkAdrAns::LinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck) void LinkAdrAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - // We can assume that true will be converted to 1 and that false will be - // converted to 0 on any C++ compiler + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8((uint8_t(m_powerAck) << 2) | (uint8_t(m_dataRateAck) << 1) | uint8_t(m_channelMaskAck)); } @@ -403,26 +336,45 @@ LinkAdrAns::Serialize(Buffer::Iterator& start) const uint8_t LinkAdrAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID uint8_t byte = start.ReadU8(); - m_powerAck = byte & 0b100; m_dataRateAck = byte & 0b10; m_channelMaskAck = byte & 0b1; - return m_serializedSize; } void LinkAdrAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); + os << "LinkAdrAns("; + os << "PowerACK=" << m_powerAck; + os << ", DataRateACK=" << m_dataRateAck; + os << ", ChannelMaskACK=" << m_channelMaskAck; + os << ")"; +} - os << "LinkAdrAns" << std::endl; +bool +LinkAdrAns::GetPowerAck() const +{ + NS_LOG_FUNCTION(this); + return m_powerAck; +} + +bool +LinkAdrAns::GetDataRateAck() const +{ + NS_LOG_FUNCTION(this); + return m_dataRateAck; +} + +bool +LinkAdrAns::GetChannelMaskAck() const +{ + NS_LOG_FUNCTION(this); + return m_channelMaskAck; } ////////////////// @@ -432,16 +384,15 @@ LinkAdrAns::Print(std::ostream& os) const DutyCycleReq::DutyCycleReq() { NS_LOG_FUNCTION(this); - m_commandType = DUTY_CYCLE_REQ; m_serializedSize = 2; } -DutyCycleReq::DutyCycleReq(uint8_t dutyCycle) - : m_maxDCycle(dutyCycle) +DutyCycleReq::DutyCycleReq(uint8_t maxDutyCycle) { - NS_LOG_FUNCTION(this); - + NS_LOG_FUNCTION(this << unsigned(maxDutyCycle)); + NS_ASSERT_MSG(!(maxDutyCycle & 0xF0), "maxDutyCycle > 4 bits"); + m_maxDutyCycle = maxDutyCycle; m_commandType = DUTY_CYCLE_REQ; m_serializedSize = 2; } @@ -449,52 +400,34 @@ DutyCycleReq::DutyCycleReq(uint8_t dutyCycle) void DutyCycleReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - start.WriteU8(m_maxDCycle); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID + start.WriteU8(m_maxDutyCycle); } uint8_t DutyCycleReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - m_maxDCycle = start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID + m_maxDutyCycle = start.ReadU8(); return m_serializedSize; } void DutyCycleReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "DutyCycleReq" << std::endl; - os << "maxDCycle: " << unsigned(m_maxDCycle) << std::endl; - os << "maxDCycle (fraction): " << GetMaximumAllowedDutyCycle() << std::endl; + NS_LOG_FUNCTION(this); + os << "DutyCycleReq("; + os << "MaxDutyCycle=" << unsigned(m_maxDutyCycle); + os << ")"; } -double -DutyCycleReq::GetMaximumAllowedDutyCycle() const +uint8_t +DutyCycleReq::GetMaxDutyCycle() const { NS_LOG_FUNCTION(this); - - // Check if we need to turn off completely - if (m_maxDCycle == 255) - { - return 0; - } - - if (m_maxDCycle == 0) - { - return 1; - } - - return 1 / std::pow(2, double(m_maxDCycle)); + return m_maxDutyCycle; } ////////////////// @@ -504,7 +437,6 @@ DutyCycleReq::GetMaximumAllowedDutyCycle() const DutyCycleAns::DutyCycleAns() { NS_LOG_FUNCTION(this); - m_commandType = DUTY_CYCLE_ANS; m_serializedSize = 1; } @@ -512,60 +444,45 @@ DutyCycleAns::DutyCycleAns() void DutyCycleAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t DutyCycleAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void DutyCycleAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "DutyCycleAns" << std::endl; + NS_LOG_FUNCTION(this); + os << "DutyCycleAns()"; } -////////////////// +///////////////////// // RxParamSetupReq // -////////////////// +///////////////////// RxParamSetupReq::RxParamSetupReq() { NS_LOG_FUNCTION(this); - m_commandType = RX_PARAM_SETUP_REQ; m_serializedSize = 5; } -RxParamSetupReq::RxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency) +RxParamSetupReq::RxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz) : m_rx1DrOffset(rx1DrOffset), m_rx2DataRate(rx2DataRate), - m_frequency(frequency) + m_frequencyHz(frequencyHz) { - NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency); - - if ((rx1DrOffset & 0b11111000) != 0) - { - NS_LOG_WARN( - "Warning: received an rx1DrOffset greater than 7. Actual value will be different."); - } - if ((rx2DataRate & 0b11110000) != 0) - { - NS_LOG_WARN( - "Warning: received a rx2DataRate greater than 15. Actual value will be different."); - } - + NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) + << uint32_t(frequencyHz)); + NS_ASSERT_MSG(!(rx1DrOffset & 0xF8), "rx1DrOffset > 3 bits"); + NS_ASSERT_MSG(!(rx2DataRate & 0xF0), "rx2DataRate > 4 bits"); m_commandType = RX_PARAM_SETUP_REQ; m_serializedSize = 5; } @@ -573,57 +490,48 @@ RxParamSetupReq::RxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, doubl void RxParamSetupReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - // Data serialization + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8((m_rx1DrOffset & 0b111) << 4 | (m_rx2DataRate & 0b1111)); - uint32_t encodedFrequency = m_frequency / 100; - NS_LOG_DEBUG(unsigned(encodedFrequency)); - NS_LOG_DEBUG(std::bitset<32>(encodedFrequency)); - start.WriteU8((encodedFrequency & 0xff0000) >> 16); // Most significant byte - start.WriteU8((encodedFrequency & 0xff00) >> 8); // Middle byte - start.WriteU8(encodedFrequency & 0xff); // Least significant byte + uint32_t encodedFrequency = m_frequencyHz / 100; + // Frequency is in little endian (lsb -> msb) + start.WriteU8(encodedFrequency); // Least significant byte + start.WriteU8(encodedFrequency >> 8); // Middle byte + start.WriteU8(encodedFrequency >> 16); // Most significant byte } uint8_t RxParamSetupReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - // Data serialization + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID uint8_t firstByte = start.ReadU8(); m_rx1DrOffset = (firstByte & 0b1110000) >> 4; m_rx2DataRate = firstByte & 0b1111; - uint32_t secondByte = start.ReadU8(); - uint32_t thirdByte = start.ReadU8(); - uint32_t fourthByte = start.ReadU8(); - uint32_t encodedFrequency = (secondByte << 16) | (thirdByte << 8) | fourthByte; - NS_LOG_DEBUG(std::bitset<32>(encodedFrequency)); - m_frequency = double(encodedFrequency) * 100; - + uint32_t encodedFrequency = 0; + // Frequency is in little endian (lsb -> msb) + encodedFrequency += start.ReadU8(); // Least significant byte + encodedFrequency += start.ReadU8() << 8; // Middle byte + encodedFrequency += start.ReadU8() << 16; // Most significant byte + m_frequencyHz = encodedFrequency * 100; return m_serializedSize; } void RxParamSetupReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "RxParamSetupReq" << std::endl; - os << "rx1DrOffset: " << unsigned(m_rx1DrOffset) << std::endl; - os << "rx2DataRate: " << unsigned(m_rx2DataRate) << std::endl; - os << "frequency: " << m_frequency << std::endl; + NS_LOG_FUNCTION(this); + os << "RxParamSetupReq("; + os << "RX1DROffset=" << unsigned(m_rx1DrOffset); + os << ", RX2DataRate=" << unsigned(m_rx2DataRate); + os << ", Frequency=" << uint32_t(m_frequencyHz); + os << ")"; } uint8_t RxParamSetupReq::GetRx1DrOffset() { NS_LOG_FUNCTION(this); - return m_rx1DrOffset; } @@ -631,7 +539,6 @@ uint8_t RxParamSetupReq::GetRx2DataRate() { NS_LOG_FUNCTION(this); - return m_rx2DataRate; } @@ -639,8 +546,7 @@ double RxParamSetupReq::GetFrequency() { NS_LOG_FUNCTION(this); - - return m_frequency; + return m_frequencyHz; } ///////////////////// @@ -650,7 +556,6 @@ RxParamSetupReq::GetFrequency() RxParamSetupAns::RxParamSetupAns() { NS_LOG_FUNCTION(this); - m_commandType = RX_PARAM_SETUP_ANS; m_serializedSize = 2; } @@ -661,7 +566,6 @@ RxParamSetupAns::RxParamSetupAns(bool rx1DrOffsetAck, bool rx2DataRateAck, bool m_channelAck(channelAck) { NS_LOG_FUNCTION(this << rx1DrOffsetAck << rx2DataRateAck << channelAck); - m_commandType = RX_PARAM_SETUP_ANS; m_serializedSize = 2; } @@ -669,11 +573,8 @@ RxParamSetupAns::RxParamSetupAns(bool rx1DrOffsetAck, bool rx2DataRateAck, bool void RxParamSetupAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - // Data serialization + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8(uint8_t(m_rx1DrOffsetAck) << 2 | uint8_t(m_rx2DataRateAck) << 1 | uint8_t(m_channelAck)); } @@ -681,29 +582,45 @@ RxParamSetupAns::Serialize(Buffer::Iterator& start) const uint8_t RxParamSetupAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID uint8_t byte = start.ReadU8(); - m_rx1DrOffsetAck = (byte & 0b100) >> 2; m_rx2DataRateAck = (byte & 0b10) >> 1; m_channelAck = byte & 0b1; - return m_serializedSize; } void RxParamSetupAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); + os << "RxParamSetupAns("; + os << "RX1DROffsetACK=" << m_rx1DrOffsetAck; + os << ", RX2DataRateACK=" << m_rx2DataRateAck; + os << ", ChannelACK=" << m_channelAck; + os << ")"; +} + +bool +RxParamSetupAns::GetRx1DrOffsetAck() const +{ + NS_LOG_FUNCTION(this); + return m_rx1DrOffsetAck; +} + +bool +RxParamSetupAns::GetRx2DataRateAck() const +{ + NS_LOG_FUNCTION(this); + return m_rx2DataRateAck; +} - os << "RxParamSetupAns" << std::endl; - os << "m_rx1DrOffsetAck: " << m_rx1DrOffsetAck << std::endl; - os << "m_rx2DataRateAck: " << m_rx2DataRateAck << std::endl; - os << "m_channelAck: " << m_channelAck << std::endl; +bool +RxParamSetupAns::GetChannelAck() const +{ + NS_LOG_FUNCTION(this); + return m_channelAck; } ////////////////// @@ -713,7 +630,6 @@ RxParamSetupAns::Print(std::ostream& os) const DevStatusReq::DevStatusReq() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_REQ; m_serializedSize = 1; } @@ -721,29 +637,23 @@ DevStatusReq::DevStatusReq() void DevStatusReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t DevStatusReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void DevStatusReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "DevStatusReq" << std::endl; + NS_LOG_FUNCTION(this); + os << "DevStatusReq()"; } ////////////////// @@ -753,7 +663,6 @@ DevStatusReq::Print(std::ostream& os) const DevStatusAns::DevStatusAns() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_ANS; m_serializedSize = 3; } @@ -763,7 +672,7 @@ DevStatusAns::DevStatusAns(uint8_t battery, uint8_t margin) m_margin(margin) { NS_LOG_FUNCTION(this << unsigned(battery) << unsigned(margin)); - + NS_ASSERT_MSG(!(margin & 0xC0), "margin > 6 bits"); m_commandType = DEV_STATUS_ANS; m_serializedSize = 3; } @@ -771,10 +680,8 @@ DevStatusAns::DevStatusAns(uint8_t battery, uint8_t margin) void DevStatusAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8(m_battery); start.WriteU8(m_margin); } @@ -782,39 +689,34 @@ DevStatusAns::Serialize(Buffer::Iterator& start) const uint8_t DevStatusAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID m_battery = start.ReadU8(); - m_margin = start.ReadU8() & 0b111111; - + m_margin = start.ReadU8(); return m_serializedSize; } void DevStatusAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "DevStatusAns" << std::endl; - os << "Battery: " << unsigned(m_battery) << std::endl; - os << "Margin: " << unsigned(m_margin) << std::endl; + NS_LOG_FUNCTION(this); + os << "DevStatusAns("; + os << "Battery=" << unsigned(m_battery); + os << ", Margin=" << unsigned(m_margin); + os << ")"; } uint8_t DevStatusAns::GetBattery() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_battery; } uint8_t DevStatusAns::GetMargin() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_margin; } @@ -825,22 +727,22 @@ DevStatusAns::GetMargin() const NewChannelReq::NewChannelReq() { NS_LOG_FUNCTION(this); - m_commandType = NEW_CHANNEL_REQ; m_serializedSize = 6; } NewChannelReq::NewChannelReq(uint8_t chIndex, - double frequency, + double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate) : m_chIndex(chIndex), - m_frequency(frequency), + m_frequencyHz(frequencyHz), m_minDataRate(minDataRate), m_maxDataRate(maxDataRate) { NS_LOG_FUNCTION(this); - + NS_ASSERT_MSG(!(minDataRate & 0xF0), "minDataRate > 4 bits"); + NS_ASSERT_MSG(!(maxDataRate & 0xF0), "maxDataRate > 4 bits"); m_commandType = NEW_CHANNEL_REQ; m_serializedSize = 6; } @@ -848,76 +750,72 @@ NewChannelReq::NewChannelReq(uint8_t chIndex, void NewChannelReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8(m_chIndex); - uint32_t encodedFrequency = m_frequency / 100; - start.WriteU8((encodedFrequency & 0xff0000) >> 16); - start.WriteU8((encodedFrequency & 0xff00) >> 8); - start.WriteU8(encodedFrequency & 0xff); + uint32_t encodedFrequency = m_frequencyHz / 100; + // Frequency is in little endian (lsb -> msb) + start.WriteU8(encodedFrequency); // Least significant byte + start.WriteU8(encodedFrequency >> 8); // Middle byte + start.WriteU8(encodedFrequency >> 16); // Most significant byte start.WriteU8((m_maxDataRate << 4) | (m_minDataRate & 0xf)); } uint8_t NewChannelReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - // Read the data + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID m_chIndex = start.ReadU8(); uint32_t encodedFrequency = 0; - encodedFrequency |= uint32_t(start.ReadU16()) << 8; - encodedFrequency |= uint32_t(start.ReadU8()); - m_frequency = double(encodedFrequency) * 100; + // Frequency is in little endian (lsb -> msb) + encodedFrequency += start.ReadU8(); // Least significant byte + encodedFrequency += start.ReadU8() << 8; // Middle byte + encodedFrequency += start.ReadU8() << 16; // Most significant byte + m_frequencyHz = encodedFrequency * 100; uint8_t dataRateByte = start.ReadU8(); m_maxDataRate = dataRateByte >> 4; m_minDataRate = dataRateByte & 0xf; - return m_serializedSize; } void NewChannelReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "NewChannelReq" << std::endl; + NS_LOG_FUNCTION(this); + os << "NewChannelReq("; + os << "ChIndex=" << unsigned(m_chIndex); + os << ", Frequency=" << uint32_t(m_frequencyHz); + os << ", MaxDR=" << unsigned(m_maxDataRate); + os << ", MinDR=" << unsigned(m_minDataRate); + os << ")"; } uint8_t NewChannelReq::GetChannelIndex() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_chIndex; } double NewChannelReq::GetFrequency() const { - NS_LOG_FUNCTION_NOARGS(); - - return m_frequency; + NS_LOG_FUNCTION(this); + return m_frequencyHz; } uint8_t NewChannelReq::GetMinDataRate() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_minDataRate; } uint8_t NewChannelReq::GetMaxDataRate() const { - NS_LOG_FUNCTION_NOARGS(); - + NS_LOG_FUNCTION(this); return m_maxDataRate; } @@ -928,7 +826,6 @@ NewChannelReq::GetMaxDataRate() const NewChannelAns::NewChannelAns() { NS_LOG_FUNCTION(this); - m_commandType = NEW_CHANNEL_ANS; m_serializedSize = 2; } @@ -938,7 +835,6 @@ NewChannelAns::NewChannelAns(bool dataRateRangeOk, bool channelFrequencyOk) m_channelFrequencyOk(channelFrequencyOk) { NS_LOG_FUNCTION(this); - m_commandType = NEW_CHANNEL_ANS; m_serializedSize = 2; } @@ -946,37 +842,44 @@ NewChannelAns::NewChannelAns(bool dataRateRangeOk, bool channelFrequencyOk) void NewChannelAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID start.WriteU8((uint8_t(m_dataRateRangeOk) << 1) | uint8_t(m_channelFrequencyOk)); } uint8_t NewChannelAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - // Read the data - uint8_t byte = start.ReadU8(); + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID + uint8_t byte = start.ReadU8(); // Read the data m_dataRateRangeOk = (byte & 0b10) >> 1; m_channelFrequencyOk = (byte & 0b1); - return m_serializedSize; } void NewChannelAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); + NS_LOG_FUNCTION(this); + os << "NewChannelAns("; + os << "DataRateRangeOk=" << m_dataRateRangeOk; + os << ", ChannelFrequencyOk=" << m_channelFrequencyOk; + os << ")"; +} + +bool +NewChannelAns::GetDataRateRangeOk() const +{ + NS_LOG_FUNCTION(this); + return m_dataRateRangeOk; +} - os << "NewChannelAns" << std::endl; - os << "DataRateRangeOk: " << m_dataRateRangeOk << std::endl; - os << "ChannelFrequencyOk: " << m_channelFrequencyOk << std::endl; +bool +NewChannelAns::GetChannelFrequencyOk() const +{ + NS_LOG_FUNCTION(this); + return m_channelFrequencyOk; } ////////////////////// @@ -986,7 +889,6 @@ NewChannelAns::Print(std::ostream& os) const RxTimingSetupReq::RxTimingSetupReq() { NS_LOG_FUNCTION(this); - m_commandType = RX_TIMING_SETUP_REQ; m_serializedSize = 2; } @@ -995,7 +897,7 @@ RxTimingSetupReq::RxTimingSetupReq(uint8_t delay) : m_delay(delay) { NS_LOG_FUNCTION(this); - + NS_ASSERT_MSG(!(delay & 0xF0), "delay field > 4 bits"); m_commandType = RX_TIMING_SETUP_REQ; m_serializedSize = 2; } @@ -1003,45 +905,32 @@ RxTimingSetupReq::RxTimingSetupReq(uint8_t delay) void RxTimingSetupReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); - // Write the data - start.WriteU8(m_delay & 0xf); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID + start.WriteU8(m_delay & 0xF); // Write the data } uint8_t RxTimingSetupReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - // Read the data - m_delay = start.ReadU8() & 0xf; - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID + m_delay = start.ReadU8() & 0xF; // Read the data return m_serializedSize; } void RxTimingSetupReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "RxTimingSetupReq" << std::endl; + NS_LOG_FUNCTION(this); + os << "RxTimingSetupReq()"; } Time RxTimingSetupReq::GetDelay() { NS_LOG_FUNCTION(this); - - if (m_delay == 0) - { - return Seconds(1); - } - return Seconds(m_delay); + return Seconds((m_delay) ? m_delay : 0); } ////////////////// @@ -1051,7 +940,6 @@ RxTimingSetupReq::GetDelay() RxTimingSetupAns::RxTimingSetupAns() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_REQ; m_serializedSize = 1; } @@ -1059,29 +947,23 @@ RxTimingSetupAns::RxTimingSetupAns() void RxTimingSetupAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t RxTimingSetupAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void RxTimingSetupAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "RxTimingSetupAns" << std::endl; + NS_LOG_FUNCTION(this); + os << "RxTimingSetupAns()"; } ////////////////// @@ -1091,7 +973,6 @@ RxTimingSetupAns::Print(std::ostream& os) const DlChannelAns::DlChannelAns() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_REQ; m_serializedSize = 1; } @@ -1099,29 +980,23 @@ DlChannelAns::DlChannelAns() void DlChannelAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t DlChannelAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void DlChannelAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "DlChannelAns" << std::endl; + NS_LOG_FUNCTION(this); + os << "DlChannelAns()"; } ////////////////// @@ -1131,7 +1006,6 @@ DlChannelAns::Print(std::ostream& os) const TxParamSetupReq::TxParamSetupReq() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_REQ; m_serializedSize = 1; } @@ -1139,29 +1013,23 @@ TxParamSetupReq::TxParamSetupReq() void TxParamSetupReq::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t TxParamSetupReq::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void TxParamSetupReq::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "TxParamSetupReq" << std::endl; + NS_LOG_FUNCTION(this); + os << "TxParamSetupReq()"; } ////////////////// @@ -1171,7 +1039,6 @@ TxParamSetupReq::Print(std::ostream& os) const TxParamSetupAns::TxParamSetupAns() { NS_LOG_FUNCTION(this); - m_commandType = DEV_STATUS_REQ; m_serializedSize = 1; } @@ -1179,29 +1046,23 @@ TxParamSetupAns::TxParamSetupAns() void TxParamSetupAns::Serialize(Buffer::Iterator& start) const { - NS_LOG_FUNCTION_NOARGS(); - - // Write the CID - start.WriteU8(GetCIDFromMacCommand(m_commandType)); + NS_LOG_FUNCTION(this); + start.WriteU8(GetCIDFromMacCommand(m_commandType)); // Write the CID } uint8_t TxParamSetupAns::Deserialize(Buffer::Iterator& start) { - NS_LOG_FUNCTION_NOARGS(); - - // Consume the CID - start.ReadU8(); - + NS_LOG_FUNCTION(this); + start.ReadU8(); // Consume the CID return m_serializedSize; } void TxParamSetupAns::Print(std::ostream& os) const { - NS_LOG_FUNCTION_NOARGS(); - - os << "TxParamSetupAns" << std::endl; + NS_LOG_FUNCTION(this); + os << "TxParamSetupAns()"; } } // namespace lorawan diff --git a/model/mac-command.h b/model/mac-command.h index 08a7359e5f..2973bc8d5f 100644 --- a/model/mac-command.h +++ b/model/mac-command.h @@ -125,8 +125,8 @@ class MacCommand : public Object class LinkCheckReq : public MacCommand { public: - LinkCheckReq(); - ~LinkCheckReq() override; //!< Destructor + LinkCheckReq(); //!< Default constructor + void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; @@ -157,13 +157,6 @@ class LinkCheckAns : public MacCommand uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; - /** - * Set the demodulation margin value. - * - * \param margin The demodulation margin to set. - */ - void SetMargin(uint8_t margin); - /** * Get the demodulation margin value. * @@ -171,13 +164,6 @@ class LinkCheckAns : public MacCommand */ uint8_t GetMargin() const; - /** - * Set the gateway count value. - * - * \param gwCnt The count value to set. - */ - void SetGwCnt(uint8_t gwCnt); - /** * Get the gateway count value. * @@ -185,11 +171,6 @@ class LinkCheckAns : public MacCommand */ uint8_t GetGwCnt() const; - /** - * Increment this MacCommand's gwCnt value. - */ - void IncrementGwCnt(); - private: uint8_t m_margin; //!< This MAC command's demodulation margin value. uint8_t m_gwCnt; //!< This MAC command's gateway count value. @@ -207,7 +188,8 @@ class LinkCheckAns : public MacCommand class LinkAdrReq : public MacCommand { public: - LinkAdrReq(); + LinkAdrReq(); //!< Default constructor + /** * Constructor with given fields. * @@ -219,15 +201,15 @@ class LinkAdrReq : public MacCommand * * \param dataRate The DataRate field to set. * \param txPower The TXPower field to set. - * \param channelMask The ChMask field to set. + * \param chMask The ChMask field to set. * \param chMaskCntl The ChMaskCntl field to set. - * \param nbRep The NbTrans field to set. + * \param nbTrans The NbTrans field to set. */ LinkAdrReq(uint8_t dataRate, uint8_t txPower, - uint16_t channelMask, + uint16_t chMask, uint8_t chMaskCntl, - uint8_t nbRep); + uint8_t nbTrans); void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -238,7 +220,7 @@ class LinkAdrReq : public MacCommand * * \return An unsigned 8-bit integer containing the data rate. */ - uint8_t GetDataRate(); + uint8_t GetDataRate() const; /** * Get the transmission power prescribed by this MAC command. @@ -249,31 +231,39 @@ class LinkAdrReq : public MacCommand * * \return The TX power, encoded as an unsigned 8-bit integer. */ - uint8_t GetTxPower(); + uint8_t GetTxPower() const; /** - * Get the list of enabled channels. This method takes the 16-bit channel mask - * and translates it to a list of integers that can be more easily parsed. + * Get the 16 bit mask of enabled channels. * - * \return The list of enabled channels. + * \return The 16 bit channel mask. */ - std::list GetEnabledChannelsList(); + uint16_t GetChMask() const; /** - * Get the number of repetitions prescribed by this MAC command. + * Get the ChMaskCntl field, used as an indicator of the 16-channel bank to apply the ChMask to. * - * \return The number of repetitions. + * The interpretation of this field is region-dependent. + * + * \return The ChMaskCntl field. */ - int GetRepetitions(); + uint8_t GetChMaskCntl() const; + + /** + * Get the number of repeated transmissions prescribed by this MAC command. + * + * \return The number of repeated transmissions. + */ + uint8_t GetNbTrans() const; private: - uint8_t m_dataRate; //!< The DataRate field, a serializable parameter for setting the - //!< spreading factor and bandwidth of end devices - uint8_t m_txPower; //!< The TXPower field, a serializable parameter for setting the - //!< transmission power of end devices - uint16_t m_channelMask; //!< The ChMask field - uint8_t m_chMaskCntl; //!< The ChMaskCntl field - uint8_t m_nbRep; //!< The NbTrans field + uint8_t m_dataRate; //!< The DataRate field, a serializable parameter for setting the + //!< spreading factor and bandwidth of end devices + uint8_t m_txPower; //!< The TXPower field, a serializable parameter for setting the + //!< transmission power of end devices + uint16_t m_chMask; //!< The ChMask field + uint8_t m_chMaskCntl; //!< The ChMaskCntl field + uint8_t m_nbTrans; //!< The NbTrans field }; /** @@ -301,6 +291,36 @@ class LinkAdrAns : public MacCommand uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; + /** + * Get the PowerAck field value of the LinkAdrAns command. + * + * \return true The power level was successfully set. + * \return false The end-device is unable to operate at or below the requested power level. The + * command was discarded and the end-device state was not changed. + */ + bool GetPowerAck() const; + + /** + * Get the DataRateAck field value of the LinkAdrAns command. + * + * \return true The data rate was successfully set. + * \return false The data rate requested is unknown to the end-device or is not possible, given + * the channel mask provided (not supported by any of the enabled channels). The command was + * discarded, and the end-device state was not changed. + */ + bool GetDataRateAck() const; + + /** + * Get the ChannelMaskAck field value of the LinkAdrAns command. + * + * \return true The channel mask sent was successfully interpreted. All currently defined + * channel states were set according to the mask. + * \return false The channel mask enables a yet undefined channel or the channel mask required + * all channels to be disabled or the channel mask is incompatible with the resulting data rate + * or TX power. The command was discarded, and the end-device state was not changed. + */ + bool GetChannelMaskAck() const; + private: bool m_powerAck; //!< The PowerACK field bool m_dataRateAck; //!< The DataRateACK field @@ -319,27 +339,28 @@ class LinkAdrAns : public MacCommand class DutyCycleReq : public MacCommand { public: - DutyCycleReq(); + DutyCycleReq(); //!< Default constructor + /** * Constructor providing initialization of all parameters. * - * \param dutyCycle The duty cycle as a 8-bit unsigned integer. + * \param maxDutyCycle The MaxDutyCycle field as a 8-bit unsigned integer. */ - DutyCycleReq(uint8_t dutyCycle); + DutyCycleReq(uint8_t maxDutyCycle); void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; /** - * Get the maximum duty cycle prescribed by this Mac command, in fraction form. + * Get the maximum duty cycle prescribed by this Mac command, encoded in 4 bits. * - * \return The maximum duty cycle. + * \return The MaxDutyCycle field value. */ - double GetMaximumAllowedDutyCycle() const; + uint8_t GetMaxDutyCycle() const; private: - uint8_t m_maxDCycle; //!< The MaxDutyCycle field + uint8_t m_maxDutyCycle; //!< The MaxDutyCycle field }; /** @@ -370,16 +391,16 @@ class DutyCycleAns : public MacCommand class RxParamSetupReq : public MacCommand { public: - RxParamSetupReq(); + RxParamSetupReq(); //!< Default constructor /** * Constructor providing initialization of all fields. * * \param rx1DrOffset The data rate offset to use for the first receive window. * \param rx2DataRate The data rate to use for the second receive window. - * \param frequency The frequency in Hz to use for the second receive window. + * \param frequencyHz The frequency in Hz to use for the second receive window. */ - RxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency); + RxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz); void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -409,7 +430,7 @@ class RxParamSetupReq : public MacCommand private: uint8_t m_rx1DrOffset; //!< The RX1DROffset field uint8_t m_rx2DataRate; //!< The RX2DataRate field - double m_frequency; //!< The Frequency field, _in Hz_ + double m_frequencyHz; //!< The Frequency field, _in Hz_ }; /** @@ -420,7 +441,8 @@ class RxParamSetupReq : public MacCommand class RxParamSetupAns : public MacCommand { public: - RxParamSetupAns(); + RxParamSetupAns(); //!< Default constructor + /** * Constructor with initialization of all parameters. * @@ -434,6 +456,31 @@ class RxParamSetupAns : public MacCommand uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; + /** + * Get the Rx1DrOffsetAck field value of the RxParamSetupAns command. + * + * \return true RX1 data-rate offset was successfully set. + * \return false The uplink/downlink data rate offset for RX1 slot is not within the allowed + * range. + */ + bool GetRx1DrOffsetAck() const; + + /** + * Get the Rx2DataRateAck field value of the RxParamSetupAns command. + * + * \return true RX2 slot data rate was successfully set. + * \return false The data rate requested is unknown to the end-device. + */ + bool GetRx2DataRateAck() const; + + /** + * Get the ChannelAck field value of the RxParamSetupAns command. + * + * \return true RX2 slot channel was successfully set. + * \return false The frequency requested is not usable by the end-device. + */ + bool GetChannelAck() const; + private: bool m_rx1DrOffsetAck; //!< The RX1DROffsetACK field bool m_rx2DataRateAck; //!< The RX2DataRateACK field @@ -444,11 +491,13 @@ class RxParamSetupAns : public MacCommand * \ingroup lorawan * * Implementation of the DevStatusReq LoRaWAN MAC command. + * + * This command holds no variables, and just consists in the CID. */ class DevStatusReq : public MacCommand { public: - DevStatusReq(); + DevStatusReq(); //!< Default constructor void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -507,17 +556,17 @@ class DevStatusAns : public MacCommand class NewChannelReq : public MacCommand { public: - NewChannelReq(); + NewChannelReq(); //!< Default constructor /** * Constructor providing initialization of all parameters. * * \param chIndex The index of the channel this command wants to operate on. - * \param frequency The new frequency for this channel in Hz. + * \param frequencyHz The new frequency for this channel in Hz. * \param minDataRate The minimum data rate allowed on this channel. * \param maxDataRate The maximum data rate allowed on this channel. */ - NewChannelReq(uint8_t chIndex, double frequency, uint8_t minDataRate, uint8_t maxDataRate); + NewChannelReq(uint8_t chIndex, double frequencyHz, uint8_t minDataRate, uint8_t maxDataRate); void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -550,7 +599,7 @@ class NewChannelReq : public MacCommand private: uint8_t m_chIndex; //!< The ChIndex field - double m_frequency; //!< The Frequency field, in Hz + double m_frequencyHz; //!< The Frequency field, in Hz uint8_t m_minDataRate; //!< The MinDR field uint8_t m_maxDataRate; //!< The MaxDR field }; @@ -579,6 +628,23 @@ class NewChannelAns : public MacCommand uint8_t Deserialize(Buffer::Iterator& start) override; void Print(std::ostream& os) const override; + /** + * Get the DataRateRangOk field of the NewChannelAns command. + * + * \return true The data-rate range is compatible with the capabilities of the end-device. + * \return false The designated data-rate range exceeds the ones currently defined for this + * end-device. + */ + bool GetDataRateRangeOk() const; + + /** + * Get the ChannelFrequencyOk field of the NewChannelAns command. + * + * \return true The end-device is able to use this frequency. + * \return false The end-device cannot use this frequency. + */ + bool GetChannelFrequencyOk() const; + private: bool m_dataRateRangeOk; //!< The Data-rate range ok field bool m_channelFrequencyOk; //!< The Channel frequency ok field @@ -592,7 +658,7 @@ class NewChannelAns : public MacCommand class RxTimingSetupReq : public MacCommand { public: - RxTimingSetupReq(); + RxTimingSetupReq(); //!< Default constructor /** * Constructor providing initialization of all parameters. @@ -621,12 +687,12 @@ class RxTimingSetupReq : public MacCommand * * Implementation of the RxTimingSetupAns LoRaWAN MAC command. * - * This MAC command has an empty payload. + * This command holds no variables, and just consists in the CID. */ class RxTimingSetupAns : public MacCommand { public: - RxTimingSetupAns(); + RxTimingSetupAns(); //!< Default constructor void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -638,12 +704,14 @@ class RxTimingSetupAns : public MacCommand /** * \ingroup lorawan * - * Implementation of the TxParamSetupAns LoRaWAN MAC command. + * Implementation of the TxParamSetupReq LoRaWAN MAC command. + * + * \todo implementation */ -class TxParamSetupAns : public MacCommand +class TxParamSetupReq : public MacCommand { public: - TxParamSetupAns(); //!< Default constructor + TxParamSetupReq(); //!< Default constructor void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -655,12 +723,14 @@ class TxParamSetupAns : public MacCommand /** * \ingroup lorawan * - * Implementation of the TxParamSetupReq LoRaWAN MAC command. + * Implementation of the TxParamSetupAns LoRaWAN MAC command. + * + * This command holds no variables, and just consists in the CID. */ -class TxParamSetupReq : public MacCommand +class TxParamSetupAns : public MacCommand { public: - TxParamSetupReq(); + TxParamSetupAns(); //!< Default constructor void Serialize(Buffer::Iterator& start) const override; uint8_t Deserialize(Buffer::Iterator& start) override; @@ -673,6 +743,8 @@ class TxParamSetupReq : public MacCommand * \ingroup lorawan * * Implementation of the DlChannelAns LoRaWAN MAC command. + * + * \todo implementation */ class DlChannelAns : public MacCommand { diff --git a/model/network-controller-components.cc b/model/network-controller-components.cc index 066f9fe213..0237052324 100644 --- a/model/network-controller-components.cc +++ b/model/network-controller-components.cc @@ -163,12 +163,30 @@ LinkCheckComponent::BeforeSendingReply(Ptr status, { status->m_reply.needsReply = true; - // Get the number of gateways that received the packet and the best - // margin - uint8_t gwCount = status->GetLastReceivedPacketInfo().gwList.size(); - - Ptr replyCommand = Create(); - replyCommand->SetGwCnt(gwCount); + auto info = status->GetLastReceivedPacketInfo(); + + // Adapted from: github.com/chirpstack/chirpstack v4.9.0 + + // Get the best demodulation margin of the most recent LinkCheckReq command + double maxRssi = -1e3; + for (const auto& [_, gwRxData] : info.gwList) + { + if (gwRxData.rxPower > maxRssi) + { + maxRssi = gwRxData.rxPower; + } + } + /// \see ns3::lorawan::AdrComponent::RxPowerToSNR + double maxSnr = maxRssi + 174 - 10 * log10(125000) - 6; + /// \todo make this a global PHY constant, manage unknown sf values + double requiredSnr[] = {-20.0, -17.5, -15.0, -12.5, -10.0, -7.5, -5}; + double diff = maxSnr - requiredSnr[12 - info.sf]; + uint8_t margin = (diff < 0) ? 0 : (diff > 254) ? 254 : diff; + + // Get the number of gateways that received the most recent LinkCheckReq command + uint8_t gwCount = info.gwList.size(); + + auto replyCommand = Create(margin, gwCount); status->m_reply.frameHeader.SetAsDownlink(); status->m_reply.frameHeader.AddCommand(replyCommand); status->m_reply.macHeader.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN); diff --git a/model/periodic-sender.cc b/model/periodic-sender.cc index e5b296fa70..580fd0d101 100644 --- a/model/periodic-sender.cc +++ b/model/periodic-sender.cc @@ -33,7 +33,7 @@ PeriodicSender::GetTypeId() .SetGroupName("lorawan") .AddAttribute("Interval", "The interval between packet sends of this app", - TimeValue(Seconds(0)), + TimeValue(Time(0)), MakeTimeAccessor(&PeriodicSender::GetInterval, &PeriodicSender::SetInterval), MakeTimeChecker()); @@ -134,8 +134,8 @@ PeriodicSender::StartApplication() // Schedule the next SendPacket event Simulator::Cancel(m_sendEvent); - NS_LOG_DEBUG("Starting up application with a first event with a " << m_initialDelay.GetSeconds() - << " seconds delay"); + NS_LOG_DEBUG("Starting up application with a first event with a " << m_initialDelay.As(Time::S) + << " delay"); m_sendEvent = Simulator::Schedule(m_initialDelay, &PeriodicSender::SendPacket, this); NS_LOG_DEBUG("Event Id: " << m_sendEvent.GetUid()); } diff --git a/model/simple-end-device-lora-phy.cc b/model/simple-end-device-lora-phy.cc index 8ed3c11f4d..9b4a269da2 100644 --- a/model/simple-end-device-lora-phy.cc +++ b/model/simple-end-device-lora-phy.cc @@ -150,7 +150,7 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, if (!IsOnFrequency(frequencyMHz)) { NS_LOG_INFO("Packet lost because it's on frequency " - << frequencyMHz << " MHz and we are listening at " << m_frequency + << frequencyMHz << " MHz and we are listening at " << m_frequencyMHz << " MHz"); // Fire the trace source for this event. @@ -216,8 +216,7 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, SwitchToRx(); // Schedule the end of the reception of the packet - NS_LOG_INFO("Scheduling reception of a packet. End in " << duration.GetSeconds() - << " seconds"); + NS_LOG_INFO("Scheduling reception of a packet. End in " << duration.As(Time::S)); Simulator::Schedule(duration, &LoraPhy::EndReceive, this, packet, event); @@ -280,6 +279,11 @@ SimpleEndDeviceLoraPhy::EndReceive(Ptr packet, PtrRemovePacketTag(tag); + tag.SetReceivePower(event->GetRxPowerdBm()); + tag.SetFrequency(event->GetFrequency()); + packet->AddPacketTag(tag); m_rxOkCallback(packet); } } diff --git a/model/sub-band.cc b/model/sub-band.cc index 7602c4a6ad..b997fd929c 100644 --- a/model/sub-band.cc +++ b/model/sub-band.cc @@ -8,8 +8,6 @@ #include "sub-band.h" -#include "ns3/log.h" - namespace ns3 { namespace lorawan @@ -17,42 +15,29 @@ namespace lorawan NS_LOG_COMPONENT_DEFINE("SubBand"); -NS_OBJECT_ENSURE_REGISTERED(SubBand); - -TypeId -SubBand::GetTypeId() -{ - static TypeId tid = TypeId("ns3::SubBand").SetParent().SetGroupName("lorawan"); - return tid; -} - -SubBand::SubBand() -{ - NS_LOG_FUNCTION(this); -} - -SubBand::SubBand(double firstFrequency, - double lastFrequency, +SubBand::SubBand(double firstFrequencyMHz, + double lastFrequencyMHz, double dutyCycle, double maxTxPowerDbm) - : m_firstFrequency(firstFrequency), - m_lastFrequency(lastFrequency), + : m_firstFrequencyMHz(firstFrequencyMHz), + m_lastFrequencyMHz(lastFrequencyMHz), m_dutyCycle(dutyCycle), - m_nextTransmissionTime(Seconds(0)), + m_nextTransmissionTime(Time(0)), m_maxTxPowerDbm(maxTxPowerDbm) { - NS_LOG_FUNCTION(this << firstFrequency << lastFrequency << dutyCycle << maxTxPowerDbm); + NS_LOG_FUNCTION(this << firstFrequencyMHz << lastFrequencyMHz << dutyCycle << maxTxPowerDbm); } -SubBand::~SubBand() +double +SubBand::GetFirstFrequency() const { - NS_LOG_FUNCTION(this); + return m_firstFrequencyMHz; } double -SubBand::GetFirstFrequency() const +SubBand::GetLastFrequency() const { - return m_firstFrequency; + return m_lastFrequencyMHz; } double @@ -62,16 +47,15 @@ SubBand::GetDutyCycle() const } bool -SubBand::BelongsToSubBand(double frequency) const +SubBand::Contains(double frequencyMHz) const { - return (frequency > m_firstFrequency) && (frequency < m_lastFrequency); + return (frequencyMHz > m_firstFrequencyMHz) && (frequencyMHz < m_lastFrequencyMHz); } bool -SubBand::BelongsToSubBand(Ptr logicalChannel) const +SubBand::Contains(Ptr logicalChannel) const { - double frequency = logicalChannel->GetFrequency(); - return BelongsToSubBand(frequency); + return Contains(logicalChannel->GetFrequency()); } void diff --git a/model/sub-band.h b/model/sub-band.h index 02512101ba..cf2101c493 100644 --- a/model/sub-band.h +++ b/model/sub-band.h @@ -12,42 +12,34 @@ #include "logical-lora-channel.h" #include "ns3/nstime.h" -#include "ns3/object.h" +#include "ns3/simple-ref-count.h" namespace ns3 { namespace lorawan { -class LogicalLoraChannel; - /** * \ingroup lorawan * * Class representing a SubBand, i.e., a frequency band subject to some * regulations on duty cycle and transmission power. */ -class SubBand : public Object +class SubBand : public SimpleRefCount { public: - /** - * Register this type. - * \return The object TypeId. - */ - static TypeId GetTypeId(); - - SubBand(); //!< Default constructor - ~SubBand() override; //!< Destructor - /** * Create a new SubBand by specifying all of its properties. * - * \param firstFrequency The SubBand's lowest frequency [MHz]. - * \param lastFrequency The SubBand's highest frequency [MHz]. + * \param firstFrequencyMHz The SubBand's lowest frequency [MHz]. + * \param lastFrequencyMHz The SubBand's highest frequency [MHz]. * \param dutyCycle The duty cycle (as a fraction) allowed on this SubBand. * \param maxTxPowerDbm The maximum transmission power [dBm] allowed on this SubBand. */ - SubBand(double firstFrequency, double lastFrequency, double dutyCycle, double maxTxPowerDbm); + SubBand(double firstFrequencyMHz, + double lastFrequencyMHz, + double dutyCycle, + double maxTxPowerDbm); /** * Get the lowest frequency of the SubBand. @@ -56,12 +48,12 @@ class SubBand : public Object */ double GetFirstFrequency() const; - ///** - // * Get the last frequency of the subband. - // * - // * \return The lowest frequency [MHz] of the SubBand. - // */ - // double GetLastFrequency (); + /** + * Get the highest frequency of the SubBand. + * + * \return The highest frequency [MHz] of the SubBand. + */ + double GetLastFrequency() const; /** * Get the duty cycle of the subband. @@ -94,20 +86,20 @@ class SubBand : public Object /** * Return whether or not a frequency belongs to this SubBand. * - * \param frequency The frequency [MHz] we want to test against the current subband. + * \param frequencyMHz The frequency [MHz] we want to test against the current subband. * \return True if the frequency is between firstFrequency and lastFrequency, * false otherwise. */ - bool BelongsToSubBand(double frequency) const; + bool Contains(double frequencyMHz) const; /** * Return whether or not a channel belongs to this SubBand. * * \param channel The channel we want to test against the current subband. - * \return True if the channel's center frequency is between firstFrequency - * and lastFrequency, false otherwise. + * \return Whether the channel's center frequency is between the first and last frequency of the + * sub-band, margins excluded. */ - bool BelongsToSubBand(Ptr channel) const; + bool Contains(Ptr channel) const; /** * Set the maximum transmission power that is allowed on this SubBand. @@ -124,8 +116,8 @@ class SubBand : public Object double GetMaxTxPowerDbm() const; private: - double m_firstFrequency; //!< Starting frequency of the subband, in MHz - double m_lastFrequency; //!< Ending frequency of the subband, in MHz + double m_firstFrequencyMHz; //!< Starting frequency of the subband, in MHz + double m_lastFrequencyMHz; //!< Ending frequency of the subband, in MHz double m_dutyCycle; //!< The duty cycle that needs to be enforced on this subband Time m_nextTransmissionTime; //!< The next time a transmission will be allowed in this subband double m_maxTxPowerDbm; //!< The maximum transmission power that is admitted on this subband diff --git a/test/lorawan-test-suite.cc b/test/lorawan-test-suite.cc index c3e3d1d7e5..8cef45066d 100644 --- a/test/lorawan-test-suite.cc +++ b/test/lorawan-test-suite.cc @@ -59,36 +59,36 @@ InterferenceTest::DoRun() LoraInterferenceHelper interferenceHelper; - double frequency = 868.1; - double differentFrequency = 868.3; + double frequencyMHz = 868.1; + double differentFrequencyMHz = 868.3; Ptr event; Ptr event1; // Test overlap duration - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - event1 = interferenceHelper.Add(Seconds(1), 14, 12, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + event1 = interferenceHelper.Add(Seconds(1), 14, 12, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1), Seconds(1), "Overlap computation didn't give the expected result"); interferenceHelper.ClearAllEvents(); - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - event1 = interferenceHelper.Add(Seconds(1.5), 14, 12, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + event1 = interferenceHelper.Add(Seconds(1.5), 14, 12, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1), Seconds(1.5), "Overlap computation didn't give the expected result"); interferenceHelper.ClearAllEvents(); - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - event1 = interferenceHelper.Add(Seconds(3), 14, 12, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + event1 = interferenceHelper.Add(Seconds(3), 14, 12, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1), Seconds(2), "Overlap computation didn't give the expected result"); interferenceHelper.ClearAllEvents(); - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - event1 = interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + event1 = interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyMHz); // Because of some strange behavior, this test would get stuck if we used the same syntax of the // previous ones. This works instead. bool retval = interferenceHelper.GetOverlapTime(event, event1) == Seconds(2); @@ -96,32 +96,32 @@ InterferenceTest::DoRun() interferenceHelper.ClearAllEvents(); // Perfect overlap, packet survives - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); interferenceHelper.ClearAllEvents(); // Perfect overlap, packet survives - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 - 7, 7, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 - 7, 7, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); interferenceHelper.ClearAllEvents(); // Perfect overlap, packet destroyed - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 - 6, 7, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 - 6, 7, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 7, "Packet was not destroyed by interference as expected"); interferenceHelper.ClearAllEvents(); // Partial overlap, packet survives - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(1), 14 - 6, 7, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(1), 14 - 6, 7, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); @@ -130,8 +130,8 @@ InterferenceTest::DoRun() // Different frequencys // Packet would be destroyed if they were on the same frequency, but survives // since they are on different frequencies - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14, 7, nullptr, differentFrequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14, 7, nullptr, differentFrequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); @@ -140,8 +140,8 @@ InterferenceTest::DoRun() // Different SFs // Packet would be destroyed if they both were SF7, but survives thanks to spreading factor // semi-orthogonality - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); @@ -149,16 +149,16 @@ InterferenceTest::DoRun() // Spreading factor imperfect orthogonality // Different SFs are orthogonal only up to a point - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 17, 8, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 17, 8, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 8, "Packet was not destroyed by interference as expected"); interferenceHelper.ClearAllEvents(); // If a more 'distant' spreading factor is used, isolation gets better - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 17, 10, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 17, 10, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet was destroyed by interference while it should have survived"); @@ -166,10 +166,10 @@ InterferenceTest::DoRun() // Cumulative interference // Same spreading factor interference is cumulative - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 8, "Packet was not destroyed by interference as expected"); @@ -177,10 +177,10 @@ InterferenceTest::DoRun() // Cumulative interference // Interference is not cumulative between different SFs - event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 9, nullptr, frequency); - interferenceHelper.Add(Seconds(2), 14 + 16, 10, nullptr, frequency); + event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 9, nullptr, frequencyMHz); + interferenceHelper.Add(Seconds(2), 14 + 16, 10, nullptr, frequencyMHz); NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event), 0, "Packet did not survive interference as expected"); @@ -346,7 +346,7 @@ HeaderTest::DoRun() // Deserialization frameHdr.Deserialize(serialized); - Ptr command = DynamicCast(*frameHdr.GetCommands().begin()); + Ptr command = DynamicCast(frameHdr.GetCommands().at(0)); uint8_t margin = command->GetMargin(); uint8_t gwCnt = command->GetGwCnt(); @@ -388,7 +388,7 @@ HeaderTest::DoRun() frameHdr1.SetAsDownlink(); pkt->RemoveHeader(frameHdr1); - Ptr linkCheckAns = DynamicCast(*frameHdr1.GetCommands().begin()); + Ptr linkCheckAns = DynamicCast(frameHdr1.GetCommands().at(0)); NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()), 10, @@ -895,10 +895,10 @@ LogicalLoraChannelTest::DoRun() ///////////////////////////// // Setup - Ptr channel1 = CreateObject(868); - Ptr channel2 = CreateObject(868); - Ptr channel3 = CreateObject(868.1); - Ptr channel4 = CreateObject(868.001); + Ptr channel1 = Create(868, 0, 5); + Ptr channel2 = Create(868, 0, 5); + Ptr channel3 = Create(868.1, 0, 5); + Ptr channel4 = Create(868.001, 0, 5); // Equality between channels // Test the == and != operators @@ -911,74 +911,64 @@ LogicalLoraChannelTest::DoRun() ////////////////// // Setup - SubBand subBand(868, 868.7, 0.01, 14); - Ptr channel5 = CreateObject(870); + auto subBand = Create(868, 868.6, 0.01, 14); + Ptr channel5 = Create(870, 0, 5); - // Test BelongsToSubBand - NS_TEST_EXPECT_MSG_EQ(subBand.BelongsToSubBand(channel3), + // Test Contains + NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3), true, - "BelongsToSubBand does not behave as expected"); - NS_TEST_EXPECT_MSG_EQ(subBand.BelongsToSubBand(channel3->GetFrequency()), + "Contains does not behave as expected"); + NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3->GetFrequency()), true, - "BelongsToSubBand does not behave as expected"); - NS_TEST_EXPECT_MSG_EQ(subBand.BelongsToSubBand(channel5), + "Contains does not behave as expected"); + NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel5), false, - "BelongsToSubBand does not behave as expected"); + "Contains does not behave as expected"); /////////////////////////////////// // Test LogicalLoraChannelHelper // /////////////////////////////////// // Setup - Ptr channelHelper = CreateObject(); - SubBand subBand1(869, 869.4, 0.1, 27); - channel1 = CreateObject(868.1); - channel2 = CreateObject(868.3); - channel3 = CreateObject(868.5); - channel4 = CreateObject(869.1); - channel5 = CreateObject(869.3); + auto channelHelper = Create(16); + auto subBand1 = Create(869.4, 869.65, 0.10, 27); + channel1 = Create(868.1, 0, 5); + channel2 = Create(868.3, 0, 5); + channel3 = Create(869.525, 0, 5); // Channel diagram // - // Channels 1 2 3 4 5 - // SubBands 868 ----- 0.1% ----- 868.7 869 ----- 1% ----- 869.4 + // Channels 1 2 3 + // SubBands 868 ----- 1% ----- 868.6 869 ----- 10% ----- 869.4 // Add SubBands and LogicalLoraChannels to the helper - channelHelper->AddSubBand(&subBand); - channelHelper->AddSubBand(&subBand1); - channelHelper->AddChannel(channel1); - channelHelper->AddChannel(channel2); - channelHelper->AddChannel(channel3); - channelHelper->AddChannel(channel4); - channelHelper->AddChannel(channel5); + channelHelper->AddSubBand(subBand); + channelHelper->AddSubBand(subBand1); + channelHelper->SetChannel(0, channel1); + channelHelper->SetChannel(1, channel2); + channelHelper->SetChannel(2, channel3); // Duty Cycle tests // (high level duty cycle behavior) /////////////////////////////////// channelHelper->AddEvent(Seconds(2), channel1); - Time expectedTimeOff = Seconds(2 / 0.01 - 2); + Time expectedTimeOff = Seconds(2 / 0.01); - // Waiting time is computed correctly - NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitingTime(channel1), + // Wait time is computed correctly + NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel1), expectedTimeOff, - "Waiting time doesn't behave as expected"); + "Wait time doesn't behave as expected"); // Duty Cycle involves the whole SubBand, not just a channel - NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitingTime(channel2), + NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel2), expectedTimeOff, - "Waiting time doesn't behave as expected"); - NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitingTime(channel3), - expectedTimeOff, - "Waiting time doesn't behave as expected"); + "Wait time doesn't behave as expected"); // Other bands are not affected by this transmission - NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitingTime(channel4), - Time(0), - "Waiting time affects other subbands"); - NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitingTime(channel5), + NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel3), Time(0), - "Waiting time affects other subbands"); + "Wait time affects other subbands"); } /** @@ -1602,6 +1592,451 @@ LorawanMacTest::DoRun() NS_LOG_DEBUG("LorawanMacTest"); } +/** + * \ingroup lorawan + * + * It tests the functionalities of LoRaWAN MAC commands received by devices. + * + * This means testing that (i) settings in the downlink MAC commands are correctly applied/rejected + * by the device, and that (ii) the correct answer (if expected) is produced by the device. + */ +class MacCommandTest : public TestCase +{ + public: + MacCommandTest(); //!< Default constructor + ~MacCommandTest() override; //!< Destructor + + private: + /** + * Have this class' MAC layer receive a downlink packet carrying the input MAC command. After, + * trigger a new empty uplink packet send that can then be used to examine the MAC command + * answers in the header. + * + * \tparam T \explicit The type of MAC command to create. + * \tparam Ts \deduced Types of the constructor arguments. + * \param [in] args MAC command constructor arguments. + * \return The list of MAC commands produced by the device as an answer. + */ + template + std::vector> RunMacCommand(Ts&&... args); + + /** + * This function resets the state of the MAC layer used for tests. Use it before each call of + * RunMacCommand. Otherwise, on consecutive calls the MAC layer will not send due to duty-cycle + * limitations. + */ + void Reset(); + + void DoRun() override; + + Ptr m_mac; //!< The end device's MAC layer used in tests. +}; + +MacCommandTest::MacCommandTest() + : TestCase("Test functionality of MAC commands when received by a device") +{ +} + +MacCommandTest::~MacCommandTest() +{ + m_mac = nullptr; +} + +template +std::vector> +MacCommandTest::RunMacCommand(Ts&&... args) +{ + Ptr pkt; + LoraFrameHeader fhdr; + LorawanMacHeader mhdr; + // Prepare DL packet with input command + pkt = Create(0); + fhdr.SetAsDownlink(); + auto cmd = Create(args...); + fhdr.AddCommand(cmd); + pkt->AddHeader(fhdr); + mhdr.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN); + pkt->AddHeader(mhdr); + // Trigger MAC layer reception + DynamicCast(m_mac->GetPhy()) + ->SwitchToStandby(); // usually done as we open Rx windows + m_mac->Receive(pkt); + // Trigger MAC layer send + pkt = Create(0); + m_mac->Send(pkt); + // Retrieve uplink MAC commands + pkt->RemoveHeader(mhdr); + fhdr.SetAsUplink(); + pkt->RemoveHeader(fhdr); + return fhdr.GetCommands(); +} + +void +MacCommandTest::Reset() +{ + // Reset MAC state + LorawanMacHelper macHelper; + macHelper.SetRegion(LorawanMacHelper::EU); + macHelper.SetDeviceType(LorawanMacHelper::ED_A); + /// \todo Create should not require a node in input. + m_mac = DynamicCast(macHelper.Install(nullptr, nullptr)); + NS_TEST_EXPECT_MSG_NE(m_mac, nullptr, "Failed to initialize MAC layer object."); + auto phy = CreateObject(); + phy->SetChannel(CreateObject()); + phy->SetMobility(CreateObject()); + m_mac->SetPhy(phy); +} + +void +MacCommandTest::DoRun() +{ + NS_LOG_DEBUG("MacCommandTest"); + + Reset(); + // LinkCheckAns: get connectivity metrics of last uplink LinkCheckReq command + { + uint8_t margin = 20; // best reception margin [dB] from demodulation floor + uint8_t gwCnt = 3; // number of gateways that received last uplink + auto answers = RunMacCommand(margin, gwCnt); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownLinkMarginDb()), + unsigned(margin), + "m_lastKnownMarginDb differs from Margin field of LinkCheckAns"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownGatewayCount()), + unsigned(gwCnt), + "m_lastKnownGatewayCount differs GwCnt field of LinkCheckAns"); + NS_TEST_EXPECT_MSG_EQ(answers.size(), + 0, + "Unexpected uplink MAC command answer(s) to LinkCheckAns"); + } + + Reset(); + // LinkAdrReq: change data rate, TX power, redundancy, or channel mask + { + uint8_t dataRate = 5; + uint8_t txPower = 2; + uint16_t chMask = 0b101; + uint8_t chMaskCntl = 0; + uint8_t nbTrans = 13; + auto answers = RunMacCommand(dataRate, txPower, chMask, chMaskCntl, nbTrans); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()), + unsigned(dataRate), + "m_dataRate does not match DataRate field of LinkAdrReq"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(), + 14 - txPower * 2, + "m_txPowerDbm does not match txPower field of LinkAdrReq"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()), + unsigned(nbTrans), + "m_nbTrans does not match nbTrans field of LinkAdrReq"); + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i + 16 * chMaskCntl); + bool actual = (c) ? c->IsEnabledForUplink() : false; + bool expected = (chMask & 0b1 << i); + NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask"); + } + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto laa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true"); + } + + Reset(); + // LinkAdrReq: ADR bit off, only change channel mask + { + uint8_t dataRate = 5; + uint8_t txPower = 2; + uint16_t chMask = 0b010; + uint8_t chMaskCntl = 0; + uint8_t nbTrans = 13; + m_mac->SetUplinkAdrBit(false); + auto answers = RunMacCommand(dataRate, txPower, chMask, chMaskCntl, nbTrans); + NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetDataRate()), + unsigned(dataRate), + "m_dataRate expected to differ from DataRate field of LinkAdrReq"); + NS_TEST_EXPECT_MSG_NE(m_mac->GetTransmissionPowerDbm(), + 14 - txPower * 2, + "m_txPowerDbm expected to not match txPower field of LinkAdrReq"); + NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetMaxNumberOfTransmissions()), + unsigned(nbTrans), + "m_nbTrans expected to differ from nbTrans field of LinkAdrReq"); + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i + 16 * chMaskCntl); + bool actual = (c) ? c->IsEnabledForUplink() : false; + bool expected = (chMask & 0b1 << i); + NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask"); + } + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto laa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false"); + NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false"); + } + + Reset(); + // LinkAdrReq: invalid chMask, data rate and power + { // WARNING: default values are manually set here + uint8_t dataRate = 12; + uint8_t txPower = 8; + uint16_t chMask = 0b0; + uint8_t chMaskCntl = 0; + uint8_t nbTrans = 6; + auto answers = RunMacCommand(dataRate, txPower, chMask, chMaskCntl, nbTrans); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()), + 0, + "m_dataRate expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(), + 14, + "m_txPowerDbm expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()), + 1, + "m_nbTrans expected to be default value"); + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i + 16 * chMaskCntl); + bool actual = (c) ? c->IsEnabledForUplink() : false; + bool expected = (uint16_t(0b111) & 0b1 << i); + NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default"); + } + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto laa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false"); + NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false"); + NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false"); + } + + Reset(); + // LinkAdrReq: invalid chMask, valid data rate and power + { // WARNING: default values are manually set here + uint8_t dataRate = 1; + uint8_t txPower = 7; + uint16_t chMask = 0b1000; // enable only non-exisitng channel + uint8_t chMaskCntl = 0; + uint8_t nbTrans = 3; + auto answers = RunMacCommand(dataRate, txPower, chMask, chMaskCntl, nbTrans); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()), + 0, + "m_dataRate expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(), + 14, + "m_txPowerDbm expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()), + 1, + "m_nbTrans expected to be default value"); + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i + 16 * chMaskCntl); + bool actual = (c) ? c->IsEnabledForUplink() : false; + bool expected = (uint16_t(0b111) & 0b1 << i); + NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default"); + } + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto laa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false"); + NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true"); + } + + Reset(); + // LinkAdrReq: fringe parameter values + { // WARNING: default values are manually set here + uint8_t dataRate = 0xF; + uint8_t txPower = 0xF; // 0x0F ignores config + uint16_t chMask = 0b0; // should be ignored because chMaskCntl is 6 + uint8_t chMaskCntl = 6; // all channels on + uint8_t nbTrans = 0; // restore default 1 + // Set device params to values different from default + m_mac->SetDataRate(3); + m_mac->SetTransmissionPowerDbm(12); + m_mac->SetMaxNumberOfTransmissions(15); + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + channels.at(0)->DisableForUplink(); + auto answers = RunMacCommand(dataRate, txPower, chMask, chMaskCntl, nbTrans); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()), + 3, + "m_dataRate expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(), + 12, + "m_txPowerDbm expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()), + 1, + "m_nbTrans expected to be default value"); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i); + bool actual = (c) ? c->IsEnabledForUplink() : false; + bool expected = (uint16_t(0b111) & 0b1 << i); + NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default"); + } + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto laa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck != true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true"); + NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true"); + } + + Reset(); + // DutyCycleReq: duty cycle to 100% + { + uint8_t maxDutyCycle = 0; + auto answers = RunMacCommand(maxDutyCycle); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(), + 1 / std::pow(2, maxDutyCycle), + "m_aggregatedDutyCycle != 1"); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto dca = DynamicCast(answers.at(0)); + NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed"); + } + + Reset(); + // DutyCycleReq: duty cycle to 12.5% + { + uint8_t maxDutyCycle = 3; + auto answers = RunMacCommand(maxDutyCycle); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(), + 1 / std::pow(2, maxDutyCycle), + "m_aggregatedDutyCycle != 1"); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto dca = DynamicCast(answers.at(0)); + NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed"); + } + + Reset(); + // RxParamSetupReq: set rx1Dr, rx2Dr, frequency + { + uint8_t rx1DrOffset = 5; + uint8_t rx2DataRate = 5; + double frequencyHz = 863500000; + m_mac->SetDataRate(5); + auto answers = RunMacCommand(rx1DrOffset, rx2DataRate, frequencyHz); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()), + unsigned(5 - rx1DrOffset), + "Rx1DataRate does not match rx1DrOffset from RxParamSetupReq"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()), + unsigned(rx2DataRate), + "Rx2DataRate does not match rx2DataRate from RxParamSetupReq"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(), + frequencyHz / 1e6, + "Rx2 frequency does not match frequency from RxParamSetupReq"); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto rpsa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), true, "Rx1DrOffsetAck != true"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), true, "Rx2DataRateAck != true"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), true, "ChannelAck expected to be true"); + } + + Reset(); + // RxParamSetupReq: invalid rx1Dr, rx2Dr, frequency + { // WARNING: default values are manually set here + uint8_t rx1DrOffset = 6; + uint8_t rx2DataRate = 12; + double frequencyHz = 871000000; + m_mac->SetDataRate(5); + auto answers = RunMacCommand(rx1DrOffset, rx2DataRate, frequencyHz); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()), + 5, + "Rx1DataRate expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()), + 0, + "Rx2DataRate expected to be default value"); + NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(), + 869.525, + "Rx2 frequency expected to be default value"); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto rpsa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), false, "Rx1DrOffsetAck != false"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), false, "Rx2DataRateAck != false"); + NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), false, "ChannelAck expected to be false"); + } + + Reset(); + // DevStatusReq: get default values + { // WARNING: default values are manually set here + auto answers = RunMacCommand(); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto dsa = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(dsa, nullptr, "DevStatusAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetBattery()), 0, "Battery expected == 0 (ext power)"); + NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetMargin()), 31, "Margin expected to be 31 (default)"); + } + + Reset(); + // NewChannelReq: add a new channel + { + uint8_t chIndex = 4; + double frequencyHz = 865100000; + uint8_t minDataRate = 1; + uint8_t maxDataRate = 4; + auto answers = RunMacCommand(chIndex, frequencyHz, minDataRate, maxDataRate); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + auto c = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray().at(chIndex); + NS_TEST_ASSERT_MSG_NE(c, nullptr, "Channel at chIndex slot expected not to be nullptr"); + NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(), + frequencyHz / 1e6, + "Channel frequency expected to equal NewChannelReq frequency"); + NS_TEST_EXPECT_MSG_EQ(c->GetMinimumDataRate(), + unsigned(minDataRate), + "Channel minDataRate expected to equal NewChannelReq minDataRate"); + NS_TEST_EXPECT_MSG_EQ(c->GetMaximumDataRate(), + unsigned(maxDataRate), + "Channel maxDataRate expected to equal NewChannelReq maxDataRate"); + auto nca = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), true, "DataRateRangeOk != true"); + NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), true, "ChannelFrequencyOk != true"); + } + + Reset(); + // NewChannelReq: invalid new channel + { // WARNING: default values are manually set here + uint8_t chIndex = 1; + double frequencyHz = 862000000; + uint8_t minDataRate = 14; + uint8_t maxDataRate = 13; + auto answers = RunMacCommand(chIndex, frequencyHz, minDataRate, maxDataRate); + NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1"); + double defaultFrequenciesMHz[3] = {868.1, 868.3, 868.5}; + auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray(); + for (size_t i = 0; i < channels.size(); i++) + { + const auto& c = channels.at(i); + if (i > 2) + { + NS_TEST_ASSERT_MSG_EQ(c, nullptr, "Channel " << i << "expected to be nullptr"); + continue; + } + NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(), + defaultFrequenciesMHz[i], + "Channel frequency expected to equal NewChannelReq frequency"); + NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMinimumDataRate()), + 0, + "Channel " << i << " minDataRate expected to be default"); + NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMaximumDataRate()), + 5, + "Channel " << i << " maxDataRate expected to be default"); + NS_TEST_EXPECT_MSG_EQ(c->IsEnabledForUplink(), + true, + "Channel " << i << " state expected to be active by default"); + } + auto nca = DynamicCast(answers.at(0)); + NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed"); + NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), false, "DataRateRangeOk != false"); + NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), false, "ChannelFrequencyOk != false"); + } +} + /** * \ingroup lorawan * @@ -1617,8 +2052,19 @@ class LorawanTestSuite : public TestSuite LorawanTestSuite::LorawanTestSuite() : TestSuite("lorawan", Type::UNIT) { - LogComponentEnable("LorawanTestSuite", LOG_LEVEL_DEBUG); - // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + // LogComponentEnable("LorawanTestSuite", LOG_LEVEL_DEBUG); + // LogComponentEnable("LorawanMac", LOG_LEVEL_DEBUG); + // LogComponentEnable("EndDeviceLorawanMac", LOG_LEVEL_DEBUG); + // LogComponentEnable("ClassAEndDeviceLorawanMac", LOG_LEVEL_DEBUG); + // LogComponentEnable("SimpleEndDeviceLoraPhy", LOG_LEVEL_DEBUG); + // LogComponentEnable("EndDeviceLoraPhy", LOG_LEVEL_DEBUG); + // LogComponentEnable("LoraPhy", LOG_LEVEL_DEBUG); + // LogComponentEnable("LoraChannel", LOG_LEVEL_DEBUG); + // LogComponentEnable("LoraFrameHeader", LOG_LEVEL_DEBUG); + // LogComponentEnableAll(LOG_PREFIX_FUNC); + // LogComponentEnableAll(LOG_PREFIX_NODE); + // LogComponentEnableAll(LOG_PREFIX_TIME); + AddTestCase(new InterferenceTest, Duration::QUICK); AddTestCase(new AddressTest, Duration::QUICK); AddTestCase(new HeaderTest, Duration::QUICK); @@ -1626,6 +2072,7 @@ LorawanTestSuite::LorawanTestSuite() AddTestCase(new LogicalLoraChannelTest, Duration::QUICK); AddTestCase(new TimeOnAirTest, Duration::QUICK); AddTestCase(new PhyConnectivityTest, Duration::QUICK); + AddTestCase(new MacCommandTest, Duration::QUICK); } // Do not forget to allocate an instance of this TestSuite diff --git a/test/network-scheduler-test-suite.cc b/test/network-scheduler-test-suite.cc index 2fc69d7972..06e42d30bb 100644 --- a/test/network-scheduler-test-suite.cc +++ b/test/network-scheduler-test-suite.cc @@ -70,8 +70,8 @@ class NetworkSchedulerTestSuite : public TestSuite NetworkSchedulerTestSuite::NetworkSchedulerTestSuite() : TestSuite("network-scheduler", Type::UNIT) { - LogComponentEnable("NetworkSchedulerTestSuite", LOG_LEVEL_DEBUG); - // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + // LogComponentEnable("NetworkSchedulerTestSuite", LOG_LEVEL_DEBUG); + AddTestCase(new NetworkSchedulerTest, Duration::QUICK); } diff --git a/test/network-server-test-suite.cc b/test/network-server-test-suite.cc index 46f19ddf45..bf34b6aaae 100644 --- a/test/network-server-test-suite.cc +++ b/test/network-server-test-suite.cc @@ -240,7 +240,7 @@ class LinkCheckTest : public TestCase * \param newValue The updated value. * \param oldValue The previous value. */ - void LastKnownGatewayCount(int newValue, int oldValue); + void LastKnownGatewayCount(uint8_t newValue, uint8_t oldValue); /** * Send a packet containing a LinkCheckReq MAC command from the input end device. @@ -254,7 +254,7 @@ class LinkCheckTest : public TestCase void DoRun() override; bool m_receivedPacketAtEd = false; //!< Set to true if a packet containing a LinkCheckAns MAC //!< command is received by the end device - int m_numberOfGatewaysThatReceivedPacket = + uint8_t m_numberOfGatewaysThatReceivedPacket = 0; //!< Stores the number of gateways that received the last packet carrying a //!< LinkCheckReq MAC command }; @@ -272,7 +272,7 @@ LinkCheckTest::~LinkCheckTest() } void -LinkCheckTest::LastKnownGatewayCount(int newValue, int oldValue) +LinkCheckTest::LastKnownGatewayCount(uint8_t newValue, uint8_t oldValue) { NS_LOG_DEBUG("Updated gateway count"); m_receivedPacketAtEd = true; @@ -344,20 +344,20 @@ NetworkServerTestSuite::NetworkServerTestSuite() { LogComponentEnable("NetworkServerTestSuite", LOG_LEVEL_DEBUG); - LogComponentEnable("NetworkServer", LOG_LEVEL_ALL); - LogComponentEnable("NetworkStatus", LOG_LEVEL_ALL); - LogComponentEnable("NetworkScheduler", LOG_LEVEL_ALL); - LogComponentEnable("NetworkController", LOG_LEVEL_ALL); - LogComponentEnable("NetworkControllerComponent", LOG_LEVEL_ALL); - LogComponentEnable("LoraNetDevice", LOG_LEVEL_ALL); - LogComponentEnable("GatewayLorawanMac", LOG_LEVEL_ALL); - LogComponentEnable("EndDeviceLorawanMac", LOG_LEVEL_ALL); - LogComponentEnable("EndDeviceLoraPhy", LOG_LEVEL_ALL); - LogComponentEnable("EndDeviceStatus", LOG_LEVEL_ALL); - - LogComponentEnableAll(LOG_PREFIX_FUNC); - LogComponentEnableAll(LOG_PREFIX_NODE); - LogComponentEnableAll(LOG_PREFIX_TIME); + // Activate only at need, as these can create problems among test suites when running ./test.py + // LogComponentEnable("NetworkServer", LOG_LEVEL_ALL); + // LogComponentEnable("NetworkStatus", LOG_LEVEL_ALL); + // LogComponentEnable("NetworkScheduler", LOG_LEVEL_ALL); + // LogComponentEnable("NetworkController", LOG_LEVEL_ALL); + // LogComponentEnable("NetworkControllerComponent", LOG_LEVEL_ALL); + // LogComponentEnable("LoraNetDevice", LOG_LEVEL_ALL); + // LogComponentEnable("GatewayLorawanMac", LOG_LEVEL_ALL); + // LogComponentEnable("EndDeviceLorawanMac", LOG_LEVEL_ALL); + // LogComponentEnable("EndDeviceLoraPhy", LOG_LEVEL_ALL); + // LogComponentEnable("EndDeviceStatus", LOG_LEVEL_ALL); + // LogComponentEnableAll(LOG_PREFIX_FUNC); + // LogComponentEnableAll(LOG_PREFIX_NODE); + // LogComponentEnableAll(LOG_PREFIX_TIME); // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER AddTestCase(new UplinkPacketTest, Duration::QUICK); diff --git a/test/network-status-test-suite.cc b/test/network-status-test-suite.cc index ac0058af7b..a24bce89f8 100644 --- a/test/network-status-test-suite.cc +++ b/test/network-status-test-suite.cc @@ -126,8 +126,8 @@ class NetworkStatusTestSuite : public TestSuite NetworkStatusTestSuite::NetworkStatusTestSuite() : TestSuite("network-status", Type::UNIT) { - LogComponentEnable("NetworkStatusTestSuite", LOG_LEVEL_DEBUG); - // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + // LogComponentEnable("NetworkStatusTestSuite", LOG_LEVEL_DEBUG); + AddTestCase(new EndDeviceStatusTest, Duration::QUICK); AddTestCase(new NetworkStatusTest, Duration::QUICK); }