A Discrete-Event Network Simulator
API
bsm-application.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 North Carolina State University
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Scott E. Carpenter <scarpen@ncsu.edu>
18  *
19  */
20 
21 #include "ns3/bsm-application.h"
22 
23 #include "ns3/log.h"
24 #include "ns3/mobility-helper.h"
25 #include "ns3/mobility-model.h"
26 #include "ns3/wave-helper.h"
27 #include "ns3/wave-mac-helper.h"
28 #include "ns3/wave-net-device.h"
29 
30 NS_LOG_COMPONENT_DEFINE("BsmApplication");
31 
32 namespace ns3
33 {
34 
35 // (Arbitrary) port for establishing socket to transmit WAVE BSMs
36 int BsmApplication::wavePort = 9080;
37 
38 NS_OBJECT_ENSURE_REGISTERED(BsmApplication);
39 
40 TypeId
42 {
43  static TypeId tid = TypeId("ns3::BsmApplication")
45  .SetGroupName("Wave")
46  .AddConstructor<BsmApplication>();
47  return tid;
48 }
49 
51  : m_waveBsmStats(nullptr),
52  m_txSafetyRangesSq(),
53  m_TotalSimTime(Seconds(10)),
54  m_wavePacketSize(200),
55  m_numWavePackets(1),
56  m_waveInterval(MilliSeconds(100)),
57  m_gpsAccuracyNs(10000),
58  m_adhocTxInterfaces(nullptr),
59  m_nodesMoving(nullptr),
60  m_unirv(nullptr),
61  m_nodeId(0),
62  m_chAccessMode(0),
63  m_txMaxDelay(MilliSeconds(10)),
64  m_prevTxDelay(MilliSeconds(0))
65 {
66  NS_LOG_FUNCTION(this);
67 }
68 
70 {
71  NS_LOG_FUNCTION(this);
72 }
73 
74 void
76 {
77  NS_LOG_FUNCTION(this);
78 
79  // chain up
81 }
82 
83 // Application Methods
84 void
85 BsmApplication::StartApplication() // Called at time specified by Start
86 {
87  NS_LOG_FUNCTION(this);
88 
89  // setup generation of WAVE BSM messages
90  Time waveInterPacketInterval = m_waveInterval;
91 
92  // BSMs are not transmitted for the first second
93  Time startTime = Seconds(1.0);
94  // total length of time transmitting WAVE packets
95  Time totalTxTime = m_TotalSimTime - startTime;
96  // total WAVE packets needing to be sent
97  m_numWavePackets = (uint32_t)(totalTxTime.GetDouble() / m_waveInterval.GetDouble());
98 
99  TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
100 
101  // every node broadcasts WAVE BSM to potentially all other nodes
106  recvSink->Bind(local);
107  recvSink->SetAllowBroadcast(true);
108 
109  // dest is broadcast address
110  InetSocketAddress remote = InetSocketAddress(Ipv4Address("255.255.255.255"), wavePort);
111  recvSink->Connect(remote);
112 
113  // Transmission start time for each BSM:
114  // We assume that the start transmission time
115  // for the first packet will be on a ns-3 time
116  // "Second" boundary - e.g., 1.0 s.
117  // However, the actual transmit time must reflect
118  // additional effects of 1) clock drift and
119  // 2) transmit delay requirements.
120  // 1) Clock drift - clocks are not perfectly
121  // synchronized across all nodes. In a VANET
122  // we assume all nodes sync to GPS time, which
123  // itself is assumed accurate to, say, 40-100 ns.
124  // Thus, the start transmission time must be adjusted
125  // by some value, t_drift.
126  // 2) Transmit delay requirements - The US
127  // minimum performance requirements for V2V
128  // BSM transmission expect a random delay of
129  // +/- 5 ms, to avoid simultaneous transmissions
130  // by all vehicles congesting the channel. Thus,
131  // we need to adjust the start transmission time by
132  // some value, t_tx_delay.
133  // Therefore, the actual transmit time should be:
134  // t_start = t_time + t_drift + t_tx_delay
135  // t_drift is always added to t_time.
136  // t_tx_delay is supposed to be +/- 5ms, but if we
137  // allow negative numbers the time could drift to a value
138  // BEFORE the interval start time (i.e., at 100 ms
139  // boundaries, we do not want to drift into the
140  // previous interval, such as at 95 ms. Instead,
141  // we always want to be at the 100 ms interval boundary,
142  // plus [0..10] ms tx delay.
143  // Thus, the average t_tx_delay will be
144  // within the desired range of [0..10] ms of
145  // (t_time + t_drift)
146 
147  // WAVE devices sync to GPS time
148  // and all devices would like to begin broadcasting
149  // their safety messages immediately at the start of
150  // the CCH interval. However, if all do so, then
151  // significant collisions occur. Thus, we assume there
152  // is some GPS sync accuracy on GPS devices,
153  // typically 40-100 ns.
154  // Get a uniformly random number for GPS sync accuracy, in ns.
156 
157  // When transmitting at a default rate of 10 Hz,
158  // the subsystem shall transmit every 100 ms +/-
159  // a random value between 0 and 5 ms. [MPR-BSMTX-TXTIM-002]
160  // Source: CAMP Vehicle Safety Communications 4 Consortium
161  // On-board Minimum Performance Requirements
162  // for V2V Safety Systems Version 1.0, December 17, 2014
163  // max transmit delay (default 10ms)
164  // get value for transmit delay, as number of ns
165  uint32_t d_ns = static_cast<uint32_t>(m_txMaxDelay.GetInteger());
166  // convert random tx delay to ns-3 time
167  // see note above regarding centering tx delay
168  // offset by 5ms + a random value.
169  Time txDelay = NanoSeconds(m_unirv->GetInteger(0, d_ns));
170  m_prevTxDelay = txDelay;
171 
172  Time txTime = startTime + tDrift + txDelay;
173  // schedule transmission of first packet
175  txTime,
177  this,
178  recvSink,
181  waveInterPacketInterval,
182  m_nodeId);
183 }
184 
185 void
186 BsmApplication::StopApplication() // Called at time specified by Stop
187 {
188  NS_LOG_FUNCTION(this);
189 }
190 
191 void
193  int nodeId,
194  Time totalTime,
195  uint32_t wavePacketSize, // bytes
196  Time waveInterval,
197  double gpsAccuracyNs,
198  std::vector<double> rangesSq, // m ^2
199  Ptr<WaveBsmStats> waveBsmStats,
200  std::vector<int>* nodesMoving,
201  int chAccessMode,
202  Time txMaxDelay)
203 {
204  NS_LOG_FUNCTION(this);
205 
206  m_unirv = CreateObject<UniformRandomVariable>();
207 
208  m_TotalSimTime = totalTime;
209  m_wavePacketSize = wavePacketSize;
210  m_waveInterval = waveInterval;
211  m_gpsAccuracyNs = gpsAccuracyNs;
212  int size = rangesSq.size();
213  m_waveBsmStats = waveBsmStats;
214  m_nodesMoving = nodesMoving;
215  m_chAccessMode = chAccessMode;
216  m_txSafetyRangesSq.clear();
217  m_txSafetyRangesSq.resize(size, 0);
218 
219  for (int index = 0; index < size; index++)
220  {
221  // stored as square of value, for optimization
222  m_txSafetyRangesSq[index] = rangesSq[index];
223  }
224 
225  m_adhocTxInterfaces = &i;
226  m_nodeId = nodeId;
227  m_txMaxDelay = txMaxDelay;
228 }
229 
230 void
232  uint32_t pktSize,
233  uint32_t pktCount,
234  Time pktInterval,
235  uint32_t sendingNodeId)
236 {
237  NS_LOG_FUNCTION(this);
238 
239  // more packets to send?
240  if (pktCount > 0)
241  {
242  // for now, we cannot tell if each node has
243  // started mobility. so, as an optimization
244  // only send if this node is moving
245  // if not, then skip
246  int txNodeId = sendingNodeId;
247  Ptr<Node> txNode = GetNode(txNodeId);
248  Ptr<MobilityModel> txPosition = txNode->GetObject<MobilityModel>();
249  NS_ASSERT(txPosition);
250 
251  int senderMoving = m_nodesMoving->at(txNodeId);
252  if (senderMoving != 0)
253  {
254  // send it!
255  socket->Send(Create<Packet>(pktSize));
256  // count it
257  m_waveBsmStats->IncTxPktCount();
258  m_waveBsmStats->IncTxByteCount(pktSize);
259  int wavePktsSent = m_waveBsmStats->GetTxPktCount();
260  if ((m_waveBsmStats->GetLogging() != 0) && ((wavePktsSent % 1000) == 0))
261  {
262  NS_LOG_UNCOND("Sending WAVE pkt # " << wavePktsSent);
263  }
264 
265  // find other nodes within range that would be
266  // expected to receive this broadbast
267  int nRxNodes = m_adhocTxInterfaces->GetN();
268  for (int i = 0; i < nRxNodes; i++)
269  {
270  Ptr<Node> rxNode = GetNode(i);
271  int rxNodeId = rxNode->GetId();
272 
273  if (rxNodeId != txNodeId)
274  {
275  Ptr<MobilityModel> rxPosition = rxNode->GetObject<MobilityModel>();
276  NS_ASSERT(rxPosition);
277  // confirm that the receiving node
278  // has also started moving in the scenario
279  // if it has not started moving, then
280  // it is not a candidate to receive a packet
281  int receiverMoving = m_nodesMoving->at(rxNodeId);
282  if (receiverMoving == 1)
283  {
284  double distSq = MobilityHelper::GetDistanceSquaredBetween(txNode, rxNode);
285  if (distSq > 0.0)
286  {
287  // dest node within range?
288  int rangeCount = m_txSafetyRangesSq.size();
289  for (int index = 1; index <= rangeCount; index++)
290  {
291  if (distSq <= m_txSafetyRangesSq[index - 1])
292  {
293  // we should expect dest node to receive broadcast pkt
294  m_waveBsmStats->IncExpectedRxPktCount(index);
295  }
296  }
297  }
298  }
299  }
300  }
301  }
302 
303  // every BSM must be scheduled with a tx time delay
304  // of +/- (5) ms. See comments in StartApplication().
305  // we handle this as a tx delay of [0..10] ms
306  // from the start of the pktInterval boundary
307  uint32_t d_ns = static_cast<uint32_t>(m_txMaxDelay.GetInteger());
308  Time txDelay = NanoSeconds(m_unirv->GetInteger(0, d_ns));
309 
310  // do not want the tx delay to be cumulative, so
311  // deduct the previous delay value. thus we adjust
312  // to schedule the next event at the next pktInterval,
313  // plus some new [0..10] ms tx delay
314  Time txTime = pktInterval - m_prevTxDelay + txDelay;
315  m_prevTxDelay = txDelay;
316 
318  txTime,
320  this,
321  socket,
322  pktSize,
323  pktCount - 1,
324  pktInterval,
325  socket->GetNode()->GetId());
326  }
327  else
328  {
329  socket->Close();
330  }
331 }
332 
333 void
335 {
336  NS_LOG_FUNCTION(this);
337 
338  Ptr<Packet> packet;
339  Address senderAddr;
340  while ((packet = socket->RecvFrom(senderAddr)))
341  {
342  Ptr<Node> rxNode = socket->GetNode();
343 
344  if (InetSocketAddress::IsMatchingType(senderAddr))
345  {
347  int nodes = m_adhocTxInterfaces->GetN();
348  for (int i = 0; i < nodes; i++)
349  {
350  if (addr.GetIpv4() == m_adhocTxInterfaces->GetAddress(i))
351  {
352  Ptr<Node> txNode = GetNode(i);
353  HandleReceivedBsmPacket(txNode, rxNode);
354  }
355  }
356  }
357  }
358 }
359 
360 void
362 {
363  NS_LOG_FUNCTION(this);
364 
365  m_waveBsmStats->IncRxPktCount();
366 
367  Ptr<MobilityModel> rxPosition = rxNode->GetObject<MobilityModel>();
368  NS_ASSERT(rxPosition);
369  // confirm that the receiving node
370  // has also started moving in the scenario
371  // if it has not started moving, then
372  // it is not a candidate to receive a packet
373  int rxNodeId = rxNode->GetId();
374  int receiverMoving = m_nodesMoving->at(rxNodeId);
375  if (receiverMoving == 1)
376  {
377  double rxDistSq = MobilityHelper::GetDistanceSquaredBetween(rxNode, txNode);
378  if (rxDistSq > 0.0)
379  {
380  int rangeCount = m_txSafetyRangesSq.size();
381  for (int index = 1; index <= rangeCount; index++)
382  {
383  if (rxDistSq <= m_txSafetyRangesSq[index - 1])
384  {
385  m_waveBsmStats->IncRxPktInRangeCount(index);
386  }
387  }
388  }
389  }
390 }
391 
392 int64_t
393 BsmApplication::AssignStreams(int64_t streamIndex)
394 {
395  NS_LOG_FUNCTION(this);
396 
397  NS_ASSERT(m_unirv); // should be set by Setup() prevoiusly
398  m_unirv->SetStream(streamIndex);
399 
400  return 1;
401 }
402 
403 Ptr<Node>
405 {
406  NS_LOG_FUNCTION(this);
407 
408  std::pair<Ptr<Ipv4>, uint32_t> interface = m_adhocTxInterfaces->Get(id);
409  Ptr<Ipv4> pp = interface.first;
410  Ptr<Node> node = pp->GetObject<Node>();
411 
412  return node;
413 }
414 
417 {
418  NS_LOG_FUNCTION(this);
419 
420  std::pair<Ptr<Ipv4>, uint32_t> interface = m_adhocTxInterfaces->Get(id);
421  Ptr<Ipv4> pp = interface.first;
422  Ptr<NetDevice> device = pp->GetObject<NetDevice>();
423 
424  return device;
425 }
426 
427 } // namespace ns3
a polymophic address class
Definition: address.h:100
The base class for all ns3 applications.
Definition: application.h:61
void DoDispose() override
Destructor implementation.
Definition: application.cc:85
Ptr< Node > GetNode() const
Definition: application.cc:107
The BsmApplication class sends and receives the IEEE 1609 WAVE (Wireless Access in Vehicular Environm...
uint32_t m_wavePacketSize
bytes
Ptr< NetDevice > GetNetDevice(int id)
Get the net device for the desired id.
Ipv4InterfaceContainer * m_adhocTxInterfaces
transmit interfaces
Time m_TotalSimTime
total sim time
int64_t AssignStreams(int64_t streamIndex)
Assign a fixed random variable stream number to the random variables used by this model.
void GenerateWaveTraffic(Ptr< Socket > socket, uint32_t pktSize, uint32_t pktCount, Time pktInterval, uint32_t sendingNodeId)
Creates and transmits a WAVE BSM packet.
std::vector< double > m_txSafetyRangesSq
tx safety range squared, for optimization
Time m_txMaxDelay
When transmitting at a default rate of 10 Hz, the subsystem shall transmit every 100 ms +/- a random ...
uint32_t m_numWavePackets
number of wave packets
double m_gpsAccuracyNs
GPS accuracy.
void ReceiveWavePacket(Ptr< Socket > socket)
Receive a WAVE BSM packet.
std::vector< int > * m_nodesMoving
nodes moving
int m_chAccessMode
WAVE channel access mode. 0=continuous PHY; 1=channel-switching.
~BsmApplication() override
Ptr< UniformRandomVariable > m_unirv
random variable
static int wavePort
(Arbitrary) port number that is used to create a socket for transmitting WAVE BSMs.
Time m_waveInterval
wave interval
void Setup(Ipv4InterfaceContainer &i, int nodeId, Time totalTime, uint32_t wavePacketSize, Time waveInterval, double gpsAccuracyNs, std::vector< double > rangesSq, Ptr< WaveBsmStats > waveBsmStats, std::vector< int > *nodesMoving, int mode, Time txDelay)
Setup BSM generation parameters for a node.
Time m_prevTxDelay
previous transmit delay
static TypeId GetTypeId()
Get the type ID.
BsmApplication()
Constructor.
void HandleReceivedBsmPacket(Ptr< Node > txNode, Ptr< Node > rxNode)
Handle the receipt of a WAVE BSM packet from sender to receiver.
void StartApplication() override
Called at time specified by Start.
void StopApplication() override
Called at time specified by Stop.
void DoDispose() override
Destructor implementation.
Ptr< WaveBsmStats > m_waveBsmStats
BSM stats.
an Inet address class
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:43
static Ipv4Address GetAny()
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
static double GetDistanceSquaredBetween(Ptr< Node > n1, Ptr< Node > n2)
Keep track of the current position and velocity of an object.
Network layer to device interface.
Definition: net-device.h:98
A network Node.
Definition: node.h:56
uint32_t GetId() const
Definition: node.cc:117
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:587
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
virtual bool SetAllowBroadcast(bool allowBroadcast)=0
Configure whether broadcast datagram transmissions are allowed.
void SetRecvCallback(Callback< void, Ptr< Socket >> receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:126
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
virtual Ptr< Node > GetNode() const =0
Return the node this socket is associated with.
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition: socket.cc:325
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition: socket.cc:72
virtual int Close()=0
Close a socket.
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetInteger() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:454
double GetDouble() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:449
a unique identifier for an interface.
Definition: type-id.h:60
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:839
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value drawn from the distribution.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionally.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:707
uint32_t pktSize
packet size used for the simulation (in bytes)