A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lr-wpan-phy.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 The Boeing Company
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author:
7 * Gary Pei <guangyu.pei@boeing.com>
8 * Sascha Alexander Jopen <jopen@cs.uni-bonn.de>
9 */
10#include "lr-wpan-phy.h"
11
12#include "lr-wpan-constants.h"
13#include "lr-wpan-error-model.h"
14#include "lr-wpan-lqi-tag.h"
15#include "lr-wpan-net-device.h"
18
19#include "ns3/abort.h"
20#include "ns3/antenna-model.h"
21#include "ns3/double.h"
22#include "ns3/error-model.h"
23#include "ns3/log.h"
24#include "ns3/mobility-model.h"
25#include "ns3/net-device.h"
26#include "ns3/node.h"
27#include "ns3/packet-burst.h"
28#include "ns3/packet.h"
29#include "ns3/pointer.h"
30#include "ns3/random-variable-stream.h"
31#include "ns3/simulator.h"
32#include "ns3/spectrum-channel.h"
33#include "ns3/spectrum-value.h"
34
35#include <array>
36
37namespace ns3
38{
39namespace lrwpan
40{
41
42NS_LOG_COMPONENT_DEFINE("LrWpanPhy");
44
45/**
46 * The data and symbol rates for the different PHY options.
47 * See Table 1 in section 6.1.1 IEEE 802.15.4-2006, IEEE 802.15.4c-2009, IEEE 802.15.4d-2009.
48 * You can check also Table 66 of 802.15.4-2011.
49 * Bit rate is in kbit/s. Symbol rate is in ksymbol/s.
50 * The index follows LrWpanPhyOption (kb/s and ksymbol/s)
51 */
52constexpr std::array<PhyDataAndSymbolRates, 10> dataSymbolRates{{
53 {20.0, 20.0}, // IEEE_802_15_4_868MHZ_BPSK
54 {40.0, 40.0}, // IEEE_802_15_4_915MHZ_BPSK
55 {20.0, 20.0}, // IEEE_802_15_4_950MHZ_BPSK
56 {250.0, 12.5}, // IEEE_802_15_4_868MHZ_ASK
57 {250.0, 50.0}, // IEEE_802_15_4_915MHZ_ASK
58 {250.0, 62.5}, // IEEE_802_15_4_780MHZ_OQPSK
59 {100.0, 25.0}, // IEEE_802_15_4_868MHZ_OQPSK
60 {250.0, 62.5}, // IEEE_802_15_4_915MHZ_OQPSK
61 {250.0, 62.5}, // IEEE_802_15_4_2_4GHZ_OQPSK
62 {0, 0}, // IEEE_802_15_4_INVALID_PHY_OPTION
63}};
64
65/**
66 * The preamble, SFD, and PHR lengths in symbols for the different PHY options.
67 * See Table 19 and Table 20 in section 6.3 IEEE 802.15.4-2006, IEEE 802.15.4c-2009, IEEE
68 * 802.15.4d-2009.
69 * The PHR is 1 octet and it follows phySymbolsPerOctet in Table 23.
70 * The index follows LrWpanPhyOption.
71 */
72constexpr std::array<PhyPpduHeaderSymbolNumber, 10> ppduHeaderSymbolNumbers{{
73 {32.0, 8.0, 8.0}, // IEEE_802_15_4_868MHZ_BPSK
74 {32.0, 8.0, 8.0}, // IEEE_802_15_4_915MHZ_BPSK
75 {32.0, 8.0, 8.0}, // IEEE_802_15_4_950MHZ_BPSK
76 {2.0, 1.0, 0.4}, // IEEE_802_15_4_868MHZ_ASK
77 {6.0, 1.0, 1.6}, // IEEE_802_15_4_915MHZ_ASK
78 {8.0, 2.0, 2.0}, // IEEE_802_15_4_780MHZ_OQPSK
79 {8.0, 2.0, 2.0}, // IEEE_802_15_4_868MHZ_OQPSK
80 {8.0, 2.0, 2.0}, // IEEE_802_15_4_915MHZ_OQPSK
81 {8.0, 2.0, 2.0}, // IEEE_802_15_4_2_4GHZ_OQPSK
82 {0, 0, 0}, // IEEE_802_15_4_INVALID_PHY_OPTION
83}};
84
85std::ostream&
86operator<<(std::ostream& os, const PhyEnumeration& state)
87{
88 switch (state)
89 {
91 os << "BUSY";
92 break;
94 os << "BUSY_RX";
95 break;
97 os << "BUSY_TX";
98 break;
100 os << "FORCE_TRX_OFF";
101 break;
103 os << "IDLE";
104 break;
106 os << "INVALID_PARAMETER";
107 break;
109 os << "RX_ON";
110 break;
112 os << "SUCCESS";
113 break;
115 os << "TRX_OFF";
116 break;
118 os << "TX_ON";
119 break;
121 os << "UNSUPPORTED";
122 break;
124 os << "READ_ONLY";
125 break;
127 os << "UNSPECIFIED";
128 break;
129 }
130 return os;
131}
132
133std::ostream&
134operator<<(std::ostream& os, const TracedValue<PhyEnumeration>& state)
135{
136 PhyEnumeration s = state;
137 return os << s;
138}
139
140TypeId
142{
143 static TypeId tid =
144 TypeId("ns3::lrwpan::LrWpanPhy")
145 .AddDeprecatedName("ns3::LrWpanPhy")
147 .SetGroupName("LrWpan")
148 .AddConstructor<LrWpanPhy>()
149 .AddAttribute("PostReceptionErrorModel",
150 "An optional packet error model can be added to the receive "
151 "packet process after any propagation-based (SNR-based) error "
152 "models have been applied. Typically this is used to force "
153 "specific packet drops, for testing purposes.",
154 PointerValue(),
157 .AddTraceSource("TrxStateValue",
158 "The state of the transceiver",
160 "ns3::TracedValueCallback::LrWpanPhyEnumeration")
161 .AddTraceSource("TrxState",
162 "The state of the transceiver",
164 "ns3::lrwpan::LrWpanPhy::StateTracedCallback")
165 .AddTraceSource("PhyTxBegin",
166 "Trace source indicating a packet has "
167 "begun transmitting over the channel medium",
169 "ns3::Packet::TracedCallback")
170 .AddTraceSource("PhyTxEnd",
171 "Trace source indicating a packet has been "
172 "completely transmitted over the channel.",
174 "ns3::Packet::TracedCallback")
175 .AddTraceSource("PhyTxDrop",
176 "Trace source indicating a packet has been "
177 "dropped by the device during transmission",
179 "ns3::Packet::TracedCallback")
180 .AddTraceSource("PhyRxBegin",
181 "Trace source indicating a packet has begun "
182 "being received from the channel medium by the device",
184 "ns3::Packet::TracedCallback")
185 .AddTraceSource("PhyRxEnd",
186 "Trace source indicating a packet has been "
187 "completely received from the channel medium "
188 "by the device",
190 "ns3::Packet::SinrTracedCallback")
191 .AddTraceSource("PhyRxDrop",
192 "Trace source indicating a packet has been "
193 "dropped by the device during reception",
195 "ns3::Packet::TracedCallback");
196 return tid;
197}
198
200 : m_edRequest(),
202{
205
206 // default PHY PIB attributes
207 m_phyPIBAttributes.phyTransmitPower = 0;
208 m_phyPIBAttributes.phyCCAMode = 1;
209
211
213 m_random->SetAttribute("Min", DoubleValue(0.0));
214 m_random->SetAttribute("Max", DoubleValue(1.0));
215
216 m_isRxCanceled = false;
218}
219
223
224void
226{
227 NS_LOG_FUNCTION(this);
228
229 // This method ensures that the local mobility model pointer holds
230 // a pointer to the Node's aggregated mobility model (if one exists)
231 // in the case that the user has not directly called SetMobility()
232 // on this LrWpanPhy during simulation setup. If the mobility model
233 // needs to be added or changed during simulation runtime, users must
234 // call SetMobility() on this object.
235
236 if (!m_mobility)
237 {
239 "Either install a MobilityModel on this object or ensure that this "
240 "object is part of a Node and NetDevice");
241 m_mobility = m_device->GetNode()->GetObject<MobilityModel>();
242 if (!m_mobility)
243 {
244 NS_LOG_WARN("Mobility not found, propagation models might not work properly");
245 }
246 }
247}
248
249void
289
292{
293 return m_device;
294}
295
298{
299 return m_mobility;
300}
301
302void
304{
305 NS_LOG_FUNCTION(this << d);
306 m_device = d;
307}
308
309void
315
316void
322
325{
326 NS_LOG_FUNCTION(this);
327 return m_channel;
328}
329
332{
333 NS_LOG_FUNCTION(this);
334 if (m_txPsd)
335 {
336 return m_txPsd->GetSpectrumModel();
337 }
338 else
339 {
340 return nullptr;
341 }
342}
343
346{
347 return m_antenna;
348}
349
350void
356
357void
359{
360 NS_LOG_FUNCTION(this << spectrumRxParams);
361
362 // 1- Add the signal to the spectrum to keep track of the transmission regardless
363 // of the origin or the state of the receiving radio.
364 m_signal->AddSignal(spectrumRxParams->psd);
365
366 // 2- Update peak power if CCA or ED if it is in progress.
368
369 // 3- Check the radio is on the right state to receceive (RX_ON) and that the signal
370 // is a lr-wpan signal, otherwise proceed to the end of the packet to be removed from
371 // the accumulated signals in the spectrum tracker.
374
375 if (!lrWpanRxParams || m_trxState != IEEE_802_15_4_PHY_RX_ON)
376 {
377 NS_LOG_DEBUG("Non-Lr-wpan signal or radio is not on RX_ON, do not process");
378 Simulator::Schedule(spectrumRxParams->duration, &LrWpanPhy::EndRx, this, spectrumRxParams);
379 return;
380 }
381
382 // The reception of the lr-wpan preamble start here
383 NS_LOG_INFO("Lr-wpan signal detected, processing preamble for a duration of "
384 << lrWpanRxParams->preambleDuration.GetSeconds() << " seconds");
385
386 Simulator::Schedule(lrWpanRxParams->preambleDuration,
388 this,
389 lrWpanRxParams);
390}
391
392void
394{
395 NS_LOG_FUNCTION(this << lrWpanRxParams);
396
397 // If in progress, update CCA peak power or ED measurement.
399
400 Ptr<Packet> p = (lrWpanRxParams->packetBurst->GetPackets()).front();
401 NS_ASSERT(p);
402
403 // Prevent PHY from receiving another packet while switching the transceiver state.
404 if (m_trxState == IEEE_802_15_4_PHY_RX_ON && !m_setTRXState.IsPending())
405 {
406 Ptr<SpectrumValue> interferenceAndNoise = m_signal->GetSignalPsd();
407 *interferenceAndNoise -= *lrWpanRxParams->psd;
408 *interferenceAndNoise += *m_noise;
409 double sinr =
411 m_phyPIBAttributes.phyCurrentChannel) /
412 LrWpanSpectrumValueHelper::TotalAvgPower(interferenceAndNoise,
413 m_phyPIBAttributes.phyCurrentChannel);
414
415 // Figure out if packet is decodable based on SINR.
416 // Std. 802.15.4-2006, appendix E, Figure E.2
417 // At SNR < -5 the BER is less than 10e-1.
418 // It's useless to even *try* to decode the packet.
419 if (10 * log10(sinr) > -5)
420 {
422
423 NS_LOG_INFO("Preamble processing completed,"
424 << " initiating the reception of the rests of the packet");
425
426 // Start tracking the packet interference
427 m_currentRxPacket = std::make_pair(lrWpanRxParams, false);
429
431
432 // Calculate RSSI
433 // In theory, the RSSI calculation should be done in the PHR, not at the end
434 // of the preamble. However since there is not much difference in ns-3, it
435 // is done here for simplicity (We avoid doing an extra endSFD event)
437 m_signal->GetSignalPsd(),
438 m_phyPIBAttributes.phyCurrentChannel)) +
439 30);
440 }
441 else
442 {
443 // The packet is *undecodable* drop it.
444 m_currentRxPacket = std::make_pair(lrWpanRxParams, true);
446 NS_LOG_INFO(this << " packet undecodable due to low SINR: " << 10 * log10(sinr)
447 << " dB");
448 }
449 }
451 {
452 // We are already receiving a packet, drop the new packet.
453 NS_LOG_INFO(this << " Packet collision detected, dropping packet");
455
456 // Another lr-wpan packet is being transmitted in the vecinity while we are receiving
457 // another packet. This affects the reception of the first packet, therefore,
458 // check interference and its impact on this packet.
460 }
461 else
462 {
463 // The current policy to process the preamble is first come first served.
464 // Therefore, if we are not in RX_ON or BUSY_RX state, we drop the packet.
465 // Other policies can be implemented in future extensions.
466 NS_LOG_DEBUG(this << " transceiver not in RX state, currently in " << m_trxState
467 << " state, dropping packet");
469 }
470
471 Time endRx = (lrWpanRxParams->duration - lrWpanRxParams->preambleDuration);
472 Simulator::Schedule(endRx, &LrWpanPhy::EndRx, this, lrWpanRxParams);
473}
474
475void
477{
478 // Calculate whether packet was lost.
481
482 // We are currently receiving a packet.
484 {
485 // NS_ASSERT (currentRxParams && !m_currentRxPacket.second);
486
487 Ptr<Packet> currentPacket = currentRxParams->packetBurst->GetPackets().front();
488 if (m_errorModel)
489 {
490 // How many bits did we receive since the last calculation?
491 double t = (Simulator::Now() - m_rxLastUpdate).ToDouble(Time::MS);
492 uint32_t chunkSize = ceil(t * (GetDataOrSymbolRate(true) / 1000));
493 Ptr<SpectrumValue> interferenceAndNoise = m_signal->GetSignalPsd();
494 *interferenceAndNoise -= *currentRxParams->psd;
495 *interferenceAndNoise += *m_noise;
496 double sinr =
497 LrWpanSpectrumValueHelper::TotalAvgPower(currentRxParams->psd,
498 m_phyPIBAttributes.phyCurrentChannel) /
499 LrWpanSpectrumValueHelper::TotalAvgPower(interferenceAndNoise,
500 m_phyPIBAttributes.phyCurrentChannel);
501 double per = 1.0 - m_errorModel->GetChunkSuccessRate(sinr, chunkSize);
502
503 // The LQI is the total packet success rate scaled to 0-255.
504 // If not already set, initialize to 255.
505 LrWpanLqiTag tag(std::numeric_limits<uint8_t>::max());
506 currentPacket->PeekPacketTag(tag);
507 uint8_t lqi = tag.Get();
508 tag.Set(lqi - (per * lqi));
509 currentPacket->ReplacePacketTag(tag);
510
511 if (m_random->GetValue() < per)
512 {
513 // The packet was destroyed, drop the packet after reception.
514 m_currentRxPacket.second = true;
515 }
516 }
517 else
518 {
519 NS_LOG_WARN("Missing ErrorModel");
520 }
521 }
523}
524
525void
527{
528 // Update CCA peak power
529 if (!m_ccaRequest.IsExpired())
530 {
531 double power =
533 m_phyPIBAttributes.phyCurrentChannel);
534 if (m_ccaPeakPower < power)
535 {
536 m_ccaPeakPower = power;
537 NS_LOG_DEBUG("Updating CCA peak power " << WToDbm(power) << " dBm");
538 }
539 }
540
541 if (!m_edRequest.IsExpired())
542 {
543 // Update the average receive power during ED.
544 Time now = Simulator::Now();
545 m_edPower.averagePower +=
547 m_phyPIBAttributes.phyCurrentChannel) *
548 (now - m_edPower.lastUpdate).GetTimeStep() / m_edPower.measurementLength.GetTimeStep();
549 m_edPower.lastUpdate = now;
550 }
551}
552
553void
555{
556 NS_LOG_FUNCTION(this << "End of packet signal after a duration: " << par->duration.GetSeconds()
557 << " seconds");
558
560
561 // Update peak power if CCA or ED if it is in progress.
563
565 if (currentRxParams == params)
566 {
568 }
569
570 // The packet reception has ended, remove it from the accumulated signals
571 // in the receptor tracker
572 m_signal->RemoveSignal(par->psd);
573
574 if (!params)
575 {
576 NS_LOG_LOGIC("Node: " << m_device->GetAddress()
577 << " Removing interferent: " << *(par->psd));
578 return;
579 }
580
581 // If this is the end of the currently received packet, check if reception was successful.
582 if (currentRxParams == params)
583 {
584 Ptr<Packet> currentPacket = currentRxParams->packetBurst->GetPackets().front();
585 NS_ASSERT(currentPacket);
586
588 m_postReceptionErrorModel->IsCorrupt(currentPacket->Copy()))
589 {
590 NS_LOG_DEBUG("Reception failed due to post-rx error model");
591 m_currentRxPacket.second = true;
592 }
593
594 // If there is no error model attached to the PHY, we always report the maximum LQI value.
595 LrWpanLqiTag tag(std::numeric_limits<uint8_t>::max());
596 currentPacket->PeekPacketTag(tag);
597 m_phyRxEndTrace(currentPacket, tag.Get());
598
599 if (!m_currentRxPacket.second)
600 {
601 m_currentRxPacket = std::make_pair(nullptr, true);
603
604 NS_LOG_INFO(" Packet successfully received,"
605 << "passing received packet to upper layer");
606
607 // The packet was successfully received, push it up the stack.
608 if (!m_pdDataIndicationCallback.IsNull())
609 {
610 m_pdDataIndicationCallback(currentPacket->GetSize(),
611 currentPacket,
612 tag.Get(),
613 m_rssi);
614 }
615 }
616 else
617 {
618 // The packet was destroyed due to interference, post-rx corruption or
619 // cancelled, therefore drop it.
620 m_phyRxDropTrace(currentPacket);
621 m_currentRxPacket = std::make_pair(nullptr, true);
622
623 if (!m_isRxCanceled)
624 {
626 }
627 else
628 {
629 // The state of The PHY was already changed when the packet was canceled
630 // due to a forced operation.
631 m_isRxCanceled = false;
632 }
633 }
634 }
635}
636
637void
639{
640 NS_LOG_FUNCTION(this << psduLength << p);
641
642 if (psduLength > lrwpan::aMaxPhyPacketSize)
643 {
644 if (!m_pdDataConfirmCallback.IsNull())
645 {
647 }
648 NS_LOG_DEBUG("Drop packet because psduLength too long: " << psduLength);
649 return;
650 }
651
652 // Prevent PHY from sending a packet while switching the transceiver state.
653 if (!m_setTRXState.IsPending())
654 {
656 {
657 // send down
659
660 // Remove a possible LQI tag from a previous transmission of the packet.
661 LrWpanLqiTag lqiTag;
662 p->RemovePacketTag(lqiTag);
663
665 m_currentTxPacket.first = p;
666 m_currentTxPacket.second = false;
667
669 txParams->duration = CalculateTxTime(p);
670
671 double preambleSymbols = ppduHeaderSymbolNumbers[m_phyOption].shrPreamble;
672 txParams->preambleDuration = Seconds(preambleSymbols / GetDataOrSymbolRate(false));
673
674 txParams->txPhy = GetObject<SpectrumPhy>();
675 txParams->psd = m_txPsd;
676 txParams->txAntenna = m_antenna;
678 pb->AddPacket(p);
679 txParams->packetBurst = pb;
680 m_channel->StartTx(txParams);
681 m_pdDataRequest = Simulator::Schedule(txParams->duration, &LrWpanPhy::EndTx, this);
683 return;
684 }
685 else if ((m_trxState == IEEE_802_15_4_PHY_RX_ON) ||
688 {
689 if (!m_pdDataConfirmCallback.IsNull())
690 {
692 }
693 // Drop packet, hit PhyTxDrop trace
695 return;
696 }
697 else
698 {
699 NS_FATAL_ERROR("This should be unreachable, or else state "
700 << m_trxState << " should be added as a case");
701 }
702 }
703 else
704 {
705 // TODO: This error code is not covered by the standard.
706 // What is the correct behavior in this case?
707 if (!m_pdDataConfirmCallback.IsNull())
708 {
710 }
711 // Drop packet, hit PhyTxDrop trace
713 return;
714 }
715}
716
717void
719{
720 NS_LOG_FUNCTION(this);
721
723 {
724 m_ccaPeakPower = 0.0;
725 Time ccaTime = Seconds(8.0 / GetDataOrSymbolRate(false));
727 }
728 else
729 {
730 if (!m_plmeCcaConfirmCallback.IsNull())
731 {
733 {
735 }
736 else
737 {
739 }
740 }
741 }
742}
743
744void
746{
747 NS_LOG_FUNCTION(this);
748 m_ccaRequest.Cancel();
749}
750
751void
753{
754 NS_LOG_FUNCTION(this);
756 {
757 // Average over the powers of all signals received until EndEd()
758 m_edPower.averagePower = 0;
759 m_edPower.lastUpdate = Simulator::Now();
760 m_edPower.measurementLength = Seconds(8.0 / GetDataOrSymbolRate(false));
761 m_edRequest = Simulator::Schedule(m_edPower.measurementLength, &LrWpanPhy::EndEd, this);
762 }
763 else
764 {
767 {
769 }
770
771 if (!m_plmeEdConfirmCallback.IsNull())
772 {
774 }
775 }
776}
777
778void
780{
781 NS_LOG_FUNCTION(this << id);
784
785 switch (id)
786 {
788 attributes->phyCurrentChannel = m_phyPIBAttributes.phyCurrentChannel;
789 break;
790 case phyCurrentPage:
791 attributes->phyCurrentPage = m_phyPIBAttributes.phyCurrentPage;
792 break;
793 case phySHRDuration:
794 attributes->phySHRDuration = GetPhySHRDuration();
795 break;
797 attributes->phySymbolsPerOctet = GetPhySymbolsPerOctet();
798 break;
799 default:
801 break;
802 }
803
805 {
806 m_plmeGetAttributeConfirmCallback(status, id, attributes);
807 }
808}
809
810// Section 6.2.2.7.3
811void
813{
814 NS_LOG_FUNCTION(this << state);
815
816 // Check valid states (Table 14)
819
820 NS_LOG_LOGIC("Trying to set m_trxState from " << m_trxState << " to " << state);
821
822 // this method always overrides previous state setting attempts
823 if (!m_setTRXState.IsExpired())
824 {
825 if (m_trxStatePending == state)
826 {
827 // Simply wait for the ongoing state switch.
828 return;
829 }
830 else
831 {
832 NS_LOG_DEBUG("Cancel m_setTRXState");
833 // Keep the transceiver state as the old state before the switching attempt.
834 m_setTRXState.Cancel();
835 }
836 }
838 {
840 }
841
842 if (state == m_trxState)
843 {
845 {
847 }
848 return;
849 }
850
851 if (((state == IEEE_802_15_4_PHY_RX_ON) || (state == IEEE_802_15_4_PHY_TRX_OFF)) &&
853 {
854 NS_LOG_DEBUG("Phy is busy; setting state pending to " << state);
855 m_trxStatePending = state;
856 return; // Send PlmeSetTRXStateConfirm later
857 }
858
859 // specification talks about being in RX_ON and having received
860 // a valid SFD. Here, we are not modelling at that level of
861 // granularity, so we just test for BUSY_RX state (any part of
862 // a packet being actively received)
863 if (state == IEEE_802_15_4_PHY_TRX_OFF)
864 {
866 (!m_currentRxPacket.second))
867 {
868 NS_LOG_DEBUG("Receiver has valid SFD; defer state change");
869 m_trxStatePending = state;
870 return; // Send PlmeSetTRXStateConfirm later
871 }
873 {
874 CancelEd(state);
877 {
879 }
880 return;
881 }
882 }
883
884 if (state == IEEE_802_15_4_PHY_TX_ON)
885 {
886 CancelEd(state);
887
888 NS_LOG_DEBUG("turn on PHY_TX_ON");
890 {
891 if (m_currentRxPacket.first)
892 {
893 // TX_ON is being forced during a reception (For example, when a ACK or Beacon is
894 // issued) The current RX frame is marked as incomplete and the reception as
895 // canceled EndRx () will handle the rest accordingly
896 NS_LOG_DEBUG("force TX_ON, terminate reception");
897 m_currentRxPacket.second = true;
898 m_isRxCanceled = true;
899 }
900
901 // If CCA is in progress, cancel CCA and return BUSY.
902 if (!m_ccaRequest.IsExpired())
903 {
904 m_ccaRequest.Cancel();
905 if (!m_plmeCcaConfirmCallback.IsNull())
906 {
908 }
909 }
910
912
913 // Delay for turnaround time (BUSY_RX|RX_ON ---> TX_ON)
914 Time setTime = Seconds((double)lrwpan::aTurnaroundTime / GetDataOrSymbolRate(false));
916 return;
917 }
919 {
920 // We do NOT change the transceiver state here. We only report that
921 // the transceiver is already in TX_ON state.
923 {
925 }
926 return;
927 }
929 {
932 {
934 }
935 return;
936 }
937 }
938
940 {
942 {
943 NS_LOG_DEBUG("force TRX_OFF, was already off");
944 }
945 else
946 {
947 NS_LOG_DEBUG("force TRX_OFF, SUCCESS");
948 if (m_currentRxPacket.first)
949 {
950 // Terminate reception
951 // Mark the packet as incomplete and reception as canceled.
952 NS_LOG_DEBUG("force TRX_OFF, terminate reception");
953 m_currentRxPacket.second = true;
954 m_isRxCanceled = true;
955 }
957 {
958 NS_LOG_DEBUG("force TRX_OFF, terminate transmission");
959 m_currentTxPacket.second = true;
960 }
962 // Clear any other state
964 }
966 {
968 }
969 return;
970 }
971
972 if (state == IEEE_802_15_4_PHY_RX_ON)
973 {
975 {
976 // Turnaround delay
977 // TODO: Does it really take aTurnaroundTime to switch the transceiver state,
978 // even when the transmitter is not busy? (6.9.1)
980
981 Time setTime = Seconds((double)lrwpan::aTurnaroundTime / GetDataOrSymbolRate(false));
983 return;
984 }
986 {
988 {
990 }
991 return;
992 }
993 }
994
995 NS_FATAL_ERROR("Unexpected transition from state " << m_trxState << " to state " << state);
996}
997
998bool
1000{
1001 NS_LOG_FUNCTION(this << channel);
1002 bool retValue = false;
1003
1004 // Bits 0-26 (27 LSB)
1005 if ((m_phyPIBAttributes.phyChannelsSupported[m_phyPIBAttributes.phyCurrentPage] &
1006 (1 << channel)) != 0)
1007 {
1008 return retValue = true;
1009 }
1010 else
1011 {
1012 return retValue;
1013 }
1014}
1015
1016bool
1018{
1019 NS_LOG_FUNCTION(this << +page);
1020 bool retValue = false;
1021
1022 // TODO: Only O-QPSK 2.4GHz is supported in the LrWpanSpectrumModel
1023 // we must limit the page until support for other modulation is added to the spectrum
1024 // model.
1025 //
1026 NS_ABORT_MSG_UNLESS(page == 0, " Only Page 0 (2.4Ghz O-QPSK supported).");
1027
1028 // IEEE 802.15.4-2006, Table 23 phyChannelsSupported Bits 27-31 (5 MSB)
1029 uint8_t supportedPage = (m_phyPIBAttributes.phyChannelsSupported[page] >> 27) & (0x1F);
1030
1031 if (page == supportedPage)
1032 {
1033 retValue = true;
1034 }
1035
1036 return retValue;
1037}
1038
1039void
1041{
1042 NS_LOG_FUNCTION(this << id << attribute);
1043 NS_ASSERT(attribute);
1045
1046 switch (id)
1047 {
1048 case phyCurrentPage: {
1049 if (!PageSupported(attribute->phyCurrentPage))
1050 {
1052 }
1053 else if (m_phyPIBAttributes.phyCurrentPage != attribute->phyCurrentPage)
1054 {
1055 // Cancel a pending transceiver state change.
1056 // Switch off the transceiver.
1057 // TODO: Is switching off the transceiver the right choice?
1060 {
1062 m_setTRXState.Cancel();
1064 {
1066 }
1067 }
1068
1069 // Any packet in transmission or reception will be corrupted.
1070 if (m_currentRxPacket.first)
1071 {
1072 m_currentRxPacket.second = true;
1073 }
1074 if (PhyIsBusy())
1075 {
1076 m_currentTxPacket.second = true;
1077 m_pdDataRequest.Cancel();
1078 m_currentTxPacket.first = nullptr;
1079 if (!m_pdDataConfirmCallback.IsNull())
1080 {
1082 }
1083 }
1084
1085 // Changing the Page can change they current PHY in use
1086 // Set the correct PHY according to the Page
1087 if (attribute->phyCurrentPage == 0)
1088 {
1089 if (m_phyPIBAttributes.phyCurrentChannel == 0)
1090 {
1091 // 868 MHz BPSK
1093 NS_LOG_INFO("Page 0, 868 MHz BPSK PHY SET");
1094 }
1095 else if (m_phyPIBAttributes.phyCurrentChannel <= 10)
1096 {
1097 // 915 MHz BPSK
1099 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1100 << ",915 MHz BPSK PHY SET");
1101 }
1102 else if (m_phyPIBAttributes.phyCurrentChannel <= 26)
1103 {
1104 // 2.4 GHz MHz O-QPSK
1106 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1107 << ", 2.4 Ghz O-QPSK PHY SET");
1108 }
1109 }
1110 else if (attribute->phyCurrentPage == 1)
1111 {
1112 if (m_phyPIBAttributes.phyCurrentChannel == 0)
1113 {
1114 // 868 MHz ASK
1116 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1117 << ", 868 MHz ASK PHY SET");
1118 }
1119 else if (m_phyPIBAttributes.phyCurrentChannel <= 10)
1120 {
1121 // 915 MHz ASK
1123 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1124 << ", 915 MHz ASK PHY SET");
1125 }
1126 else
1127 {
1128 // No longer valid channel
1130 m_phyPIBAttributes.phyCurrentChannel = 0;
1131 NS_LOG_INFO("Channel no longer valid in new page "
1132 << (uint32_t)attribute->phyCurrentPage
1133 << ", setting new default channel "
1134 << (uint32_t)m_phyPIBAttributes.phyCurrentChannel);
1135 NS_LOG_INFO("868 MHz ASK PHY SET");
1136 }
1137 }
1138 else if (attribute->phyCurrentPage == 2)
1139 {
1140 if (m_phyPIBAttributes.phyCurrentChannel == 0)
1141 {
1142 // 868 MHz O-QPSK
1144 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1145 << ", 868 MHz O-QPSK PHY SET");
1146 }
1147 else if (m_phyPIBAttributes.phyCurrentChannel <= 10)
1148 {
1149 // 915 MHz O-QPSK
1151 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1152 << ", 915 MHz O-QPSK PHY SET");
1153 }
1154 else
1155 {
1156 // No longer valid channel
1158 m_phyPIBAttributes.phyCurrentChannel = 0;
1159 NS_LOG_INFO("Channel no longer valid in new page "
1160 << (uint32_t)attribute->phyCurrentPage
1161 << ", setting new default channel "
1162 << (uint32_t)m_phyPIBAttributes.phyCurrentChannel);
1163 NS_LOG_INFO("868 MHz O-QPSK PHY SET");
1164 }
1165 }
1166 else if (attribute->phyCurrentPage == 5)
1167 {
1168 if (m_phyPIBAttributes.phyCurrentChannel <= 3)
1169 {
1170 // 780 MHz O-QPSK
1172 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1173 << ", 915 MHz O-QPSK PHY SET");
1174 }
1175 else
1176 {
1177 // No longer valid channel
1179 m_phyPIBAttributes.phyCurrentChannel = 0;
1180 NS_LOG_INFO("Channel no longer valid in new page "
1181 << (uint32_t)attribute->phyCurrentPage
1182 << ", setting new default channel "
1183 << (uint32_t)m_phyPIBAttributes.phyCurrentChannel);
1184 NS_LOG_INFO("780 MHz O-QPSK PHY SET");
1185 }
1186 }
1187 else if (attribute->phyCurrentPage == 6)
1188 {
1189 if (m_phyPIBAttributes.phyCurrentChannel <= 9)
1190 {
1191 // 950 MHz BPSK
1193 NS_LOG_INFO("Page " << (uint32_t)attribute->phyCurrentPage
1194 << ", 950 MHz BPSK PHY SET");
1195 }
1196 else
1197 {
1199 m_phyPIBAttributes.phyCurrentChannel = 0;
1200 NS_LOG_INFO("Channel no longer valid in new page "
1201 << (uint32_t)attribute->phyCurrentPage
1202 << ", setting new default channel "
1203 << (uint32_t)m_phyPIBAttributes.phyCurrentChannel);
1204 NS_LOG_INFO("950 MHz BPSK PHY SET");
1205 }
1206 }
1207
1208 m_phyPIBAttributes.phyCurrentPage = attribute->phyCurrentPage;
1209
1210 // TODO: Set the maximum possible sensitivity by default.
1211 // This maximum sensitivity depends on the modulation used.
1212 // Currently Only O-QPSK 250kbps is supported so we use its max sensitivity.
1213 SetRxSensitivity(-106.58);
1214 }
1215 break;
1216 }
1217 case phyCurrentChannel: {
1218 if (!ChannelSupported(attribute->phyCurrentChannel))
1219 {
1221 }
1222 if (m_phyPIBAttributes.phyCurrentChannel != attribute->phyCurrentChannel)
1223 {
1224 // Cancel a pending transceiver state change.
1225 // Switch off the transceiver.
1226 // TODO: Is switching off the transceiver the right choice?
1229 {
1231 m_setTRXState.Cancel();
1233 {
1235 }
1236 }
1237
1238 // Any packet in transmission or reception will be corrupted.
1239 if (m_currentRxPacket.first)
1240 {
1241 m_currentRxPacket.second = true;
1242 }
1243 if (PhyIsBusy())
1244 {
1245 m_currentTxPacket.second = true;
1246 m_pdDataRequest.Cancel();
1247 m_currentTxPacket.first = nullptr;
1248 if (!m_pdDataConfirmCallback.IsNull())
1249 {
1251 }
1252 }
1253
1254 m_phyPIBAttributes.phyCurrentChannel = attribute->phyCurrentChannel;
1255
1256 // use the prev configured sensitivity before changing the channel
1258 }
1259 break;
1260 }
1261 case phyChannelsSupported: { // only the first element is considered in the array
1262 if ((attribute->phyChannelsSupported[0] & 0xf8000000) != 0)
1263 { // 5 MSBs reserved
1265 }
1266 else
1267 {
1268 m_phyPIBAttributes.phyChannelsSupported[0] = attribute->phyChannelsSupported[0];
1269 }
1270 break;
1271 }
1272 case phyTransmitPower: {
1273 if (attribute->phyTransmitPower & 0xC0)
1274 {
1275 NS_LOG_LOGIC("LrWpanPhy::PlmeSetAttributeRequest error - can not change read-only "
1276 "attribute bits.");
1278 }
1279 else
1280 {
1281 m_phyPIBAttributes.phyTransmitPower = attribute->phyTransmitPower;
1282 LrWpanSpectrumValueHelper psdHelper;
1285 m_phyPIBAttributes.phyCurrentChannel);
1286 }
1287 break;
1288 }
1289 case phyCCAMode: {
1290 if ((attribute->phyCCAMode < 1) || (attribute->phyCCAMode > 3))
1291 {
1293 }
1294 else
1295 {
1296 m_phyPIBAttributes.phyCCAMode = attribute->phyCCAMode;
1297 }
1298 break;
1299 }
1300 default: {
1302 break;
1303 }
1304 }
1305
1307 {
1309 }
1310}
1311
1312void
1318
1319void
1325
1326void
1332
1333void
1339
1340void
1346
1347void
1353
1354void
1360
1361void
1363{
1364 NS_LOG_LOGIC(this << " state: " << m_trxState << " -> " << newState);
1365
1367 m_trxState = newState;
1368
1371 {
1372 // The MAC is set on RxOnWhenIdle = false, therefore when need to turn off
1373 // the radio
1374 NS_LOG_DEBUG("Turning off radio, appliying pending state");
1376 }
1377}
1378
1379bool
1386
1387void
1389{
1390 NS_LOG_FUNCTION(this);
1392
1393 if (!m_edRequest.IsExpired())
1394 {
1395 m_edRequest.Cancel();
1396 if (!m_plmeEdConfirmCallback.IsNull())
1397 {
1398 m_plmeEdConfirmCallback(state, 0);
1399 }
1400 }
1401}
1402
1403void
1405{
1406 NS_LOG_FUNCTION(this);
1407
1408 m_edPower.averagePower +=
1410 m_phyPIBAttributes.phyCurrentChannel) *
1411 (Simulator::Now() - m_edPower.lastUpdate).GetTimeStep() /
1412 m_edPower.measurementLength.GetTimeStep();
1413
1414 uint8_t energyLevel;
1415
1416 // Per IEEE802.15.4-2006 sec 6.9.7
1417 double ratio = m_edPower.averagePower / m_rxSensitivity;
1418 ratio = 10.0 * log10(ratio);
1419 if (ratio <= 10.0)
1420 { // less than 10 dB
1421 energyLevel = 0;
1422 }
1423 else if (ratio >= 40.0)
1424 { // less than 40 dB
1425 energyLevel = 255;
1426 }
1427 else
1428 {
1429 // in-between with linear increase per sec 6.9.7
1430 energyLevel = static_cast<uint8_t>(((ratio - 10.0) / 30.0) * 255.0);
1431 }
1432
1433 if (!m_plmeEdConfirmCallback.IsNull())
1434 {
1436 }
1437}
1438
1439void
1441{
1442 NS_LOG_FUNCTION(this);
1443 PhyEnumeration sensedChannelState = IEEE_802_15_4_PHY_UNSPECIFIED;
1444
1445 // Update peak power.
1446 double power = LrWpanSpectrumValueHelper::TotalAvgPower(m_signal->GetSignalPsd(),
1447 m_phyPIBAttributes.phyCurrentChannel);
1448 if (m_ccaPeakPower < power)
1449 {
1450 m_ccaPeakPower = power;
1451 }
1452
1453 if (PhyIsBusy())
1454 {
1455 sensedChannelState = IEEE_802_15_4_PHY_BUSY;
1456 }
1457 else if (m_phyPIBAttributes.phyCCAMode == 1)
1458 { // sec 6.9.9 ED detection
1459 // -- ED threshold at most 10 dB above receiver sensitivity.
1460 if (10 * log10(m_ccaPeakPower / m_rxSensitivity) >= 10.0)
1461 {
1462 sensedChannelState = IEEE_802_15_4_PHY_BUSY;
1463 }
1464 else
1465 {
1466 sensedChannelState = IEEE_802_15_4_PHY_IDLE;
1467 }
1468 }
1469 else if (m_phyPIBAttributes.phyCCAMode == 2)
1470 {
1471 // sec 6.9.9 carrier sense only
1473 {
1474 // We currently do not model PPDU reception in detail. Instead we model
1475 // packet reception starting with the first bit of the preamble.
1476 // Therefore, this code will never be reached, as PhyIsBusy() would
1477 // already lead to a channel busy condition.
1478 // TODO: Change this, if we also model preamble and SFD detection.
1479 sensedChannelState = IEEE_802_15_4_PHY_BUSY;
1480 }
1481 else
1482 {
1483 sensedChannelState = IEEE_802_15_4_PHY_IDLE;
1484 }
1485 }
1486 else if (m_phyPIBAttributes.phyCCAMode == 3)
1487 { // sect 6.9.9 both
1488 if ((10 * log10(m_ccaPeakPower / m_rxSensitivity) >= 10.0) &&
1490 {
1491 // Again, this code will never be reached, if we are already receiving
1492 // a packet, as PhyIsBusy() would already lead to a channel busy condition.
1493 // TODO: Change this, if we also model preamble and SFD detection.
1494 sensedChannelState = IEEE_802_15_4_PHY_BUSY;
1495 }
1496 else
1497 {
1498 sensedChannelState = IEEE_802_15_4_PHY_IDLE;
1499 }
1500 }
1501 else
1502 {
1503 NS_ASSERT_MSG(false, "Invalid CCA mode");
1504 }
1505
1506 NS_LOG_LOGIC(this << "channel sensed state: " << sensedChannelState);
1507
1508 if (!m_plmeCcaConfirmCallback.IsNull())
1509 {
1510 m_plmeCcaConfirmCallback(sensedChannelState);
1511 }
1512}
1513
1514void
1529
1530void
1532{
1533 NS_LOG_FUNCTION(this);
1534
1537
1538 if (!m_currentTxPacket.second)
1539 {
1540 NS_LOG_DEBUG("Packet successfully transmitted");
1542 if (!m_pdDataConfirmCallback.IsNull())
1543 {
1545 }
1546 }
1547 else
1548 {
1549 NS_LOG_DEBUG("Packet transmission aborted");
1551 if (!m_pdDataConfirmCallback.IsNull())
1552 {
1553 // See if this is ever entered in another state
1556 }
1557 }
1558 m_currentTxPacket.first = nullptr;
1559 m_currentTxPacket.second = false;
1560
1561 // We may be waiting to apply a pending state change.
1563 {
1564 // Only change the state immediately, if the transceiver is not already
1565 // switching the state.
1566 if (!m_setTRXState.IsPending())
1567 {
1568 NS_LOG_LOGIC("Apply pending state change to " << m_trxStatePending);
1572 {
1574 }
1575 }
1576 }
1577 else
1578 {
1580 {
1582 }
1583 }
1584}
1585
1586Time
1588{
1589 NS_LOG_FUNCTION(this << packet);
1590
1591 bool isData = true;
1592 Time txTime = GetPpduHeaderTxTime();
1593
1594 txTime += Seconds(packet->GetSize() * 8.0 / GetDataOrSymbolRate(isData));
1595
1596 return txTime;
1597}
1598
1599uint8_t
1601{
1602 return m_phyPIBAttributes.phyCurrentPage;
1603}
1604
1605uint8_t
1607{
1608 return m_phyPIBAttributes.phyCurrentChannel;
1609}
1610
1611double
1613{
1614 double rate = 0.0;
1615
1617
1618 if (isData)
1619 {
1620 rate = dataSymbolRates[m_phyOption].bitRate;
1621 }
1622 else
1623 {
1624 rate = dataSymbolRates[m_phyOption].symbolRate;
1625 }
1626
1627 return (rate * 1000.0);
1628}
1629
1630Time
1632{
1633 NS_LOG_FUNCTION(this);
1634
1635 bool isData = false;
1636 double totalPpduHdrSymbols;
1637
1639
1640 totalPpduHdrSymbols = ppduHeaderSymbolNumbers[m_phyOption].shrPreamble +
1643
1644 return Seconds(totalPpduHdrSymbols / GetDataOrSymbolRate(isData));
1645}
1646
1647void
1649{
1650 NS_LOG_FUNCTION(this);
1651
1653
1654 // TODO: Only O-QPSK 2.4GHz is supported in the LrWpanSpectrumModel
1655 // we must limit the page until support for other modulations is added to the spectrum
1656 // model.
1657 NS_ABORT_MSG_UNLESS(phyOption == IEEE_802_15_4_2_4GHZ_OQPSK, " Only 2.4Ghz O-QPSK supported.");
1658
1659 // Set default Channel and Page
1660 // IEEE 802.15.4-2006 Table 2, section 6.1.1
1661 // IEEE 802.15.4c-2009 Table 2, section 6.1.2.2
1662 // IEEE 802.15.4d-2009 Table 2, section 6.1.2.2
1663 switch (phyOption)
1664 {
1666 // IEEE 802.15.4-2006 868 MHz BPSK (Page 0, Channel 0)
1667 m_phyPIBAttributes.phyCurrentPage = 0;
1668 m_phyPIBAttributes.phyCurrentChannel = 0;
1669 break;
1671 // IEEE 802.15.4-2006 915 MHz BPSK (Page 0, Channels 1 to 10)
1672 m_phyPIBAttributes.phyCurrentPage = 0;
1673 m_phyPIBAttributes.phyCurrentChannel = 1;
1674 break;
1676 // IEEE 802.15.4d-2009 950 MHz BPSK (Page 6, Channels 0 to 9)
1677 m_phyPIBAttributes.phyCurrentPage = 6;
1678 m_phyPIBAttributes.phyCurrentChannel = 0;
1679 break;
1681 // IEEE 802.15.4-2006 868 MHz ASK (Page 1, Channel 0)
1682 m_phyPIBAttributes.phyCurrentPage = 1;
1683 m_phyPIBAttributes.phyCurrentChannel = 0;
1684 break;
1686 // IEEE 802.15.4-2006 915 MHz ASK (Page 1, Channel 1 to 10)
1687 m_phyPIBAttributes.phyCurrentPage = 1;
1688 m_phyPIBAttributes.phyCurrentChannel = 1;
1689 break;
1691 // IEEE 802.15.4c-2009 780 MHz O-QPSK (Page 5, Channel 0 to 3)
1692 m_phyPIBAttributes.phyCurrentPage = 5;
1693 m_phyPIBAttributes.phyCurrentChannel = 0;
1694 break;
1696 // IEEE 802.15.4-2006 868 MHz O-QPSK (Page 2, Channel 0)
1697 m_phyPIBAttributes.phyCurrentPage = 2;
1698 m_phyPIBAttributes.phyCurrentChannel = 0;
1699 break;
1701 // IEEE 802.15.4-2006 915 MHz O-QPSK (Page 2, Channels 1 to 10)
1702 m_phyPIBAttributes.phyCurrentPage = 2;
1703 m_phyPIBAttributes.phyCurrentChannel = 1;
1704 break;
1706 // IEEE 802.15.4-2009 2.4 GHz O-QPSK (Page 0, Channels 11 to 26)
1707 m_phyPIBAttributes.phyCurrentPage = 0;
1708 m_phyPIBAttributes.phyCurrentChannel = 11;
1709 break;
1711 // IEEE 802.15.4-2006 Use Non-Registered Page and channel
1712 m_phyPIBAttributes.phyCurrentPage = 31;
1713 m_phyPIBAttributes.phyCurrentChannel = 26;
1714 break;
1715 }
1716
1718
1719 m_phyOption = phyOption;
1720 // TODO: Fix/Update list when more modulations are supported.
1721 // IEEE 802.15.4-2006, Table 23
1722 // 5 MSB = Page number, 27 LSB = Supported Channels (1= supported, 0 Not supported)
1723 // Currently only page 0, channels 11-26 supported.
1724 m_phyPIBAttributes.phyChannelsSupported[0] =
1725 0x7FFF800; // Page 0 should support, Channels 0 to 26 (0x07FFFFFF)
1726
1727 for (int i = 1; i <= 31; i++)
1728 {
1729 // Page 1 to 31, No support (Page set to 31, all channels 0)
1730 m_phyPIBAttributes.phyChannelsSupported[i] = 0xF8000000;
1731 }
1732
1733 m_edPower.averagePower = 0.0;
1734 m_edPower.lastUpdate = Seconds(0);
1735 m_edPower.measurementLength = Seconds(0);
1736
1737 // TODO: Change the limits Rx sensitivity when other modulations are supported
1738 // Currently, only O-QPSK 250kbps is supported and its maximum possible sensitivity is
1739 // equal to -106.58 dBm and its minimum sensitivity is defined as -85 dBm
1740 SetRxSensitivity(-106.58);
1741
1743 m_currentRxPacket = std::make_pair(nullptr, true);
1744 m_currentTxPacket = std::make_pair(nullptr, true);
1745 m_errorModel = nullptr;
1746}
1747
1748void
1749LrWpanPhy::SetRxSensitivity(double dbmSensitivity)
1750{
1751 NS_LOG_FUNCTION(this << dbmSensitivity << "dBm");
1752
1753 // See IEEE 802.15.4-2011 Sections 10.3.4, 11.3.4, 13.3.4, 13.3.4, 14.3.4, 15.3.4
1755 {
1756 if (dbmSensitivity > -92)
1757 {
1758 NS_ABORT_MSG("The minimum Rx sensitivity for this band should be at least -92 dBm");
1759 }
1760 }
1761 else
1762 {
1763 if (dbmSensitivity > -85)
1764 {
1765 NS_ABORT_MSG("The minimum Rx sensitivity for this band should be at least -85 dBm");
1766 }
1767 }
1768
1769 // Calculate the noise factor required to reduce the Rx sensitivity.
1770 // The maximum possible sensitivity in the current modulation is used as a reference
1771 // to calculate the noise factor (F). The noise factor is a dimensionless ratio.
1772 // Currently only one PHY modulation is supported:
1773 // O-QPSK 250kpps which has a Max Rx sensitivity: -106.58 dBm (Noise factor = 1).
1774 // After Rx sensitivity is set, this becomes the new point where PER < 1 % for a
1775 // PSDU of 20 bytes as described by the standard.
1776
1777 // TODO: recalculate maxRxSensitivity (Noise factor = 1) when additional modulations are
1778 // supported.
1779 double maxRxSensitivityW = DbmToW(-106.58);
1780
1781 LrWpanSpectrumValueHelper psdHelper;
1784 m_phyPIBAttributes.phyCurrentChannel);
1785 // Update thermal noise + noise factor added.
1786 long double noiseFactor = DbmToW(dbmSensitivity) / maxRxSensitivityW;
1787 psdHelper.SetNoiseFactor(noiseFactor);
1788 m_noise = psdHelper.CreateNoisePowerSpectralDensity(m_phyPIBAttributes.phyCurrentChannel);
1789
1790 m_signal = Create<LrWpanInterferenceHelper>(m_noise->GetSpectrumModel());
1791 // Change receiver sensitivity from dBm to Watts
1792 m_rxSensitivity = DbmToW(dbmSensitivity);
1793}
1794
1795double
1797{
1798 NS_LOG_FUNCTION(this);
1799 // Change receiver sensitivity from Watt to dBm
1800 return WToDbm(m_rxSensitivity);
1801}
1802
1805{
1806 NS_LOG_FUNCTION(this);
1807 return m_phyOption;
1808}
1809
1810void
1812{
1813 NS_LOG_FUNCTION(this << txPsd);
1814 NS_ASSERT(txPsd);
1815 m_txPsd = txPsd;
1816 NS_LOG_INFO("\t computed tx_psd: " << *txPsd << "\t stored tx_psd: " << *m_txPsd);
1817}
1818
1819void
1821{
1822 NS_LOG_FUNCTION(this << noisePsd);
1823 NS_LOG_INFO("\t computed noise_psd: " << *noisePsd);
1824 NS_ASSERT(noisePsd);
1825 m_noise = noisePsd;
1826}
1827
1834
1835void
1842
1845{
1846 NS_LOG_FUNCTION(this);
1847 return m_errorModel;
1848}
1849
1850uint64_t
1859
1860double
1868
1869double
1871{
1872 double powerWatts =
1874 m_phyPIBAttributes.phyCurrentChannel);
1875 return WToDbm(powerWatts);
1876}
1877
1878int8_t
1880{
1882
1883 // The nominal Tx power is stored in the PIB as a 6-bit
1884 // twos-complement, signed number.
1885
1886 // The 5 LSBs can be copied - as their representation
1887 // is the same for unsigned and signed integers.
1888 int8_t nominalTxPower = phyTransmitPower & 0x1F;
1889
1890 // Now check the 6th LSB (the "sign" bit).
1891 // It's a twos-complement format, so the "sign"
1892 // bit represents -2^5 = -32.
1893 if (phyTransmitPower & 0x20)
1894 {
1895 nominalTxPower -= 32;
1896 }
1897 return nominalTxPower;
1898}
1899
1900double
1902{
1903 return (10 * log10(1000 * watt));
1904}
1905
1906double
1908{
1909 return (pow(10.0, dbm / 10.0) / 1000.0);
1910}
1911
1912int64_t
1914{
1915 NS_LOG_FUNCTION(this);
1916 m_random->SetStream(stream);
1917 return 1;
1918}
1919
1920void
1926
1927} // namespace lrwpan
1928} // namespace ns3
return result
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Keep track of the current position and velocity of an object.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:518
virtual void DoDispose()
Destructor implementation.
Definition object.cc:430
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
@ MS
millisecond
Definition nstime.h:107
Trace classes with value semantics.
a unique identifier for an interface.
Definition type-id.h:50
TypeId AddDeprecatedName(const std::string &name)
Add an deprecated name for a TypeId.
Definition type-id.cc:860
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Represent the LQI (Link Quality Estination).
void Set(uint8_t lqi)
Set the LQI to the given value.
uint8_t Get() const
Get the LQI value.
Make LrWpanPhy a SpectrumPhy so we can enable the eventual modeling of device interference.
void PlmeEdRequest()
IEEE 802.15.4-2006 section 6.2.2.3 PLME-ED.request Perform an ED per section 6.9.7.
void PlmeSetAttributeRequest(PhyPibAttributeIdentifier id, Ptr< PhyPibAttributes > attribute)
IEEE 802.15.4-2006 section 6.2.2.9 PLME-SET.request Set attributes per definition from Table 23 in se...
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
void SetRxSensitivity(double dbmSensitivity)
Set the receiver power sensitivity used by this device in dBm.
EventId m_pdDataRequest
Scheduler event of a currently running data transmission request.
void EndRx(Ptr< SpectrumSignalParameters > params)
Finish the reception of a frame.
void SetTxPowerSpectralDensity(Ptr< SpectrumValue > txPsd)
Set the Power Spectral Density of outgoing signals in W/Hz.
Ptr< AntennaModel > m_antenna
The antenna used by the transceiver.
std::pair< Ptr< LrWpanSpectrumSignalParameters >, bool > m_currentRxPacket
Status information of the currently received packet.
Ptr< NetDevice > m_device
The configured net device.
bool ChannelSupported(uint8_t channel)
Check if the given channel is supported by the PHY.
void SetPlmeGetAttributeConfirmCallback(PlmeGetAttributeConfirmCallback c)
set the callback for the end of an GetAttribute, as part of the interconnections between the PHY and ...
int8_t GetNominalTxPowerFromPib(uint8_t phyTransmitPower)
Calculates the nominal transmit power of the device in decibels relative to 1 mW according to the rep...
void DoInitialize() override
Initialize() implementation.
void SetAntenna(Ptr< AntennaModel > a)
Set the attached antenna.
Ptr< const SpectrumModel > GetRxSpectrumModel() const override
void DoDispose() override
Destructor implementation.
TracedCallback< Ptr< const Packet > > m_phyTxBeginTrace
The trace source fired when a packet begins the transmission process on the medium.
void EndCca()
Called at the end of the CCA.
Ptr< SpectrumChannel > m_channel
The channel attached to this transceiver.
void SetPostReceptionErrorModel(const Ptr< ErrorModel > em)
Attach a receive ErrorModel to the LrWpanPhy.
double GetRxSensitivity()
Get the receiver power sensitivity used by this device in dBm.
PhyOption GetMyPhyOption()
Get the currently configured PHY option.
PacketAndStatus m_currentTxPacket
Status information of the currently transmitted packet.
void EndSetTRXState()
Called after applying a deferred transceiver state switch.
PdDataConfirmCallback m_pdDataConfirmCallback
This callback is used to report packet transmission status to the MAC layer.
void SetChannel(Ptr< SpectrumChannel > c) override
Set the channel attached to this device.
void PlmeGetAttributeRequest(PhyPibAttributeIdentifier id)
IEEE 802.15.4-2006 section 6.2.2.5 PLME-GET.request Get attributes per definition from Table 23 in se...
void SetPdDataConfirmCallback(PdDataConfirmCallback c)
set the callback for the end of a TX, as part of the interconnections between the PHY and the MAC.
Ptr< LrWpanInterferenceHelper > m_signal
The accumulated signals currently received by the transceiver, including the signal of a possibly rec...
void SetPdDataIndicationCallback(PdDataIndicationCallback c)
set the callback for the end of a RX, as part of the interconnections between the PHY and the MAC.
TracedCallback< Ptr< const Packet > > m_phyTxEndTrace
The trace source fired when a packet ends the transmission process on the medium.
double WToDbm(double watt)
Transform watts (W) to decibels milliwatts (dBm).
uint8_t GetCurrentPage() const
Get The current channel page number in use in this PHY from the PIB attributes.
PhyPibAttributes m_phyPIBAttributes
The current PHY PIB attributes.
Ptr< MobilityModel > m_mobility
The mobility model used by the PHY.
void SetErrorModel(Ptr< LrWpanErrorModel > e)
set the error model to use
void SetMobility(Ptr< MobilityModel > m) override
Set the mobility model associated with this device.
PlmeSetTRXStateConfirmCallback m_plmeSetTRXStateConfirmCallback
This callback is used to report transceiver state change status to the MAC.
void SetNoisePowerSpectralDensity(Ptr< const SpectrumValue > noisePsd)
Set the noise power spectral density.
int8_t m_rssi
The Received Signal Strength Indicator value in dBm of the last received packet.
TracedCallback< Time, PhyEnumeration, PhyEnumeration > m_trxStateLogger
The trace source fired when the phy layer changes the transceiver state.
EdPower m_edPower
Helper value for tracking the average power during ED.
Time m_rxLastUpdate
Timestamp of the last calculation of the PER of a packet currently received.
EventId m_setTRXState
Scheduler event of a currently running deferred transceiver state switch.
Ptr< MobilityModel > GetMobility() const override
Get the associated MobilityModel instance.
void SetPlmeSetAttributeConfirmCallback(PlmeSetAttributeConfirmCallback c)
set the callback for the end of an SetAttribute, as part of the interconnections between the PHY and ...
void SetPhyOption(PhyOption phyOption)
Set the modulation option used by this PHY.
void PlmeCcaRequest()
IEEE 802.15.4-2006 section 6.2.2.1 PLME-CCA.request Perform a CCA per section 6.9....
TracedValue< PhyEnumeration > m_trxState
The current transceiver state.
void SetPlmeSetTRXStateConfirmCallback(PlmeSetTRXStateConfirmCallback c)
set the callback for the end of an SetTRXState, as part of the interconnections between the PHY and t...
double GetCurrentSignalPsd()
Get the current accumulated sum of signals in the transceiver including signals considered as interfe...
void SetPlmeCcaConfirmCallback(PlmeCcaConfirmCallback c)
set the callback for the end of a CCA, as part of the interconnections between the PHY and the MAC.
void EndPreamble(Ptr< LrWpanSpectrumSignalParameters > lrWpanRxParams)
During the reception of the preamble, if it was found that the signal was strong enough,...
Ptr< LrWpanErrorModel > m_errorModel
The error model describing the bit and packet error rates.
void EndTx()
Finish the transmission of a frame.
void SetPlmeEdConfirmCallback(PlmeEdConfirmCallback c)
set the callback for the end of an ED, as part of the interconnections between the PHY and the MAC.
uint8_t GetCurrentChannelNum() const
Get The current channel number in use in this PHY from the PIB attributes.
void PlmeSetTRXStateRequest(PhyEnumeration state)
IEEE 802.15.4-2006 section 6.2.2.7 PLME-SET-TRX-STATE.request Set PHY state.
LrWpanPhy()
Default constructor.
TracedCallback< Ptr< const Packet > > m_phyRxBeginTrace
The trace source fired when a packet begins the reception process from the medium.
PlmeSetAttributeConfirmCallback m_plmeSetAttributeConfirmCallback
This callback is used to report attribute set results back to the MAC.
PhyEnumeration m_trxStatePending
The next pending state to applied after the current action of the PHY is completed.
TracedCallback< Ptr< const Packet > > m_phyRxDropTrace
The trace source fired when the phy layer drops a packet it has received.
double GetPhySymbolsPerOctet() const
Get the number of symbols per octet, depending on the currently selected channel.
PdDataIndicationCallback m_pdDataIndicationCallback
This callback is used to notify incoming packets to the MAC layer.
Ptr< LrWpanErrorModel > GetErrorModel() const
get the error model in use
void StartRx(Ptr< SpectrumSignalParameters > params) override
Notify the SpectrumPhy instance of an incoming waveform.
double m_rxSensitivity
The receiver sensitivity in Watts.
void CcaCancel()
Cancel an ongoing CCA request.
void CheckInterference()
Check if the interference destroys a frame currently received.
EventId m_ccaRequest
Scheduler event of a currently running CCA request.
Ptr< SpectrumChannel > GetChannel()
Get the currently attached channel.
Ptr< ErrorModel > m_postReceptionErrorModel
Error model for receive packet events.
PlmeCcaConfirmCallback m_plmeCcaConfirmCallback
This callback is used to report CCA status to the MAC or CSMA/CA.
uint64_t GetPhySHRDuration() const
Get the duration of the SHR (preamble and SFD) in symbols, depending on the currently selected channe...
bool m_isRxCanceled
Indicates if the reception of frame has been canceled.
void CancelEd(PhyEnumeration state)
Cancel an ongoing ED procedure.
Ptr< NetDevice > GetDevice() const override
Get the associated NetDevice instance.
void PdDataRequest(const uint32_t psduLength, Ptr< Packet > p)
IEEE 802.15.4-2006 section 6.2.1.1 PD-DATA.request Request to transfer MPDU from MAC (transmitting).
void UpdateEnergyTracking()
Update Clear Channel Assestment (CCA) or Energy Detection (ED) energy values if an energy tracking ev...
double DbmToW(double dbm)
Transforms decibels milliwatts (dBm) to watts (W).
Ptr< UniformRandomVariable > m_random
Uniform random variable stream.
EventId m_edRequest
Scheduler event of a currently running ED request.
PhyOption m_phyOption
The currently configured PHY type.
Ptr< SpectrumValue > m_txPsd
The transmit power spectral density.
bool PageSupported(uint8_t page)
Check if the given page is supported by the PHY.
Time GetPpduHeaderTxTime()
Calculate the time required for sending the PPDU header, that is the preamble, SFD and PHR.
void EndEd()
Called at the end of the ED procedure.
void SetDevice(Ptr< NetDevice > d) override
Set the associated NetDevice instance.
double GetDataOrSymbolRate(bool isData)
implement PLME SetAttribute confirm SAP bit rate is in bit/s.
PlmeGetAttributeConfirmCallback m_plmeGetAttributeConfirmCallback
This callback is used to report requested attribute values back to the MAC.
Ptr< Object > GetAntenna() const override
Get the AntennaModel used by this SpectrumPhy instance for transmission and/or reception.
TracedCallback< Ptr< const Packet > > m_phyTxDropTrace
The trace source fired when the phy layer drops a packet as it tries to transmit it.
TracedCallback< Ptr< const Packet >, double > m_phyRxEndTrace
The trace source fired when a packet ends the reception process from the medium.
double m_ccaPeakPower
Helper value for the peak power value during CCA.
Time CalculateTxTime(Ptr< const Packet > packet)
Calculate the time required for sending the given packet, including preamble, SFD and PHR.
Ptr< const SpectrumValue > GetNoisePowerSpectralDensity()
Get the noise power spectral density.
bool PhyIsBusy() const
Check if the PHY is busy, which is the case if the PHY is currently sending or receiving a frame.
PlmeEdConfirmCallback m_plmeEdConfirmCallback
This callback is used to report ED status to the MAC.
Ptr< const SpectrumValue > m_noise
The spectral density for for the noise.
void ChangeTrxState(PhyEnumeration newState)
Change the PHY state to the given new state, firing the state change trace.
static TypeId GetTypeId()
Get the type ID.
This class defines all functions to create spectrum model for LrWpan.
Ptr< SpectrumValue > CreateNoisePowerSpectralDensity(uint32_t channel)
create spectrum value for noise
static double TotalAvgPower(Ptr< const SpectrumValue > psd, uint32_t channel)
total average power of the signal is the integral of the PSD using the limits of the given channel
Ptr< SpectrumValue > CreateTxPowerSpectralDensity(double txPower, uint32_t channel)
create spectrum value
void SetNoiseFactor(double f)
Set the noise factor added to the thermal noise.
constexpr uint32_t aMaxPhyPacketSize
The maximum packet size accepted by the PHY.
constexpr uint32_t aTurnaroundTime
The turnaround time in symbol periods for switching the transceiver from RX to TX or vice-versa.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:250
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:273
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:253
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Callback< void, uint32_t, Ptr< Packet >, uint8_t, int8_t > PdDataIndicationCallback
This method implements the PD SAP: PdDataIndication.
PhyOption
This Phy option will be used to index various Tables in IEEE802.15.4-2011.
Definition lr-wpan-phy.h:84
Callback< void, PhyEnumeration > PlmeCcaConfirmCallback
This method implements the PD SAP: PlmeCcaConfirm.
Callback< void, PhyEnumeration > PlmeSetTRXStateConfirmCallback
This method implements the PD SAP: PlmeSetTRXStateConfirm.
Callback< void, PhyEnumeration, uint8_t > PlmeEdConfirmCallback
This method implements the PD SAP: PlmeEdConfirm.
Callback< void, PhyEnumeration, PhyPibAttributeIdentifier, Ptr< PhyPibAttributes > > PlmeGetAttributeConfirmCallback
This method implements the PD SAP: PlmeGetAttributeConfirm.
PhyEnumeration
IEEE802.15.4-2006 PHY Emumerations Table 18 in section 6.2.3.
Callback< void, PhyEnumeration > PdDataConfirmCallback
This method implements the PD SAP: PdDataConfirm.
Callback< void, PhyEnumeration, PhyPibAttributeIdentifier > PlmeSetAttributeConfirmCallback
This method implements the PD SAP: PlmeSetAttributeConfirm.
PhyPibAttributeIdentifier
IEEE802.15.4-2006 PHY PIB Attribute Identifiers Table 23 in section 6.4.2.
@ IEEE_802_15_4_915MHZ_OQPSK
Definition lr-wpan-phy.h:92
@ IEEE_802_15_4_2_4GHZ_OQPSK
Definition lr-wpan-phy.h:93
@ IEEE_802_15_4_915MHZ_ASK
Definition lr-wpan-phy.h:89
@ IEEE_802_15_4_780MHZ_OQPSK
Definition lr-wpan-phy.h:90
@ IEEE_802_15_4_868MHZ_OQPSK
Definition lr-wpan-phy.h:91
@ IEEE_802_15_4_915MHZ_BPSK
Definition lr-wpan-phy.h:86
@ IEEE_802_15_4_868MHZ_BPSK
Definition lr-wpan-phy.h:85
@ IEEE_802_15_4_950MHZ_BPSK
Definition lr-wpan-phy.h:87
@ IEEE_802_15_4_INVALID_PHY_OPTION
Definition lr-wpan-phy.h:94
@ IEEE_802_15_4_868MHZ_ASK
Definition lr-wpan-phy.h:88
@ IEEE_802_15_4_PHY_BUSY
@ IEEE_802_15_4_PHY_READ_ONLY
@ IEEE_802_15_4_PHY_BUSY_TX
@ IEEE_802_15_4_PHY_RX_ON
@ IEEE_802_15_4_PHY_TRX_OFF
@ IEEE_802_15_4_PHY_TX_ON
@ IEEE_802_15_4_PHY_INVALID_PARAMETER
@ IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE
@ IEEE_802_15_4_PHY_SUCCESS
@ IEEE_802_15_4_PHY_FORCE_TRX_OFF
@ IEEE_802_15_4_PHY_BUSY_RX
@ IEEE_802_15_4_PHY_IDLE
@ IEEE_802_15_4_PHY_UNSPECIFIED
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
constexpr std::array< PhyDataAndSymbolRates, 10 > dataSymbolRates
The data and symbol rates for the different PHY options.
constexpr std::array< PhyPpduHeaderSymbolNumber, 10 > ppduHeaderSymbolNumbers
The preamble, SFD, and PHR lengths in symbols for the different PHY options.
std::ostream & operator<<(std::ostream &os, const SuperframeField &superframeField)
Stream insertion operator.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605