From c2054cb25bf7a9261de7fdbcca931e4dcea301d4 Mon Sep 17 00:00:00 2001 From: Alberto Gallegos Ramonet Date: Fri, 6 Mar 2020 00:33:44 +0100 Subject: [PATCH] lr-wpan: Beacon Enabled Mode Direct transmissions --- AUTHORS | 1 - src/lr-wpan/examples/lr-wpan-mlme.cc | 211 +++++ src/lr-wpan/examples/wscript | 3 + src/lr-wpan/helper/lr-wpan-helper.cc | 57 ++ src/lr-wpan/helper/lr-wpan-helper.h | 13 + src/lr-wpan/model/lr-wpan-csmaca.cc | 255 +++++- src/lr-wpan/model/lr-wpan-csmaca.h | 112 ++- src/lr-wpan/model/lr-wpan-fields.cc | 491 ++++++++++ src/lr-wpan/model/lr-wpan-fields.h | 314 +++++++ src/lr-wpan/model/lr-wpan-mac-header.cc | 10 - src/lr-wpan/model/lr-wpan-mac-header.h | 39 +- src/lr-wpan/model/lr-wpan-mac-pl-headers.cc | 240 +++++ src/lr-wpan/model/lr-wpan-mac-pl-headers.h | 165 ++++ src/lr-wpan/model/lr-wpan-mac.cc | 852 ++++++++++++++++-- src/lr-wpan/model/lr-wpan-mac.h | 753 +++++++++++++--- src/lr-wpan/test/lr-wpan-ifs-test.cc | 283 ++++++ .../test/lr-wpan-slotted-csmaca-test.cc | 342 +++++++ src/lr-wpan/wscript | 6 + .../examples/example-ping-lr-wpan-beacon.cc | 181 ++++ src/sixlowpan/examples/wscript | 4 + 20 files changed, 4001 insertions(+), 331 deletions(-) create mode 100644 src/lr-wpan/examples/lr-wpan-mlme.cc create mode 100644 src/lr-wpan/model/lr-wpan-fields.cc create mode 100644 src/lr-wpan/model/lr-wpan-fields.h create mode 100644 src/lr-wpan/model/lr-wpan-mac-pl-headers.cc create mode 100644 src/lr-wpan/model/lr-wpan-mac-pl-headers.h create mode 100644 src/lr-wpan/test/lr-wpan-ifs-test.cc create mode 100644 src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc create mode 100644 src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc diff --git a/AUTHORS b/AUTHORS index b180f6795..be18facda 100644 --- a/AUTHORS +++ b/AUTHORS @@ -83,7 +83,6 @@ Tom Henderson (tomhend@u.washington.edu) Christopher Hepner (hepner@hs-ulm.de) Budiarto Herman (budiarto.herman@magister.fi) Tom Hewer (tomhewer@mac.com) -Jack Higgins (shattered.feelings@gmail.com) Kristian A. Hiorth (kristahi@ifi.uio.no) Kim Højgaard-Hansen (kimrhh@gmail.com) Chris Hood (chood8@gatech.edu) diff --git a/src/lr-wpan/examples/lr-wpan-mlme.cc b/src/lr-wpan/examples/lr-wpan-mlme.cc new file mode 100644 index 000000000..c7ad3ca65 --- /dev/null +++ b/src/lr-wpan/examples/lr-wpan-mlme.cc @@ -0,0 +1,211 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + */ + +/* + * Coordinator End Device + * N0 <---------------- N1 + * (dev0) (dev1) + * + * This example demonstrate the usage of the MAC primitives involved in + * direct transmissions for the beacon enabled mode of IEEE 802.15.4-2011. + * A single packet is sent from an end device to the coordinator during the CAP + * of the first incoming superframe. + * + * This example do not demonstrate a full protocol stack usage. + * For full protocol stack usage refer to 6lowpan examples. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ns3; + +static void BeaconIndication (MlmeBeaconNotifyIndicationParams params, Ptr p) +{ + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << " secs | Received BEACON packet of size " << p->GetSize ()); +} + +static void DataIndication (McpsDataIndicationParams params, Ptr p) +{ + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << " secs | Received DATA packet of size " << p->GetSize ()); +} + +static void TransEndIndication (McpsDataConfirmParams params) +{ + // In the case of transmissions with the Ack flag activated, the transaction is only + // successful if the Ack was received. + if (params.m_status == LrWpanMcpsDataConfirmStatus::IEEE_802_15_4_SUCCESS) + { + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << " secs | Transmission successfully sent"); + } +} + +static void DataIndicationCoordinator (McpsDataIndicationParams params, Ptr p) +{ + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Coordinator Received DATA packet (size " << p->GetSize () << " bytes)"); +} + +static void StartConfirm (MlmeStartConfirmParams params) +{ + if (params.m_status == MLMESTART_SUCCESS) + { + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "Beacon status SUCESSFUL"); + } +} + + +int main (int argc, char *argv[]) +{ + + + LogComponentEnableAll (LOG_PREFIX_TIME); + LogComponentEnableAll (LOG_PREFIX_FUNC); + LogComponentEnable ("LrWpanMac", LOG_LEVEL_INFO); + LogComponentEnable ("LrWpanCsmaCa", LOG_LEVEL_INFO); + + + LrWpanHelper lrWpanHelper; + + // Create 2 nodes, and a NetDevice for each one + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + + Ptr dev0 = CreateObject (); + Ptr dev1 = CreateObject (); + + dev0->SetAddress (Mac16Address ("00:01")); + dev1->SetAddress (Mac16Address ("00:02")); + + Ptr channel = CreateObject (); + Ptr propModel = CreateObject (); + Ptr delayModel = CreateObject (); + channel->AddPropagationLossModel (propModel); + channel->SetPropagationDelayModel (delayModel); + + dev0->SetChannel (channel); + dev1->SetChannel (channel); + + n0->AddDevice (dev0); + n1->AddDevice (dev1); + + ///////////////// Mobility /////////////////////// + Ptr sender0Mobility = CreateObject (); + sender0Mobility->SetPosition (Vector (0,0,0)); + dev0->GetPhy ()->SetMobility (sender0Mobility); + Ptr sender1Mobility = CreateObject (); + + sender1Mobility->SetPosition (Vector (0,10,0)); //10 m distance + dev1->GetPhy ()->SetMobility (sender1Mobility); + + + /////// MAC layer Callbacks hooks///////////// + + MlmeStartConfirmCallback cb0; + cb0 = MakeCallback (&StartConfirm); + dev0->GetMac ()->SetMlmeStartConfirmCallback (cb0); + + McpsDataConfirmCallback cb1; + cb1 = MakeCallback (&TransEndIndication); + dev1->GetMac ()->SetMcpsDataConfirmCallback (cb1); + + MlmeBeaconNotifyIndicationCallback cb3; + cb3 = MakeCallback (&BeaconIndication); + dev1->GetMac ()->SetMlmeBeaconNotifyIndicationCallback (cb3); + + McpsDataIndicationCallback cb4; + cb4 = MakeCallback (&DataIndication); + dev1->GetMac ()->SetMcpsDataIndicationCallback (cb4); + + McpsDataIndicationCallback cb5; + cb5 = MakeCallback (&DataIndicationCoordinator); + dev0->GetMac ()->SetMcpsDataIndicationCallback (cb5); + + + + //////////// Manual device association //////////////////// + // Note: We manually associate the devices to a PAN coordinator + // because currently there is no automatic association behavior (bootstrap); + // The PAN COORDINATOR does not need to associate or set its + // PAN Id or its own coordinator id, these are set + // by the MLME-start.request primitive when used. + + dev1->GetMac ()->SetPanId (5); + dev1->GetMac ()->SetAssociatedCoor (Mac16Address ("00:01")); + + + + ///////////////////// Start transmitting beacons from coordinator //////////////////////// + + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = 5; + params.m_bcnOrd = 14; + params.m_sfrmOrd = 6; + Simulator::ScheduleWithContext (1, Seconds (2.0), + &LrWpanMac::MlmeStartRequest, + dev0->GetMac (), params); + + ///////////////////// Transmission of data Packets from end device ////////////////////// + + Ptr p1 = Create (5); + McpsDataRequestParams params2; + params2.m_dstPanId = 5; + params2.m_srcAddrMode = SHORT_ADDR; + params2.m_dstAddrMode = SHORT_ADDR; + params2.m_dstAddr = Mac16Address ("00:01"); + params2.m_msduHandle = 0; + // params2.m_txOptions = TX_OPTION_ACK; // Enable direct transmission with Ack + + ///////////////////////////////////////////////////////////////////////////////////// + // Examples of time parameters for transmissions in the first incoming superframe. // + ///////////////////////////////////////////////////////////////////////////////////// + + // 2.981 sec No time to finish CCA in CAP, the transmission at this time will cause + // the packet to be deferred to the next superframe. + + // 2.98272 sec No time to finish random backoff delay in CAP, the transmission at this + // time will cause the packet to be deferred to the next superframe. + + // 2.93 sec Enough time, the packet can be transmitted within the CAP of the first superframe + + + // MCPS-DATA.request Beacon enabled Direct Transmission (dev1) + // Frame transmission from End Device to Coordinator (Direct transmission) + Simulator::ScheduleWithContext (1, Seconds (2.93), + &LrWpanMac::McpsDataRequest, + dev1->GetMac (), params2, p1); + + + Simulator::Stop (Seconds (600)); + Simulator::Run (); + + Simulator::Destroy (); + return 0; +} diff --git a/src/lr-wpan/examples/wscript b/src/lr-wpan/examples/wscript index 5039d5282..635544510 100644 --- a/src/lr-wpan/examples/wscript +++ b/src/lr-wpan/examples/wscript @@ -15,3 +15,6 @@ def build(bld): obj = bld.create_ns3_program('lr-wpan-error-distance-plot', ['lr-wpan', 'stats']) obj.source = 'lr-wpan-error-distance-plot.cc' + + obj = bld.create_ns3_program('lr-wpan-mlme', ['lr-wpan']) + obj.source = 'lr-wpan-mlme.cc' diff --git a/src/lr-wpan/helper/lr-wpan-helper.cc b/src/lr-wpan/helper/lr-wpan-helper.cc index 27a984d8a..26b0e6f1a 100644 --- a/src/lr-wpan/helper/lr-wpan-helper.cc +++ b/src/lr-wpan/helper/lr-wpan-helper.cc @@ -254,6 +254,63 @@ LrWpanHelper::AssociateToPan (NetDeviceContainer c, uint16_t panId) return; } +void +LrWpanHelper::AssociateToBeaconPan (NetDeviceContainer c, uint16_t panId, Mac16Address coor, uint8_t bcnOrd, uint8_t sfrmOrd) +{ + NetDeviceContainer devices; + uint16_t id = 1; + uint8_t idBuf[2]; + Mac16Address address; + + if (bcnOrd > 14) + { + NS_LOG_DEBUG("The Beacon Order must be an int between 0 and 14"); + return; + } + + + if ((sfrmOrd > 14) || (sfrmOrd > bcnOrd)) + { + NS_LOG_DEBUG("The Superframe Order must be an int between 0 and 14, and less or equal to Beacon Order"); + return; + } + + for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); i++) + { + Ptr device = DynamicCast (*i); + if (device) + { + idBuf[0] = (id >> 8) & 0xff; + idBuf[1] = (id >> 0) & 0xff; + address.CopyFrom (idBuf); + + device->GetMac ()->SetShortAddress (address); + + if (address == coor) + { + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = panId; + params.m_bcnOrd = bcnOrd; + params.m_sfrmOrd = sfrmOrd; + + Ptr uniformRandomVariable = CreateObject ();; + Time jitter = Time (MilliSeconds (uniformRandomVariable->GetInteger (0, 10))); + + Simulator::Schedule (jitter, &LrWpanMac::MlmeStartRequest, + device->GetMac (), params); + } + else + { + device->GetMac ()->SetPanId (panId); + device->GetMac ()->SetAssociatedCoor(coor); + } + id++; + } + } + return; +} + /** * @brief Write a packet in a PCAP file * @param file the output file diff --git a/src/lr-wpan/helper/lr-wpan-helper.h b/src/lr-wpan/helper/lr-wpan-helper.h index 67a4d8d77..06c966b6a 100644 --- a/src/lr-wpan/helper/lr-wpan-helper.h +++ b/src/lr-wpan/helper/lr-wpan-helper.h @@ -112,6 +112,19 @@ public: */ void AssociateToPan (NetDeviceContainer c, uint16_t panId); + /** + * \brief Associate the nodes to the same PAN and initiate beacon enabled mode. + * + * \param c a set of nodes + * \param panID the PAN id + * \param coor the address of the PAN coordinator + * \param bcnOrd indicates the interval between beacons. + * The value must be an int between 0 and 14. + * \param sfrmOrd indicates the length of the superframe. + * The value must be an int between 0 and 14 and less or equal to the bcnOrd + */ + void AssociateToBeaconPan (NetDeviceContainer c, uint16_t panId, Mac16Address coor, uint8_t bcnOrd, uint8_t sfrmOrd); + /** * Helper to enable all LrWpan log components with one statement */ diff --git a/src/lr-wpan/model/lr-wpan-csmaca.cc b/src/lr-wpan/model/lr-wpan-csmaca.cc index 33ca2af38..634a45dec 100644 --- a/src/lr-wpan/model/lr-wpan-csmaca.cc +++ b/src/lr-wpan/model/lr-wpan-csmaca.cc @@ -18,6 +18,7 @@ * Author: * kwong yin * Sascha Alexander Jopen + * Alberto Gallegos Ramonet */ #include "lr-wpan-csmaca.h" @@ -26,6 +27,10 @@ #include #include +#undef NS_LOG_APPEND_CONTEXT +#define NS_LOG_APPEND_CONTEXT \ + std::clog << "[address " << m_mac->GetShortAddress () << "] "; + namespace ns3 { NS_LOG_COMPONENT_DEFINE ("LrWpanCsmaCa"); @@ -50,14 +55,16 @@ LrWpanCsmaCa::LrWpanCsmaCa () m_isSlotted = false; m_NB = 0; m_CW = 2; - m_BLE = false; + m_macBattLifeExt = false; m_macMinBE = 3; m_macMaxBE = 5; m_macMaxCSMABackoffs = 4; - m_aUnitBackoffPeriod = 20; //20 symbols + m_aUnitBackoffPeriod = 20; // symbols m_random = CreateObject (); m_BE = m_macMinBE; m_ccaRequestRunning = false; + m_randomBackoffPeriodsLeft = 0; + m_coorDest = false; } LrWpanCsmaCa::~LrWpanCsmaCa () @@ -68,7 +75,9 @@ LrWpanCsmaCa::~LrWpanCsmaCa () void LrWpanCsmaCa::DoDispose () { - m_lrWpanMacStateCallback = MakeNullCallback< void, LrWpanMacState> (); + m_lrWpanMacStateCallback = MakeNullCallback (); + m_lrWpanMacTransCostCallback = MakeNullCallback (); + Cancel (); m_mac = 0; } @@ -169,26 +178,66 @@ LrWpanCsmaCa::GetUnitBackoffPeriod (void) const return m_aUnitBackoffPeriod; } + Time LrWpanCsmaCa::GetTimeToNextSlot (void) const { NS_LOG_FUNCTION (this); - // TODO: Calculate the offset to the next slot. + // The reference for the beginning of the CAP changes depending + // on the data packet being sent from the Coordinator/outgoing frame (Tx beacon time reference) + // or other device/incoming frame (Rx beacon time reference). - return Seconds (0); + uint32_t elapsedSuperframe; + uint64_t currentTimeSymbols; + uint32_t symbolsToBoundary; + Time nextBoundary; + + currentTimeSymbols = Simulator::Now ().GetSeconds () * m_mac->GetPhy ()->GetDataOrSymbolRate (false); + + + if (m_coorDest) + { + // Take the Incoming Frame Reference + elapsedSuperframe = currentTimeSymbols - m_mac->m_beaconRxTime; + } + else + { + // Take the Outgoing Frame Reference + elapsedSuperframe = currentTimeSymbols - m_mac->m_macBeaconTxTime; + } + + symbolsToBoundary = m_aUnitBackoffPeriod - std::fmod (elapsedSuperframe,m_aUnitBackoffPeriod); + nextBoundary = MicroSeconds (symbolsToBoundary * 1000 * 1000 / m_mac->GetPhy ()->GetDataOrSymbolRate (false)); + + NS_LOG_DEBUG ("Elapsed symbols in CAP: " << elapsedSuperframe << "(" << elapsedSuperframe / m_aUnitBackoffPeriod << " backoff periods)"); + NS_LOG_DEBUG ("Next backoff period boundary in " << symbolsToBoundary << " symbols (" + << nextBoundary.GetSeconds () << " s)"); + + + return nextBoundary; } + + void LrWpanCsmaCa::Start () - { NS_LOG_FUNCTION (this); m_NB = 0; if (IsSlottedCsmaCa ()) { + // TODO: Check if the current PHY is using the Japanese band 950 Mhz: + // (IEEE_802_15_4_950MHZ_BPSK and IEEE_802_15_4_950MHZ_2GFSK) + // if in use, m_CW = 1. + // Currently 950 Mhz band PHYs are not supported in ns-3. + // To know the current used PHY, making the method for GetPhy()->GetMyPhyOption() + // public is necessary. Alternatively, the current PHY used + // can be known using phyCurrentPage variable. + m_CW = 2; - if (m_BLE) + + if (m_macBattLifeExt) { m_BE = std::min (static_cast (2), m_macMinBE); } @@ -196,23 +245,20 @@ LrWpanCsmaCa::Start () { m_BE = m_macMinBE; } - //TODO: for slotted, locate backoff period boundary. i.e. delay to the next slot boundary + + // m_coorDest to decide between incoming and outgoing superframes times + m_coorDest = m_mac->isCoordDest (); + + // Locate backoff period boundary. (i.e. a time delay to align with the next backoff period boundary) Time backoffBoundary = GetTimeToNextSlot (); m_randomBackoffEvent = Simulator::Schedule (backoffBoundary, &LrWpanCsmaCa::RandomBackoffDelay, this); + } else { m_BE = m_macMinBE; m_randomBackoffEvent = Simulator::ScheduleNow (&LrWpanCsmaCa::RandomBackoffDelay, this); } - /* - * TODO: If using Backoff.cc (will need to modify Backoff::GetBackoffTime) - * Backoff.m_minSlots = 0; - * Backoff.m_ceiling = m_BE; - * Backoff.ResetBackoffTime(); //m_NB is same as m_numBackoffRetries in Backoff.h - * Backoff.m_maxRetries = macMaxCSMABackoffs; - * Backoff.m_slotTime = m_backoffPeriod; - */ } void @@ -223,65 +269,166 @@ LrWpanCsmaCa::Cancel () m_canProceedEvent.Cancel (); } -/* - * Delay for backoff period in the range 0 to 2^BE -1 units - * TODO: If using Backoff.cc (Backoff::GetBackoffTime) will need to be slightly modified - */ + + void LrWpanCsmaCa::RandomBackoffDelay () { NS_LOG_FUNCTION (this); uint64_t upperBound = (uint64_t) pow (2, m_BE) - 1; - uint64_t backoffPeriod; Time randomBackoff; uint64_t symbolRate; - bool isData = false; + uint32_t backoffPeriodsLeftInCap; + symbolRate = (uint64_t) m_mac->GetPhy ()->GetDataOrSymbolRate (false); //symbols per second - symbolRate = (uint64_t) m_mac->GetPhy ()->GetDataOrSymbolRate (isData); //symbols per second - backoffPeriod = (uint64_t)m_random->GetValue (0, upperBound+1); // num backoff periods - randomBackoff = MicroSeconds (backoffPeriod * GetUnitBackoffPeriod () * 1000 * 1000 / symbolRate); + // We should not recalculate the random backoffPeriods if we are in a slotted CSMA-CA and the + // transmission was previously deferred (m_randomBackoffPeriods != 0) + if (m_randomBackoffPeriodsLeft == 0 || IsUnSlottedCsmaCa ()) + { + m_randomBackoffPeriodsLeft = (uint64_t)m_random->GetValue (0, upperBound + 1); + } + + randomBackoff = MicroSeconds (m_randomBackoffPeriodsLeft * GetUnitBackoffPeriod () * 1000 * 1000 / symbolRate); if (IsUnSlottedCsmaCa ()) { - NS_LOG_LOGIC ("Unslotted: requesting CCA after backoff of " << randomBackoff.GetMicroSeconds () << " us"); + NS_LOG_DEBUG ("Unslotted CSMA-CA: requesting CCA after backoff of " << m_randomBackoffPeriodsLeft << + " periods (" << randomBackoff.GetSeconds () << " s)"); m_requestCcaEvent = Simulator::Schedule (randomBackoff, &LrWpanCsmaCa::RequestCCA, this); } else { - NS_LOG_LOGIC ("Slotted: proceeding after backoff of " << randomBackoff.GetMicroSeconds () << " us"); - m_canProceedEvent = Simulator::Schedule (randomBackoff, &LrWpanCsmaCa::CanProceed, this); + // We must make sure there are enough backoff periods left in the CAP, otherwise we continue in + // the CAP of the next superframe after the transmission/reception of the beacon (and the IFS) + backoffPeriodsLeftInCap = GetBackoffPeriodsLeftInCap (); + + NS_LOG_DEBUG ("Slotted CSMA-CA: proceeding after backoff of " << m_randomBackoffPeriodsLeft << + " periods (" << randomBackoff.GetSeconds () << " s)"); + + Time rmnCapTime = MicroSeconds (backoffPeriodsLeftInCap * GetUnitBackoffPeriod () * 1000 * 1000 / symbolRate); + NS_LOG_DEBUG ("Backoff periods left in CAP: " << backoffPeriodsLeftInCap << " (" << rmnCapTime.GetSeconds () << " s)"); + + if (m_randomBackoffPeriodsLeft > backoffPeriodsLeftInCap) + { + m_randomBackoffPeriodsLeft = m_randomBackoffPeriodsLeft - backoffPeriodsLeftInCap; + NS_LOG_DEBUG ("No time in CAP to complete backoff delay, deferring to the next CAP"); + + m_endCapEvent = Simulator::Schedule (rmnCapTime, &LrWpanCsmaCa::DeferCsmaTimeout, this); + } + else + { + m_canProceedEvent = Simulator::Schedule (randomBackoff, &LrWpanCsmaCa::CanProceed, this); + } } } -// TODO : Determine if transmission can be completed before end of CAP for the slotted csmaca -// If not delay to the next CAP + +uint32_t +LrWpanCsmaCa::GetBackoffPeriodsLeftInCap () +{ + uint64_t currentTimeSymbols; + uint16_t capSymbols; + uint64_t endCapSymbols; + uint64_t activeSlot; + + + //At this point, the currentTime should be aligned on a backoff period boundary + + + currentTimeSymbols = Simulator::Now ().GetMicroSeconds () * 1000 * 1000 * + m_mac->GetPhy ()->GetDataOrSymbolRate (false); + + if (m_coorDest) + { // Take Incoming frame reference + activeSlot = m_mac->m_incomingSuperframeDuration / 16; + capSymbols = activeSlot * (m_mac->m_incomingFnlCapSlot + 1); + endCapSymbols = m_mac->m_beaconRxTime + capSymbols; + } + else + { // Take Outgoing frame reference + activeSlot = m_mac->m_superframeDuration / 16; + capSymbols = activeSlot * (m_mac->m_fnlCapSlot + 1); + endCapSymbols = m_mac->m_macBeaconTxTime + capSymbols; + } + + return ((endCapSymbols - currentTimeSymbols) / m_aUnitBackoffPeriod); +} + + void LrWpanCsmaCa::CanProceed () { NS_LOG_FUNCTION (this); - bool canProceed = true; + uint32_t backoffPeriodsLeftInCap; + uint16_t ccaSymbols; + uint32_t transactionSymbols; + uint64_t symbolRate; - if (m_BLE) + ccaSymbols = 0; + m_randomBackoffPeriodsLeft = 0; + symbolRate = (uint64_t) m_mac->GetPhy ()->GetDataOrSymbolRate (false); + backoffPeriodsLeftInCap = GetBackoffPeriodsLeftInCap (); + + + // TODO: On the 950 Mhz Band (Japanese Band) + // only a single CCA check is performed; + // the CCA check duration time is: + // + // CCA symbols = phyCCADuration * m_CW (1) + // other PHYs: + // CCA symbols = 8 * m_CW(2) + // + // note: phyCCADuration & 950Mhz band PHYs are + // not currently implemented in ns-3. + ccaSymbols += 8 * m_CW; + + // The MAC sublayer shall proceed if the remaining CSMA-CA algorithm steps + // can be completed before the end of the CAP. + // See IEEE 802.15.4-2011 (Sections 5.1.1.1 and 5.1.1.4) + // Transaction = 2 CCA + frame transmission (PPDU) + turnaroudtime or Ack time (optional) + IFS + + transactionSymbols = ccaSymbols + m_mac->GetTxPacketSymbols (); + + if (m_mac->isTxAckReq ()) { + NS_LOG_DEBUG ("ACK duration symbols: " << m_mac->GetMacAckWaitDuration ()); + transactionSymbols += m_mac->GetMacAckWaitDuration (); } else { + //time the PHY takes to switch from TX to Rx or Rx to Tx + transactionSymbols += m_mac->GetPhy ()->aTurnaroundTime; + } + transactionSymbols += m_mac->GetIfsSize (); + + // Report the transaction cost + if (!m_lrWpanMacTransCostCallback.IsNull ()) + { + m_lrWpanMacTransCostCallback (transactionSymbols); } - if (canProceed) + NS_LOG_DEBUG ("Total required transaction symbols: " << transactionSymbols); + + if (transactionSymbols > (backoffPeriodsLeftInCap * GetUnitBackoffPeriod ())) { - // TODO: For slotted, Perform CCA on backoff period boundary i.e. delay to next slot boundary - Time backoffBoundary = GetTimeToNextSlot (); - m_requestCcaEvent = Simulator::Schedule (backoffBoundary, &LrWpanCsmaCa::RequestCCA, this); + NS_LOG_DEBUG ("Transaction of " << transactionSymbols << " symbols " << + "cannot be completed in CAP, deferring transmission to the next CAP"); + + Time waitTime = MicroSeconds (backoffPeriodsLeftInCap * GetUnitBackoffPeriod () * 1000 * 10000 / symbolRate); + + NS_LOG_DEBUG ("Symbols left in CAP: " << backoffPeriodsLeftInCap * GetUnitBackoffPeriod () << + " (" << waitTime.GetSeconds () << "s)"); + + m_endCapEvent = Simulator::Schedule (waitTime, &LrWpanCsmaCa::DeferCsmaTimeout, this); } else { - Time nextCap = Seconds (0); - m_randomBackoffEvent = Simulator::Schedule (nextCap, &LrWpanCsmaCa::RandomBackoffDelay, this); + m_requestCcaEvent = Simulator::ScheduleNow (&LrWpanCsmaCa::RequestCCA,this); } + } void @@ -292,9 +439,13 @@ LrWpanCsmaCa::RequestCCA () m_mac->GetPhy ()->PlmeCcaRequest (); } -/* - * This function is called when the phy calls back after completing a PlmeCcaRequest - */ +void +LrWpanCsmaCa::DeferCsmaTimeout () +{ + NS_LOG_FUNCTION (this); + m_lrWpanMacStateCallback (MAC_CSMA_DEFERRED); +} + void LrWpanCsmaCa::PlmeCcaConfirm (LrWpanPhyEnumeration status) { @@ -364,6 +515,15 @@ LrWpanCsmaCa::PlmeCcaConfirm (LrWpanPhyEnumeration status) } } + +void +LrWpanCsmaCa::SetLrWpanMacTransCostCallback (LrWpanMacTransCostCallback c) +{ + NS_LOG_FUNCTION (this); + m_lrWpanMacTransCostCallback = c; +} + + void LrWpanCsmaCa::SetLrWpanMacStateCallback (LrWpanMacStateCallback c) { @@ -371,6 +531,13 @@ LrWpanCsmaCa::SetLrWpanMacStateCallback (LrWpanMacStateCallback c) m_lrWpanMacStateCallback = c; } +void +LrWpanCsmaCa::SetBatteryLifeExtension (bool batteryLifeExtension) +{ + m_macBattLifeExt = batteryLifeExtension; +} + + int64_t LrWpanCsmaCa::AssignStreams (int64_t stream) { @@ -385,4 +552,10 @@ LrWpanCsmaCa::GetNB (void) return m_NB; } +bool +LrWpanCsmaCa::GetBatteryLifeExtension (void) +{ + return m_macBattLifeExt; +} + } //namespace ns3 diff --git a/src/lr-wpan/model/lr-wpan-csmaca.h b/src/lr-wpan/model/lr-wpan-csmaca.h index 92b573159..b6ba0c481 100644 --- a/src/lr-wpan/model/lr-wpan-csmaca.h +++ b/src/lr-wpan/model/lr-wpan-csmaca.h @@ -18,6 +18,7 @@ * Author: * kwong yin * Sascha Alexander Jopen + * Alberto Gallegos Ramonet */ #ifndef LR_WPAN_CSMACA_H @@ -34,10 +35,18 @@ class UniformRandomVariable; /** * \ingroup lr-wpan * - * This method informs the MAC whether the channel is idle or busy. + * This method informs the MAC whether the channel is idle or busy. */ typedef Callback LrWpanMacStateCallback; - +/** + * \ingroup lr-wpan + * + * This method informs the transaction cost in a slotted CSMA-CA data transmission. + * i.e. Reports number of symbols (time) it would take slotted CSMA-CA to process the current transaction. + * 1 Transaction = 2 CCA + frame transmission (PPDU) + turnaroudtime or Ack time (optional) + IFS + * See IEEE 802.15.4-2011 (Sections 5.1.1.1 and 5.1.1.4) + */ +typedef Callback LrWpanMacTransCostCallback; /** * \ingroup lr-wpan * @@ -54,20 +63,17 @@ public: * \return the object TypeId */ static TypeId GetTypeId (void); - /** * Default constructor. */ LrWpanCsmaCa (void); virtual ~LrWpanCsmaCa (void); - /** * Set the MAC to which this CSMA/CA implementation is attached to. * * \param mac the used MAC */ void SetMac (Ptr mac); - /** * Get the MAC to which this CSMA/CA implementation is attached to. * @@ -79,26 +85,22 @@ public: * Configure for the use of the slotted CSMA/CA version. */ void SetSlottedCsmaCa (void); - /** * Configure for the use of the unslotted CSMA/CA version. */ void SetUnSlottedCsmaCa (void); - /** * Check if the slotted CSMA/CA version is being used. * * \return true, if slotted CSMA/CA is used, false otherwise. */ bool IsSlottedCsmaCa (void) const; - /** * Check if the unslotted CSMA/CA version is being used. * * \return true, if unslotted CSMA/CA is used, false otherwise. */ bool IsUnSlottedCsmaCa (void) const; - /** * Set the minimum backoff exponent value. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -106,7 +108,6 @@ public: * \param macMinBE the minimum backoff exponent value */ void SetMacMinBE (uint8_t macMinBE); - /** * Get the minimum backoff exponent value. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -114,7 +115,6 @@ public: * \return the minimum backoff exponent value */ uint8_t GetMacMinBE (void) const; - /** * Set the maximum backoff exponent value. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -122,7 +122,6 @@ public: * \param macMaxBE the maximum backoff exponent value */ void SetMacMaxBE (uint8_t macMaxBE); - /** * Get the maximum backoff exponent value. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -130,7 +129,6 @@ public: * \return the maximum backoff exponent value */ uint8_t GetMacMaxBE (void) const; - /** * Set the maximum number of backoffs. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. @@ -146,7 +144,6 @@ public: * \return the maximum number of backoffs */ uint8_t GetMacMaxCSMABackoffs (void) const; - /** * Set the number of symbols forming the basic time period used by the * CSMA-CA algorithm. @@ -155,7 +152,6 @@ public: * \param unitBackoffPeriod the period length in symbols */ void SetUnitBackoffPeriod (uint64_t unitBackoffPeriod); - /** * Get the number of symbols forming the basic time period used by the * CSMA-CA algorithm. @@ -164,30 +160,26 @@ public: * \return the period length in symbols */ uint64_t GetUnitBackoffPeriod (void) const; - /** - * Get the amount of time from now to the beginning of the next slot. + * Locates the time to the next backoff period boundary and returns the + * amount of time left (in symbols). * * \return time offset to the next slot */ Time GetTimeToNextSlot (void) const; - /** * Start CSMA-CA algorithm (step 1), initialize NB, BE for both slotted and unslotted - * CSMA-CA. For the slotted initialize CW plus also start on the backoff boundary + * CSMA-CA. For slotted CSMA-CA initializes CW and starts the backoff slot count. */ void Start (void); - /** * Cancel CSMA-CA algorithm. */ void Cancel (void); - /** * In step 2 of the CSMA-CA, perform a random backoff in the range of 0 to 2^BE -1 */ void RandomBackoffDelay (void); - /** * In the slotted CSMA-CA, after random backoff, determine if the remaining * CSMA-CA operation can proceed, i.e. can the entire transactions can be @@ -196,12 +188,15 @@ public: * proceed function RequestCCA() is called. */ void CanProceed (void); - /** * Request the Phy to perform CCA (Step 3) */ void RequestCCA (void); - + /** + * The CSMA algorithm call this function at the end of the CAP to return the MAC state + * back to to IDLE after a transmission was deferred due to the lack of time in the CAP. + */ + void DeferCsmaTimeout (void); /** * IEEE 802.15.4-2006 section 6.2.2.2 * PLME-CCA.confirm status @@ -214,7 +209,14 @@ public: * treat as channel access failure (step 4). */ void PlmeCcaConfirm (LrWpanPhyEnumeration status); - + /** + * Set the callback function to report a transaction cost in slotted CSMA-CA. The callback is + * triggered in CanProceed() after calculating the transaction cost (2 CCA checks,transmission cost, turnAroundTime, ifs) + * in the boundary of an Active Period. + * + * \param trans the transaction cost callback + */ + void SetLrWpanMacTransCostCallback (LrWpanMacTransCostCallback trans); /** * Set the callback function to the MAC. Used at the end of a Channel Assessment, as part of the * interconnections between the CSMA-CA and the MAC. The callback @@ -223,7 +225,12 @@ public: * \param macState the mac state callback */ void SetLrWpanMacStateCallback (LrWpanMacStateCallback macState); - + /** + * Set the value of the Battery Life Extension + * + * \param batteryLifeExtension the Battery Life Extension value active or inactive + */ + void SetBatteryLifeExtension (bool batteryLifeExtension); /** * Assign a fixed random variable stream number to the random variables * used by this model. Return the number of streams that have been assigned. @@ -232,13 +239,18 @@ public: * \return the number of stream indices assigned by this model */ int64_t AssignStreams (int64_t stream); - /** * Get the number of CSMA retries * * \returns the number of CSMA retries */ uint8_t GetNB (void); + /** + * Get the value of the Battery Life Extension + * + * \returns true or false to Battery Life Extension support + */ + bool GetBatteryLifeExtension (void); private: // Disable implicit copy constructors @@ -251,90 +263,98 @@ private: * \returns */ LrWpanCsmaCa& operator= (LrWpanCsmaCa const &); - - virtual void DoDispose (void); + virtual void DoDispose (void); + /** + * \brief Get the periods left in the CAP portion of the Outgoing or Incoming frame. + * \return num of backoff periods left in the CAP + */ + uint32_t GetBackoffPeriodsLeftInCap (); + /** + * The callback to inform the cost of a transaction in slotted CSMA-CA. + */ + LrWpanMacTransCostCallback m_lrWpanMacTransCostCallback; /** * The callback to inform the configured MAC of the CSMA/CA result. */ LrWpanMacStateCallback m_lrWpanMacStateCallback; - /** * Beacon-enabled slotted or nonbeacon-enabled unslotted CSMA-CA. */ bool m_isSlotted; - /** - * The MAC instance for which this CSMAÄ/CA implementation is configured. + * The MAC instance for which this CSMA/CA implemenation is configured. */ Ptr m_mac; - /** * Number of backoffs for the current transmission. */ uint8_t m_NB; - /** * Contention window length (used in slotted ver only). */ uint8_t m_CW; - /** * Backoff exponent. */ uint8_t m_BE; - /** * Battery Life Extension. */ - bool m_BLE; - + bool m_macBattLifeExt; /** * Minimum backoff exponent. 0 - macMaxBE, default 3 */ uint8_t m_macMinBE; // - /** * Maximum backoff exponent. 3 - 8, default 5 */ uint8_t m_macMaxBE; - /** * Maximum number of backoffs. 0 - 5, default 4 */ uint8_t m_macMaxCSMABackoffs; - /** * Number of symbols per CSMA/CA time unit, default 20 symbols. */ uint64_t m_aUnitBackoffPeriod; - + /** + * Count the number of remaining random backoff periods left to delay. + */ + uint64_t m_randomBackoffPeriodsLeft; /** * Uniform random variable stream. */ Ptr m_random; - /** * Scheduler event for the start of the next random backoff/slot. */ EventId m_randomBackoffEvent; - + /** + * Scheduler event for the end of the current CAP + */ + EventId m_endCapEvent; /** * Scheduler event when to start the CCA after a random backoff. */ EventId m_requestCcaEvent; - /** * Scheduler event for checking if we can complete the transmission before the * end of the CAP. */ EventId m_canProceedEvent; - /** * Flag indicating that the PHY is currently running a CCA. Used to prevent * reporting the channel status to the MAC while canceling the CSMA algorithm. */ bool m_ccaRequestRunning; + /** + * Indicates whether the CSMA procedure is targeted for a message to be sent to the coordinator. + * Used to run slotted CSMA/CA on the incoming or outgoing superframe + * according to the target. + */ + bool m_coorDest; + }; } diff --git a/src/lr-wpan/model/lr-wpan-fields.cc b/src/lr-wpan/model/lr-wpan-fields.cc new file mode 100644 index 000000000..c89227c66 --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-fields.cc @@ -0,0 +1,491 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + */ + + + +#include "lr-wpan-fields.h" +#include +#include + +namespace ns3 { + +SuperframeField::SuperframeField () +{ + SetBeaconOrder (15); + SetSuperframeOrder (15); + SetFinalCapSlot (0); + SetBattLifeExt (false); + SetPanCoor (false); + SetAssocPermit (false); +} + +void +SuperframeField::SetSuperframe (uint16_t superFrmSpec) +{ + m_sspecBcnOrder = (superFrmSpec) & (0x0F); //Bits 0-3 + m_sspecSprFrmOrder = (superFrmSpec >> 4) & (0x0F); //Bits 4-7 + m_sspecFnlCapSlot = (superFrmSpec >> 8) & (0x0F); //Bits 8-11 + m_sspecBatLifeExt = (superFrmSpec >> 12) & (0x01); //Bit 12 + //Bit 13 (Reserved) + m_sspecPanCoor = (superFrmSpec >> 14) & (0x01); //Bit 14 + m_sspecAssocPermit = (superFrmSpec >> 15) & (0x01); //Bit 15 +} + +void +SuperframeField::SetBeaconOrder (uint8_t bcnOrder) +{ + if (bcnOrder > 15) + { + std::cout << "SuperframeField Beacon Order value must be 15 or less\n"; + } + else + { + m_sspecBcnOrder = bcnOrder; + } +} + +void +SuperframeField::SetSuperframeOrder (uint8_t frmOrder) +{ + if (frmOrder > 15) + { + std::cout << "SuperframeField Frame Order value must be 15 or less\n"; + } + else + { + m_sspecSprFrmOrder = frmOrder; + } +} + +void +SuperframeField::SetFinalCapSlot (uint8_t capSlot) +{ + if (capSlot > 15) + { + std::cout << "The final slot cannot greater than the slots in a CAP (15)\n"; + } + else + { + m_sspecFnlCapSlot = capSlot; + } +} + +void +SuperframeField::SetBattLifeExt (bool battLifeExt) +{ + m_sspecBatLifeExt = battLifeExt; +} + +void +SuperframeField::SetPanCoor (bool panCoor) +{ + m_sspecPanCoor = panCoor; +} + +void +SuperframeField::SetAssocPermit (bool assocPermit) +{ + m_sspecAssocPermit = assocPermit; +} + +uint8_t +SuperframeField::GetBeaconOrder (void) const +{ + return m_sspecBcnOrder; +} + +uint8_t +SuperframeField::GetFrameOrder (void) const +{ + return m_sspecSprFrmOrder; +} + +uint8_t +SuperframeField::GetFinalCapSlot (void) const +{ + return m_sspecFnlCapSlot; +} + +bool +SuperframeField::IsBattLifeExt (void) const +{ + return m_sspecBatLifeExt; +} + +bool +SuperframeField::IsPanCoor (void) const +{ + return m_sspecPanCoor; +} + +bool +SuperframeField::IsAssocPermit (void) const +{ + return m_sspecAssocPermit; +} + +uint16_t +SuperframeField::GetSuperframe (void) const +{ + uint16_t superframe; + + superframe = m_sspecBcnOrder & (0x0F); // Bits 0-3 + superframe |= (m_sspecSprFrmOrder << 4) & (0x0F << 4); // Bits 4-7 + superframe |= (m_sspecFnlCapSlot << 8) & (0x0F << 8); // Bits 8-11 + superframe |= (m_sspecBatLifeExt << 12) & (0x01 << 12); // Bit 12 + // Bit 13 (Reserved) + superframe |= (m_sspecPanCoor << 14) & (0x01 << 14); // Bit 14 + superframe |= (m_sspecAssocPermit << 15) & (0x01 << 15); // Bit 15 + + return superframe; +} + +uint32_t +SuperframeField::GetSerializedSize (void) const +{ + return 2; // 2 Octets (superframeSpec) +} + +Buffer::Iterator +SuperframeField::Serialize (Buffer::Iterator i) const +{ + i.WriteHtolsbU16 (GetSuperframe ()); + return i; +} + +Buffer::Iterator +SuperframeField::Deserialize (Buffer::Iterator i) +{ + uint16_t superframe = i.ReadLsbtohU16 (); + SetSuperframe (superframe); + + return i; +} + +/** + * output stream output operator + * + * \param os output stream + * \param superframeField The Superframe Specification Field + * + * \returns output stream + */ +std::ostream & +operator << (std::ostream &os, const SuperframeField &superframeField) +{ + os << " Beacon Order = " << uint32_t (superframeField.GetBeaconOrder ()) + << ", Frame Order = " << uint32_t (superframeField.GetFrameOrder ()) + << ", Final CAP slot = " << uint32_t (superframeField.GetFinalCapSlot ()) + << ", Battery Life Ext = " << bool (superframeField.IsBattLifeExt ()) + << ", PAN Coordinator = " << bool (superframeField.IsPanCoor ()) + << ", Association Permit = " << bool (superframeField.IsAssocPermit ()); + return os; +} + +/*********************************************************** + * Guaranteed Time Slots (GTS) Fields + ***********************************************************/ + +GtsFields::GtsFields () +{ + // GTS Specification Field + m_gtsSpecDescCount = 0; + m_gtsSpecPermit = 0; + // GTS Direction Field + m_gtsDirMask = 0; +} + +uint8_t +GtsFields::GetGtsSpecField (void) const +{ + uint8_t gtsSpecField; + + gtsSpecField = m_gtsSpecDescCount & (0x07); // Bits 0-2 + // Bits 3-6 (Reserved) + gtsSpecField |= (m_gtsSpecPermit << 7) & (0x01 << 7); // Bit 7 + + return gtsSpecField; +} + +uint8_t +GtsFields::GetGtsDirectionField (void) const +{ + uint8_t gtsDirectionField; + + gtsDirectionField = m_gtsDirMask & (0x7F); // Bit 0-6 + // Bit 7 (Reserved) + return gtsDirectionField; +} + +void +GtsFields::SetGtsSpecField (uint8_t gtsSpec) +{ + m_gtsSpecDescCount = (gtsSpec) & (0x07); // Bits 0-2 + // Bits 3-6 (Reserved) + m_gtsSpecPermit = (gtsSpec >> 7) & (0x01); // Bit 7 +} + +void +GtsFields::SetGtsDirectionField (uint8_t gtsDir) +{ + m_gtsDirMask = (gtsDir) & (0x7F); // Bits 0-6 + // Bit 7 (Reserved) +} + +uint32_t +GtsFields::GetSerializedSize (void) const +{ + uint32_t size; + + size = 1; // 1 octet GTS Specification Field + if (m_gtsSpecDescCount > 0) + { + size += 1; // 1 octet GTS Direction Field + size += (m_gtsSpecDescCount * 3); // 3 octets per GTS descriptor + } + + return size; +} + +Buffer::Iterator +GtsFields::Serialize (Buffer::Iterator i) const +{ + i.WriteU8 (GetGtsSpecField ()); + + if (m_gtsSpecDescCount > 0) + { + uint8_t gtsDescStartAndLenght; + i.WriteU8 (GetGtsDirectionField ()); + + for (int j = 0; j < m_gtsSpecDescCount; j++) + { + WriteTo (i,m_gtsList[j].m_gtsDescDevShortAddr); + + gtsDescStartAndLenght = m_gtsList[j].m_gtsDescStartSlot & (0x0F); + gtsDescStartAndLenght = (m_gtsList[j].m_gtsDescLength << 4) & (0x0F); + + i.WriteU8 (gtsDescStartAndLenght); + } + } + return i; +} + +Buffer::Iterator +GtsFields::Deserialize (Buffer::Iterator i) +{ + + uint8_t gtsSpecField = i.ReadU8 (); + SetGtsSpecField (gtsSpecField); + + if (m_gtsSpecDescCount > 0) + { + uint8_t gtsDirectionField = i.ReadU8 (); + SetGtsDirectionField (gtsDirectionField); + + uint8_t gtsDescStartAndLenght; + for (int j = 0; j < m_gtsSpecDescCount; j++) + { + ReadFrom (i, m_gtsList[j].m_gtsDescDevShortAddr); + + gtsDescStartAndLenght = i.ReadU8 (); + m_gtsList[j].m_gtsDescStartSlot = (gtsDescStartAndLenght) & (0x0F); + m_gtsList[j].m_gtsDescLength = (gtsDescStartAndLenght >> 4) & (0x0F); + } + } + return i; +} + + +/*********************************************************** + * Pending Address Fields + ***********************************************************/ + +PendingAddrFields::PendingAddrFields () +{ + m_pndAddrSpecNumShortAddr = 0; + m_pndAddrSpecNumExtAddr = 0; +} + + +uint8_t +PendingAddrFields::GetNumShortAddr (void) const +{ + return m_pndAddrSpecNumShortAddr; +} + + +uint8_t +PendingAddrFields::GetNumExtAddr (void) const +{ + return m_pndAddrSpecNumExtAddr; +} + +uint8_t +PendingAddrFields::GetPndAddrSpecField (void) const +{ + uint8_t pndAddrSpecField; + + pndAddrSpecField = m_pndAddrSpecNumShortAddr & (0x07); // Bits 0-2 + // Bit 3 (Reserved) + pndAddrSpecField |= (m_pndAddrSpecNumExtAddr << 4) & (0x07 << 4); // Bits 4-6 + // Bit 7 (Reserved) + + return pndAddrSpecField; +} + +void +PendingAddrFields::AddAddress (Mac16Address shortAddr) +{ + uint8_t totalPendAddr = m_pndAddrSpecNumShortAddr + m_pndAddrSpecNumExtAddr; + + if (totalPendAddr == 7) + { + return; + } + else + { + m_shortAddrList[m_pndAddrSpecNumShortAddr] = shortAddr; + m_pndAddrSpecNumShortAddr++; + } +} + +void +PendingAddrFields::AddAddress (Mac64Address extAddr) +{ + uint8_t totalPendAddr = m_pndAddrSpecNumShortAddr + m_pndAddrSpecNumExtAddr; + + if (totalPendAddr == 7) + { + return; + } + else + { + m_extAddrList[m_pndAddrSpecNumExtAddr] = extAddr; + m_pndAddrSpecNumExtAddr++; + } +} + +bool +PendingAddrFields::SearchAddress (Mac16Address shortAddr) +{ + for (int j = 0; j <= m_pndAddrSpecNumShortAddr; j++) + { + if (shortAddr == m_shortAddrList[j]) + { + return true; + } + } + + return false; +} + + +bool +PendingAddrFields::SearchAddress (Mac64Address extAddr) +{ + for (int j = 0; j <= m_pndAddrSpecNumExtAddr; j++) + { + if (extAddr == m_extAddrList[j]) + { + return true; + } + } + + return false; +} + + +void +PendingAddrFields::SetPndAddrSpecField (uint8_t pndAddrSpecField) +{ + m_pndAddrSpecNumShortAddr = (pndAddrSpecField) & (0x07); // Bit 0-2 + // Bit 3 + m_pndAddrSpecNumExtAddr = (pndAddrSpecField >> 4) & (0x07); // Bit 4-6 + // Bit 7 +} + + +uint32_t +PendingAddrFields::GetSerializedSize (void) const +{ + uint32_t size; + + size = 1; // 1 octet (Pending Address Specification Field) + size = size + (m_pndAddrSpecNumShortAddr * 2); // X octets (Short Pending Address List) + size = size + (m_pndAddrSpecNumExtAddr * 8); // X octets (Extended Pending Address List) + + return size; +} + +Buffer::Iterator +PendingAddrFields::Serialize (Buffer::Iterator i) const +{ + i.WriteU8 (GetPndAddrSpecField ()); + + for (int j = 0; j < m_pndAddrSpecNumShortAddr; j++) + { + WriteTo (i,m_shortAddrList[j]); + } + + for (int k = 0; k < m_pndAddrSpecNumExtAddr; k++ ) + { + WriteTo (i,m_extAddrList[k]); + } + + return i; +} + +Buffer::Iterator +PendingAddrFields::Deserialize (Buffer::Iterator i) +{ + uint8_t pndAddrSpecField = i.ReadU8 (); + + SetPndAddrSpecField (pndAddrSpecField); + + for (int j = 0; j < m_pndAddrSpecNumShortAddr; j++) + { + ReadFrom (i, m_shortAddrList[j]); + } + + for (int k = 0; k < m_pndAddrSpecNumExtAddr; k++) + { + ReadFrom (i, m_extAddrList[k]); + } + + return i; +} + +/** + * output stream output operator + * + * \param os output stream + * \param PendingAddrField the Pending Address Specification Field + * + * \returns output stream + */ +std::ostream & +operator << (std::ostream &os, const PendingAddrFields &pendingAddrFields) +{ + os << " Num. Short Addr = " << uint32_t (pendingAddrFields.GetNumShortAddr ()) + << ", Num. Ext Addr = " << uint32_t (pendingAddrFields.GetNumExtAddr ()); + return os; +} + +} // ns-3 namespace diff --git a/src/lr-wpan/model/lr-wpan-fields.h b/src/lr-wpan/model/lr-wpan-fields.h new file mode 100644 index 000000000..1fbc69299 --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-fields.h @@ -0,0 +1,314 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + * + * This file implements Information Fields present in IEEE 802.15.4-2011. + * Information Fields are in practice similar to the Information Elements(IE) + * introduced in later revisions of the standard, however, they lack + * descriptors and common format unlike the IEs. To keep this implementation + * consistent with the IEEE 802.15.4-2011 std. the present file implements + * Information Fields not Information Elements. + */ +#ifndef LR_WPAN_FIELDS_H +#define LR_WPAN_FIELDS_H + + +#include +#include +#include "ns3/buffer.h" +#include + + +namespace ns3 { + +/** + * The device Capabilities. + */ +enum DeviceType +{ + RFD = 0, //!< Reduced Functional Device (RFD) + FFD = 1 //!< Full Functional Device (FFD) +}; + +/** + * \ingroup lr-wpan + * Represent the Superframe Specification information field. + * See IEEE 802.15.4-2011 Section 5.2.2.1.2 Figure 41 + */ +class SuperframeField +{ + +public: + SuperframeField (); + /** + * Set the whole Superframe Specification Information field. + * \param superFrm The Superframe Specification information field. + */ + void SetSuperframe (uint16_t superFrm); + /** + * Set the superframe specification Beacon Order field. + * \param bcnOrder The beacon order value to set in the superframe. + */ + void SetBeaconOrder (uint8_t bcnOrder); + /** + * Set the superframe specification Superframe Order field. + * \param frmOrder The frame Order value to set on the superframe. + */ + void SetSuperframeOrder (uint8_t frmOrder); + /** + * Set the superframe specification Final CAP slot field. + * \param capSlot Set the final slot of the Contention Access Period (CAP). + */ + void SetFinalCapSlot (uint8_t capSlot); + /** + * Set the Superframe Specification Battery Life Extension (BLE). + * \param battLifeExt Sets true or false the value of the Battery Life Extension flag of the superframe field. + */ + void SetBattLifeExt (bool battLifeExt); + /** + * Set the Superframe Specification PAN coordinator field. + * \param panCoor set true or false the value for the PAN Coordinator flag of the superframe field. + */ + void SetPanCoor (bool panCoor); + /** + * Set the Superframe Specification Association Permit field. + * \param assocPermit set true or false the value of the Association Permit flag of the superframe field. + */ + void SetAssocPermit (bool assocPermit); + /** + * Get the Superframe Specification Beacon Order field. + */ + uint8_t GetBeaconOrder (void) const; + /** + * Get the Superframe Specification Frame Order field. + */ + uint8_t GetFrameOrder (void) const; + /** + * Check if the Final CAP Slot bit is enabled. + */ + uint8_t GetFinalCapSlot (void) const; + /** + * Check if the Battery Life Extension bit is enabled. + */ + bool IsBattLifeExt (void) const; + /** + * Check if the PAN Coordinator bit is enabled. + */ + bool IsPanCoor (void) const; + /** + * Check if the Association Permit bit is enabled. + */ + bool IsAssocPermit (void) const; + /** + * Get the Superframe specification information field. + * \return the Superframe Specification Information field bits. + */ + uint16_t GetSuperframe (void) const; + /** + * Get the size of the serialized Superframe specification information field. + * \return the size of the serialized field. + */ + uint32_t GetSerializedSize (void) const; + /** + * Serialize the entire superframe specification field. + * \param i an iterator which points to where the superframe specification field should be written. + * \return an iterator. + */ + Buffer::Iterator Serialize (Buffer::Iterator i) const; + /** + * Deserialize the entire superframe specification field. + * \param i an iterator which points to where the superframe specification field should be read. + * \return an iterator. + */ + Buffer::Iterator Deserialize (Buffer::Iterator i); + + +private: + // Superframe Specification field + // See IEEE 802.14.15-2011 5.2.2.1.2 + uint8_t m_sspecBcnOrder; //!< Superframe Specification field Beacon Order (Bit 0-3) + uint8_t m_sspecSprFrmOrder; //!< Superframe Specification field Superframe Order (Bit 4-7) + uint8_t m_sspecFnlCapSlot; //!< Superframe Specification field Final CAP slot (Bit 8-11) + bool m_sspecBatLifeExt; //!< Superframe Specification field Battery Life Extension (Bit 12) + //!< Superframe Specification field Reserved (not necessary) (Bit 13) + bool m_sspecPanCoor; //!< Superframe Specification field PAN Coordinator (Bit 14) + bool m_sspecAssocPermit; //!< Superframe Specification field Association Permit (Bit 15) + +}; +std::ostream &operator << (std::ostream &os, const SuperframeField &superframeField); + +/** + * \ingroup lr-wpan + * Represent the GTS information fields. + * See IEEE 802.15.4-2011 Section 5.2.2 Figure 39 + */ +class GtsFields +{ + +public: + GtsFields (); + /** + * Get the GTS Specification Field from the GTS Fields + * \return The GTS Spcecification Field + */ + uint8_t GetGtsSpecField (void) const; + /** + * Get the GTS Direction Field from the GTS Fields + * \return The GTS Direction Field + */ + uint8_t GetGtsDirectionField (void) const; + /** + * Set the GTS Specification Field to the GTS Fields + * gtsSpec The GTS Specification Field to set. + */ + void SetGtsSpecField (uint8_t gtsSpec); + /** + * Set the GTS direction field to the GTS Fields + * gtsDir The GTS Direction Field to set + */ + void SetGtsDirectionField (uint8_t gtsDir); + /** + * Get the size of the serialized GTS fields. + * \return the size of the serialized fields. + */ + uint32_t GetSerializedSize (void) const; + /** + * Serialize the entire GTS fields. + * \param i an iterator which points to where the superframe specification field should be written. + * \return an iterator. + */ + Buffer::Iterator Serialize (Buffer::Iterator i) const; + /** + * Deserialize the entire GTS fields. + * \param i an iterator which points to where the superframe specification field should be read. + * \return an iterator. + */ + Buffer::Iterator Deserialize (Buffer::Iterator i); + +private: + //GTS Descriptor + struct gtsDescriptor + { + Mac16Address m_gtsDescDevShortAddr; //!< GTS Descriptor Device Short Address (Bit 0-15) + u_int8_t m_gtsDescStartSlot; //!< GTS Descriptor GTS Starting Slot(Bit 16-19) + u_int8_t m_gtsDescLength; //!< GTS Descriptor GTS Length (Bit 20-23) + }; + + //GTS specification field + u_int8_t m_gtsSpecDescCount; //!< GTS specification field Descriptor Count (Bit 0-2) + //!< GTS specification field Reserved (Not necessary) (Bit 3-6) + u_int8_t m_gtsSpecPermit; //!< GTS specification field GTS Permit (Bit 7) + //GTS Direction field + u_int8_t m_gtsDirMask; //!< GTS Direction field Directions Mask (Bit 0-6) + //!< GTS Direction field Reserved (Not Necessary) (Bit 7) + //GTS List + gtsDescriptor m_gtsList[6]; //!< GTS List field (maximum descriptors stored == 7) +}; +std::ostream &operator << (std::ostream &os, const GtsFields >sFields); + + + +/** + * \ingroup lr-wpan + * Represent the Pending Address Specification field. + * See IEEE 802.15.4-2011 Section 5.2.2.1.6. Figure 45 + */ +class PendingAddrFields +{ + +public: + PendingAddrFields (); + /** + * Add a short Pending Address to the Address List. + * \param shortAddr The extended Pending Address List. + */ + void AddAddress (Mac16Address shortAddr); + /** + * Add a extended Pending Address to the Address List. + * \param extAddr The extended Pending Address List. + */ + void AddAddress (Mac64Address extAddr); + /** + * Search for the short Pending Address in the Address List. + * \param shortAddr The extended Address to look in the Address List. + * \return True if the address exist in the extended Address List. + */ + bool SearchAddress (Mac16Address shortAddr); + /** + * Search for the extended Pending Address in the Address List. + * \param extAddr The extended Address to look in the Address List. + * \return True if the address exist in the extended Address List. + */ + bool SearchAddress (Mac64Address extAddr); + /** + * Get the whole Pending Address Specification Field from the Pending Address Fields. + * \return The Pending Address Specification Field. + */ + uint8_t GetPndAddrSpecField (void) const; + /** + * Get the number of Short Pending Address indicated in the Pending Address Specification Field. + * \return The number Short Pending Address. + */ + uint8_t GetNumShortAddr (void) const; + /** + * Get the number of Extended Pending Address indicated in the Pending Address Specification Field. + * \return The number Short Pending Address. + */ + uint8_t GetNumExtAddr (void) const; + + /** + * Set the whole Pending Address Specification field. This field is part of the + * Pending Address Fields header. + * \param pndAddrSpecField The Pending Address Specification Field + */ + void SetPndAddrSpecField (uint8_t pndAddrSpecField); + /** + * Get the size of the serialized Pending Address Fields. + * \return the size of the serialized fields. + */ + uint32_t GetSerializedSize (void) const; + /** + * Serialize the entire Pending Address Fields. + * \param i an iterator which points to where the Pending Address Fields should be written. + * \return an iterator. + */ + Buffer::Iterator Serialize (Buffer::Iterator i) const; + /** + * Deserialize the all the Pending Address Fields. + * \param start an iterator which points to where the Pending Address Fields should be read. + * \return an iterator. + */ + Buffer::Iterator Deserialize (Buffer::Iterator i); + +private: + // Pending Address Specification Field + uint8_t m_pndAddrSpecNumShortAddr; //!< Pending Address Specification field Number of Short Address (Bits 0-2) + //!< Pending Address Specification field Reserved (Not Necessary)(Bit 3) + uint8_t m_pndAddrSpecNumExtAddr; //!< Pending Address Specification field Number of Extended Address (Bits 4-6) + //!< Pending Address Specification field Reserved (Not Necessary) (Bit 7) + // Address List + std::array m_shortAddrList; //!< Pending Short Address List + std::array m_extAddrList; //!< Pending Extended Address List + +}; +std::ostream &operator << (std::ostream &os, const PendingAddrFields &pendingAddrFields); + + +} //end namespace ns3 + +#endif /* LR_WPAN_FIELDS_H */ diff --git a/src/lr-wpan/model/lr-wpan-mac-header.cc b/src/lr-wpan/model/lr-wpan-mac-header.cc index ec349d2d3..a6747990e 100644 --- a/src/lr-wpan/model/lr-wpan-mac-header.cc +++ b/src/lr-wpan/model/lr-wpan-mac-header.cc @@ -252,31 +252,24 @@ LrWpanMacHeader::GetKeyIdIndex (void) const return(m_auxKeyIdKeyIndex); } - bool LrWpanMacHeader::IsBeacon (void) const { return(m_fctrlFrmType == LRWPAN_MAC_BEACON); } - - bool LrWpanMacHeader::IsData (void) const { return(m_fctrlFrmType == LRWPAN_MAC_DATA); } - - bool LrWpanMacHeader::IsAcknowledgment (void) const { return(m_fctrlFrmType == LRWPAN_MAC_ACKNOWLEDGMENT); } - - bool LrWpanMacHeader::IsCommand (void) const { @@ -787,9 +780,6 @@ LrWpanMacHeader::Deserialize (Buffer::Iterator start) return i.GetDistanceFrom (start); } -// ---------------------------------------------------------------------------------------------------------- - - } //namespace ns3 diff --git a/src/lr-wpan/model/lr-wpan-mac-header.h b/src/lr-wpan/model/lr-wpan-mac-header.h index dd5ee6ec4..04a0ec326 100644 --- a/src/lr-wpan/model/lr-wpan-mac-header.h +++ b/src/lr-wpan/model/lr-wpan-mac-header.h @@ -54,17 +54,16 @@ class LrWpanMacHeader : public Header { public: - /** * The possible MAC types, see IEEE 802.15.4-2006, Table 79. */ enum LrWpanMacType { - LRWPAN_MAC_BEACON = 0, //!< LRWPAN_MAC_BEACON - LRWPAN_MAC_DATA = 1, //!< LRWPAN_MAC_DATA - LRWPAN_MAC_ACKNOWLEDGMENT = 2,//!< LRWPAN_MAC_ACKNOWLEDGMENT - LRWPAN_MAC_COMMAND = 3, //!< LRWPAN_MAC_COMMAND - LRWPAN_MAC_RESERVED //!< LRWPAN_MAC_RESERVED + LRWPAN_MAC_BEACON = 0, //!< LRWPAN_MAC_BEACON + LRWPAN_MAC_DATA = 1, //!< LRWPAN_MAC_DATA + LRWPAN_MAC_ACKNOWLEDGMENT = 2, //!< LRWPAN_MAC_ACKNOWLEDGMENT + LRWPAN_MAC_COMMAND = 3, //!< LRWPAN_MAC_COMMAND + LRWPAN_MAC_RESERVED //!< LRWPAN_MAC_RESERVED }; /** @@ -113,37 +112,31 @@ public: * \return the Frame control field */ uint16_t GetFrameControl (void) const; - /** * Check if Security Enabled bit of Frame Control is enabled * \return true if Security Enabled bit is enabled */ bool IsSecEnable (void) const; - /** * Check if Frame Pending bit of Frame Control is enabled * \return true if Frame Pending bit is enabled */ bool IsFrmPend (void) const; - /** * Check if Ack. Request bit of Frame Control is enabled * \return true if Ack. Request bit is enabled */ bool IsAckReq (void) const; - /** * Check if PAN ID Compression bit of Frame Control is enabled * \return true if PAN ID Compression bit is enabled */ bool IsPanIdComp (void) const; - /** * Get the Reserved bits of Frame control field * \return the Reserved bits */ uint8_t GetFrmCtrlRes (void) const; - /** * Get the Dest. Addressing Mode of Frame control field * \return the Dest. Addressing Mode bits @@ -159,13 +152,11 @@ public: * \return the Source Addressing Mode bits */ uint8_t GetSrcAddrMode (void) const; - /** * Get the frame Sequence number * \return the sequence number */ uint8_t GetSeqNum (void) const; - /** * Get the Destination PAN ID * \return the Destination PAN ID @@ -196,7 +187,6 @@ public: * \return the Source Extended address */ Mac64Address GetExtSrcAddr (void) const; - /** * Get the Auxiliary Security Header - Security Control Octect * \return the Auxiliary Security Header - Security Control Octect @@ -223,7 +213,6 @@ public: * \return the Auxiliary Security Header - Security Control - Reserved bits */ uint8_t GetSecCtrlReserved (void) const; - /** * Get the Auxiliary Security Header - Key Identifier - Key Source (2 Octects) * \return the Auxiliary Security Header - Key Identifier - Key Source (2 Octects) @@ -239,7 +228,6 @@ public: * \return the Auxiliary Security Header - Key Identifier - Key Index */ uint8_t GetKeyIdIndex (void) const; - /** * Returns true if the header is a beacon * \return true if the header is a beacon @@ -260,59 +248,48 @@ public: * \return true if the header is a command */ bool IsCommand (void) const; - /** * Set the Frame Control field "Frame Type" bits * \param wpanMacType the frame type */ void SetType (enum LrWpanMacType wpanMacType); - /** * Set the whole Frame Control field * \param frameControl the Frame Control field */ void SetFrameControl (uint16_t frameControl); - /** * Set the Frame Control field "Security Enabled" bit to true */ void SetSecEnable (void); - /** * Set the Frame Control field "Security Enabled" bit to false */ void SetSecDisable (void); - /** * Set the Frame Control field "Frame Pending" bit to true */ void SetFrmPend (void); - /** * Set the Frame Control field "Frame Pending" bit to false */ void SetNoFrmPend (void); - /** * Set the Frame Control field "Ack. Request" bit to true */ void SetAckReq (void); - /** * Set the Frame Control field "Ack. Request" bit to false */ void SetNoAckReq (void); - /** * Set the Frame Control field "PAN ID Compression" bit to true */ void SetPanIdComp (void); - /** * Set the Frame Control field "PAN ID Compression" bit to false */ void SetNoPanIdComp (void); - /** * Set the Frame Control field "Reserved" bits * \param res reserved bits @@ -333,13 +310,11 @@ public: * \param addrMode Source address mode */ void SetSrcAddrMode (uint8_t addrMode); - /** * Set the Sequence number * \param seqNum sequence number */ void SetSeqNum (uint8_t seqNum); - /* The Source/Destination Addressing fields are only set if SrcAddrMode/DstAddrMode are set */ /** * Set Source address fields @@ -377,7 +352,6 @@ public: * \param frmCntr the "Frame Counter" octect */ void SetFrmCounter (uint32_t frmCntr); - /** * Set the Security Control field "Security Level" bits (3 bits) * \param secLevel the "Security Level" bits @@ -388,13 +362,11 @@ public: * \param keyIdMode the "Key Identifier Mode" bits */ void SetKeyIdMode (uint8_t keyIdMode); - /** * Set the Security Control field "Reserved" bits (3 bits) * \param res the "Reserved" bits */ void SetSecCtrlReserved (uint8_t res); - /* Variable length will be dependent on Key Id Mode*/ /** * Set the Key Index @@ -413,7 +385,6 @@ public: * \param keyIndex the Key index */ void SetKeyId (uint64_t keySrc, uint8_t keyIndex); - /** * \brief Get the type ID. * \return the object TypeId diff --git a/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc b/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc new file mode 100644 index 000000000..be0b4daa6 --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc @@ -0,0 +1,240 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2020 Ritsumeikan University, Shiga, 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 + */ + +#include "lr-wpan-mac-pl-headers.h" +#include + +namespace ns3 { + +/*********************************************************** + * Beacon MAC Payload + ***********************************************************/ + +BeaconPayloadHeader::BeaconPayloadHeader () +{ +} + +NS_OBJECT_ENSURE_REGISTERED (BeaconPayloadHeader); + +TypeId +BeaconPayloadHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::BeaconPayloadHeader") + .SetParent
() + .SetGroupName ("LrWpan") + .AddConstructor () + ; + return tid; +} + +TypeId +BeaconPayloadHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +BeaconPayloadHeader::GetSerializedSize (void) const +{ + uint32_t size = 0; + size += m_superframeField.GetSerializedSize (); + size += m_gtsFields.GetSerializedSize (); + size += m_pndAddrFields.GetSerializedSize (); + + return size; +} + +void +BeaconPayloadHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i = m_superframeField.Serialize (i); + i = m_gtsFields.Serialize (i); + i = m_pndAddrFields.Serialize (i); +} + +uint32_t +BeaconPayloadHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + i = m_superframeField.Deserialize (i); + i = m_gtsFields.Deserialize (i); + i = m_pndAddrFields.Deserialize (i); + + return i.GetDistanceFrom (start); +} + + +void +BeaconPayloadHeader::Print (std::ostream &os) const +{ + os << "| Superframe Spec Field | = " << m_superframeField + << "| GTS Spec Field | = " << m_gtsFields.GetGtsSpecField () + << "| Pending Spec Field| =" << m_pndAddrFields.GetPndAddrSpecField (); +} + + +void +BeaconPayloadHeader::SetSuperframeSpecField (SuperframeField sf) +{ + m_superframeField = sf; +} + +void +BeaconPayloadHeader::SetGtsFields (GtsFields gtsFields) +{ + m_gtsFields = gtsFields; +} + +void +BeaconPayloadHeader::SetPndAddrFields (PendingAddrFields pndAddrFields) +{ + m_pndAddrFields = pndAddrFields; +} + +SuperframeField +BeaconPayloadHeader::GetSuperframeSpecField (void) const +{ + return m_superframeField; +} + +GtsFields +BeaconPayloadHeader::GetGtsFields (void) const +{ + return m_gtsFields; +} + +PendingAddrFields +BeaconPayloadHeader::GetPndAddrFields (void) const +{ + return m_pndAddrFields; +} + + +/*********************************************************** + * Command MAC Payload + ***********************************************************/ + +CommandPayloadHeader::CommandPayloadHeader () +{ + SetCommandFrameType (CMD_RESERVED); +} + + +CommandPayloadHeader::CommandPayloadHeader (enum MacCommand macCmd) +{ + SetCommandFrameType (macCmd); +} + +NS_OBJECT_ENSURE_REGISTERED (CommandPayloadHeader); + +TypeId +CommandPayloadHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::CommandPayloadHeader") + .SetParent
() + .SetGroupName ("LrWpan") + .AddConstructor () + ; + return tid; +} + +TypeId +CommandPayloadHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +CommandPayloadHeader::GetSerializedSize (void) const +{ + uint32_t size = 1; + + return size; +} + +void +CommandPayloadHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_cmdFrameId); +} + +uint32_t +CommandPayloadHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_cmdFrameId = i.ReadU8 (); + + return i.GetDistanceFrom (start); +} + +void +CommandPayloadHeader::Print (std::ostream &os) const +{ + os << "| MAC Command Frame ID | = " << (uint32_t) m_cmdFrameId; +} + +void +CommandPayloadHeader::SetCommandFrameType (MacCommand macCommand) +{ + m_cmdFrameId = macCommand; +} + + +CommandPayloadHeader::MacCommand +CommandPayloadHeader::GetCommandFrameType (void) const +{ + switch (m_cmdFrameId) + { + case 0x01: + return ASSOCIATION_REQ; + break; + case 0x02: + return ASSOCIATION_RESP; + break; + case 0x03: + return DISASSOCIATION_NOTIF; + break; + case 0x04: + return DATA_REQ; + break; + case 0x05: + return PANID_CONFLICT; + break; + case 0x06: + return ORPHAN_NOTIF; + break; + case 0x07: + return BEACON_REQ; + break; + case 0x08: + return COOR_REALIGN; + break; + case 0x09: + return GTS_REQ; + break; + default: + return CMD_RESERVED; + } +} + + +} // ns3 namespace diff --git a/src/lr-wpan/model/lr-wpan-mac-pl-headers.h b/src/lr-wpan/model/lr-wpan-mac-pl-headers.h new file mode 100644 index 000000000..7647083ab --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-mac-pl-headers.h @@ -0,0 +1,165 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + */ + +#ifndef LR_WPAN_MAC_PL_HEADERS_H +#define LR_WPAN_MAC_PL_HEADERS_H + +#include +#include +#include +#include "lr-wpan-fields.h" + + +namespace ns3 { + + + +/** + * \ingroup lr-wpan + * Implements the header for the MAC payload beacon frame according to + * the IEEE 802.15.4-2011 Std. + */ +class BeaconPayloadHeader : public Header +{ + +public: + BeaconPayloadHeader (); + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + TypeId GetInstanceTypeId (void) const; + uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); + void Print (std::ostream &os) const; + /** + * Set the superframe specification field to the beacon payload header. + * \param sfrmField The superframe specification field + */ + void SetSuperframeSpecField (SuperframeField sfrmField); + /** + * Set the superframe Guaranteed Time Slot (GTS) fields to the beacon payload header. + * \param gtsFields The GTS fields. + */ + void SetGtsFields (GtsFields gtsFields); + /** + * Set the superframe Pending Address fields to the beacon payload header. + * \param pndAddrFields The Pending Address fields. + */ + void SetPndAddrFields (PendingAddrFields pndAddrFields); + /** + * Get the superframe specification field from the beacon payload header. + * \return The superframe specification field + */ + SuperframeField GetSuperframeSpecField (void) const; + /** + * Get the Guaranteed Time Slots (GTS) fields from the beacon payload header. + * \return The GTS fields. + */ + GtsFields GetGtsFields (void) const; + /*** + * Get the pending address fields from the beacon payload header. + * \return The Pending Address fields. + */ + PendingAddrFields GetPndAddrFields (void) const; + +private: + /** + * Superframe Specification Field + */ + SuperframeField m_superframeField; + /** + * GTS Fields + */ + GtsFields m_gtsFields; + /** + * Pending Address Fields + */ + PendingAddrFields m_pndAddrFields; + +}; + + +/** + * \ingroup lr-wpan + * Implements the header for the MAC payload command frame according to + * the IEEE 802.15.4-2011 Std. + */ +class CommandPayloadHeader : public Header +{ + +public: + /** + * The MAC command frames. + * See IEEE 802.15.4-2011, Table 5 + */ + enum MacCommand + { + ASSOCIATION_REQ = 0x01, //!< Association request (RFD true: Tx) + ASSOCIATION_RESP = 0x02, //!< Association response (RFD true: Rx) + DISASSOCIATION_NOTIF = 0x03, //!< Disassociation notification (RFD true: TX, Rx) + DATA_REQ = 0x04, //!< Data Request (RFD true: Tx) + PANID_CONFLICT = 0x05, //!< Pan ID conflict notification (RFD true: Tx) + ORPHAN_NOTIF = 0x06, //!< Orphan Notification (RFD true: Tx) + BEACON_REQ = 0x07, //!< Beacon Request (RFD true: none ) + COOR_REALIGN = 0x08, //!< Coordinator Realignment (RFD true: Rx) + GTS_REQ = 0x09, //!< GTS Request (RFD true: none) + CMD_RESERVED = 0xff //!< Reserved + }; + + + CommandPayloadHeader (void); + /** + * Constructor + * \param macCmd the command type of this command header + */ + CommandPayloadHeader (enum MacCommand macCmd); + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + TypeId GetInstanceTypeId (void) const; + uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); + void Print (std::ostream &os) const; + + /** + * Set the command frame type + */ + void SetCommandFrameType (MacCommand macCmd); + /** + * Get the command frame type + */ + MacCommand GetCommandFrameType (void) const; + + +private: + /** The command Frame Identifier*/ + uint8_t m_cmdFrameId; + +}; + +} // namespace ns3 + +#endif /* LR_WPAN_MAC_PL_HEADERS_H */ diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index b81dee668..ecc4e8166 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -21,10 +21,12 @@ * Tom Henderson * Sascha Alexander Jopen * Erwan Livolant + * Alberto Gallegos Ramonet */ #include "lr-wpan-mac.h" #include "lr-wpan-csmaca.h" #include "lr-wpan-mac-header.h" +#include "lr-wpan-mac-pl-headers.h" #include "lr-wpan-mac-trailer.h" #include #include @@ -44,7 +46,13 @@ NS_LOG_COMPONENT_DEFINE ("LrWpanMac"); NS_OBJECT_ENSURE_REGISTERED (LrWpanMac); -const uint32_t LrWpanMac::aMinMPDUOverhead = 9; // Table 85 +//IEEE 802.15.4-2011 Table 51 +const uint32_t LrWpanMac::aMinMPDUOverhead = 9; +const uint32_t LrWpanMac::aBaseSlotDuration = 60; +const uint32_t LrWpanMac::aNumSuperframeSlots = 16; +const uint32_t LrWpanMac::aBaseSuperframeDuration = aBaseSlotDuration * aNumSuperframeSlots; +const uint32_t LrWpanMac::aMaxLostBeacons = 4; +const uint32_t LrWpanMac::aMaxSIFSFrameSize = 18; TypeId LrWpanMac::GetTypeId (void) @@ -115,6 +123,14 @@ LrWpanMac::GetTypeId (void) "The state of LrWpan Mac", MakeTraceSourceAccessor (&LrWpanMac::m_lrWpanMacState), "ns3::TracedValueCallback::LrWpanMacState") + .AddTraceSource ("MacIncSuperframeStatus", + "The period status of the incoming superframe", + MakeTraceSourceAccessor (&LrWpanMac::m_incSuperframeStatus), + "ns3::TracedValueCallback::SuperframeState") + .AddTraceSource ("MacOutSuperframeStatus", + "The period status of the outgoing superframe", + MakeTraceSourceAccessor (&LrWpanMac::m_outSuperframeStatus), + "ns3::TracedValueCallback::SuperframeState") .AddTraceSource ("MacState", "The state of LrWpan Mac", MakeTraceSourceAccessor (&LrWpanMac::m_macStateLogger), @@ -133,10 +149,15 @@ LrWpanMac::LrWpanMac () // First set the state to a known value, call ChangeMacState to fire trace source. m_lrWpanMacState = MAC_IDLE; + ChangeMacState (MAC_IDLE); + m_incSuperframeStatus = INACTIVE; + m_outSuperframeStatus = INACTIVE; + m_macRxOnWhenIdle = true; - m_macPanId = 0; + m_macPanId = 0xffff; + m_deviceCapability = DeviceType::FFD; m_associationStatus = ASSOCIATED; m_selfExt = Mac64Address::Allocate (); m_macPromiscuousMode = false; @@ -144,11 +165,27 @@ LrWpanMac::LrWpanMac () m_retransmission = 0; m_numCsmacaRetry = 0; m_txPkt = 0; + m_ifs = 0; + + m_macLIFSPeriod = 40; + m_macSIFSPeriod = 12; + + m_macBeaconOrder = 15; + m_macSuperframeOrder = 15; + m_macTransactionPersistanceTime = 500; //0x01F5 + m_macAutoRequest = true; + + m_incomingBeaconOrder = 15; + m_incomingSuperframeOrder = 15; + m_beaconTrackingOn = false; + m_numLostBeacons = 0; + Ptr uniformVar = CreateObject (); uniformVar->SetAttribute ("Min", DoubleValue (0.0)); uniformVar->SetAttribute ("Max", DoubleValue (255.0)); m_macDsn = SequenceNumber8 (uniformVar->GetValue ()); + m_macBsn = SequenceNumber8 (uniformVar->GetValue ()); m_shortAddress = Mac16Address ("00:00"); } @@ -190,6 +227,8 @@ LrWpanMac::DoDispose () m_mcpsDataIndicationCallback = MakeNullCallback< void, McpsDataIndicationParams, Ptr > (); m_mcpsDataConfirmCallback = MakeNullCallback< void, McpsDataConfirmParams > (); + m_beaconEvent.Cancel (); + Object::DoDispose (); } @@ -340,10 +379,11 @@ LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr p) } macHdr.SetSecDisable (); - //extract the last 3 bits in TxOptions and map to macHdr + //extract the first 3 bits in TxOptions int b0 = params.m_txOptions & TX_OPTION_ACK; int b1 = params.m_txOptions & TX_OPTION_GTS; int b2 = params.m_txOptions & TX_OPTION_INDIRECT; + if (b0 == TX_OPTION_ACK) { // Set AckReq bit only if the destination is not the broadcast address. @@ -352,111 +392,533 @@ LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr p) macHdr.SetAckReq (); } } - else if (b0 == 0) + else { macHdr.SetNoAckReq (); } - else - { - confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER; - NS_LOG_ERROR (this << "Incorrect TxOptions bit 0 not 0/1"); - if (!m_mcpsDataConfirmCallback.IsNull ()) - { - m_mcpsDataConfirmCallback (confirmParams); - } - return; - } - //if is Slotted CSMA means its beacon enabled - if (m_csmaCa->IsSlottedCsmaCa ()) + + if (b1 == TX_OPTION_GTS) { - if (b1 == TX_OPTION_GTS) + //TODO:GTS Transmission + } + else if (b2 == TX_OPTION_INDIRECT) + { + // Indirect Tx + // A COORDINATOR will save the packet in the pending queue and await for data + // requests from its associated devices. The devices are aware of pending data, + // from the pending bit information extracted from the received beacon. + // A DEVICE must be tracking beacons (MLME-SYNC.request is running) before attempting + // request data from the coordinator. + + + //TODO: Check if the current device is coordinator or PAN coordinator + p->AddHeader (macHdr); + + LrWpanMacTrailer macTrailer; + // Calculate FCS if the global attribute ChecksumEnable is set. + if (Node::ChecksumEnabled ()) { - //TODO:GTS Transmission + macTrailer.EnableFcs (true); + macTrailer.SetFcs (p); } - else if (b1 == 0) + p->AddTrailer (macTrailer); + + if (m_txQueue.size () == m_txQueue.max_size ()) { - //TODO:CAP Transmission + confirmParams.m_status = IEEE_802_15_4_TRANSACTION_OVERFLOW; + if (!m_mcpsDataConfirmCallback.IsNull ()) + { + m_mcpsDataConfirmCallback (confirmParams); + } } else { - NS_LOG_ERROR (this << "Incorrect TxOptions bit 1 not 0/1"); - confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER; - if (!m_mcpsDataConfirmCallback.IsNull ()) + IndTxQueueElement *indTxQElement = new IndTxQueueElement; + uint64_t unitPeriodSymbols; + Time expireTime; + + if (m_macBeaconOrder == 15) { - m_mcpsDataConfirmCallback (confirmParams); + unitPeriodSymbols = aBaseSuperframeDuration; } - return; + else + { + unitPeriodSymbols = ((uint64_t) 1 << m_macBeaconOrder) * aBaseSuperframeDuration; + } + + //TODO: check possible incorrect expire time here. + + expireTime = MicroSeconds (Simulator::Now () + m_macTransactionPersistanceTime * + unitPeriodSymbols * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); + indTxQElement->expireTime = expireTime; + indTxQElement->txQMsduHandle = params.m_msduHandle; + indTxQElement->txQPkt = p; + + m_indTxQueue.push_back (indTxQElement); + + std::cout << "Indirect Transmission Pushed | Elements in the queue: " << m_indTxQueue.size () + << " " << "Element to expire in: " << expireTime.GetSeconds () << "secs\n"; } } else { - if (b1 != 0) + // Direct Tx + // From this point the packet will be pushed to a Tx queue and immediately + // use a slotted (beacon-enabled) or unslotted (nonbeacon-enabled) version of CSMA/CA + // before sending the packet, depending on whether it has previously + // received a valid beacon or not. + + p->AddHeader (macHdr); + + LrWpanMacTrailer macTrailer; + // Calculate FCS if the global attribute ChecksumEnable is set. + if (Node::ChecksumEnabled ()) { - NS_LOG_ERROR (this << "for non-beacon-enables PAN, bit 1 should always be set to 0"); - confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER; - if (!m_mcpsDataConfirmCallback.IsNull ()) - { - m_mcpsDataConfirmCallback (confirmParams); - } - return; + macTrailer.EnableFcs (true); + macTrailer.SetFcs (p); } + p->AddTrailer (macTrailer); + + m_macTxEnqueueTrace (p); + + TxQueueElement *txQElement = new TxQueueElement; + txQElement->txQMsduHandle = params.m_msduHandle; + txQElement->txQPkt = p; + m_txQueue.push_back (txQElement); + CheckQueue (); } - if (b2 == TX_OPTION_INDIRECT) +} + + +void +LrWpanMac::MlmeStartRequest (MlmeStartRequestParams params) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (m_deviceCapability == DeviceType::FFD); + + MlmeStartConfirmParams confirmParams; + + + if (GetShortAddress () == Mac16Address ("ff:ff")) { - //TODO :indirect tx - } - else if (b2 == 0) - { - //TODO :direct tx - } - else - { - NS_LOG_ERROR (this << "Incorrect TxOptions bit 2 not 0/1"); - confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER; - if (!m_mcpsDataConfirmCallback.IsNull ()) + NS_LOG_ERROR (this << " Invalid MAC short address" ); + confirmParams.m_status = MLMESTART_NO_SHORT_ADDRESS; + if (!m_mlmeStartConfirmCallback.IsNull ()) { - m_mcpsDataConfirmCallback (confirmParams); + m_mlmeStartConfirmCallback (confirmParams); } return; } - p->AddHeader (macHdr); + if ( (params.m_logCh > 26) + || (params.m_bcnOrd > 15) + || (params.m_sfrmOrd > params.m_bcnOrd)) + { + NS_LOG_ERROR (this << " One or more parameters are invalid" ); + confirmParams.m_status = MLMESTART_INVALID_PARAMETER; + if (!m_mlmeStartConfirmCallback.IsNull ()) + { + m_mlmeStartConfirmCallback (confirmParams); + } + return; + } + + + if (params.m_coorRealgn) //Coordinator Realignment + { + // TODO:: Send realignment request command frame in CSMA/CA + return; + } + else + { + if (params.m_panCoor) + { + m_panCoor = true; + m_macPanId = params.m_PanId; + + // Setting Channel and Page in the LrWpanPhy + LrWpanPhyPibAttributes pibAttr; + pibAttr.phyCurrentChannel = params.m_logCh; + pibAttr.phyCurrentPage = params.m_logChPage; + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentChannel,&pibAttr); + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentPage,&pibAttr); + } + + NS_ASSERT (params.m_PanId != 0xffff); + + + m_macBeaconOrder = params.m_bcnOrd; + if (m_macBeaconOrder == 15) + { + //Non-beacon enabled PAN + m_macSuperframeOrder = 15; + m_beaconInterval = 0; + m_csmaCa->SetUnSlottedCsmaCa (); + + confirmParams.m_status = MLMESTART_SUCCESS; + if (!m_mlmeStartConfirmCallback.IsNull ()) + { + m_mlmeStartConfirmCallback (confirmParams); + } + } + else + { + m_macSuperframeOrder = params.m_sfrmOrd; + m_csmaCa->SetBatteryLifeExtension (params.m_battLifeExt); + + m_csmaCa->SetSlottedCsmaCa (); + + //TODO: Calculate the real Final CAP slot (requires GTS implementation) + // FinalCapSlot = Superframe duration slots - CFP slots. + // In the current implementation the value of the final cap slot is equal to + // the total number of possible slots in the superframe (15). + m_fnlCapSlot = 15; + + m_beaconInterval = ((uint32_t) 1 << m_macBeaconOrder) * aBaseSuperframeDuration; + m_superframeDuration = ((uint32_t) 1 << m_macSuperframeOrder) * aBaseSuperframeDuration; + + //TODO: change the beacon sending according to the startTime parameter (if not PAN coordinator) + + m_capEvent = Simulator::ScheduleNow (&LrWpanMac::StartCAP, this, SuperframeType::OUTGOING); + } + } +} + + +void +LrWpanMac::MlmeSyncRequest (MlmeSyncRequestParams params) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (params.m_logCh <= 26 && m_macPanId != 0xffff); + + //change phy current logical channel + LrWpanPhyPibAttributes pibAttr; + pibAttr.phyCurrentChannel = params.m_logCh; + m_phy->PlmeSetAttributeRequest (LrWpanPibAttributeIdentifier::phyCurrentChannel,&pibAttr); + + //Enable Phy receiver + m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_RX_ON); + + uint64_t searchSymbols; + Time searchBeaconTime; + + if (m_trackingEvent.IsRunning ()) + { + m_trackingEvent.Cancel (); + } + + if (params.m_trackBcn) + { + m_numLostBeacons = 0; + //search for a beacon for a time = incomingSuperframe symbols + 960 symbols + searchSymbols = ((uint64_t) 1 << m_incomingBeaconOrder) + 1 * aBaseSuperframeDuration; + searchBeaconTime = MicroSeconds (searchSymbols * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); + m_beaconTrackingOn = true; + m_trackingEvent = Simulator::Schedule (searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this); + } + else + { + m_beaconTrackingOn = false; + } + +} + + +void +LrWpanMac::MlmePollRequest (MlmePollRequestParams params) +{ + NS_LOG_FUNCTION (this); + + + LrWpanMacHeader macHdr (LrWpanMacHeader::LRWPAN_MAC_COMMAND, m_macBsn.GetValue ()); + m_macBsn++; + + CommandPayloadHeader macPayload (CommandPayloadHeader::DATA_REQ); + + Ptr beaconPacket = Create (); + + +} + + +void +LrWpanMac::SendOneBeacon () +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (m_lrWpanMacState == MAC_IDLE); + + LrWpanMacHeader macHdr (LrWpanMacHeader::LRWPAN_MAC_BEACON, m_macBsn.GetValue ()); + m_macBsn++; + BeaconPayloadHeader macPayload; + Ptr beaconPacket = Create (); LrWpanMacTrailer macTrailer; + + macHdr.SetDstAddrMode (LrWpanMacHeader::SHORTADDR); + macHdr.SetDstAddrFields (GetPanId (),Mac16Address ("ff:ff")); + + //see IEEE 802.15.4-2011 Section 5.1.2.4 + if (GetShortAddress () == Mac16Address ("ff:fe")) + { + macHdr.SetSrcAddrMode (LrWpanMacHeader::EXTADDR); + macHdr.SetSrcAddrFields (GetPanId (),GetExtendedAddress ()); + } + else + { + macHdr.SetSrcAddrMode (LrWpanMacHeader::SHORTADDR); + macHdr.SetSrcAddrFields (GetPanId (), GetShortAddress ()); + } + + + macHdr.SetSecDisable (); + macHdr.SetNoAckReq (); + + + macPayload.SetSuperframeSpecField (GetSuperframeField ()); + macPayload.SetGtsFields (GetGtsFields ()); + macPayload.SetPndAddrFields (GetPendingAddrFields ()); + + + + beaconPacket->AddHeader (macPayload); + beaconPacket->AddHeader (macHdr); + + // Calculate FCS if the global attribute ChecksumEnable is set. if (Node::ChecksumEnabled ()) { macTrailer.EnableFcs (true); - macTrailer.SetFcs (p); + macTrailer.SetFcs (beaconPacket); } - p->AddTrailer (macTrailer); - m_macTxEnqueueTrace (p); + beaconPacket->AddTrailer (macTrailer); - TxQueueElement *txQElement = new TxQueueElement; - txQElement->txQMsduHandle = params.m_msduHandle; - txQElement->txQPkt = p; - m_txQueue.push_back (txQElement); + //Set the Beacon packet to be transmitted + m_txPkt = beaconPacket; + + //The beacon transmission time in symbols. + m_macBeaconTxTime = Simulator::Now ().GetSeconds () * m_phy->GetDataOrSymbolRate (false); + + + ChangeMacState (MAC_SENDING); + m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_TX_ON); + +} + + +void +LrWpanMac::StartCAP (SuperframeType superframeType) +{ + uint32_t activeSlot; + uint32_t capDuration; + Time capTime; + + if (superframeType == OUTGOING) + { + m_outSuperframeStatus = CAP; + activeSlot = m_superframeDuration / 16; + capDuration = activeSlot * (m_fnlCapSlot + 1); + capTime = Seconds (capDuration / m_phy->GetDataOrSymbolRate (false)); + NS_LOG_DEBUG ("Outgoing superframe CAP duration " << capDuration << " symbols (" << capTime.GetSeconds () << " s)"); + NS_LOG_DEBUG ("Active Slots duration " << activeSlot << " symbols"); + + m_capEvent = Simulator::Schedule (MicroSeconds (capTime.GetMicroSeconds ()), + &LrWpanMac::StartCFP, this, SuperframeType::OUTGOING); + + m_beaconEvent = Simulator::ScheduleNow (&LrWpanMac::SendOneBeacon, this); + } + else + { + m_incSuperframeStatus = CAP; + activeSlot = m_incomingSuperframeDuration / 16; + capDuration = activeSlot * (m_incomingFnlCapSlot + 1); + capTime = Seconds (capDuration / m_phy->GetDataOrSymbolRate (false)); + + NS_LOG_DEBUG ("Incoming superframe CAP duration " << capDuration << " symbols (" << capTime.GetSeconds () << " s)"); + NS_LOG_DEBUG ("Active Slots duration " << activeSlot << " symbols"); + + m_capEvent = Simulator::Schedule (MicroSeconds (capTime.GetMicroSeconds ()), + &LrWpanMac::StartCFP, this, SuperframeType::INCOMING); + } CheckQueue (); + } + +void +LrWpanMac::StartCFP (SuperframeType superframeType) +{ + uint32_t activeSlot; + uint32_t cfpDuration; + Time cfpTime; + + if (superframeType == INCOMING) + { + activeSlot = m_incomingSuperframeDuration / 16; + cfpDuration = activeSlot * (15 - m_incomingFnlCapSlot); + cfpTime = Seconds (cfpDuration / m_phy->GetDataOrSymbolRate (false)); + if (cfpDuration > 0) + { + m_incSuperframeStatus = CFP; + } + + NS_LOG_DEBUG ("Incoming superframe CFP duration " << cfpDuration << " symbols (" << cfpTime.GetSeconds () << " s)"); + + m_incCfpEvent = Simulator::Schedule (MicroSeconds (cfpTime.GetMicroSeconds ()), + &LrWpanMac::StartInactivePeriod, this, SuperframeType::INCOMING); + } + else + { + activeSlot = m_superframeDuration / 16; + cfpDuration = activeSlot * (15 - m_fnlCapSlot); + cfpTime = Seconds (cfpDuration / m_phy->GetDataOrSymbolRate (false)); + + if (cfpDuration > 0) + { + m_outSuperframeStatus = CFP; + } + + NS_LOG_DEBUG ("Outgoing superframe CFP duration " << cfpDuration << " symbols (" << cfpTime.GetSeconds () << " s)"); + + m_cfpEvent = Simulator::Schedule (MicroSeconds (cfpTime.GetMicroSeconds ()), + &LrWpanMac::StartInactivePeriod, this, SuperframeType::OUTGOING); + + } + //TODO: Start transmit or receive GTS here. +} + + +void +LrWpanMac::StartInactivePeriod (SuperframeType superframeType) +{ + uint32_t inactiveDuration; + Time inactiveTime; + + if (superframeType == INCOMING) + { + inactiveDuration = m_incomingBeaconInterval - m_incomingSuperframeDuration; + inactiveTime = Seconds (inactiveDuration / m_phy->GetDataOrSymbolRate (false)); + + if (inactiveDuration > 0) + { + m_incSuperframeStatus = INACTIVE; + } + + NS_LOG_DEBUG ("Incoming superframe Inactive duration " << inactiveDuration << " symbols (" << inactiveTime.GetSeconds () << " s)"); + } + else + { + inactiveDuration = m_beaconInterval - m_superframeDuration; + inactiveTime = Seconds (inactiveDuration / m_phy->GetDataOrSymbolRate (false)); + + if (inactiveDuration > 0) + { + m_outSuperframeStatus = INACTIVE; + } + + NS_LOG_DEBUG ("Outgoing superframe Inactive duration " << inactiveDuration << " symbols (" << inactiveTime.GetSeconds () << " s)"); + m_capEvent = Simulator::Schedule (MicroSeconds (inactiveTime.GetMicroSeconds ()), + &LrWpanMac::StartCAP, this, SuperframeType::OUTGOING); + } +} + + + +void +LrWpanMac::BeaconSearchTimeout (void) +{ + if (m_numLostBeacons > aMaxLostBeacons) + { + MlmeSyncLossIndicationParams syncLossParams; + //syncLossParams.m_logCh = + syncLossParams.m_lossReason = MLMESYNCLOSS_BEACON_LOST; + syncLossParams.m_panId = m_macPanId; + m_mlmeSyncLossIndicationCallback (syncLossParams); + + m_beaconTrackingOn = false; + m_numLostBeacons = 0; + } + else + { + m_numLostBeacons++; + + //Search for one more beacon + uint64_t searchSymbols; + Time searchBeaconTime; + searchSymbols = ((uint64_t) 1 << m_incomingBeaconOrder) + 1 * aBaseSuperframeDuration; + searchBeaconTime = MicroSeconds (searchSymbols * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); + m_trackingEvent = Simulator::Schedule (searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this); + + } +} + + void LrWpanMac::CheckQueue () { NS_LOG_FUNCTION (this); - - // Pull a packet from the queue and start sending, if we are not already sending. + // Pull a packet from the queue and start sending if we are not already sending. if (m_lrWpanMacState == MAC_IDLE && !m_txQueue.empty () && m_txPkt == 0 && !m_setMacState.IsRunning ()) { TxQueueElement *txQElement = m_txQueue.front (); m_txPkt = txQElement->txQPkt; - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + //TODO: this should check if the node is a coordinator and using the outcoming superframe not just the PAN coordinator + if (m_csmaCa->IsUnSlottedCsmaCa () || (m_outSuperframeStatus == CAP && m_panCoor) || m_incSuperframeStatus == CAP) + { + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + } } } + +SuperframeField +LrWpanMac::GetSuperframeField () +{ + SuperframeField sfrmSpec; + + sfrmSpec.SetBeaconOrder (m_macBeaconOrder); + sfrmSpec.SetSuperframeOrder (m_macSuperframeOrder); + sfrmSpec.SetFinalCapSlot (m_fnlCapSlot); + + if (m_csmaCa->GetBatteryLifeExtension ()) + { + sfrmSpec.SetBattLifeExt (true); + } + + if (m_panCoor) + { + sfrmSpec.SetPanCoor (true); + } + //TODO: It is possible to do association using Beacons, + // however, the current implementation only support manual association. + // The association permit should be set here. + + return sfrmSpec; +} + +GtsFields +LrWpanMac::GetGtsFields () +{ + GtsFields gtsFields; + + // TODO: Logic to populate the GTS Fields from local information here + + return gtsFields; +} + +PendingAddrFields +LrWpanMac::GetPendingAddrFields () +{ + PendingAddrFields pndAddrFields; + + // TODO: Logic to populate the Pending Address Fields from local information here + return pndAddrFields; +} + + void LrWpanMac::SetCsmaCa (Ptr csmaCa) { @@ -487,11 +949,34 @@ LrWpanMac::SetMcpsDataConfirmCallback (McpsDataConfirmCallback c) m_mcpsDataConfirmCallback = c; } +void +LrWpanMac::SetMlmeStartConfirmCallback (MlmeStartConfirmCallback c) +{ + m_mlmeStartConfirmCallback = c; +} + +void +LrWpanMac::SetMlmeBeaconNotifyIndicationCallback (MlmeBeaconNotifyIndicationCallback c) +{ + m_mlmeBeaconNotifyIndicationCallback = c; +} + +void +LrWpanMac::SetMlmeSyncLossIndicationCallback (MlmeSyncLossIndicationCallback c) +{ + m_mlmeSyncLossIndicationCallback = c; +} + +void +LrWpanMac::SetMlmePollConfirmCallback (MlmePollConfirmCallback c) +{ + m_mlmePollConfirmCallback = c; +} + void LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) { NS_ASSERT (m_lrWpanMacState == MAC_IDLE || m_lrWpanMacState == MAC_ACK_PENDING || m_lrWpanMacState == MAC_CSMA); - NS_LOG_FUNCTION (this << psduLength << p << (uint16_t)lqi); bool acceptFrame; @@ -567,6 +1052,8 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) if (m_macPromiscuousMode) { //level 2 filtering + //TODO: Fix here, this should trigger different Indication Callbacks + //depending the type of frame received (data,command, beacon) if (!m_mcpsDataIndicationCallback.IsNull ()) { NS_LOG_DEBUG ("promiscuous mode, forwarding up"); @@ -574,7 +1061,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) } else { - NS_LOG_ERROR (this << " Data Indication Callback not initialised"); + NS_LOG_ERROR (this << " Data Indication Callback not initialized"); } } else @@ -595,7 +1082,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) } if (acceptFrame - && (receivedMacHdr.GetDstAddrMode () == 2)) + && (receivedMacHdr.GetDstAddrMode () == SHORT_ADDR)) { if (receivedMacHdr.GetShortDstAddr () == m_shortAddress) { @@ -620,7 +1107,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) } if (acceptFrame - && (receivedMacHdr.GetDstAddrMode () == 3)) + && (receivedMacHdr.GetDstAddrMode () == EXT_ADDR)) { acceptFrame = (receivedMacHdr.GetExtDstAddr () == m_selfExt); } @@ -644,7 +1131,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) || (receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_COMMAND)) && (receivedMacHdr.GetSrcAddrMode () > 1)) { - acceptFrame = receivedMacHdr.GetSrcPanId () == m_macPanId; // \todo need to check if PAN coord + acceptFrame = receivedMacHdr.GetSrcPanId () == m_macPanId; // TODO: need to check if PAN coord } if (acceptFrame) @@ -678,10 +1165,121 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) // Cancel any pending MAC state change, ACKs have higher priority. m_setMacState.Cancel (); ChangeMacState (MAC_IDLE); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SendAck, this, receivedMacHdr.GetSeqNum ()); } - if (receivedMacHdr.IsData () && !m_mcpsDataIndicationCallback.IsNull ()) + if (receivedMacHdr.IsBeacon ()) + { + NS_LOG_DEBUG ("Beacon received"); + + //TODO: Handle mlme-scan.request here + + // The Rx time of the beacon in symbols + m_beaconRxTime = Simulator::Now ().GetSeconds () * m_phy->GetDataOrSymbolRate (false); + + + // Device not associated. + if (m_macPanId == 0xffff) + { + //TODO: mlme-associate.request here. + NS_LOG_ERROR (this << "The current device is not associated to any coordinator"); + return; + } + + + if (m_macPanId != receivedMacHdr.GetDstPanId ()) + { + return; + } + + BeaconPayloadHeader receivedMacPayload; + p->RemoveHeader (receivedMacPayload); + + SuperframeField incomingSuperframe; + incomingSuperframe = receivedMacPayload.GetSuperframeSpecField (); + + m_incomingBeaconOrder = incomingSuperframe.GetBeaconOrder (); + m_incomingSuperframeOrder = incomingSuperframe.GetFrameOrder (); + m_incomingFnlCapSlot = incomingSuperframe.GetFinalCapSlot (); + + m_incomingBeaconInterval = ((uint32_t) 1 << m_incomingBeaconOrder) * aBaseSuperframeDuration; + m_incomingSuperframeDuration = aBaseSuperframeDuration * ((uint32_t) 1 << m_incomingSuperframeOrder); + + if (incomingSuperframe.IsBattLifeExt ()) + { + m_csmaCa->SetBatteryLifeExtension (true); + } + else + { + m_csmaCa->SetBatteryLifeExtension (false); + } + + + + if (m_incomingBeaconOrder < 15 && !m_csmaCa->IsSlottedCsmaCa ()) + { + m_csmaCa->SetSlottedCsmaCa (); + } + + + + //TODO: get Incoming frame GTS Fields here + + + //Begin CAP on the current device using info from the Incoming superframe + m_incCapEvent = Simulator::ScheduleNow (&LrWpanMac::StartCAP, this,SuperframeType::INCOMING); + + + // Send a Beacon notification only if we are not + // automatically sending data command requests or the beacon contains + // a beacon payload in its MAC payload. + // see IEEE 802.15.4-2011 Section 6.2.4.1 + if ((m_macAutoRequest == false) || p->GetSize () > 0) + { + //TODO: Add the rest of the MlmeBeaconNotifyIndication params + if (!m_mlmeBeaconNotifyIndicationCallback.IsNull ()) + { + MlmeBeaconNotifyIndicationParams beaconParams; + beaconParams.m_bsn = receivedMacHdr.GetSeqNum (); + m_mlmeBeaconNotifyIndicationCallback (beaconParams,originalPkt); + } + } + + if (m_macAutoRequest) + { + // check if MLME-SYNC.request was previously issued and running + // Sync. is necessary to handle pending messages (indirect transmissions) + if (m_trackingEvent.IsRunning ()) + { + m_trackingEvent.Cancel (); + m_numLostBeacons = 0; + + if (m_beaconTrackingOn) + { + //if tracking option is on keep tracking the next beacon + uint64_t searchSymbols; + Time searchBeaconTime; + + searchSymbols = ((uint64_t) 1 << m_incomingBeaconOrder) + 1 * aBaseSuperframeDuration; + searchBeaconTime = MicroSeconds (searchSymbols * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); + m_trackingEvent = Simulator::Schedule (searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this); + } + + PendingAddrFields pndAddrFields; + pndAddrFields = receivedMacPayload.GetPndAddrFields (); + + //TODO: Ignore pending request if the address is in the GTS list. + // If the address is not in the GTS list, then check if the address + // is in the short address pending list or in the extended address + // pending list. + + + + } + } + } + else if (receivedMacHdr.IsData () && !m_mcpsDataIndicationCallback.IsNull ()) { // If it is a data frame, push it up the stack. NS_LOG_DEBUG ("PdDataIndication(): Packet is for me; forwarding up"); @@ -690,6 +1288,7 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) else if (receivedMacHdr.IsAcknowledgment () && m_txPkt && m_lrWpanMacState == MAC_ACK_PENDING) { LrWpanMacHeader macHdr; + Time ifsWaitTime = MicroSeconds (GetIfsSize () * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); m_txPkt->PeekHeader (macHdr); if (receivedMacHdr.GetSeqNum () == macHdr.GetSeqNum ()) { @@ -706,8 +1305,9 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) m_mcpsDataConfirmCallback (confirmParams); } RemoveFirstTxQElement (); - m_setMacState.Cancel (); - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + + // Ack was succesfully received, wait for the Interframe Space (IFS) and then proceed + m_ifsEvent = Simulator::Schedule (ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this); } else { @@ -734,6 +1334,8 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) } } + + void LrWpanMac::SendAck (uint8_t seqno) { @@ -761,6 +1363,7 @@ LrWpanMac::SendAck (uint8_t seqno) // Switch transceiver to TX mode. Proceed sending the Ack on confirm. ChangeMacState (MAC_SENDING); m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_TX_ON); + } void @@ -805,6 +1408,15 @@ LrWpanMac::AckWaitTimeout (void) } } +void +LrWpanMac::IfsWaitTimeout (void) +{ + NS_LOG_DEBUG ("MESSAGE SENT and IFS APPLIED"); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); +} + + bool LrWpanMac::PrepareRetransmission (void) { @@ -839,18 +1451,30 @@ void LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) { NS_ASSERT (m_lrWpanMacState == MAC_SENDING); - NS_LOG_FUNCTION (this << status << m_txQueue.size ()); LrWpanMacHeader macHdr; + Time ifsWaitTime; + m_txPkt->PeekHeader (macHdr); + if (status == IEEE_802_15_4_PHY_SUCCESS) { if (!macHdr.IsAcknowledgment ()) { - // We have just send a regular data packet, check if we have to wait - // for an ACK. - if (macHdr.IsAckReq ()) + if (macHdr.IsBeacon ()) + { + Time ifsWaitTime = MicroSeconds (GetIfsSize () * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); + m_txPkt = 0; + NS_LOG_DEBUG ("Beacon Sent"); + MlmeStartConfirmParams mlmeConfirmParams; + mlmeConfirmParams.m_status = MLMESTART_SUCCESS; + if (!m_mlmeStartConfirmCallback.IsNull ()) + { + m_mlmeStartConfirmCallback (mlmeConfirmParams); + } + } + else if (macHdr.IsAckReq ()) // We have sent a regular data packet, check if we have to wait for an ACK. { // wait for the ack or the next retransmission timeout // start retransmission timer @@ -874,6 +1498,7 @@ LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) confirmParams.m_status = IEEE_802_15_4_SUCCESS; m_mcpsDataConfirmCallback (confirmParams); } + ifsWaitTime = MicroSeconds (GetIfsSize () * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); RemoveFirstTxQElement (); } } @@ -912,8 +1537,17 @@ LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) NS_FATAL_ERROR ("Transmission attempt failed with PHY status " << status); } - m_setMacState.Cancel (); - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + + if (!ifsWaitTime.IsZero ()) + { + m_ifsEvent = Simulator::Schedule (ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this); + } + else + { + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + } + } void @@ -1039,9 +1673,14 @@ LrWpanMac::SetLrWpanMacState (LrWpanMacState macState) } // remove the copy of the packet that was just sent RemoveFirstTxQElement (); - ChangeMacState (MAC_IDLE); } + else if (m_lrWpanMacState == MAC_CSMA && macState == MAC_CSMA_DEFERRED) + { + ChangeMacState (MAC_IDLE); + m_txPkt = 0; + std::cout << "THIS PACKET WAS DEFERRED! macstate " << m_lrWpanMacState << "\n"; + } } LrWpanAssociationStatus @@ -1097,4 +1736,73 @@ LrWpanMac::SetMacMaxFrameRetries (uint8_t retries) m_macMaxFrameRetries = retries; } +bool +LrWpanMac::isCoordDest (void) +{ + NS_ASSERT (m_txPkt); + LrWpanMacHeader macHdr; + m_txPkt->PeekHeader (macHdr); + + if (m_macCoordShortAddress == macHdr.GetShortDstAddr () + || m_macCoordExtendedAddress == macHdr.GetExtDstAddr ()) + { + return true; + } + else + { + std::cout << "ERROR: Packet not for the coordinator!\n"; + return false; + + } + +} + +uint32_t +LrWpanMac::GetIfsSize () +{ + NS_ASSERT (m_txPkt); + + if (m_txPkt->GetSize () <= aMaxSIFSFrameSize) + { + return m_macSIFSPeriod; + } + else + { + return m_macLIFSPeriod; + } +} + +void +LrWpanMac::SetAssociatedCoor (Mac16Address mac) +{ + m_macCoordShortAddress = mac; +} + +void +LrWpanMac::SetAssociatedCoor (Mac64Address mac) +{ + m_macCoordExtendedAddress = mac; +} + + +uint64_t +LrWpanMac::GetTxPacketSymbols (void) +{ + NS_ASSERT (m_txPkt); + // Sync Header (SHR) + 8 bits PHY header (PHR) + PSDU + return (m_phy->GetPhySHRDuration () + 1 * m_phy->GetPhySymbolsPerOctet () + + (m_txPkt->GetSize () * m_phy->GetPhySymbolsPerOctet ())); +} + +bool +LrWpanMac::isTxAckReq (void) +{ + NS_ASSERT (m_txPkt); + LrWpanMacHeader macHdr; + m_txPkt->PeekHeader (macHdr); + + return macHdr.IsAckReq (); +} + } // namespace ns3 + diff --git a/src/lr-wpan/model/lr-wpan-mac.h b/src/lr-wpan/model/lr-wpan-mac.h index 63e95176c..2f467e31c 100644 --- a/src/lr-wpan/model/lr-wpan-mac.h +++ b/src/lr-wpan/model/lr-wpan-mac.h @@ -20,6 +20,7 @@ * kwong yin * Tom Henderson * Sascha Alexander Jopen + * Alberto Gallegos Ramonet */ #ifndef LR_WPAN_MAC_H #define LR_WPAN_MAC_H @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -70,11 +72,38 @@ typedef enum MAC_CSMA, //!< MAC_CSMA MAC_SENDING, //!< MAC_SENDING MAC_ACK_PENDING, //!< MAC_ACK_PENDING - CHANNEL_ACCESS_FAILURE,//!< CHANNEL_ACCESS_FAILURE + CHANNEL_ACCESS_FAILURE, //!< CHANNEL_ACCESS_FAILURE CHANNEL_IDLE, //!< CHANNEL_IDLE - SET_PHY_TX_ON //!< SET_PHY_TX_ON + SET_PHY_TX_ON, //!< SET_PHY_TX_ON + MAC_GTS, //!< MAC_GTS + MAC_INACTIVE, //!< MAC_INACTIVE + MAC_CSMA_DEFERRED //!< MAC_CSMA_DEFERRED } LrWpanMacState; +/** + * \ingroup lr-wpan + * + * Superframe status + */ +typedef enum +{ + CAP, //!< Contention Access Period + CFP, //!< Contention Free Period + INACTIVE //!< Inactive Period or unslotted CSMA-CA +} SuperframeStatus; + +/** + * \ingroup lr-wpan + * + * Superframe type + */ +typedef enum +{ + OUTGOING = 0, //!< Outgoing Superframe + INCOMING = 1 //!< Incoming Superframe +} SuperframeType; + + namespace TracedValueCallback { /** @@ -84,8 +113,18 @@ namespace TracedValueCallback { * \param [in] oldValue original value of the traced variable * \param [in] newValue new value of the traced variable */ - typedef void (* LrWpanMacState)(LrWpanMacState oldValue, - LrWpanMacState newValue); +typedef void (*LrWpanMacState)(LrWpanMacState oldValue, + LrWpanMacState newValue); + +/** + * \ingroup lr-wpan + * TracedValue callback signature for SuperframeStatus. + * + * \param [in] oldValue original value of the traced variable + * \param [in] newValue new value of the traced variable + */ +typedef void (*SuperframeStatus)(SuperframeStatus oldValue, + SuperframeStatus newValue); } // namespace TracedValueCallback @@ -137,6 +176,56 @@ typedef enum IEEE_802_15_4_INVALID_PARAMETER = 11 } LrWpanMcpsDataConfirmStatus; +/** + * \ingroup lr-wpan + * + * Table 35 of IEEE 802.15.4-2011 + */ +typedef enum +{ + MLMESTART_SUCCESS = 0, + MLMESTART_NO_SHORT_ADDRESS = 1, + MLMESTART_SUPERFRAME_OVERLAP = 2, + MLMESTART_TRACKING_OFF = 3, + MLMESTART_INVALID_PARAMETER = 4, + MLMESTART_COUNTER_ERROR = 5, + MLMESTART_FRAME_TOO_LONG = 6, + MLMESTART_UNAVAILABLE_KEY = 7, + MLMESTART_UNSUPPORTED_SECURITY = 8, + MLMESTART_CHANNEL_ACCESS_FAILURE = 9 +} LrWpanMlmeStartConfirmStatus; + +/** + * \ingroup lr-wpan + * + * Table 37 of IEEE 802.15.4-2011 + */ +typedef enum +{ + MLMESYNCLOSS_PAN_ID_CONFLICT = 0, + MLMESYNCLOSS_REALIGMENT = 1, + MLMESYNCLOSS_BEACON_LOST = 2, + MLMESYNCLOSS_SUPERFRAME_OVERLAP = 3 +} LrWpanSyncLossReason; + + +/** + * \ingroup lr-wpan + * + * Table 39 of IEEE 802.15.4-2011 + */ +typedef enum +{ + MLMEPOLL_SUCCESS = 0, + MLMEPOLL_CHANNEL_ACCESS_FAILURE = 2, + MLMEPOLL_NO_ACK = 3, + MLMEPOLL_NO_DATA = 4, + MLMEPOLL_COUNTER_ERROR = 5, + MLMEPOLL_FRAME_TOO_LONG = 6, + MLMEPOLL_UNAVAILABLE_KEY = 7, + MLMEPOLL_UNSUPPORTED_SECURITY = 8, + MLMEPOLL_INVALID_PARAMETER = 9 +} LrWpanMlmePollConfirmStatus; /** * \ingroup lr-wpan @@ -147,11 +236,11 @@ struct McpsDataRequestParams { McpsDataRequestParams () : m_srcAddrMode (SHORT_ADDR), - m_dstAddrMode (SHORT_ADDR), - m_dstPanId (0), - m_dstAddr (), - m_msduHandle (0), - m_txOptions (0) + m_dstAddrMode (SHORT_ADDR), + m_dstPanId (0), + m_dstAddr (), + m_msduHandle (0), + m_txOptions (0) { } LrWpanAddressMode m_srcAddrMode; //!< Source address mode @@ -173,7 +262,6 @@ struct McpsDataConfirmParams uint8_t m_msduHandle; //!< MSDU handle LrWpanMcpsDataConfirmStatus m_status; //!< The status of the last MSDU transmission }; - /** * \ingroup lr-wpan * @@ -181,18 +269,126 @@ struct McpsDataConfirmParams */ struct McpsDataIndicationParams { - uint8_t m_srcAddrMode; //!< Source address mode - uint16_t m_srcPanId; //!< Source PAN identifier - Mac16Address m_srcAddr; //!< Source address + uint8_t m_srcAddrMode; //!< Source address mode + uint16_t m_srcPanId; //!< Source PAN identifier + Mac16Address m_srcAddr; //!< Source address Mac64Address m_srcExtAddr; //!< Source extended address - uint8_t m_dstAddrMode; //!< Destination address mode - uint16_t m_dstPanId; //!< Destination PAN identifier - Mac16Address m_dstAddr; //!< Destination address + uint8_t m_dstAddrMode; //!< Destination address mode + uint16_t m_dstPanId; //!< Destination PAN identifier + Mac16Address m_dstAddr; //!< Destination address Mac64Address m_dstExtAddr; //!< Destination extended address uint8_t m_mpduLinkQuality; //!< LQI value measured during reception of the MPDU - uint8_t m_dsn; //!< The DSN of the received data frame + uint8_t m_dsn; //!< The DSN of the received data frame }; +/** + * \ingroup lr-wpan + * + * MLME-START.request params. See 802.15.4-2011 Section 6.2.12.1 + */ +struct MlmeStartRequestParams +{ + MlmeStartRequestParams () + : m_PanId (0), + m_logCh (11), + m_logChPage (0), + m_startTime (0), + m_bcnOrd (15), + m_sfrmOrd (15), + m_panCoor (false), + m_battLifeExt (false), + m_coorRealgn (false) + { + } + uint16_t m_PanId; //!< Pan Identifier used by the device. + uint8_t m_logCh; //!< Logical channel on which to start using the new superframe configuration. + uint32_t m_logChPage; //!< Logical channel page on which to start using the new superframe configuration. + uint32_t m_startTime; //!< Time at which to begin transmitting beacons (Used by Coordinator not PAN Coordinators). The time is specified in symbols. + uint8_t m_bcnOrd; //!< Beacon Order, Used to calculate the beacon interval, a value of 15 indicates no periodic beacons will be transmitted. + uint8_t m_sfrmOrd; //!< Superframe Order, indicates the length of the CAP in time slots. + bool m_panCoor; //!< On true this device will become coordinator. + bool m_battLifeExt; //!< Flag indicating whether or not the Battery life extension (BLE) features are used. + bool m_coorRealgn; //!< True if a realignment request command is to be transmitted prior changing the superframe. +}; +/** + * \ingroup lr-wpan + * + * MLME-SYNC.request params. See 802.15.4-2011 Section 6.2.13.1 + */ +struct MlmeSyncRequestParams +{ + MlmeSyncRequestParams () + : m_logCh (), + m_trackBcn (false) + { + } + uint8_t m_logCh; //!< The channel number on which to attempt coordinator synchronization. + bool m_trackBcn; //!< True if the mlme sync with the next beacon and attempts to track future beacons. False if mlme sync only the next beacon. +}; +/** + * \ingroup lr-wpan + * + * MLME-POLL.request params. See 802.15.4-2011 Section 6.2.14.1 + */ +struct MlmePollRequestParams +{ + MlmePollRequestParams () + : m_coorAddrMode (SHORT_ADDR), + m_coorPanId (0), + m_coorShortAddr (), + m_coorExtAddr () + { + } + LrWpanAddressMode m_coorAddrMode; //!< The addressing mode of the coordinator to which the pool is intended. + uint16_t m_coorPanId; //!< The PAN id of the coordinator to which the poll is intended. + Mac16Address m_coorShortAddr; //!< Coordintator short address. + Mac64Address m_coorExtAddr; //!< Coordinator extended address. + +}; +/** + * \ingroup lr-wpan + * + * MLME-START.confirm params. See 802.15.4-2011 Section 6.2.12.2 + */ +struct MlmeStartConfirmParams +{ + LrWpanMlmeStartConfirmStatus m_status; //!< The status of a MLME-start.request +}; +/** + * \ingroup lr-wpan + * + * MLME-BEACON-NOTIFY.indication params. See 802.15.4-2011 Section 6.2.4.1, Table 16 + */ +struct MlmeBeaconNotifyIndicationParams +{ + uint8_t m_bsn; //!< The beacon sequence number + //TODO: Add other params + //m_PanDesc; + //m_PenAddrSpec + //m_sduAddrList + //m_sduLength + //m_sdu; +}; +/** + * \ingroup lr-wpan + * + * MLME-SYNC-LOSS.indication params. See 802.15.4-2011 Section 6.2.13.2, Table 37 + */ +struct MlmeSyncLossIndicationParams +{ + LrWpanSyncLossReason m_lossReason; //!< The reason for the lost of synchronization. + uint16_t m_panId; //!< The PAN identifier with which the device lost synchronization or to which it was realigned. + uint8_t m_logCh; //!< The channel number on which the device lost synchronization or to which it was realigned. +}; +/** + * \ingroup lr-wpan + * + * MLME-START.confirm params. See 802.15.4-2011 Section 6.2.14.2 + */ +struct MlmePollConfirmParams +{ + LrWpanMlmePollConfirmStatus m_status; //!< The confirmation status resulting from a MLME-poll.request. +}; /** * \ingroup lr-wpan * @@ -201,7 +397,6 @@ struct McpsDataIndicationParams * transmission request */ typedef Callback McpsDataConfirmCallback; - /** * \ingroup lr-wpan * @@ -209,15 +404,49 @@ typedef Callback McpsDataConfirmCallback; * frame and wants to deliver it to the higher layer. * * \todo for now, we do not deliver all of the parameters in section - * 7.1.1.3.1 but just send up the packet. + * 802.15.4-2006 7.1.1.3.1 but just send up the packet. */ typedef Callback > McpsDataIndicationCallback; - - /** * \ingroup lr-wpan * - * Class that implements the LR-WPAN Mac state machine + * This callback is called after a MlmeStartRequest has been called from + * the higher layer. It returns a status of the outcome of the + * transmission request + */ +typedef Callback MlmeStartConfirmCallback; +/** + * \ingroup lr-wpan + * + * This callback is called after a Mlme has successfully received a + * beacon frame and wants to deliver it to the higher layer. + * + * \todo for now, we do not deliver all of the parameters in section + * 802.15.4-2006 6.2.4.1 but just send up the packet. + */ +typedef Callback > MlmeBeaconNotifyIndicationCallback; +/** + * \ingroup lr-wpan + * + * This callback is called to indicate the loss of synchronization with + * a coordinator. + * + * \todo for now, we do not deliver all of the parameters in section + * See IEEE 802.15.4-2011 6.2.13.2. + */ +typedef Callback MlmeSyncLossIndicationCallback; +/** + * \ingroup lr-wpan + * + * This callback is called after a Mlme-Poll.Request has been called from + * the higher layer. It returns a status of the outcome of the + * transmission request + */ +typedef Callback MlmePollConfirmCallback; +/** + * \ingroup lr-wpan + * + * Class that implements the LR-WPAN MAC state machine */ class LrWpanMac : public Object { @@ -228,33 +457,59 @@ public: * \return the object TypeId */ static TypeId GetTypeId (void); - + //MAC sublayer constants /** * The minimum number of octets added by the MAC sublayer to the PSDU. - * See IEEE 802.15.4-2006, section 7.4.1, Table 85 + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. */ static const uint32_t aMinMPDUOverhead; - + /** + * Length of a superframe slot in symbols. Defaults to 60 symbols in each + * superframe slot. + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. + */ + static const uint32_t aBaseSlotDuration; + /** + * Number of a superframe slots per superframe. Defaults to 16. + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. + */ + static const uint32_t aNumSuperframeSlots; + /** + * Length of a superframe in symbols. Defaults to + * aBaseSlotDuration * aNumSuperframeSlots in symbols. + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. + */ + static const uint32_t aBaseSuperframeDuration; + /** + * The number of consecutive lost beacons that will + * cause the MAC sublayer of a receiving device to + * declare a loss of synchronization. + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. + */ + static const uint32_t aMaxLostBeacons; + /** + * The maximum size of an MPDU, in octets, that can be + * followed by a Short InterFrame Spacing (SIFS) period. + * See IEEE 802.15.4-2011, section 6.4.1, Table 51. + */ + static const uint32_t aMaxSIFSFrameSize; /** * Default constructor. */ LrWpanMac (void); virtual ~LrWpanMac (void); - /** * Check if the receiver will be enabled when the MAC is idle. * * \return true, if the receiver is enabled during idle periods, false otherwise */ bool GetRxOnWhenIdle (void); - /** * Set if the receiver should be enabled when the MAC is idle. * * \param rxOnWhenIdle set to true to enable the receiver during idle periods */ void SetRxOnWhenIdle (bool rxOnWhenIdle); - // XXX these setters will become obsolete if we use the attribute system /** * Set the short address of this MAC. @@ -262,42 +517,36 @@ public: * \param address the new address */ void SetShortAddress (Mac16Address address); - /** * Get the short address of this MAC. * * \return the short address */ Mac16Address GetShortAddress (void) const; - /** * Set the extended address of this MAC. * * \param address the new address */ void SetExtendedAddress (Mac64Address address); - /** * Get the extended address of this MAC. * * \return the extended address */ Mac64Address GetExtendedAddress (void) const; - /** * Set the PAN id used by this MAC. * * \param panId the new PAN id. */ void SetPanId (uint16_t panId); - /** * Get the PAN id used by this MAC. * * \return the PAN id. */ uint16_t GetPanId (void) const; - /** * IEEE 802.15.4-2006, section 7.1.1.1 * MCPS-DATA.request @@ -307,28 +556,50 @@ public: * \param p the packet to be transmitted */ void McpsDataRequest (McpsDataRequestParams params, Ptr p); - + /** + * IEEE 802.15.4-2006, section 7.1.14.1 + * MLME-START.request + * Request to allow a PAN coordinator to initiate + * a new PAN or beginning a new superframe configuration. + * + * \param params the request parameters + */ + void MlmeStartRequest (MlmeStartRequestParams params); + /** + * IEEE 802.15.4-2011, section 6.2.13.1 + * MLME-SYNC.request + * Request to synchronize with the coordinator by acquiring and, + * if specified, tracking beacons. + * + * \param params the request parameters + */ + void MlmeSyncRequest (MlmeSyncRequestParams params); + /** + * IEEE 802.15.4-2011, section 6.2.14.2 + * MLME-POLL.request + * Prompts the device to request data from the coordinator. + * + * \param params the request parameters + */ + void MlmePollRequest (MlmePollRequestParams params); /** * Set the CSMA/CA implementation to be used by the MAC. * * \param csmaCa the CSMA/CA implementation */ void SetCsmaCa (Ptr csmaCa); - /** * Set the underlying PHY for the MAC. * * \param phy the PHY */ void SetPhy (Ptr phy); - /** * Get the underlying PHY of the MAC. * * \return the PHY */ Ptr GetPhy (void); - /** * Set the callback for the indication of an incoming data packet. * The callback implements MCPS-DATA.indication SAP of IEEE 802.15.4-2006, @@ -337,7 +608,6 @@ public: * \param c the callback */ void SetMcpsDataIndicationCallback (McpsDataIndicationCallback c); - /** * Set the callback for the confirmation of a data transmission request. * The callback implements MCPS-DATA.confirm SAP of IEEE 802.15.4-2006, @@ -346,8 +616,41 @@ public: * \param c the callback */ void SetMcpsDataConfirmCallback (McpsDataConfirmCallback c); + /** + * Set the callback for the confirmation of a data transmission request. + * The callback implements MLME-START.confirm SAP of IEEE 802.15.4-2006, + * section 7.1.14.2. + * + * \param c the callback + */ + void SetMlmeStartConfirmCallback (MlmeStartConfirmCallback 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, + * section 6.2.4.1. + * + * \param c the callback + */ + void SetMlmeBeaconNotifyIndicationCallback (MlmeBeaconNotifyIndicationCallback c); + /** + * Set the callback for the loss of synchronization with a coordinator. + * The callback implements MLME-BEACON-NOTIFY.indication SAP of IEEE 802.15.4-2011, + * section 6.2.13.2. + * + * \param c the callback + */ + void SetMlmeSyncLossIndicationCallback (MlmeSyncLossIndicationCallback c); + /** + * Set the callback for the confirmation of a data transmission request. + * The callback implements MLME-POLL.confirm SAP of IEEE 802.15.4-2011, + * section 6.2.14.2 + * + * \param c the callback + */ + void SetMlmePollConfirmCallback (MlmePollConfirmCallback c); // interfaces between MAC and PHY + /** * IEEE 802.15.4-2006 section 6.2.1.3 * PD-DATA.indication @@ -357,22 +660,19 @@ public: * @param lqi Link quality (LQI) value measured during reception of the PPDU */ void PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi); - /** * IEEE 802.15.4-2006 section 6.2.1.2 * Confirm the end of transmission of an MPDU to MAC * @param status to report to MAC - * PHY PD-DATA.confirm status + * PHY PD-DATA.confirm status */ void PdDataConfirm (LrWpanPhyEnumeration status); - /** * IEEE 802.15.4-2006 section 6.2.2.2 * PLME-CCA.confirm status * @param status TRX_OFF, BUSY or IDLE */ void PlmeCcaConfirm (LrWpanPhyEnumeration status); - /** * IEEE 802.15.4-2006 section 6.2.2.4 * PLME-ED.confirm status and energy level @@ -380,7 +680,6 @@ public: * @param energyLevel 0x00-0xff ED level for the channel */ void PlmeEdConfirm (LrWpanPhyEnumeration status, uint8_t energyLevel); - /** * IEEE 802.15.4-2006 section 6.2.2.6 * PLME-GET.confirm @@ -392,7 +691,6 @@ public: void PlmeGetAttributeConfirm (LrWpanPhyEnumeration status, LrWpanPibAttributeIdentifier id, LrWpanPhyPibAttributes* attribute); - /** * IEEE 802.15.4-2006 section 6.2.2.8 * PLME-SET-TRX-STATE.confirm @@ -400,7 +698,6 @@ public: * @param status in RX_ON,TRX_OFF,FORCE_TRX_OFF,TX_ON */ void PlmeSetTRXStateConfirm (LrWpanPhyEnumeration status); - /** * IEEE 802.15.4-2006 section 6.2.2.10 * PLME-SET.confirm @@ -410,14 +707,12 @@ public: */ void PlmeSetAttributeConfirm (LrWpanPhyEnumeration status, LrWpanPibAttributeIdentifier id); - /** * CSMA-CA algorithm calls back the MAC after executing channel assessment. * - * \param macState indicate BUSY or IDLE channel condition + * \param macState indicate BUSY oder IDLE channel condition */ void SetLrWpanMacState (LrWpanMacState macState); - /** * Get the current association status. * @@ -432,110 +727,225 @@ public: */ void SetAssociationStatus (LrWpanAssociationStatus status); - //MAC sublayer constants - /** - * Length of a superframe slot in symbols. Defaults to 60 symbols in each - * superframe slot. - * See IEEE 802.15.4-2006, section 7.4.1, Table 85. - */ - uint64_t m_aBaseSlotDuration; - - /** - * Number of a superframe slots per superframe. Defaults to 16. - * See IEEE 802.15.4-2006, section 7.4.1, Table 85. - */ - uint64_t m_aNumSuperframeSlots; - - /** - * Length of a superframe in symbols. Defaults to - * aBaseSlotDuration * aNumSuperframeSlots in symbols. - * See IEEE 802.15.4-2006, section 7.4.1, Table 85. - */ - uint64_t m_aBaseSuperframeDuration; //MAC PIB attributes + /** * The time that the device transmitted its last beacon frame, in symbol * periods. Only 24 bits used. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ uint64_t m_macBeaconTxTime; - + /** + * The time that the device received its last beacon frame, in symbol + * periods. Only 24 bits used. + */ + uint64_t m_beaconRxTime; + /** + * The short address of the coordinator through which the device is + * associated. + * 0xFFFF indicates this value is unknown. + * 0xFFFE indicates the coordinator is only using its extended address. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + Mac16Address m_macCoordShortAddress; + /** + * The extended address of the coordinator through which the device + * is associated. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + Mac64Address m_macCoordExtendedAddress; /** * Symbol boundary is same as m_macBeaconTxTime. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ uint64_t m_macSyncSymbolOffset; - /** - * Specification of how often the coordinator transmits its beacon. - * 0 - 15 with 15 means no beacons are being sent. - * See IEEE 802.15.4-2006, section 7.4.2, Table 86. + * Used by a PAN coordinator or coordinator. + * Defines how often the coordinator transmits its beacon + * (outgoing superframe). Range 0 - 15 with 15 meaning no beacons are being sent. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. */ - uint64_t m_macBeaconOrder; - + uint8_t m_macBeaconOrder; /** - * The length of the active portion of the outgoing superframe, including the - * beacon frame. + * Used by a PAN coordinator or coordinator. The length of the active portion + * of the outgoing superframe, including the beacon frame. * 0 - 15 with 15 means the superframe will not be active after the beacon. - * See IEEE 802.15.4-2006, section 7.4.2, Table 86. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. */ - uint64_t m_macSuperframeOrder; - + uint8_t m_macSuperframeOrder; + /** + * The maximum time (in superframe periods) that a transaction is stored by a + * coordinator and indicated in its beacon. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + uint16_t m_macTransactionPersistanceTime; + /** + * Indication of the Slot where the CAP portion of the OUTGOING Superframe ends. + */ + uint8_t m_fnlCapSlot; + /** + * The beaconOrder value of the INCOMING frame. Used by all devices that have a parent. + * Specification of how often the parent coordinator transmits its beacon. + * 0 - 15 with 15 means the parent is not currently transmitting beacons. + */ + uint8_t m_incomingBeaconOrder; + /** + * Used by all devices that have a parent. + * The length of the active portion of the INCOMING superframe, including the + * beacon frame. + * 0 - 15 with 15 meaning the superframe will not be active after the beacon. + */ + uint8_t m_incomingSuperframeOrder; + /** + * Indication of the Slot where the CAP portion of the INCOMING Superframe ends. + */ + uint8_t m_incomingFnlCapSlot; /** * Indicates if MAC sublayer is in receive all mode. True mean accept all * frames from PHY. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ bool m_macPromiscuousMode; - /** * 16 bits id of PAN on which this device is operating. 0xffff means not - * asscoiated. + * associated. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ uint16_t m_macPanId; - /** * Sequence number added to transmitted data or MAC command frame, 00-ff. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ SequenceNumber8 m_macDsn; - + /** + * Sequence number added to transmitted beacon frame, 00-ff. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + SequenceNumber8 m_macBsn; /** * The maximum number of retries allowed after a transmission failure. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ uint8_t m_macMaxFrameRetries; - /** * Indication of whether the MAC sublayer is to enable its receiver during * idle periods. * See IEEE 802.15.4-2006, section 7.4.2, Table 86. */ bool m_macRxOnWhenIdle; - + /** + * The minimum time forming a Long InterFrame Spacing (LIFS) period. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + uint32_t m_macLIFSPeriod; + /** + * The minimum time forming a Short InterFrame Spacing (SIFS) period. + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + uint32_t m_macSIFSPeriod; + /** + * Indication of whether a device automatically sends data request command + * if its address is listed in the beacon frame. + * TRUE = request command automatically is sent. This command also affects + * the generation of MLME-BEACON-NOTIFY.indication (6.2.4.1) + * See IEEE 802.15.4-2011, section 6.4.2, Table 52. + */ + bool m_macAutoRequest; + /** + * The value of the necessary InterFrame Space after the transmission of a packet. + */ + uint32_t m_ifs; + /** + * Indication of whether the current device is the PAN coordinator + */ + bool m_panCoor; + /** + * Indication of the Interval used by the coordinator to transmit beacon frames + * expressed in symbols. + */ + uint32_t m_beaconInterval; + /** + * Indication of the superframe duration in symbols. + * (e.g. 1 symbol = 4 bits in a 250kbps O-QPSK PHY) + */ + uint32_t m_superframeDuration; + /** + * Indication of the interval a node should receive a superframe + * expressed in symbols. + */ + uint32_t m_incomingBeaconInterval; + /** + * Indication of the superframe duration in symbols + * (e.g. 1 symbol = 4 bits in a 250kbps O-QPSK PHY) + */ + uint32_t m_incomingSuperframeDuration; + /** + * Indication of current device capability (FFD or RFD) + */ + uint8_t m_deviceCapability; + /** + * Indication of whether the current device is tracking incoming beacons. + */ + bool m_beaconTrackingOn; + /** + * The number of consecutive loss beacons in a beacon tracking operation. + */ + uint8_t m_numLostBeacons; /** * Get the macAckWaitDuration attribute value. * * \return the maximum number symbols to wait for an acknowledgment frame */ uint64_t GetMacAckWaitDuration (void) const; - /** * Get the macMaxFrameRetries attribute value. * * \return the maximum number of retries */ uint8_t GetMacMaxFrameRetries (void) const; - /** * Set the macMaxFrameRetries attribute value. * * \param retries the maximum number of retries */ void SetMacMaxFrameRetries (uint8_t retries); - + /** + * Check if the packet destination is its coordinator + * + * \return True if m_txPkt (packet awaiting to be sent) destination is its coordinator + */ + bool isCoordDest (void); + /** + * Check if the packet destination is its coordinator + * + *\param mac The coordinator short MAC Address + */ + void SetAssociatedCoor (Mac16Address mac); + /** + * Check if the packet destination is its coordinator + * + *\param mac The coordinator extended MAC Address + */ + void SetAssociatedCoor (Mac64Address mac); + /** + * Get the size of the Interframe Space according to MPDU size (m_txPkt). + * + * \return the IFS size in symbols + */ + uint32_t GetIfsSize (); + /** + * Obtain the number of symbols in the packet which is currently being sent by the MAC layer. + * + *\return packet number of symbols + * */ + uint64_t GetTxPacketSymbols (void); + /** + * Check if the packet to transmit requires acknowledgment + * + *\return True if the Tx packet requires acknowledgment + * */ + bool isTxAckReq (void); /** * TracedCallback signature for sent packets. * @@ -543,8 +953,7 @@ public: * \param [in] retries The number of retries. * \param [in] backoffs The number of CSMA backoffs. */ - typedef void (* SentTracedCallback) - (Ptr packet, uint8_t retries, uint8_t backoffs); + typedef void (*SentTracedCallback)(Ptr packet, uint8_t retries, uint8_t backoffs); /** * TracedCallback signature for LrWpanMacState change events. @@ -555,9 +964,9 @@ public: * TracedValue \c MacStateValue. The \c MacState TracedCallback will * be removed in a future release. */ - typedef void (* StateTracedCallback) - (LrWpanMacState oldState, LrWpanMacState newState); - + typedef void (*StateTracedCallback)(LrWpanMacState oldState, LrWpanMacState newState); + + protected: // Inherited from Object. virtual void DoInitialize (void); @@ -571,34 +980,74 @@ private: { uint8_t txQMsduHandle; //!< MSDU Handle Ptr txQPkt; //!< Queued packet - }; + }; + /** + * Helper structure for managing indirect transmission queue elements. + */ + struct IndTxQueueElement + { + uint8_t txQMsduHandle; //!< MSDU Handle. + Ptr txQPkt; //!< Queued packet. + Time expireTime; //!< The expiration time of the packet in the indirect transmission queue. + }; + /** + * Called to send a single beacon frame. + */ + void SendOneBeacon (void); + /** + * Called to begin the Contention Free Period (CFP) in a + * beacon-enabled mode. + * + * \param superframeType The incoming or outgoing superframe reference + */ + void StartCFP (SuperframeType superframeType); + /** + * Called to begin the Contention Access Period (CAP) in a + * beacon-enabled mode. + * + * \param superframeType The incoming or outgoing superframe reference + */ + void StartCAP (SuperframeType superframeType); + /** + * Start the Inactive Period in a beacon-enabled mode. + * + * \param superframeType The incoming or outgoing superframe reference + * + */ + void StartInactivePeriod (SuperframeType superframeType); + /** + * Called if the device is unable to locate a beacon in the time set by MLME-SYNC.request. + */ + void BeaconSearchTimeout (void); /** * Send an acknowledgment packet for the given sequence number. * * \param seqno the sequence number for the ACK */ void SendAck (uint8_t seqno); - /** * Remove the tip of the transmission queue, including clean up related to the * last packet transmission. */ void RemoveFirstTxQElement (); - /** * Change the current MAC state to the given new state. * * \param newState the new state */ void ChangeMacState (LrWpanMacState newState); - /** * Handle an ACK timeout with a packet retransmission, if there are * retransmission left, or a packet drop. */ void AckWaitTimeout (void); - + /** + * After a successful transmission of a frame (beacon, data) or an ack frame reception, + * the mac layer wait an Interframe Space (IFS) time and triggers this function + * to continue with the MAC flow. + */ + void IfsWaitTimeout (void); /** * Check for remaining retransmissions for the packet currently being sent. * Drop the packet, if there are no retransmissions left. @@ -606,13 +1055,27 @@ private: * \return true, if the packet should be retransmitted, false otherwise. */ bool PrepareRetransmission (void); - /** * Check the transmission queue. If there are packets in the transmission * queue and the MAC is idle, pick the first one and initiate a packet * transmission. */ void CheckQueue (void); + /** + * Constructs a Superframe specification field from the local information, + * the superframe Specification field is necessary to create a beacon frame. + */ + SuperframeField GetSuperframeField (void); + /** + * Constructs the Guaranteed Time Slots (GTS) Fields from local information + * The GTS Fields are part of the beacon frame. + */ + GtsFields GetGtsFields (void); + /** + * Constructs Pending Address Fields from the local information, + * the Pending Address Fields are part of the beacon frame. + */ + PendingAddrFields GetPendingAddrFields (void); /** * The trace source fired when packets are considered as successfully sent @@ -625,7 +1088,6 @@ private: * \see class CallBackTraceSource */ TracedCallback, uint8_t, uint8_t > m_sentPktTrace; - /** * The trace source fired when packets come into the "top" of the device * at the L3/L2 transition, when being queued for transmission. @@ -633,7 +1095,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macTxEnqueueTrace; - /** * The trace source fired when packets are dequeued from the * L3/l2 transmission queue. @@ -641,14 +1102,12 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macTxDequeueTrace; - /** * The trace source fired when packets are being sent down to L1. * * \see class CallBackTraceSource */ TracedCallback > m_macTxTrace; - /** * The trace source fired when packets where successfully transmitted, that is * an acknowledgment was received, if requested, or the packet was @@ -657,7 +1116,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macTxOkTrace; - /** * The trace source fired when packets are dropped due to missing ACKs or * because of transmission failures in L1. @@ -665,7 +1123,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macTxDropTrace; - /** * The trace source fired for packets successfully received by the device * immediately before being forwarded up to higher layers (at the L2/L3 @@ -674,7 +1131,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macPromiscRxTrace; - /** * The trace source fired for packets successfully received by the device * immediately before being forwarded up to higher layers (at the L2/L3 @@ -683,7 +1139,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macRxTrace; - /** * The trace source fired for packets successfully received by the device * but dropped before being forwarded up to higher layers (at the L2/L3 @@ -692,7 +1147,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_macRxDropTrace; - /** * A trace source that emulates a non-promiscuous protocol sniffer connected * to the device. Unlike your average everyday sniffer, this trace source @@ -732,7 +1186,6 @@ private: * \see class CallBackTraceSource */ TracedCallback > m_promiscSnifferTrace; - /** * A trace source that fires when the LrWpanMac changes states. * Parameters are the old mac state and the new mac state. @@ -742,87 +1195,133 @@ private: * TracedValue. */ TracedCallback m_macStateLogger; - /** * The PHY associated with this MAC. */ Ptr m_phy; - /** * The CSMA/CA implementation used by this MAC. */ Ptr m_csmaCa; - + /** + * This callback is used to notify incoming beacon packets to the upper layers. + * See IEEE 802.15.4-2011, section 6.2.4.1. + */ + MlmeBeaconNotifyIndicationCallback m_mlmeBeaconNotifyIndicationCallback; + /** + * This callback is used to indicate the loss of synchronization with a coordinator. + * See IEEE 802.15.4-2011, section 6.2.13.2. + */ + MlmeSyncLossIndicationCallback m_mlmeSyncLossIndicationCallback; + /** + * This callback is used to report the status after a device send data command request to + * the coordinator to transmit data. + * See IEEE 802.15.4-2011, section 6.2.14.2. + */ + MlmePollConfirmCallback m_mlmePollConfirmCallback; + /** + * This callback is used to report the start of a new PAN or + * the begin of a new superframe configuration. + * See IEEE 802.15.4-2006, section 7.1.14.2. + */ + MlmeStartConfirmCallback m_mlmeStartConfirmCallback; /** * This callback is used to notify incoming packets to the upper layers. * See IEEE 802.15.4-2006, section 7.1.1.3. */ McpsDataIndicationCallback m_mcpsDataIndicationCallback; - /** * This callback is used to report data transmission request status to the * upper layers. * See IEEE 802.15.4-2006, section 7.1.1.2. */ McpsDataConfirmCallback m_mcpsDataConfirmCallback; - /** * The current state of the MAC layer. */ TracedValue m_lrWpanMacState; - + /** + * The current period of the incoming superframe. + */ + TracedValue m_incSuperframeStatus; + /** + * The current period of the outgoing superframe. + */ + TracedValue m_outSuperframeStatus; /** * The current association status of the MAC layer. */ LrWpanAssociationStatus m_associationStatus; - /** * The packet which is currently being sent by the MAC layer. */ Ptr m_txPkt; // XXX need packet buffer instead of single packet - /** * The short address used by this MAC. Currently we do not have complete * extended address support in the MAC, nor do we have the association * primitives, so this address has to be configured manually. */ Mac16Address m_shortAddress; - /** * The extended address used by this MAC. Extended addresses are currently not * really supported. */ Mac64Address m_selfExt; - /** * The transmit queue used by the MAC. */ std::deque m_txQueue; - + /** + * The indirect transmit queue used by the MAC pending messages. + */ + std::deque m_indTxQueue; /** * The number of already used retransmission for the currently transmitted * packet. */ uint8_t m_retransmission; - /** * The number of CSMA/CA retries used for sending the current packet. */ uint8_t m_numCsmacaRetry; - /** * Scheduler event for the ACK timeout of the currently transmitted data * packet. */ EventId m_ackWaitTimeout; - /** * Scheduler event for a deferred MAC state change. */ EventId m_setMacState; + /** + * Scheduler event for Interframe spacing wait time. + */ + EventId m_ifsEvent; + /** + * Scheduler event for generation of one beacon. + */ + EventId m_beaconEvent; + /** + * Scheduler event for the end of the outgoing superframe CAP. + **/ + EventId m_capEvent; + /** + * Scheduler event for the end of the outgoing superframe CFP. + */ + EventId m_cfpEvent; + /** + * Scheduler event for the end of the incoming superframe CAP. + **/ + EventId m_incCapEvent; + /** + * Scheduler event for the end of the incoming superframe CFP. + */ + EventId m_incCfpEvent; + /** + * Scheduler event to track the incoming beacons. + */ + EventId m_trackingEvent; }; - - } // namespace ns3 #endif /* LR_WPAN_MAC_H */ diff --git a/src/lr-wpan/test/lr-wpan-ifs-test.cc b/src/lr-wpan/test/lr-wpan-ifs-test.cc new file mode 100644 index 000000000..f9632ee8d --- /dev/null +++ b/src/lr-wpan/test/lr-wpan-ifs-test.cc @@ -0,0 +1,283 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ns3/rng-seed-manager.h" + +#include +#include + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("lr-wpan-ifs-test"); + +/** + * \ingroup lr-wpan-test + * \ingroup tests + * + * \brief LrWpan Dataframe transmission with Interframe Space + */ +class LrWpanDataIfsTestCase : public TestCase +{ +public: + LrWpanDataIfsTestCase (); + virtual ~LrWpanDataIfsTestCase (); + + + +private: + static void DataConfirm (LrWpanDataIfsTestCase *testcase, + Ptr dev, + McpsDataConfirmParams params); + + static void DataReceived (LrWpanDataIfsTestCase *testcase, + Ptr dev, + Ptr); + + static void MacState (LrWpanDataIfsTestCase *testcase, + Ptr dev, + LrWpanMacState oldValue, + LrWpanMacState newValue); + + + + virtual void DoRun (void); + Time m_lastTxTime; //!< The time of the last transmitted packet + Time m_ackRxTime; //!< The time of the received acknoledgment. + Time m_endIfs; //!< The time where the Interframe Space ended. + + +}; + + +LrWpanDataIfsTestCase::LrWpanDataIfsTestCase () + : TestCase ("Lrwpan: IFS with and without ACK") +{ + +} + +LrWpanDataIfsTestCase::~LrWpanDataIfsTestCase () +{ + +} + +void +LrWpanDataIfsTestCase::DataConfirm (LrWpanDataIfsTestCase *testcase, Ptr dev, McpsDataConfirmParams params) +{ + std::cout << Simulator::Now ().GetSeconds () << " | Dataframe Sent\n"; + testcase->m_lastTxTime = Simulator::Now (); + +} + +void +LrWpanDataIfsTestCase::DataReceived (LrWpanDataIfsTestCase *testcase,Ptr dev, Ptr p) +{ + Ptr RxPacket = p->Copy (); + LrWpanMacHeader receivedMacHdr; + RxPacket->RemoveHeader (receivedMacHdr); + + NS_ASSERT (receivedMacHdr.IsAcknowledgment ()); + testcase->m_ackRxTime = Simulator::Now (); + + std::cout << Simulator::Now ().GetSeconds () << " | ACK received\n"; +} + +void +LrWpanDataIfsTestCase::MacState (LrWpanDataIfsTestCase *testcase, Ptr dev,LrWpanMacState oldValue, LrWpanMacState newValue) +{ + // Check the time after the MAC layer go back to IDLE state + // (i.e. after the packet has been sent and the IFS is finished) + + if (newValue == LrWpanMacState::MAC_IDLE) + { + testcase->m_endIfs = Simulator::Now (); + std::cout << Simulator::Now ().GetSeconds () << " | MAC layer is free\n"; + } + +} + +void +LrWpanDataIfsTestCase::DoRun () +{ + // Test of Interframe Spaces (IFS) + + // The MAC layer needs a finite amount of time to process the data received from the PHY. + // To allow this, to successive transmitted frames must be separated for at least one IFS. + // The IFS size depends on the transmitted frame. This test verifies that the IFS is correctly + // implemented and its size correspond to the situations described by the standard. + // For more info see IEEE 802.15.4-2011 Section 5.1.1.3 + + + // Create 2 nodes, and a NetDevice for each one + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + + Ptr dev0 = CreateObject (); + Ptr dev1 = CreateObject (); + + dev0->SetAddress (Mac16Address ("00:01")); + dev1->SetAddress (Mac16Address ("00:02")); + + // Each device must be attached to the same channel + Ptr channel = CreateObject (); + Ptr propModel = CreateObject (); + Ptr delayModel = CreateObject (); + channel->AddPropagationLossModel (propModel); + channel->SetPropagationDelayModel (delayModel); + + dev0->SetChannel (channel); + dev1->SetChannel (channel); + + // To complete configuration, a LrWpanNetDevice must be added to a node + n0->AddDevice (dev0); + n1->AddDevice (dev1); + + // Connect to trace files in the MAC layer + dev0->GetMac ()->TraceConnectWithoutContext ("MacStateValue", MakeBoundCallback (&LrWpanDataIfsTestCase::MacState, this, dev0)); + dev0->GetMac ()->TraceConnectWithoutContext ("MacRx", MakeBoundCallback (&LrWpanDataIfsTestCase::DataReceived, this, dev0)); + + Ptr sender0Mobility = CreateObject (); + sender0Mobility->SetPosition (Vector (0,0,0)); + dev0->GetPhy ()->SetMobility (sender0Mobility); + Ptr sender1Mobility = CreateObject (); + // Configure position 10 m distance + sender1Mobility->SetPosition (Vector (0,10,0)); + dev1->GetPhy ()->SetMobility (sender1Mobility); + + McpsDataConfirmCallback cb0; + cb0 = MakeBoundCallback (&LrWpanDataIfsTestCase::DataConfirm, this, dev0); + dev0->GetMac ()->SetMcpsDataConfirmCallback (cb0); + + Ptr p0 = Create (2); + McpsDataRequestParams params; + params.m_dstPanId = 0; + + params.m_srcAddrMode = SHORT_ADDR; + params.m_dstAddrMode = SHORT_ADDR; + params.m_dstAddr = Mac16Address ("00:02"); + params.m_msduHandle = 0; + + Time ifsSize; + + //////////////////////// SIFS /////////////////////////// + + Simulator::ScheduleWithContext (1, Seconds (0.0), + &LrWpanMac::McpsDataRequest, + dev0->GetMac (), params, p0); + + + Simulator::Run (); + + // MPDU = MAC header (11 bytes) + MSDU (2 bytes)+ MAC trailer (2 bytes) = 15) + // MPDU (15 bytes) < 18 bytes therefore IFS = SIFS + // SIFS = 12 symbols (192 Microseconds on a 2.4Ghz O-QPSK PHY) + ifsSize = m_endIfs - m_lastTxTime; + NS_TEST_EXPECT_MSG_EQ (ifsSize, Time (MicroSeconds (192)), "Wrong Short InterFrame Space (SIFS) Size after dataframe Tx"); + + //////////////////////// LIFS /////////////////////////// + + p0 = Create (6); + + Simulator::ScheduleWithContext (1, Seconds (0.0), + &LrWpanMac::McpsDataRequest, + dev0->GetMac (), params, p0); + + + Simulator::Run (); + + // MPDU = MAC header (11 bytes) + MSDU (6 bytes)+ MAC trailer (2 bytes) = 19) + // MPDU (19 bytes) > 18 bytes therefore IFS = LIFS + // LIFS = 20 symbols (640 Microseconds on a 2.4Ghz O-QPSK PHY) + ifsSize = m_endIfs - m_lastTxTime; + NS_TEST_EXPECT_MSG_EQ (ifsSize, Time (MicroSeconds (640)), "Wrong Long InterFrame Space (LIFS) Size after dataframe Tx"); + + //////////////////////// SIFS after ACK ////////////////// + + params.m_txOptions = TX_OPTION_ACK; + p0 = Create (2); + + Simulator::ScheduleWithContext (1, Seconds (0.0), + &LrWpanMac::McpsDataRequest, + dev0->GetMac (), params, p0); + + Simulator::Run (); + + // MPDU = MAC header (11 bytes) + MSDU (2 bytes)+ MAC trailer (2 bytes) = 15) + // MPDU (15 bytes) < 18 bytes therefore IFS = SIFS + // SIFS = 12 symbols (192 Microseconds on a 2.4Ghz O-QPSK PHY) + ifsSize = m_endIfs - m_ackRxTime; + NS_TEST_EXPECT_MSG_EQ (ifsSize, Time (MicroSeconds (192)), "Wrong Short InterFrame Space (SIFS) Size after ACK Rx"); + + //////////////////////// LIFS after ACK ////////////////// + + params.m_txOptions = TX_OPTION_ACK; + p0 = Create (6); + + Simulator::ScheduleWithContext (1, Seconds (0.0), + &LrWpanMac::McpsDataRequest, + dev0->GetMac (), params, p0); + + + Simulator::Run (); + + // MPDU = MAC header (11 bytes) + MSDU (6 bytes)+ MAC trailer (2 bytes) = 19) + // MPDU (19 bytes) > 18 bytes therefore IFS = LIFS + // LIFS = 20 symbols (640 Microseconds on a 2.4Ghz O-QPSK PHY) + ifsSize = m_endIfs - m_ackRxTime; + NS_TEST_EXPECT_MSG_EQ (ifsSize, Time (MicroSeconds (640)), "Wrong Long InterFrame Space (LIFS) Size after ACK Rx"); + + Simulator::Destroy (); + +} + + +/** + * \ingroup lr-wpan-test + * \ingroup tests + * + * \brief LrWpan IFS TestSuite + */ + +class LrWpanIfsTestSuite : public TestSuite +{ +public: + LrWpanIfsTestSuite (); +}; + +LrWpanIfsTestSuite::LrWpanIfsTestSuite () + : TestSuite ("lr-wpan-ifs-test", UNIT) +{ + AddTestCase (new LrWpanDataIfsTestCase, TestCase::QUICK); +} + +static LrWpanIfsTestSuite lrWpanIfsTestSuite; //!< Static variable for test initialization + + + + diff --git a/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc b/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc new file mode 100644 index 000000000..93490ef9f --- /dev/null +++ b/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc @@ -0,0 +1,342 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 Ritsumeikan University, Shiga, 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("lr-wpan-slotted-csma-test"); + +/** + * \ingroup lr-wpan-test + * \ingroup tests + * + * \brief Test the correct allocation of DIRECT transmissions in the + * contention access period (CAP) of the superframe + * (Slotted CSMA-CA algorithm). + */ +class LrWpanSlottedCsmacaTestCase : public TestCase +{ +public: + LrWpanSlottedCsmacaTestCase (); + virtual ~LrWpanSlottedCsmacaTestCase (); + + + +private: + /** + * \brief Function called when McpsDataConfirm is hit. + * \param testcase The TestCase. + * \param dev The LrWpanNetDevice. + * \param params The McpsDataConfirm parameters. + */ + static void TransEndIndication (LrWpanSlottedCsmacaTestCase *testcase, + Ptr dev, + McpsDataConfirmParams params); + /** + * \brief Function called when McpsDataIndication is hit. + * \param testcase The TestCase. + * \param dev The LrWpanNetDevice. + * \param params The McpsDataIndication parameters. + * \param p The received packet. + */ + static void DataIndicationCoordinator (LrWpanSlottedCsmacaTestCase *testcase, + Ptr dev, + McpsDataIndicationParams params, + Ptr p); + /** + * \brief Function called when MlmeStartConfirm is hit. + * \param testcase The TestCase. + * \param dev The LrWpanNetDevice. + * \param params The MlmeStartConfirm parameters. + */ + static void StartConfirm (LrWpanSlottedCsmacaTestCase *testcase, + Ptr dev, + MlmeStartConfirmParams params); + + /** + * \brief Function called on each Superframe status change (CAP|CFP|INACTIVE). + * \param testcase The TestCase. + * \param dev The LrWpanNetDevice. + * \param oldValue The previous superframe status. + * \param newValue THe new superframe status. + */ + static void IncomingSuperframeStatus (LrWpanSlottedCsmacaTestCase *testcase, + Ptr dev, + SuperframeStatus oldValue, + SuperframeStatus newValue); + + /** + * \brief Function called to indicated the calculated transaction cost in slotted CSMA-CA + * \param testcase The TestCase. + * \param dev The LrWpanNetDevice. + * \param trans The transaction cost in symbols. + */ + static void TransactionCost (LrWpanSlottedCsmacaTestCase *testcase, + Ptr dev, + uint32_t trans); + + virtual void DoRun (void); + + Time m_startCap; //!< The time of the start of the Contention Access Period (CAP). + Time m_apBoundary; //!< Indicates the time after the calculation of the transaction cost (A boundary of an Active Period in the CAP) + Time m_sentTime; //!< Indicates the time after a successful transmission. + uint32_t m_transCost; //!< The current transaction cost in symbols. +}; + + +LrWpanSlottedCsmacaTestCase::LrWpanSlottedCsmacaTestCase () + : TestCase ("Lrwpan: Slotted CSMA-CA test") +{ + m_transCost = 0; +} + +LrWpanSlottedCsmacaTestCase::~LrWpanSlottedCsmacaTestCase () +{ + +} + +void +LrWpanSlottedCsmacaTestCase::TransEndIndication (LrWpanSlottedCsmacaTestCase *testcase, Ptr dev, McpsDataConfirmParams params) +{ + // In the case of transmissions with the acknowledgment flag activated, the transmission is only + // successful if the acknowledgment was received. + if (params.m_status == LrWpanMcpsDataConfirmStatus::IEEE_802_15_4_SUCCESS) + { + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Transmission successfully sent"); + testcase->m_sentTime = Simulator::Now (); + } +} + +void +LrWpanSlottedCsmacaTestCase::DataIndicationCoordinator (LrWpanSlottedCsmacaTestCase *testcase, Ptr dev, McpsDataIndicationParams params, Ptr p) +{ + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Coordinator Received DATA packet (size " << p->GetSize () << " bytes)"); +} + +void +LrWpanSlottedCsmacaTestCase::StartConfirm (LrWpanSlottedCsmacaTestCase *testcase, Ptr dev, MlmeStartConfirmParams params) +{ + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Beacon Sent"); +} + +void +LrWpanSlottedCsmacaTestCase::IncomingSuperframeStatus (LrWpanSlottedCsmacaTestCase *testcase, Ptr dev,SuperframeStatus oldValue, SuperframeStatus newValue) +{ + if (newValue == SuperframeStatus::CAP) + { + testcase->m_startCap = Simulator::Now (); + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Incoming superframe CAP starts"); + } +} + +void +LrWpanSlottedCsmacaTestCase::TransactionCost (LrWpanSlottedCsmacaTestCase *testcase, Ptr dev, uint32_t trans) +{ + testcase->m_apBoundary = Simulator::Now (); + testcase->m_transCost = trans; + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "s Transaction Cost is:" << trans); + +} + + + + + +void +LrWpanSlottedCsmacaTestCase::DoRun () +{ + // Create 2 nodes, and a NetDevice for each one + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + + Ptr dev0 = CreateObject (); + Ptr dev1 = CreateObject (); + + dev0->SetAddress (Mac16Address ("00:01")); + dev1->SetAddress (Mac16Address ("00:02")); + + // Each device must be attached to the same channel + Ptr channel = CreateObject (); + Ptr propModel = CreateObject (); + Ptr delayModel = CreateObject (); + channel->AddPropagationLossModel (propModel); + channel->SetPropagationDelayModel (delayModel); + + dev0->SetChannel (channel); + dev1->SetChannel (channel); + + // To complete configuration, a LrWpanNetDevice must be added to a node + n0->AddDevice (dev0); + n1->AddDevice (dev1); + + + // Set mobility + Ptr sender0Mobility = CreateObject (); + sender0Mobility->SetPosition (Vector (0,0,0)); + dev0->GetPhy ()->SetMobility (sender0Mobility); + Ptr sender1Mobility = CreateObject (); + + sender1Mobility->SetPosition (Vector (0,10,0)); + dev1->GetPhy ()->SetMobility (sender1Mobility); + + + // MAC layer and CSMA-CA callback hooks + + MlmeStartConfirmCallback cb0; + cb0 = MakeBoundCallback (&LrWpanSlottedCsmacaTestCase::StartConfirm, this, dev0); + dev0->GetMac ()->SetMlmeStartConfirmCallback (cb0); + + McpsDataConfirmCallback cb1; + cb1 = MakeBoundCallback (&LrWpanSlottedCsmacaTestCase::TransEndIndication, this, dev1); + dev1->GetMac ()->SetMcpsDataConfirmCallback (cb1); + + LrWpanMacTransCostCallback cb2; + cb2 = MakeBoundCallback (&LrWpanSlottedCsmacaTestCase::TransactionCost, this, dev1); + dev1->GetCsmaCa ()->SetLrWpanMacTransCostCallback (cb2); + + McpsDataIndicationCallback cb5; + cb5 = MakeBoundCallback (&LrWpanSlottedCsmacaTestCase::DataIndicationCoordinator, this, dev0); + dev0->GetMac ()->SetMcpsDataIndicationCallback (cb5); + + + // Connect to trace in the MAC layer + dev1->GetMac ()->TraceConnectWithoutContext ("MacIncSuperframeStatus", + MakeBoundCallback (&LrWpanSlottedCsmacaTestCase::IncomingSuperframeStatus, this, dev1)); + + + // Manual Device Association + // Note: We manually associate dev1 device to a PAN coordinator + // because currently there is no automatic association behavior; + // The PAN COORDINATOR does not need to associate, set + // PAN Id or its own coordinator id, these are set + // by the MLME-start.request primitive when used. + + dev1->GetMac ()->SetPanId (5); + dev1->GetMac ()->SetAssociatedCoor (Mac16Address ("00:01")); + + + // Dev0 sets the start time for beacons + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = 5; + params.m_bcnOrd = 14; + params.m_sfrmOrd = 6; + Simulator::ScheduleWithContext (1, Seconds (2.0), + &LrWpanMac::MlmeStartRequest, + dev0->GetMac (), params); + + // Dev1 sets the transmission of data packet + + Ptr p1 = Create (5); // 5 bytes of dummy data + McpsDataRequestParams params2; + params2.m_dstPanId = 5; + params2.m_srcAddrMode = SHORT_ADDR; + params2.m_dstAddrMode = SHORT_ADDR; + params2.m_dstAddr = Mac16Address ("00:01"); + params2.m_msduHandle = 0; + + + // Beacon-enabled | Device to Coordinator | Direct transmission + Simulator::ScheduleWithContext (1, Seconds (2.93), + &LrWpanMac::McpsDataRequest, + dev1->GetMac (), params2, p1); + + + Simulator::Stop (Seconds (4)); + Simulator::Run (); + + Time activePeriodsSum; + Time transactionTime; + uint64_t symbolRate; + u_int32_t activePeriodSize = 20; + double boundary; + + + // Verifies that the CCA checks and the rest of the transaction runs + // on a boundary of an Active Period in the slotted CSMA-CA. + + symbolRate = (uint64_t) dev1->GetMac ()->GetPhy ()->GetDataOrSymbolRate (false); + activePeriodsSum = m_apBoundary - m_startCap; + boundary = (activePeriodsSum.GetMicroSeconds () * 1000 * 1000 * symbolRate) % activePeriodSize; + + NS_TEST_EXPECT_MSG_EQ (boundary, 0, "Error, the transaction is not calculated on a boundary of an Active Period in the CAP"); + + + // Slotted CSMA-CA needs to precalculate the cost of the transaction to ensure there + // is enough time in the CAP to complete the transmission. The following checks that such + // pre-calculation matches the time it took to complete the transmission. + + // The calculated transaction includes the IFS time, so we need to subtract its value to compare it. + // MPDU = MAC Header + MSDU (payload) + // Mac Header = 13 bytes + // If the MPDU is > aMaxSIFSFrameSize (18 bytes) then IFS = LIFS (40 symbols), else IFS = SIFS (12 symbols) + + uint32_t ifsSize; + if (p1->GetSize () > 18) + { + ifsSize = 40; + } + else + { + ifsSize = 12; + } + + transactionTime = MicroSeconds ((m_transCost - ifsSize) * 1000 * 1000 / symbolRate); + + NS_TEST_EXPECT_MSG_EQ (m_sentTime,(m_apBoundary + transactionTime),"Error, the transaction time is not the expected value"); + + Simulator::Destroy (); + +} + + +/** + * \ingroup lr-wpan-test + * \ingroup tests + * + * \brief LrWpan Slotted CSMA-CA TestSuite + */ + +class LrWpanSlottedCsmacaTestSuite : public TestSuite +{ +public: + LrWpanSlottedCsmacaTestSuite (); +}; + +LrWpanSlottedCsmacaTestSuite::LrWpanSlottedCsmacaTestSuite () + : TestSuite ("lr-wpan-slotted-csmaca", UNIT) +{ + AddTestCase (new LrWpanSlottedCsmacaTestCase, TestCase::QUICK); +} + +static LrWpanSlottedCsmacaTestSuite lrWpanSlottedCsmacaTestSuite; //!< Static variable for test initialization + + diff --git a/src/lr-wpan/wscript b/src/lr-wpan/wscript index e7a195fb3..bd19b803f 100644 --- a/src/lr-wpan/wscript +++ b/src/lr-wpan/wscript @@ -8,6 +8,8 @@ def build(bld): 'model/lr-wpan-phy.cc', 'model/lr-wpan-mac.cc', 'model/lr-wpan-mac-header.cc', + 'model/lr-wpan-mac-pl-headers.cc', + 'model/lr-wpan-fields.cc', 'model/lr-wpan-mac-trailer.cc', 'model/lr-wpan-csmaca.cc', 'model/lr-wpan-net-device.cc', @@ -27,6 +29,8 @@ def build(bld): 'test/lr-wpan-packet-test.cc', 'test/lr-wpan-pd-plme-sap-test.cc', 'test/lr-wpan-spectrum-value-helper-test.cc', + 'test/lr-wpan-ifs-test.cc', + 'test/lr-wpan-slotted-csmaca-test.cc', ] headers = bld(features='ns3header') @@ -37,6 +41,8 @@ def build(bld): 'model/lr-wpan-phy.h', 'model/lr-wpan-mac.h', 'model/lr-wpan-mac-header.h', + 'model/lr-wpan-mac-pl-headers.h', + 'model/lr-wpan-fields.h', 'model/lr-wpan-mac-trailer.h', 'model/lr-wpan-csmaca.h', 'model/lr-wpan-net-device.h', diff --git a/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc b/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc new file mode 100644 index 000000000..0eb43f19d --- /dev/null +++ b/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc @@ -0,0 +1,181 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2020 Ritsumeikan University, Shiga, 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 + */ + + +#include +#include "ns3/core-module.h" +#include "ns3/internet-module.h" +#include "ns3/internet-apps-module.h" +#include "ns3/mobility-module.h" +#include "ns3/spectrum-module.h" +#include "ns3/propagation-module.h" +#include "ns3/sixlowpan-module.h" +#include "ns3/lr-wpan-module.h" + +using namespace ns3; + + +static void dataSentMacConfirm (McpsDataConfirmParams params) +{ + // In the case of transmissions with the Ack flag activated, the transaction is only + // successful if the Ack was received. + if (params.m_status == LrWpanMcpsDataConfirmStatus::IEEE_802_15_4_SUCCESS) + { + NS_LOG_UNCOND ("**********" << Simulator::Now ().GetSeconds () << " secs | Transmission successfully sent"); + } +} + + +int main (int argc, char** argv) +{ + + bool verbose = false; + + CommandLine cmd; + cmd.AddValue ("verbose", "turn on log components", verbose); + cmd.Parse (argc, argv); + + if (verbose) + { + LogComponentEnableAll (LOG_PREFIX_TIME); + LogComponentEnableAll (LOG_PREFIX_FUNC); + LogComponentEnable ("LrWpanMac", LOG_LEVEL_INFO); + LogComponentEnable ("LrWpanCsmaCa", LOG_LEVEL_INFO); + LogComponentEnable ("LrWpanHelper", LOG_LEVEL_ALL); + LogComponentEnable ("Ping6Application", LOG_LEVEL_INFO); + } + + + NodeContainer nodes; + nodes.Create (2); + + MobilityHelper mobility; + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (20), + "DeltaY", DoubleValue (20), + "GridWidth", UintegerValue (3), + "LayoutType", StringValue ("RowFirst")); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (nodes); + + LrWpanHelper lrWpanHelper; + // Add and install the LrWpanNetDevice for each node + NetDeviceContainer lrwpanDevices = lrWpanHelper.Install (nodes); + + Ptr dev1 = lrwpanDevices.Get (0)->GetObject (); + Ptr dev2 = lrwpanDevices.Get (1)->GetObject (); + + McpsDataConfirmCallback cb1; + cb1 = MakeCallback (&dataSentMacConfirm); + dev1->GetMac ()->SetMcpsDataConfirmCallback (cb1); + dev2->GetMac ()->SetMcpsDataConfirmCallback (cb1); + + + // Fake PAN association, coordinator assignment, short address assignment and initialization + // of beacon-enabled mode in 802.15.4-2011. + // This is needed because the lr-wpan module does not provide (yet) + // a full PAN association procedure. + + // AssociateToBeaconPan (devices, PAN ID, Coordinator Address, Beacon Order, Superframe Order) + + // Must be careful not setting the beacon order (BO) and the superframe order (SO) too far apart + // or the ping reply (ICMPV6 echo reply) can time out during the inactive period of the superframe. + // A full time table of the BO/SO time equivalence can be found at the end of this document. + // The current configuration is BO = 14, SO = 13 : + + // Contention Access Period (CAP) Inactive + // (125.82912 secs) (125.82088) + // |---------------------------------------------|-------------------------------------------| + // Beacon Beacon + // Beacon Interval = 251.65 secs + // |-----------------------------------------------------------------------------------------| + + lrWpanHelper.AssociateToBeaconPan (lrwpanDevices, 0, Mac16Address ("00:01"), 14,13); + + + InternetStackHelper internetv6; + internetv6.Install (nodes); + + SixLowPanHelper sixlowpan; + NetDeviceContainer devices = sixlowpan.Install (lrwpanDevices); + + Ipv6AddressHelper ipv6; + ipv6.SetBase (Ipv6Address ("2001:2::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer deviceInterfaces; + deviceInterfaces = ipv6.Assign (devices); + + + // Send ping packets after the 2nd second of the simulation during the + // first 8 seconds of the CAP in the incoming superframe + + uint32_t packetSize = 10; + uint32_t maxPacketCount = 5; + Time interPacketInterval = Seconds (1); + Ping6Helper ping6; + + ping6.SetLocal (deviceInterfaces.GetAddress (0, 1)); + ping6.SetRemote (deviceInterfaces.GetAddress (1, 1)); + + ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + ping6.SetAttribute ("Interval", TimeValue (interPacketInterval)); + ping6.SetAttribute ("PacketSize", UintegerValue (packetSize)); + ApplicationContainer apps = ping6.Install (nodes.Get (0)); + + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + AsciiTraceHelper ascii; + lrWpanHelper.EnableAsciiAll (ascii.CreateFileStream ("Ping-6LoW-lr-wpan-beacon.tr")); + lrWpanHelper.EnablePcapAll (std::string ("Ping-6LoW-lr-wpan-beacon"), true); + + + Simulator::Stop (Seconds (600)); + + Simulator::Run (); + Simulator::Destroy (); + +} + +// BO/SO values to time equivalence +// These times are only valid for a 250kbps O-QPSK modulation, +// times differ with other modulation configurations. + +// +------------------------+ +// | BO/SO | Time (secs) | +// +------------------------+ +// | 0 | 0.01536 secs | +// | 1 | 0.03072 secs | +// | 2 | 0.06144 secs | +// | 3 | 0.12288 secs | +// | 4 | 0.24576 secs | +// | 5 | 0.49152 secs | +// | 6 | 0.98304 secs | +// | 7 | 1.96608 secs | +// | 8 | 3.93216 secs | +// | 9 | 7.86432 secs | +// | 10 | 15.72864 secs | +// | 11 | 31.45728 secs | +// | 12 | 62.91456 secs | +// | 13 | 125.82912 secs | +// | 14 | 251.65 secs | +// +------------------------+ diff --git a/src/sixlowpan/examples/wscript b/src/sixlowpan/examples/wscript index 3a13a607c..915b22320 100644 --- a/src/sixlowpan/examples/wscript +++ b/src/sixlowpan/examples/wscript @@ -11,6 +11,10 @@ def build(bld): obj = bld.create_ns3_program('example-ping-lr-wpan', ['network', 'sixlowpan', 'internet', 'lr-wpan', 'internet-apps']) obj.source = 'example-ping-lr-wpan.cc' + + obj = bld.create_ns3_program('example-ping-lr-wpan-beacon', + ['network', 'sixlowpan', 'internet', 'lr-wpan', 'internet-apps']) + obj.source = 'example-ping-lr-wpan-beacon.cc' obj = bld.create_ns3_program('example-ping-lr-wpan-mesh-under', ['network', 'sixlowpan', 'internet', 'lr-wpan', 'internet-apps', 'csma'])