diff --git a/CHANGES.md b/CHANGES.md index a281863c6..1006b039e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ Changes from ns-3.36 to ns-3.37 * Adds support for channel paging to the **LrWpanPhy** (only placeholder, a single modulation/band is currently supported). * Adds supporting structures used by **LrWpanMac** (PAN descriptor, Command Payload Header, Capability Field). * Mac(8|16|48|64)Address address allocation pool is now reset between consecutive runs. +* Adds support for **LrWpanMac** energy detection (ED) scan. ### Changes to build system diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ce6a54519..a4c9d4945 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -17,6 +17,7 @@ Release 3-dev - (lr-wpan) !959 - Add PHY channel page support - (lr-wpan) Adds PAN descriptor, CommandPayload Header and Capability Field - (wifi) !984 - MultiUserScheduler can request channel access periodically +- (lr-wpan) !991 - Adds MAC ED scan support ### Bugs fixed diff --git a/src/lr-wpan/doc/lr-wpan.rst b/src/lr-wpan/doc/lr-wpan.rst index 7312b197f..b93949234 100644 --- a/src/lr-wpan/doc/lr-wpan.rst +++ b/src/lr-wpan/doc/lr-wpan.rst @@ -100,6 +100,8 @@ MAC Primitives * MCPS-DATA.Indication * MLME-START.Request * MLME-START.Confirm +* MLME-SCAN.Request +* MLME-SCAN.Confirm PHY Primitives ++++++++++++++ @@ -135,6 +137,26 @@ Std 802.15.4-2006, section 7.5.6.2 is supported, including acknowledgements. Only short addressing completely implemented. Various trace sources are supported, and trace sources can be hooked to sinks. +The implemented ns-3 MAC supports scanning. Typically, a scanning request is preceded +by an association request but these can be used independently. +IEEE 802.15.4 supports 4 types of scanning: + +* Energy Detection (ED) Scan: In an energy scan, a device or a coordinator scan a set number of channels +looking for traces of energy. The maximum energy registered during a given amount of time is stored. +Energy scan is typically used to measure the quality of a channel at any given time. For this reason, +coordinators often use this scan before initiating a PAN on a channel. + +* Active Scan: + +* Passive Scan: + +* Orphan Scan: + +In active and passive scans, the link quality indicator (LQI) is the main parameter used to +determine the optimal coordinator. LQI values range from 0 to 255. Where 255 is the highest quality +link value and 0 the lowest. Typically, a link lower than 127 is considered a link with poor quality. + + PHY ### @@ -294,6 +316,7 @@ The following examples have been written, which can be found in ``src/lr-wpan/ex * ``lr-wpan-error-model-plot.cc``: An example to test the phy. * ``lr-wpan-packet-print.cc``: An example to print out the MAC header fields. * ``lr-wpan-phy-test.cc``: An example to test the phy. +* ``lr-wpan-ed-scan.cc``: Simple example showing the use of energy detection (ED) scan in the MAC. In particular, the module enables a very simplified end-to-end data transfer scenario, implemented in ``lr-wpan-data.cc``. The figure diff --git a/src/lr-wpan/examples/CMakeLists.txt b/src/lr-wpan/examples/CMakeLists.txt index e33d7c306..9ccd32495 100644 --- a/src/lr-wpan/examples/CMakeLists.txt +++ b/src/lr-wpan/examples/CMakeLists.txt @@ -3,6 +3,7 @@ set(base_examples lr-wpan-mlme lr-wpan-packet-print lr-wpan-phy-test + lr-wpan-ed-scan ) foreach( diff --git a/src/lr-wpan/examples/lr-wpan-ed-scan.cc b/src/lr-wpan/examples/lr-wpan-ed-scan.cc new file mode 100644 index 000000000..5031564cf --- /dev/null +++ b/src/lr-wpan/examples/lr-wpan-ed-scan.cc @@ -0,0 +1,171 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Tokushima University, Japan. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Alberto Gallegos Ramonet + */ + +/* [00:01] [00:02] [00:03] + * PAN 5 Coordinator End Device PAN 7 Coordinator + * N0 (dev0) ----------------N1 (dev1) ------------------------------ N2 (dev2) + * Channel 12 ED Scan Channels 11-14 Channel 14 + * + * |--------10 m----------------|----------30 m -----------------------| + * + * This example demonstrate the usage of the MAC ED Scan primitive as + * described by IEEE 802.15.4-2011. + * + * At the beginning of the simulation, PAN coordinators N0 (Channel 12) and N2 (Channel 14) + * start transmitting beacon frames on their respective channels. At the same time, + * end device N1 will scan through channels (11,12,13 and 14) looking for energy. + * i.e. multiple energy scans on each channel (PLME-ED calls). The results of the Max energy + * read registered for each channel is shown after the last channel scan is finished. + * + * The radio uses the default Sensibility and Rx Power provided by the + * LogDistancePropagationLossModel. The simulation might take a few seconds to complete. + * + * ED range: 0 - 255 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ns3; + + +static void ScanConfirm (MlmeScanConfirmParams params) +{ + if (params.m_status == MLMESCAN_SUCCESS && params.m_scanType == MLMESCAN_ED ) + { + std::cout << Simulator::Now ().As (Time::S) << "| Scan status SUCCESSFUL\n"; + std::cout << "Results for Energy Scan:" << + "\nPage: " << params.m_chPage << "\n"; + for (uint8_t i = 0; i < params.m_energyDetList.size (); i++) + { + std::cout << "Channel " << static_cast (i + 11) << ": " << +params.m_energyDetList[i] << "\n"; + } + } +} + + +int main (int argc, char *argv[]) +{ + + LogComponentEnableAll (LogLevel (LOG_PREFIX_TIME | LOG_PREFIX_FUNC)); + + // Create 2 PAN coordinator nodes, and 1 end device + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + + Ptr dev0 = CreateObject (); + Ptr dev1 = CreateObject (); + Ptr dev2 = CreateObject (); + + dev0->SetAddress (Mac16Address ("00:01")); + dev1->SetAddress (Mac16Address ("00:02")); + dev2->SetAddress (Mac16Address ("00:03")); + + + // Configure Spectrum channel + Ptr channel = CreateObject (); + Ptr propModel = CreateObject (); + Ptr delayModel = CreateObject (); + channel->AddPropagationLossModel (propModel); + channel->SetPropagationDelayModel (delayModel); + + dev0->SetChannel (channel); + dev1->SetChannel (channel); + dev2->SetChannel (channel); + + n0->AddDevice (dev0); + n1->AddDevice (dev1); + n2->AddDevice (dev2); + + + // MAC layer Callbacks hooks + MlmeScanConfirmCallback scb; + scb = MakeCallback (&ScanConfirm); + dev1->GetMac ()->SetMlmeScanConfirmCallback (scb); + + + Ptr PanCoordinatorN0Mobility = CreateObject (); + PanCoordinatorN0Mobility->SetPosition (Vector (0,0,0)); + dev0->GetPhy ()->SetMobility (PanCoordinatorN0Mobility); + + Ptr endDeviceN1Mobility = CreateObject (); + endDeviceN1Mobility->SetPosition (Vector (10,0,0)); + dev1->GetPhy ()->SetMobility (endDeviceN1Mobility); + + Ptr PanCoordinatorN2Mobility = CreateObject (); + PanCoordinatorN2Mobility->SetPosition (Vector (40,0,0)); + dev2->GetPhy ()->SetMobility (PanCoordinatorN2Mobility); + + + // PAN coordinator N0 starts transmit beacons on channel 12 + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = 5; + params.m_bcnOrd = 3; + params.m_sfrmOrd = 3; + params.m_logCh = 12; + Simulator::ScheduleWithContext (1, Seconds (2.0), + &LrWpanMac::MlmeStartRequest, + dev0->GetMac (), params); + + // PAN coordinator N2 transmit beacons on channel 14 + MlmeStartRequestParams params2; + params2.m_panCoor = true; + params2.m_PanId = 7; + params2.m_bcnOrd = 3; + params2.m_sfrmOrd = 3; + params2.m_logCh = 14; + Simulator::ScheduleWithContext (1, Seconds (2.0), + &LrWpanMac::MlmeStartRequest, + dev2->GetMac (), params2); + + + // Device 1 initiate channels scan on channels 11, 12, 13, and 14 looking for energy + // Scan Channels represented by bits 0-26 (27 LSB) + // ch 14 ch 11 + // | | + // 0x7800 = 0000000000000000111100000000000 + // scanDuration per channel = aBaseSuperframeDuration * (2^14+1) = 251.65 secs + MlmeScanRequestParams scanParams; + scanParams.m_chPage = 0; + scanParams.m_scanChannels = 0x7800; + scanParams.m_scanDuration = 14; + scanParams.m_scanType = MLMESCAN_ED; + Simulator::ScheduleWithContext (1, Seconds (2.0), + &LrWpanMac::MlmeScanRequest, + dev1->GetMac (), scanParams); + + + Simulator::Stop (Seconds (2000)); + Simulator::Run (); + + Simulator::Destroy (); + return 0; +} diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index 607bbfcfe..ec2faa682 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -185,6 +185,10 @@ LrWpanMac::LrWpanMac () m_beaconTrackingOn = false; m_numLostBeacons = 0; + m_pendPrimitive = MLME_NONE; + m_channelScanIndex = 0; + m_maxEnergyLevel = 0; + Ptr uniformVar = CreateObject (); uniformVar->SetAttribute ("Min", DoubleValue (0.0)); @@ -607,6 +611,67 @@ LrWpanMac::MlmeStartRequest (MlmeStartRequestParams params) } } +void +LrWpanMac::MlmeScanRequest (MlmeScanRequestParams params) +{ + NS_LOG_FUNCTION (this); + + MlmeScanConfirmParams confirmParams; + confirmParams.m_scanType = params.m_scanType; + confirmParams.m_chPage = params.m_chPage; + + if (m_scanEvent.IsRunning () || m_scanEnergyEvent.IsRunning ()) + { + if (!m_mlmeScanConfirmCallback.IsNull ()) + { + confirmParams.m_status = MLMESCAN_SCAN_IN_PROGRESS; + m_mlmeScanConfirmCallback (confirmParams); + } + NS_LOG_ERROR (this << " A channel scan is already in progress"); + return; + } + + if (params.m_scanDuration > 14 || params.m_scanType > MLMESCAN_PASSIVE) + { + if (!m_mlmeScanConfirmCallback.IsNull ()) + { + confirmParams.m_status = MLMESCAN_INVALID_PARAMETER; + m_mlmeScanConfirmCallback (confirmParams); + } + NS_LOG_ERROR (this << "Invalid scan duration or unsupported scan type"); + return; + } + // Temporary store macPanId and set macPanId to 0xFFFF to accept all beacons. + m_macPanIdScan = m_macPanId; + m_macPanId = 0xFFFF; + + + m_panDescriptorList.clear (); + m_energyDetectList.clear (); + + //TODO: stop beacon transmission + + // Cancel any ongoing CSMA/CA operations and set to unslotted mode for scan + m_csmaCa->Cancel (); + m_capEvent.Cancel (); + m_cfpEvent.Cancel (); + m_incCapEvent.Cancel (); + m_incCfpEvent.Cancel (); + m_trackingEvent.Cancel (); + m_csmaCa->SetUnSlottedCsmaCa (); + + + m_channelScanIndex = 0; + + // Mark primitive as pending and save the scan params while the new page and/or channel is set. + m_scanParams = params; + m_pendPrimitive = MLME_SCAN_REQ; + + LrWpanPhyPibAttributes pibAttr; + pibAttr.phyCurrentPage = params.m_chPage; + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentPage,&pibAttr); + +} void LrWpanMac::MlmeSyncRequest (MlmeSyncRequestParams params) @@ -719,6 +784,59 @@ LrWpanMac::SendOneBeacon () m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_TX_ON); } +void +LrWpanMac::EndChannelEnergyScan () +{ + // Add the results of channel energy scan to the detectList + m_energyDetectList.push_back (m_maxEnergyLevel); + m_maxEnergyLevel = 0; + + m_channelScanIndex++; + + bool channelFound = false; + for (int i = m_channelScanIndex; i <= 26; i++) + { + if ((m_scanParams.m_scanChannels & (1 << m_channelScanIndex)) != 0) + { + channelFound = true; + break; + } + m_channelScanIndex++; + } + + if (channelFound) + { + //switch to the next channel in the list and restart scan + LrWpanPhyPibAttributes pibAttr; + pibAttr.phyCurrentChannel = m_channelScanIndex; + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentChannel,&pibAttr); + } + else + { + // Scan on all channels on the list completed + // Return to the MAC values previous to start of the first scan. + m_macPanId = m_macPanIdScan; + m_macPanIdScan = 0; + + // TODO: restart beacon transmissions that were active before the beginning of the scan + // (i.e when a coordinator perform a scan and it was already transmitting beacons) + + // All channels scanned, report success + if (!m_mlmeScanConfirmCallback.IsNull ()) + { + MlmeScanConfirmParams confirmParams; + confirmParams.m_status = MLMESCAN_SUCCESS; + confirmParams.m_chPage = m_phy->GetCurrentPage (); + confirmParams.m_scanType = m_scanParams.m_scanType; + confirmParams.m_energyDetList = m_energyDetectList; + m_mlmeScanConfirmCallback (confirmParams); + } + m_pendPrimitive = MLME_NONE; + m_channelScanIndex = 0; + m_scanParams = {}; + + } +} void LrWpanMac::StartCAP (SuperframeType superframeType) @@ -997,6 +1115,12 @@ LrWpanMac::SetMlmeStartConfirmCallback (MlmeStartConfirmCallback c) m_mlmeStartConfirmCallback = c; } +void +LrWpanMac::SetMlmeScanConfirmCallback (MlmeScanConfirmCallback c) +{ + m_mlmeScanConfirmCallback = c; +} + void LrWpanMac::SetMlmeBeaconNotifyIndicationCallback (MlmeBeaconNotifyIndicationCallback c) { @@ -1028,7 +1152,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) // level 2 filtering if promiscuous mode pass frame to higher layer otherwise perform level 3 filtering // level 3 filtering accept frame // if Frame type and version is not reserved, and - // if there is a dstPanId then dstPanId=m_macPanId or broadcastPanI, and + // if there is a dstPanId then dstPanId=m_macPanId or broadcastPanId, and // if there is a shortDstAddr then shortDstAddr =shortMacAddr or broadcastAddr, and // if beacon frame then srcPanId = m_macPanId // if only srcAddr field in Data or Command frame,accept frame if srcPanId=m_macPanId @@ -1126,8 +1250,21 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) if (acceptFrame && (receivedMacHdr.GetDstAddrMode () > 1)) { - acceptFrame = receivedMacHdr.GetDstPanId () == m_macPanId - || receivedMacHdr.GetDstPanId () == 0xffff; + // Accept frame if: + + // 1) Have the same macPanId + // 2) Or is Message to all PANs + // 3) Or Is a beacon and the macPanId is not present (bootstrap) + acceptFrame = (receivedMacHdr.GetDstPanId () == m_macPanId || receivedMacHdr.GetDstPanId () == 0xffff) + || (m_macPanId == 0xffff && receivedMacHdr.IsBeacon ()); + } + + if (acceptFrame + && (receivedMacHdr.GetShortDstAddr () == Mac16Address ("FF:FF"))) + { + // A broadcast message (e.g. beacons) should not be received by the device who issues it. + acceptFrame = (receivedMacHdr.GetShortSrcAddr () != GetShortAddress ()); + // TODO: shouldn't this be filtered by the PHY? } if (acceptFrame @@ -1177,6 +1314,12 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) } } + // Energy Scan is running, reject any frames + if (m_scanEnergyEvent.IsRunning ()) + { + acceptFrame = false; + } + if (acceptFrame && ((receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_DATA) || (receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_COMMAND)) @@ -1660,6 +1803,15 @@ LrWpanMac::PlmeEdConfirm (LrWpanPhyEnumeration status, uint8_t energyLevel) { NS_LOG_FUNCTION (this << status << energyLevel); + if (energyLevel > m_maxEnergyLevel) + { + m_maxEnergyLevel = energyLevel; + } + + if (Simulator::GetDelayLeft (m_scanEnergyEvent) > Seconds (8.0 / m_phy->GetDataOrSymbolRate (false))) + { + m_phy->PlmeEdRequest (); + } } void @@ -1694,7 +1846,12 @@ LrWpanMac::PlmeSetTRXStateConfirm (LrWpanPhyEnumeration status) { NS_ASSERT (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS || status == IEEE_802_15_4_PHY_TRX_OFF); - if (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS) + if (status == IEEE_802_15_4_PHY_RX_ON && m_scanEnergyEvent.IsRunning ()) + { + // Kick start Energy Detection Scan + m_phy->PlmeEdRequest (); + } + else if (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS) { // Check if there is not messages to transmit when going idle CheckQueue (); @@ -1719,6 +1876,82 @@ LrWpanMac::PlmeSetAttributeConfirm (LrWpanPhyEnumeration status, LrWpanPibAttributeIdentifier id) { NS_LOG_FUNCTION (this << status << id); + if (id == LrWpanPibAttributeIdentifier::phyCurrentPage && m_pendPrimitive == MLME_SCAN_REQ ) + { + if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS) + { + // get the first channel to scan from scan channel list + bool channelFound = false; + for (int i = m_channelScanIndex; i <= 26; i++) + { + if ((m_scanParams.m_scanChannels & (1 << m_channelScanIndex)) != 0) + { + channelFound = true; + break; + } + m_channelScanIndex++; + } + + if (channelFound) + { + LrWpanPhyPibAttributes pibAttr; + pibAttr.phyCurrentChannel = m_channelScanIndex; + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentChannel,&pibAttr); + } + } + else + { + if (!m_mlmeScanConfirmCallback.IsNull ()) + { + MlmeScanConfirmParams confirmParams; + confirmParams.m_scanType = m_scanParams.m_scanType; + confirmParams.m_chPage = m_scanParams.m_chPage; + confirmParams.m_status = MLMESCAN_INVALID_PARAMETER; + m_mlmeScanConfirmCallback (confirmParams); + } + NS_LOG_ERROR (this << "Channel Scan: Invalid channel page"); + } + } + else if (id == LrWpanPibAttributeIdentifier::phyCurrentChannel && m_pendPrimitive == MLME_SCAN_REQ) + { + if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS) + { + uint64_t symbolRate = static_cast (m_phy->GetDataOrSymbolRate (false)); + uint64_t scanDuration = aBaseSuperframeDuration * ((static_cast (1 << m_scanParams.m_scanDuration)) + 1); + Time nextScanTime = Seconds (static_cast (scanDuration / symbolRate)); + + switch (m_scanParams.m_scanType) + { + case MLMESCAN_ED: + m_maxEnergyLevel = 0; + m_scanEnergyEvent = Simulator::Schedule (nextScanTime, &LrWpanMac::EndChannelEnergyScan, this); + // set phy to RX_ON and kick start the first PLME-ED.request + m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_RX_ON); + break; + case MLMESCAN_ACTIVE: + // TODO: add active scan support + break; + case MLMESCAN_PASSIVE: + // TODO: add passive scan support + break; + case MLMESCAN_ORPHAN: + // TODO: add orphan scan support + break; + } + } + else + { + if (!m_mlmeScanConfirmCallback.IsNull ()) + { + MlmeScanConfirmParams confirmParams; + confirmParams.m_scanType = m_scanParams.m_scanType; + confirmParams.m_chPage = m_scanParams.m_chPage; + confirmParams.m_status = MLMESCAN_INVALID_PARAMETER; + m_mlmeScanConfirmCallback (confirmParams); + } + NS_LOG_ERROR ("Channel " << m_channelScanIndex << " could not be set in the current page"); + } + } } void diff --git a/src/lr-wpan/model/lr-wpan-mac.h b/src/lr-wpan/model/lr-wpan-mac.h index 0c05cc0e2..f7e937ed3 100644 --- a/src/lr-wpan/model/lr-wpan-mac.h +++ b/src/lr-wpan/model/lr-wpan-mac.h @@ -104,6 +104,19 @@ typedef enum INCOMING = 1 //!< Incoming Superframe } SuperframeType; +/** + * \ingroup lr-wpan + * + * Indicates a pending MAC primitive + */ +typedef enum +{ + MLME_NONE = 0, //!< No pending primitive + MLME_START_REQ = 1, //!< Pending MLME-START.request primitive + MLME_SCAN_REQ = 2, //!< Pending MLME-SCAN.request primitive + MLME_ASSOC_REQ = 3, //!< Pending MLME-ASSOCIATION.request primitive + MLME_SYNC_REQ = 4 //!< Pending MLME-SYNC.request primitive +} PendingPrimitiveStatus; namespace TracedValueCallback { @@ -156,6 +169,19 @@ typedef enum DISASSOCIATED = 0xff } LrWpanAssociationStatus; +/** + * \ingroup lr-wpan + * + * Table 30 of IEEE 802.15.4-2011 + */ +typedef enum +{ + MLMESCAN_ED = 0x00, + MLMESCAN_ACTIVE = 0x01, + MLMESCAN_PASSIVE = 0x02, + MLMESCAN_ORPHAN = 0x03 +} LrWpanMlmeScanType; + /** * \ingroup lr-wpan * @@ -196,6 +222,24 @@ typedef enum MLMESTART_CHANNEL_ACCESS_FAILURE = 9 } LrWpanMlmeStartConfirmStatus; +/** + * \ingroup lr-wpan + * + * Table 31 of IEEE 802.15.4-2011 + */ +typedef enum +{ + MLMESCAN_SUCCESS = 0, + MLMESCAN_LIMIT_REACHED = 1, + MLMESCAN_NO_BEACON = 2, + MLMESCAN_SCAN_IN_PROGRESS = 3, + MLMESCAN_COUNTER_ERROR = 4, + MLMESCAN_FRAME_TOO_LONG = 5, + MLMESCAN_UNAVAILABLE_KEY = 6, + MLMESCAN_UNSUPPORTED_SECURITY = 7, + MLMESCAN_INVALID_PARAMETER = 8 +} LrWpanMlmeScanConfirmStatus; + /** * \ingroup lr-wpan * @@ -360,6 +404,32 @@ struct MlmePollRequestParams Mac64Address m_coorExtAddr; //!< Coordinator extended address. +}; +/** + * \ingroup lr-wpan + * + * MLME-SCAN.request params. See IEEE 802.15.4-2011 Section 6.2.10.1 Table 30 + */ +struct MlmeScanRequestParams +{ + LrWpanMlmeScanType m_scanType {}; //!< Indicates the type of scan performed as described in IEEE 802.15.4-2011 (5.1.2.1). + uint32_t m_scanChannels {0x7FFFFFF}; //!< The channel numbers to be scanned. + uint8_t m_scanDuration {14}; //!< A value used to calculate the length of time to spend scanning [aBaseSuperframeDuration * (2^m_scanDuration +)]. + uint32_t m_chPage; //!< The channel page on which to perform scan. +}; +/** + * \ingroup lr-wpan + * + * MLME-SCAN.confirm params. See IEEE 802.15.4-2011 Section 6.2.10.2 + */ +struct MlmeScanConfirmParams +{ + LrWpanMlmeScanConfirmStatus m_status; //!< The status of the scan request. + LrWpanMlmeScanType m_scanType; //!< Indicates the type of scan performed (ED,ACTIVE,PASSIVE,ORPHAN). + uint32_t m_chPage; //!< The channel page on which the scan was performed. + std::vector m_unscannedCh; //!< A list of channels given in the request which were not scanned (Not valid for ED scans). + std::vector m_energyDetList; //!< A list of energy measurements, one for each channel searched during ED scan (Not valid for Active, Passive or Orphan Scans) + std::vector m_panDescList; //!< A list of PAN descriptor, one for each beacon found (Not valid for ED and Orphan scans). }; /** * \ingroup lr-wpan @@ -459,6 +529,13 @@ typedef Callback MlmeSyncLossIndicationCallb * transmission request */ typedef Callback MlmePollConfirmCallback; +/** + * \ingroup lr-wpan + * + * This callback is called after a MlmeScanRequest has been called from + * the higher layer. It returns a status of the outcome of the scan. + */ +typedef Callback MlmeScanConfirmCallback; /** * \ingroup lr-wpan * @@ -581,6 +658,14 @@ public: * \param params the request parameters */ void MlmeStartRequest (MlmeStartRequestParams params); + /** + * IEEE 802.15.4-2011, section 6.2.10.1 + * MLME-SCAN.request + * Request primitive used to initiate a channel scan over a given list of channels. + * + * \param params the scan request parameters + */ + void MlmeScanRequest (MlmeScanRequestParams params); /** * IEEE 802.15.4-2011, section 6.2.13.1 * MLME-SYNC.request @@ -640,6 +725,14 @@ public: * \param c the callback */ void SetMlmeStartConfirmCallback (MlmeStartConfirmCallback c); + /** + * Set the callback for the confirmation of a data transmission request. + * The callback implements MLME-SCAN.confirm SAP of IEEE 802.15.4-2011, + * section 6.2.10.2. + * + * \param c the callback + */ + void SetMlmeScanConfirmCallback (MlmeScanConfirmCallback c); /** * Set the callback for the indication of an incoming beacon packet. * The callback implements MLME-BEACON-NOTIFY.indication SAP of IEEE 802.15.4-2011, @@ -836,6 +929,11 @@ public: * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ uint16_t m_macPanId; + /** + * Temporally stores the value of the current m_macPanId when a MLME-SCAN.request is performed. + * See IEEE 802.15.4-2011, section 5.1.2.1.2. + */ + uint16_t m_macPanIdScan; /** * Sequence number added to transmitted data or MAC command frame, 00-ff. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -875,6 +973,10 @@ public: * See IEEE 802.15.4-2011, section 6.4.2, Table 52. */ bool m_macAutoRequest; + /** + * The maximum energy level detected during ED scan on the current channel. + */ + uint8_t m_maxEnergyLevel; /** * The value of the necessary InterFrame Space after the transmission of a packet. */ @@ -1021,6 +1123,10 @@ private: * Called to send a single beacon frame. */ void SendOneBeacon (void); + /** + * Called at the end of one ED channel scan. + */ + void EndChannelEnergyScan (void); /** * Called to begin the Contention Free Period (CFP) in a * beacon-enabled mode. @@ -1256,6 +1362,12 @@ private: * See IEEE 802.15.4-2011, section 6.2.13.2. */ MlmeSyncLossIndicationCallback m_mlmeSyncLossIndicationCallback; + /** + * This callback is used to report the result of a scan on a group of channels for the + * selected channel page. + * See IEEE 802.15.4-2011, section 6.2.10.2. + */ + MlmeScanConfirmCallback m_mlmeScanConfirmCallback; /** * This callback is used to report the status after a device send data command request to * the coordinator to transmit data. @@ -1318,6 +1430,28 @@ private: * The indirect transmit queue used by the MAC pending messages. */ std::deque m_indTxQueue; + /** + * The list of PAN descriptors accumulated during channel scans, used to select a PAN to associate. + */ + std::vector m_panDescriptorList; + /** + * The list of energy measurements, one for each channel searched during an ED scan. + */ + std::vector m_energyDetectList; + /** + * The parameters used during a MLME-SCAN.request. These parameters are stored here while + * PLME-SET operations (set channel page, set channel number) and multiple ed scans take place. + */ + MlmeScanRequestParams m_scanParams; + /** + * The channel list index used to obtain the current scanned channel. + */ + uint16_t m_channelScanIndex; + /** + * Indicates the pending primitive when PLME.SET operation (page or channel switch) is called from + * within another MLME primitive (e.g. Association, Scan, Sync, Start). + */ + PendingPrimitiveStatus m_pendPrimitive; /** * The number of already used retransmission for the currently transmitted * packet. @@ -1364,6 +1498,14 @@ private: * Scheduler event to track the incoming beacons. */ EventId m_trackingEvent; + /** + * Scheduler event for the end of a channel scan. + */ + EventId m_scanEvent; + /** + * Scheduler event for the end of a ED channel scan. + */ + EventId m_scanEnergyEvent; }; } // namespace ns3