lora-network-status.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 University of Padova
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Davide Magrin <magrinda@dei.unipd.it>
19  * Martina Capuzzo <capuzzom@dei.unipd.it>
20  *
21  * Modified by: Bastien Tauran <bastien.tauran@viveris.fr>
22  */
23 
24 #include "lora-network-status.h"
25 
26 #include "lora-beam-tag.h"
27 #include "lora-device-address.h"
28 #include "lora-end-device-status.h"
29 #include "lora-gateway-status.h"
31 #include "satellite-topology.h"
32 
33 #include <ns3/log.h>
34 #include <ns3/net-device.h>
35 #include <ns3/node-container.h>
36 #include <ns3/packet.h>
37 #include <ns3/pointer.h>
38 #include <ns3/singleton.h>
39 
40 #include <map>
41 #include <stdint.h>
42 #include <utility>
43 
44 namespace ns3
45 {
46 
47 NS_LOG_COMPONENT_DEFINE("LoraNetworkStatus");
48 
49 NS_OBJECT_ENSURE_REGISTERED(LoraNetworkStatus);
50 
51 TypeId
53 {
54  static TypeId tid = TypeId("ns3::LoraNetworkStatus").AddConstructor<LoraNetworkStatus>();
55  return tid;
56 }
57 
59 {
60  NS_LOG_FUNCTION_NOARGS();
61 
62  m_forwardLinkRegenerationMode = Singleton<SatTopology>::Get()->GetForwardLinkRegenerationMode();
63  m_uniform = CreateObject<UniformRandomVariable>();
64 }
65 
67 {
68  NS_LOG_FUNCTION_NOARGS();
69 }
70 
71 void
72 LoraNetworkStatus::AddNode(Ptr<LorawanMacEndDeviceClassA> edMac)
73 {
74  NS_LOG_FUNCTION(this << edMac);
75 
76  // Check whether this device already exists in our list
77  LoraDeviceAddress edAddress = edMac->GetDeviceAddress();
78  if (m_endDeviceStatuses.find(edAddress) == m_endDeviceStatuses.end())
79  {
80  // The device doesn't exist. Create new EndDeviceStatus
81  Ptr<LoraEndDeviceStatus> edStatus =
82  CreateObject<LoraEndDeviceStatus>(edAddress,
83  edMac->GetObject<LorawanMacEndDeviceClassA>());
84 
85  // Add it to the map
86  m_endDeviceStatuses.insert(
87  std::pair<LoraDeviceAddress, Ptr<LoraEndDeviceStatus>>(edAddress, edStatus));
88  NS_LOG_DEBUG("Added to the list a device with address " << edAddress.Print());
89  }
90 }
91 
92 void
93 LoraNetworkStatus::AddGateway(Ptr<Node> gw, Address& address, Ptr<LoraGatewayStatus> gwStatus)
94 {
95  NS_LOG_FUNCTION(this << address << gwStatus);
96 
97  // Check whether this device already exists in the list
98  if (m_gatewayStatuses.find(address) == m_gatewayStatuses.end())
99  {
100  // The device doesn't exist.
101 
102  // Add it to the map
103  m_gatewayStatuses.insert(std::pair<Address, Ptr<LoraGatewayStatus>>(address, gwStatus));
104  NS_LOG_DEBUG("Added to the list a gateway with address " << address);
105  }
106 
107  // Get the PointToPointNetDevice
108  Ptr<PointToPointNetDevice> p2pNetDevice;
109  for (uint32_t i = 0; i < gw->GetNDevices(); i++)
110  {
111  p2pNetDevice = gw->GetDevice(i)->GetObject<PointToPointNetDevice>();
112  if (p2pNetDevice != nullptr)
113  {
114  break;
115  }
116  }
117 
118  m_gws.insert(std::make_pair(gw, p2pNetDevice));
119 }
120 
121 void
122 LoraNetworkStatus::OnReceivedPacket(Ptr<const Packet> packet, const Address& gwAddress)
123 {
124  NS_LOG_FUNCTION(this << packet << gwAddress);
125 
126  // Create a copy of the packet
127  Ptr<Packet> myPacket = packet->Copy();
128 
129  // Extract the headers
130  LorawanMacHeader macHdr;
131  myPacket->RemoveHeader(macHdr);
132  LoraFrameHeader frameHdr;
133  frameHdr.SetAsUplink();
134  myPacket->RemoveHeader(frameHdr);
135 
136  // Update the correct EndDeviceStatus object
137  LoraDeviceAddress edAddr = frameHdr.GetAddress();
138  NS_LOG_DEBUG("Node address: " << edAddr);
139  m_endDeviceStatuses.at(edAddr)->InsertReceivedPacket(packet, gwAddress);
140 }
141 
142 bool
144 {
145  // Throws out of range if no device is found
146  return m_endDeviceStatuses.at(deviceAddress)->NeedsReply();
147 }
148 
149 Address
151 {
152  NS_LOG_FUNCTION(this << deviceAddress << window);
153 
154  // Get the endDeviceStatus we are interested in
155  Ptr<LoraEndDeviceStatus> edStatus = m_endDeviceStatuses.at(deviceAddress);
156  double replyFrequency;
157  if (window == 1)
158  {
159  replyFrequency = edStatus->GetFirstReceiveWindowFrequency();
160  }
161  else if (window == 2)
162  {
163  replyFrequency = edStatus->GetSecondReceiveWindowFrequency();
164  }
165  else
166  {
167  NS_ABORT_MSG("Invalid window value");
168  }
169 
170  // Get the list of gateways that this device can reach
171  // NOTE: At this point, we could also take into account the whole network to
172  // identify the best gateway according to various metrics. For now, we just
173  // ask the EndDeviceStatus to pick the best gateway for us via its method.
174  std::map<double, Address> gwAddresses = edStatus->GetPowerGatewayMap();
175 
177  {
178  uint8_t beamToUse = edStatus->GetBeamId();
179  Ptr<Node> gateway;
180  std::vector<Address> possibleAddresses;
181  Ptr<SatLorawanNetDevice> lorawanNetDevice;
182  for (std::map<Ptr<Node>, Ptr<PointToPointNetDevice>>::iterator it = m_gws.begin();
183  it != m_gws.end();
184  it++)
185  {
186  gateway = it->first;
187  for (uint32_t i = 0; i < gateway->GetNDevices(); i++)
188  {
189  lorawanNetDevice = gateway->GetDevice(i)->GetObject<SatLorawanNetDevice>();
190  if (lorawanNetDevice != nullptr)
191  {
192  uint8_t beam = lorawanNetDevice->GetMac()->GetBeamId();
193  if (beam == beamToUse)
194  {
195  possibleAddresses.push_back(it->second->GetAddress());
196  }
197  }
198  }
199  }
200  if (possibleAddresses.size() > 0)
201  {
202  return possibleAddresses[m_uniform->GetInteger() % possibleAddresses.size()];
203  }
204  else
205  {
206  return gwAddresses.begin()->second;
207  }
208  }
209 
210  // By iterating on the map in reverse, we go from the 'best'
211  // gateway, i.e. the one with the highest received power, to the
212  // worst.
213  Address bestGwAddress;
214  for (auto it = gwAddresses.rbegin(); it != gwAddresses.rend(); it++)
215  {
216  bool isAvailable =
217  m_gatewayStatuses.find(it->second)->second->IsAvailableForTransmission(replyFrequency);
218  if (isAvailable)
219  {
220  bestGwAddress = it->second;
221  break;
222  }
223  }
224 
225  return bestGwAddress;
226 }
227 
228 void
229 LoraNetworkStatus::SendThroughGateway(Ptr<Packet> packet, Address gwAddress)
230 {
231  NS_LOG_FUNCTION(packet << gwAddress);
232 
233  m_gatewayStatuses.find(gwAddress)->second->GetNetDevice()->Send(packet, gwAddress, 0x0800);
234 }
235 
236 Ptr<Packet>
238 {
239  // Get the reply packet
240  Ptr<LoraEndDeviceStatus> edStatus = m_endDeviceStatuses.find(edAddress)->second;
241  Ptr<Packet> packet = edStatus->GetCompleteReplyPacket();
242 
243  // Apply the appropriate tag
244  LoraTag tag;
245  tag.SetModcod(edStatus->GetModcod());
246  switch (windowNumber)
247  {
248  case 1: {
249  tag.SetDataRate(edStatus->GetMac()->GetFirstReceiveWindowDataRate());
250  tag.SetFrequency(edStatus->GetFirstReceiveWindowFrequency());
251  break;
252  }
253  case 2: {
254  tag.SetDataRate(edStatus->GetMac()->GetSecondReceiveWindowDataRate());
255  tag.SetFrequency(edStatus->GetSecondReceiveWindowFrequency());
256  break;
257  }
258  }
259 
260  packet->AddPacketTag(tag);
261 
262  // Apply the appropriate tag
263  LoraBeamTag beamTag;
264  beamTag.SetBeamId(edStatus->GetBeamId());
265  packet->AddPacketTag(beamTag);
266  return packet;
267 }
268 
269 Ptr<LoraEndDeviceStatus>
270 LoraNetworkStatus::GetEndDeviceStatus(Ptr<const Packet> packet)
271 {
272  NS_LOG_FUNCTION(this << packet);
273 
274  // Get the address
275  LorawanMacHeader mHdr;
276  LoraFrameHeader fHdr;
277  Ptr<Packet> myPacket = packet->Copy();
278  myPacket->RemoveHeader(mHdr);
279  myPacket->RemoveHeader(fHdr);
280  auto it = m_endDeviceStatuses.find(fHdr.GetAddress());
281  if (it != m_endDeviceStatuses.end())
282  {
283  return (*it).second;
284  }
285  else
286  {
287  NS_LOG_ERROR("EndDeviceStatus not found");
288  return 0;
289  }
290 }
291 
292 Ptr<LoraEndDeviceStatus>
294 {
295  NS_LOG_FUNCTION(this << address);
296 
297  auto it = m_endDeviceStatuses.find(address);
298  if (it != m_endDeviceStatuses.end())
299  {
300  return (*it).second;
301  }
302  else
303  {
304  NS_LOG_ERROR("EndDeviceStatus not found");
305  return 0;
306  }
307 }
308 
309 int
311 {
312  NS_LOG_FUNCTION(this);
313 
314  return m_endDeviceStatuses.size();
315 }
316 } // namespace ns3
Tag used to save various data about a packet, like its Spreading Factor and data about interference.
Definition: lora-beam-tag.h:37
void SetBeamId(uint8_t beamId)
Set which beamId this packet was transmitted with.
This class represents the device address of a LoraWAN End Device.
std::string Print(void) const
Print the address bit-by-bit to a human-readable string.
This class represents the Frame header (FHDR) used in a LoraWAN network.
void SetAsUplink(void)
State that this is an uplink message.
LoraDeviceAddress GetAddress(void) const
Get this header's device address value.
This class represents the knowledge about the state of the network that is available at the Network S...
void AddNode(Ptr< LorawanMacEndDeviceClassA > edMac)
Add a device to the ones that are tracked by this LoraNetworkStatus object.
void OnReceivedPacket(Ptr< const Packet > packet, const Address &gwaddress)
Update network status on the received packet.
std::map< Ptr< Node >, Ptr< PointToPointNetDevice > > m_gws
void AddGateway(Ptr< Node > gw, Address &address, Ptr< LoraGatewayStatus > gwStatus)
Add this gateway to the list of gateways connected to the network.
Ptr< Packet > GetReplyForDevice(LoraDeviceAddress edAddress, int windowNumber)
Get the reply for the specified device address.
Address GetBestGatewayForDevice(LoraDeviceAddress deviceAddress, int window)
Return whether we have a gateway that is available to send a reply to the specified device.
static TypeId GetTypeId(void)
Ptr< LoraEndDeviceStatus > GetEndDeviceStatus(Ptr< const Packet > packet)
Get the EndDeviceStatus for the device that sent a packet.
Ptr< UniformRandomVariable > m_uniform
SatEnums::RegenerationMode_t m_forwardLinkRegenerationMode
bool NeedsReply(LoraDeviceAddress deviceAddress)
Return whether the specified device needs a reply.
int CountEndDevices(void)
Return the number of end devices currently managed by the server.
void SendThroughGateway(Ptr< Packet > packet, Address gwAddress)
Send a packet through a Gateway.
std::map< Address, Ptr< LoraGatewayStatus > > m_gatewayStatuses
std::map< LoraDeviceAddress, Ptr< LoraEndDeviceStatus > > m_endDeviceStatuses
Tag used to save various data about a packet, like its Spreading Factor and data about interference.
Definition: lora-tag.h:41
void SetDataRate(uint8_t dataRate)
Set the data rate for this packet.
Definition: lora-tag.cc:154
void SetFrequency(double frequency)
Set the frequency of the packet.
Definition: lora-tag.cc:136
void SetModcod(uint8_t modcod)
Set the modcod for this packet.
Definition: lora-tag.cc:166
Class representing the MAC layer of a Class A LoRaWAN device.
This class represents the Mac header of a LoRaWAN packet.
SatLorawanNetDevice to be utilized in the UT and GW nodes for IoT configuration.
Ptr< SatMac > GetMac(void) const
Get a Mac pointer.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.