A Discrete-Event Network Simulator
API
lr-wpan-csmaca.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 The Boeing Company
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:
18 * kwong yin <kwong-sang.yin@boeing.com>
19 * Sascha Alexander Jopen <jopen@cs.uni-bonn.de>
20 * Alberto Gallegos Ramonet <ramonet@fc.ritsumei.ac.jp>
21 */
22
23#include "lr-wpan-csmaca.h"
24
25#include "lr-wpan-constants.h"
26
27#include <ns3/log.h>
28#include <ns3/random-variable-stream.h>
29#include <ns3/simulator.h>
30
31#include <algorithm>
32
33#undef NS_LOG_APPEND_CONTEXT
34#define NS_LOG_APPEND_CONTEXT std::clog << "[address " << m_mac->GetShortAddress() << "] ";
35
36namespace ns3
37{
38
39NS_LOG_COMPONENT_DEFINE("LrWpanCsmaCa");
40
41NS_OBJECT_ENSURE_REGISTERED(LrWpanCsmaCa);
42
43TypeId
45{
46 static TypeId tid = TypeId("ns3::LrWpanCsmaCa")
48 .SetGroupName("LrWpan")
49 .AddConstructor<LrWpanCsmaCa>();
50 return tid;
51}
52
54{
55 // TODO-- make these into ns-3 attributes
56
57 m_isSlotted = false;
58 m_NB = 0;
59 m_CW = 2;
60 m_macBattLifeExt = false;
61 m_macMinBE = 3;
62 m_macMaxBE = 5;
64 m_random = CreateObject<UniformRandomVariable>();
66 m_ccaRequestRunning = false;
68 m_coorDest = false;
69}
70
72{
73 m_mac = nullptr;
74}
75
76void
78{
79 m_lrWpanMacStateCallback = MakeNullCallback<void, LrWpanMacState>();
80 m_lrWpanMacTransCostCallback = MakeNullCallback<void, uint32_t>();
81
82 Cancel();
83 m_mac = nullptr;
84}
85
86void
88{
89 m_mac = mac;
90}
91
94{
95 return m_mac;
96}
97
98void
100{
101 NS_LOG_FUNCTION(this);
102 m_isSlotted = true;
103}
104
105void
107{
108 NS_LOG_FUNCTION(this);
109 m_isSlotted = false;
110}
111
112bool
114{
115 NS_LOG_FUNCTION(this);
116 return (m_isSlotted);
117}
118
119bool
121{
122 NS_LOG_FUNCTION(this);
123 return (!m_isSlotted);
124}
125
126void
128{
129 NS_LOG_FUNCTION(this << macMinBE);
130 NS_ASSERT_MSG(macMinBE <= m_macMaxBE,
131 "MacMinBE (" << macMinBE << ") should be <= MacMaxBE (" << m_macMaxBE << ")");
132 m_macMinBE = macMinBE;
133}
134
135uint8_t
137{
138 NS_LOG_FUNCTION(this);
139 return m_macMinBE;
140}
141
142void
144{
145 NS_LOG_FUNCTION(this << macMaxBE);
146 NS_ASSERT_MSG(macMaxBE >= 3 && macMaxBE <= 8,
147 "MacMaxBE (" << macMaxBE << ") should be >= 3 and <= 8");
148 m_macMaxBE = macMaxBE;
149}
150
151uint8_t
153{
154 NS_LOG_FUNCTION(this);
155 return m_macMaxBE;
156}
157
158void
159LrWpanCsmaCa::SetMacMaxCSMABackoffs(uint8_t macMaxCSMABackoffs)
160{
161 NS_LOG_FUNCTION(this << macMaxCSMABackoffs);
162 NS_ASSERT_MSG(macMaxCSMABackoffs <= 5, "MacMaxCSMABackoffs should be <= 5");
163 m_macMaxCSMABackoffs = macMaxCSMABackoffs;
164}
165
166uint8_t
168{
169 NS_LOG_FUNCTION(this);
171}
172
173Time
175{
176 NS_LOG_FUNCTION(this);
177
178 // The reference for the beginning of the SUPERFRAME (the active period) changes depending
179 // on the data packet being sent from the Coordinator/outgoing frame (Tx beacon time reference)
180 // or other device/incoming frame (Rx beacon time reference ).
181
182 Time elapsedSuperframe; // (i.e The beacon + the elapsed CAP)
183 Time currentTime = Simulator::Now();
184 double symbolsToBoundary;
185 Time nextBoundary;
186 uint64_t elapsedSuperframeSymbols;
187 uint64_t symbolRate =
188 (uint64_t)m_mac->GetPhy()->GetDataOrSymbolRate(false); // symbols per second
189 Time timeAtBoundary;
190
191 if (m_coorDest)
192 {
193 // Take the Incoming Frame Reference
194 elapsedSuperframe = currentTime - m_mac->m_macBeaconRxTime;
195
196 Time beaconTime [[maybe_unused]] = Seconds((double)m_mac->m_rxBeaconSymbols / symbolRate);
197 Time elapsedCap [[maybe_unused]] = elapsedSuperframe - beaconTime;
198 NS_LOG_DEBUG("Elapsed incoming CAP symbols: " << (elapsedCap.GetSeconds() * symbolRate)
199 << " (" << elapsedCap.As(Time::S) << ")");
200 }
201 else
202 {
203 // Take the Outgoing Frame Reference
204 elapsedSuperframe = currentTime - m_mac->m_macBeaconTxTime;
205 }
206
207 // get a close value to the the boundary in symbols
208 elapsedSuperframeSymbols = elapsedSuperframe.GetSeconds() * symbolRate;
209 symbolsToBoundary = lrwpan::aUnitBackoffPeriod -
210 std::fmod((double)elapsedSuperframeSymbols, lrwpan::aUnitBackoffPeriod);
211
212 timeAtBoundary = Seconds((double)(elapsedSuperframeSymbols + symbolsToBoundary) / symbolRate);
213
214 // get the exact time boundary
215 nextBoundary = timeAtBoundary - elapsedSuperframe;
216
217 NS_LOG_DEBUG("Elapsed Superframe symbols: " << elapsedSuperframeSymbols << " ("
218 << elapsedSuperframe.As(Time::S) << ")");
219
220 NS_LOG_DEBUG("Next backoff period boundary in approx. "
221 << nextBoundary.GetSeconds() * symbolRate << " symbols ("
222 << nextBoundary.As(Time::S) << ")");
223
224 return nextBoundary;
225}
226
227void
229{
230 NS_LOG_FUNCTION(this);
231 m_NB = 0;
232 if (IsSlottedCsmaCa())
233 {
234 // TODO: Check if the current PHY is using the Japanese band 950 Mhz:
235 // (IEEE_802_15_4_950MHZ_BPSK and IEEE_802_15_4_950MHZ_2GFSK)
236 // if in use, m_CW = 1.
237 // Currently 950 Mhz band PHYs are not supported in ns-3.
238 // To know the current used PHY, making the method for GetPhy()->GetMyPhyOption()
239 // public is necessary. Alternatively, the current PHY used
240 // can be known using phyCurrentPage variable.
241
242 m_CW = 2;
243
245 {
246 m_BE = std::min(static_cast<uint8_t>(2), m_macMinBE);
247 }
248 else
249 {
251 }
252
253 // m_coorDest to decide between incoming and outgoing superframes times
254 m_coorDest = m_mac->isCoordDest();
255
256 // Locate backoff period boundary. (i.e. a time delay to align with the next backoff period
257 // boundary)
258 Time backoffBoundary = GetTimeToNextSlot();
261 }
262 else
263 {
266 }
267}
268
269void
271{
275 m_mac->GetPhy()->CcaCancel();
276}
277
278void
280{
281 NS_LOG_FUNCTION(this);
282
283 uint64_t upperBound = (uint64_t)pow(2, m_BE) - 1;
284 Time randomBackoff;
285 uint64_t symbolRate;
286 Time timeLeftInCap;
287
288 symbolRate = (uint64_t)m_mac->GetPhy()->GetDataOrSymbolRate(false); // symbols per second
289
290 // We should not recalculate the random backoffPeriods if we are in a slotted CSMA-CA and the
291 // transmission was previously deferred (m_randomBackoffPeriods != 0)
293 {
294 m_randomBackoffPeriodsLeft = (uint64_t)m_random->GetValue(0, upperBound + 1);
295 }
296
297 randomBackoff =
299
300 if (IsUnSlottedCsmaCa())
301 {
302 NS_LOG_DEBUG("Unslotted CSMA-CA: requesting CCA after backoff of "
303 << m_randomBackoffPeriodsLeft << " periods (" << randomBackoff.As(Time::S)
304 << ")");
306 }
307 else
308 {
309 // We must make sure there is enough time left in the CAP, otherwise we continue in
310 // the CAP of the next superframe after the transmission/reception of the beacon (and the
311 // IFS)
312 timeLeftInCap = GetTimeLeftInCap();
313
314 NS_LOG_DEBUG("Slotted CSMA-CA: proceeding after random backoff of "
315 << m_randomBackoffPeriodsLeft << " periods ("
316 << (randomBackoff.GetSeconds() * symbolRate) << " symbols or "
317 << randomBackoff.As(Time::S) << ")");
318
319 NS_LOG_DEBUG("Backoff periods left in CAP: "
320 << ((timeLeftInCap.GetSeconds() * symbolRate) / lrwpan::aUnitBackoffPeriod)
321 << " (" << (timeLeftInCap.GetSeconds() * symbolRate) << " symbols or "
322 << timeLeftInCap.As(Time::S) << ")");
323
324 if (randomBackoff >= timeLeftInCap)
325 {
326 uint64_t usedBackoffs =
327 (double)(timeLeftInCap.GetSeconds() * symbolRate) / lrwpan::aUnitBackoffPeriod;
328 m_randomBackoffPeriodsLeft -= usedBackoffs;
329 NS_LOG_DEBUG("No time in CAP to complete backoff delay, deferring to the next CAP");
332 }
333 else
334 {
336 }
337 }
338}
339
340Time
342{
343 Time currentTime;
344 uint64_t capSymbols;
345 Time endCapTime;
346 uint64_t activeSlot;
347 uint64_t symbolRate;
348 Time rxBeaconTime;
349
350 // At this point, the currentTime should be aligned on a backoff period boundary
351 currentTime = Simulator::Now();
352 symbolRate = (uint64_t)m_mac->GetPhy()->GetDataOrSymbolRate(false); // symbols per second
353
354 if (m_coorDest)
355 { // Take Incoming frame reference
356 activeSlot = m_mac->m_incomingSuperframeDuration / 16;
357 capSymbols = activeSlot * (m_mac->m_incomingFnlCapSlot + 1);
358 endCapTime = m_mac->m_macBeaconRxTime + Seconds((double)capSymbols / symbolRate);
359 }
360 else
361 { // Take Outgoing frame reference
362 activeSlot = m_mac->m_superframeDuration / 16;
363 capSymbols = activeSlot * (m_mac->m_fnlCapSlot + 1);
364 endCapTime = m_mac->m_macBeaconTxTime + Seconds((double)capSymbols / symbolRate);
365 }
366
367 return (endCapTime - currentTime);
368}
369
370void
372{
373 NS_LOG_FUNCTION(this);
374
375 Time timeLeftInCap;
376 uint16_t ccaSymbols;
377 uint32_t transactionSymbols;
378 Time transactionTime;
379 uint64_t symbolRate;
380
381 ccaSymbols = 0;
383 symbolRate = (uint64_t)m_mac->GetPhy()->GetDataOrSymbolRate(false);
384 timeLeftInCap = GetTimeLeftInCap();
385
386 // TODO: On the 950 Mhz Band (Japanese Band)
387 // only a single CCA check is performed;
388 // the CCA check duration time is:
389 //
390 // CCA symbols = phyCCADuration * m_CW (1)
391 // other PHYs:
392 // CCA symbols = 8 * m_CW(2)
393 //
394 // note: phyCCADuration & 950Mhz band PHYs are
395 // not currently implemented in ns-3.
396 ccaSymbols += 8 * m_CW;
397
398 // The MAC sublayer shall proceed if the remaining CSMA-CA algorithm steps
399 // can be completed before the end of the CAP.
400 // See IEEE 802.15.4-2011 (Sections 5.1.1.1 and 5.1.1.4)
401 // Transaction = 2 CCA + frame transmission (SHR+PHR+PPDU) + turnaroudtime*2 (Rx->Tx & Tx->Rx) +
402 // IFS (LIFS or SIFS) and Ack time (if ack flag true)
403
404 transactionSymbols = ccaSymbols + m_mac->GetTxPacketSymbols();
405
406 if (m_mac->isTxAckReq())
407 {
408 NS_LOG_DEBUG("ACK duration symbols: " << m_mac->GetMacAckWaitDuration());
409 transactionSymbols += m_mac->GetMacAckWaitDuration();
410 }
411 else
412 {
413 // time the PHY takes to switch from Rx to Tx and Tx to Rx
414 transactionSymbols += (lrwpan::aTurnaroundTime * 2);
415 }
416 transactionSymbols += m_mac->GetIfsSize();
417
418 // Report the transaction cost
420 {
421 m_lrWpanMacTransCostCallback(transactionSymbols);
422 }
423
424 transactionTime = Seconds((double)transactionSymbols / symbolRate);
425 NS_LOG_DEBUG("Total required transaction: " << transactionSymbols << " symbols ("
426 << transactionTime.As(Time::S) << ")");
427
428 if (transactionTime > timeLeftInCap)
429 {
430 NS_LOG_DEBUG("Transaction of "
431 << transactionSymbols << " symbols "
432 << "cannot be completed in CAP, deferring transmission to the next CAP");
433
434 NS_LOG_DEBUG("Symbols left in CAP: " << (timeLeftInCap.GetSeconds() * symbolRate) << " ("
435 << timeLeftInCap.As(Time::S) << ")");
436
438 }
439 else
440 {
442 }
443}
444
445void
447{
448 NS_LOG_FUNCTION(this);
449 m_ccaRequestRunning = true;
450 m_mac->GetPhy()->PlmeCcaRequest();
451}
452
453void
455{
456 NS_LOG_FUNCTION(this);
458}
459
460void
462{
463 NS_LOG_FUNCTION(this << status);
464
465 // Only react on this event, if we are actually waiting for a CCA.
466 // If the CSMA algorithm was canceled, we could still receive this event from
467 // the PHY. In this case we ignore the event.
469 {
470 m_ccaRequestRunning = false;
471 if (status == IEEE_802_15_4_PHY_IDLE)
472 {
473 if (IsSlottedCsmaCa())
474 {
475 m_CW--;
476 if (m_CW == 0)
477 {
478 // inform MAC channel is idle
480 {
481 NS_LOG_LOGIC("Notifying MAC of idle channel");
483 }
484 }
485 else
486 {
487 NS_LOG_LOGIC("Perform CCA again, m_CW = " << m_CW);
489 this); // Perform CCA again
490 }
491 }
492 else
493 {
494 // inform MAC, channel is idle
496 {
497 NS_LOG_LOGIC("Notifying MAC of idle channel");
499 }
500 }
501 }
502 else
503 {
504 if (IsSlottedCsmaCa())
505 {
506 m_CW = 2;
507 }
508 m_BE = std::min(static_cast<uint16_t>(m_BE + 1), static_cast<uint16_t>(m_macMaxBE));
509 m_NB++;
511 {
512 // no channel found so cannot send pkt
513 NS_LOG_DEBUG("Channel access failure");
515 {
516 NS_LOG_LOGIC("Notifying MAC of Channel access failure");
518 }
519 return;
520 }
521 else
522 {
523 NS_LOG_DEBUG("Perform another backoff; m_NB = " << static_cast<uint16_t>(m_NB));
526 this); // Perform another backoff (step 2)
527 }
528 }
529 }
530}
531
532void
534{
535 NS_LOG_FUNCTION(this);
537}
538
539void
541{
542 NS_LOG_FUNCTION(this);
544}
545
546void
548{
549 m_macBattLifeExt = batteryLifeExtension;
550}
551
552int64_t
554{
555 NS_LOG_FUNCTION(this);
556 m_random->SetStream(stream);
557 return 1;
558}
559
560uint8_t
562{
563 return m_NB;
564}
565
566bool
568{
569 return m_macBattLifeExt;
570}
571
572} // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
bool IsNull() const
Check for null implementation.
Definition: callback.h:572
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
This class is a helper for the LrWpanMac to manage the Csma/CA state machine according to IEEE 802....
Ptr< LrWpanMac > m_mac
The MAC instance for which this CSMA/CA implementation is configured.
void SetBatteryLifeExtension(bool batteryLifeExtension)
Set the value of the Battery Life Extension.
void PlmeCcaConfirm(LrWpanPhyEnumeration status)
IEEE 802.15.4-2006 section 6.2.2.2 PLME-CCA.confirm status.
LrWpanCsmaCa()
Default constructor.
void RequestCCA()
Request the Phy to perform CCA (Step 3)
uint8_t GetMacMinBE() const
Get the minimum backoff exponent value.
bool m_isSlotted
Beacon-enabled slotted or nonbeacon-enabled unslotted CSMA-CA.
uint8_t m_BE
Backoff exponent.
EventId m_canProceedEvent
Scheduler event for checking if we can complete the transmission before the end of the CAP.
static TypeId GetTypeId()
Get the type ID.
EventId m_randomBackoffEvent
Scheduler event for the start of the next random backoff/slot.
void SetUnSlottedCsmaCa()
Configure for the use of the unslotted CSMA/CA version.
void DeferCsmaTimeout()
The CSMA algorithm call this function at the end of the CAP to return the MAC state back to to IDLE a...
bool IsUnSlottedCsmaCa() const
Check if the unslotted CSMA/CA version is being used.
void SetMac(Ptr< LrWpanMac > mac)
Set the MAC to which this CSMA/CA implementation is attached to.
uint8_t GetNB() const
Get the number of CSMA retries.
LrWpanMacStateCallback m_lrWpanMacStateCallback
The callback to inform the configured MAC of the CSMA/CA result.
Ptr< LrWpanMac > GetMac() const
Get the MAC to which this CSMA/CA implementation is attached to.
LrWpanMacTransCostCallback m_lrWpanMacTransCostCallback
The callback to inform the cost of a transaction in slotted CSMA-CA.
void Cancel()
Cancel CSMA-CA algorithm.
EventId m_requestCcaEvent
Scheduler event when to start the CCA after a random backoff.
bool m_coorDest
Indicates whether the CSMA procedure is targeted for a message to be sent to the coordinator.
bool IsSlottedCsmaCa() const
Check if the slotted CSMA/CA version is being used.
void SetLrWpanMacTransCostCallback(LrWpanMacTransCostCallback trans)
Set the callback function to report a transaction cost in slotted CSMA-CA.
void SetMacMaxBE(uint8_t macMaxBE)
Set the maximum backoff exponent value.
void RandomBackoffDelay()
In step 2 of the CSMA-CA, perform a random backoff in the range of 0 to 2^BE -1.
uint8_t m_macMaxBE
Maximum backoff exponent.
void SetMacMinBE(uint8_t macMinBE)
Set the minimum backoff exponent value.
bool GetBatteryLifeExtension() const
Get the value of the Battery Life Extension.
uint8_t m_CW
Contention window length (used in slotted ver only).
uint8_t m_macMinBE
Minimum backoff exponent.
uint8_t GetMacMaxCSMABackoffs() const
Get the maximum number of backoffs.
bool m_macBattLifeExt
Battery Life Extension.
Time GetTimeToNextSlot() const
Locates the time to the next backoff period boundary in the SUPERFRAME and returns the amount of time...
uint8_t GetMacMaxBE() const
Get the maximum backoff exponent value.
void SetSlottedCsmaCa()
Configure for the use of the slotted CSMA/CA version.
EventId m_endCapEvent
Scheduler event for the end of the current CAP.
void CanProceed()
In the slotted CSMA-CA, after random backoff, determine if the remaining CSMA-CA operation can procee...
uint64_t m_randomBackoffPeriodsLeft
Count the number of remaining random backoff periods left to delay.
Time GetTimeLeftInCap()
Get the time left in the CAP portion of the Outgoing or Incoming superframe.
~LrWpanCsmaCa() override
bool m_ccaRequestRunning
Flag indicating that the PHY is currently running a CCA.
void SetLrWpanMacStateCallback(LrWpanMacStateCallback macState)
Set the callback function to the MAC.
void DoDispose() override
Destructor implementation.
void Start()
Start CSMA-CA algorithm (step 1), initialize NB, BE for both slotted and unslotted CSMA-CA.
uint8_t m_NB
Number of backoffs for the current transmission.
Ptr< UniformRandomVariable > m_random
Uniform random variable stream.
void SetMacMaxCSMABackoffs(uint8_t macMaxCSMABackoffs)
Set the maximum number of backoffs.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
uint8_t m_macMaxCSMABackoffs
Maximum number of backoffs.
A base class which provides memory management and object aggregation.
Definition: object.h:89
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:417
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
@ S
second
Definition: nstime.h:116
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
double GetValue(double min, double max)
Get the next random value drawn from the distribution.
constexpr uint32_t aUnitBackoffPeriod
Number of symbols per CSMA/CA time unit, default 20 symbols.
constexpr uint32_t aTurnaroundTime
The turnaround time in symbol periods for switching the transceiver from RX to TX or vice-versa.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
LrWpanPhyEnumeration
IEEE802.15.4-2006 PHY Emumerations Table 18 in section 6.2.3.
Definition: lr-wpan-phy.h:109
@ CHANNEL_ACCESS_FAILURE
CHANNEL_ACCESS_FAILURE.
Definition: lr-wpan-mac.h:78
@ MAC_CSMA_DEFERRED
MAC_CSMA_DEFERRED.
Definition: lr-wpan-mac.h:83
@ CHANNEL_IDLE
CHANNEL_IDLE.
Definition: lr-wpan-mac.h:79
@ IEEE_802_15_4_PHY_IDLE
Definition: lr-wpan-phy.h:114
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Every class exported by the ns3 library is enclosed in the ns3 namespace.
mac
Definition: third.py:85