From 74532df514d3d55275eb50347c75915eaf723c53 Mon Sep 17 00:00:00 2001 From: Alberto Gallegos Date: Wed, 31 Mar 2021 10:51:03 +0000 Subject: [PATCH] lr-wpan: IFS bug fix (it also solves #238) --- src/lr-wpan/model/lr-wpan-mac.cc | 71 ++++++++---- src/lr-wpan/model/lr-wpan-mac.h | 6 +- src/lr-wpan/test/lr-wpan-ifs-test.cc | 161 +++++++++++++++++++++------ 3 files changed, 184 insertions(+), 54 deletions(-) diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index 11164eb43..b8ad1f603 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -140,6 +140,11 @@ LrWpanMac::GetTypeId (void) "the sent packet", MakeTraceSourceAccessor (&LrWpanMac::m_sentPktTrace), "ns3::LrWpanMac::SentTracedCallback") + .AddTraceSource ("IfsEnd", + "Trace source reporting the end of an " + "Interframe space (IFS) ", + MakeTraceSourceAccessor (&LrWpanMac::m_macIfsEndTrace), + "ns3::Packet::TracedCallback") ; return tid; } @@ -390,7 +395,7 @@ LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr p) { // short address and ACK requested. Mac16Address shortAddr = macHdr.GetShortDstAddr (); - if (shortAddr.IsBroadcast() || shortAddr.IsMulticast()) + if (shortAddr.IsBroadcast () || shortAddr.IsMulticast ()) { NS_LOG_LOGIC ("LrWpanMac::McpsDataRequest: requested an ACK on broadcast or multicast destination (" << shortAddr << ") - forcefully removing it."); macHdr.SetNoAckReq (); @@ -899,9 +904,13 @@ LrWpanMac::CheckQueue () //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) { - TxQueueElement *txQElement = m_txQueue.front (); - m_txPkt = txQElement->txQPkt; - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + // check MAC is not in a IFS + if (!m_ifsEvent.IsRunning ()) + { + TxQueueElement *txQElement = m_txQueue.front (); + m_txPkt = txQElement->txQPkt; + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + } } } } @@ -1362,9 +1371,10 @@ 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); + m_ifsEvent = Simulator::Schedule (ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime); } else { @@ -1433,7 +1443,7 @@ LrWpanMac::RemoveFirstTxQElement () Ptr pkt = p->Copy (); LrWpanMacHeader hdr; pkt->RemoveHeader (hdr); - if (!hdr.GetShortDstAddr ().IsBroadcast () && !hdr.GetShortDstAddr ().IsMulticast()) + if (!hdr.GetShortDstAddr ().IsBroadcast () && !hdr.GetShortDstAddr ().IsMulticast ()) { m_sentPktTrace (p, m_retransmission + 1, m_numCsmacaRetry); } @@ -1466,11 +1476,27 @@ LrWpanMac::AckWaitTimeout (void) } void -LrWpanMac::IfsWaitTimeout (void) +LrWpanMac::IfsWaitTimeout (Time ifsTime) { - NS_LOG_DEBUG ("IFS Completed"); - m_setMacState.Cancel (); - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + uint64_t symbolRate = (uint64_t) m_phy->GetDataOrSymbolRate (false); + Time lifsTime = Seconds ((double) m_macLIFSPeriod / symbolRate); + Time sifsTime = Seconds ((double) m_macSIFSPeriod / symbolRate); + + if (ifsTime == lifsTime) + { + NS_LOG_DEBUG ("LIFS of " << m_macLIFSPeriod << " symbols (" << ifsTime.As (Time::S) << ") completed "); + } + else if (ifsTime == sifsTime) + { + NS_LOG_DEBUG ("SIFS of " << m_macSIFSPeriod << " symbols (" << ifsTime.As (Time::S) << ") completed "); + } + else + { + NS_LOG_DEBUG ("Unknown IFS size (" << ifsTime.As (Time::S) << ") completed "); + } + + m_macIfsEndTrace (ifsTime); + CheckQueue (); } @@ -1612,14 +1638,13 @@ LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) if (!ifsWaitTime.IsZero ()) { - m_ifsEvent = Simulator::Schedule (ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this); - } - else - { - m_setMacState.Cancel (); - m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + m_ifsEvent = Simulator::Schedule (ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime); } + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + + } void @@ -1668,7 +1693,13 @@ LrWpanMac::PlmeSetTRXStateConfirm (LrWpanPhyEnumeration status) else if (m_lrWpanMacState == MAC_IDLE) { NS_ASSERT (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS || status == IEEE_802_15_4_PHY_TRX_OFF); - // Do nothing special when going idle. + + if (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS) + { + // Check if there is not messages to transmit when going idle + CheckQueue (); + } + } else if (m_lrWpanMacState == MAC_ACK_PENDING) { @@ -1710,7 +1741,7 @@ LrWpanMac::SetLrWpanMacState (LrWpanMacState macState) m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_TRX_OFF); } - CheckQueue (); + } else if (macState == MAC_ACK_PENDING) { @@ -1805,7 +1836,7 @@ LrWpanMac::GetMacMaxFrameRetries (void) const void LrWpanMac::PrintTransmitQueueSize (void) { - NS_LOG_DEBUG("Transit Queue Size: "< m_macIfsEndTrace; /** * The trace source fired when packets are considered as successfully sent * or the transmission has been given up. diff --git a/src/lr-wpan/test/lr-wpan-ifs-test.cc b/src/lr-wpan/test/lr-wpan-ifs-test.cc index f9632ee8d..ba87f547f 100644 --- a/src/lr-wpan/test/lr-wpan-ifs-test.cc +++ b/src/lr-wpan/test/lr-wpan-ifs-test.cc @@ -37,6 +37,7 @@ using namespace ns3; NS_LOG_COMPONENT_DEFINE ("lr-wpan-ifs-test"); + /** * \ingroup lr-wpan-test * \ingroup tests @@ -49,79 +50,128 @@ public: LrWpanDataIfsTestCase (); virtual ~LrWpanDataIfsTestCase (); - - private: static void DataConfirm (LrWpanDataIfsTestCase *testcase, Ptr dev, McpsDataConfirmParams params); + static void DataConfirm1 (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); + static void PhyDataRxStart (LrWpanDataIfsTestCase *testcase, + Ptr dev, + Ptr); + + static void DataReceived2 (LrWpanDataIfsTestCase *testcase, + Ptr dev, + Ptr); + + static void IfsEnd (LrWpanDataIfsTestCase *testcase, + Ptr dev, + Time IfsTime); 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_ackRxTime; //!< The time of the received acknowledgment. Time m_endIfs; //!< The time where the Interframe Space ended. + Time m_phyStartRx; //!< The time the phy start receiving a packet. }; LrWpanDataIfsTestCase::LrWpanDataIfsTestCase () - : TestCase ("Lrwpan: IFS with and without ACK") -{ - -} + : TestCase ("Lrwpan: IFS tests") +{} LrWpanDataIfsTestCase::~LrWpanDataIfsTestCase () -{ - -} +{} void LrWpanDataIfsTestCase::DataConfirm (LrWpanDataIfsTestCase *testcase, Ptr dev, McpsDataConfirmParams params) { - std::cout << Simulator::Now ().GetSeconds () << " | Dataframe Sent\n"; + // get the end time of tranmissions from dev 0 (Node 0) testcase->m_lastTxTime = Simulator::Now (); +} +void +LrWpanDataIfsTestCase::DataConfirm1 (LrWpanDataIfsTestCase *testcase, Ptr dev, McpsDataConfirmParams params) +{ + // get the end time of tranmissions from dev 1 (Node 1) + testcase->m_lastTxTime = Simulator::Now (); } void LrWpanDataIfsTestCase::DataReceived (LrWpanDataIfsTestCase *testcase,Ptr dev, Ptr p) { + // Callback for Data received in the Dev0 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) + if (receivedMacHdr.IsAcknowledgment ()) { - testcase->m_endIfs = Simulator::Now (); - std::cout << Simulator::Now ().GetSeconds () << " | MAC layer is free\n"; + testcase->m_ackRxTime = Simulator::Now (); + std::cout << Simulator::Now ().GetSeconds () << " | Dev0 (Node 0) received Acknowledgment.\n"; + } + else if (receivedMacHdr.GetShortDstAddr ().IsBroadcast ()) + { + std::cout << Simulator::Now ().GetSeconds () << " | Dev0 (Node 0) received Broadcast. \n"; } } +void +LrWpanDataIfsTestCase::PhyDataRxStart (LrWpanDataIfsTestCase *testcase, Ptr dev, Ptr) +{ + //get the start time the phy in dev 0 ( Node 0) start receiving a frame + testcase->m_phyStartRx = Simulator::Now (); +} + +void +LrWpanDataIfsTestCase::DataReceived2 (LrWpanDataIfsTestCase *testcase,Ptr dev, Ptr p) +{ + // Callback for Data received in the Dev1 + Ptr RxPacket = p->Copy (); + LrWpanMacHeader receivedMacHdr; + RxPacket->RemoveHeader (receivedMacHdr); + + if (receivedMacHdr.GetShortDstAddr ().IsBroadcast ()) + { + std::cout << Simulator::Now ().GetSeconds () << " | Dev1 (Node 1) received Broadcast. \n"; + + // Bcst received, respond with another bcst + + Ptr p0 = Create (50); // 50 bytes of dummy data + McpsDataRequestParams params1; + params1.m_dstPanId = 0; + params1.m_srcAddrMode = SHORT_ADDR; + params1.m_dstAddrMode = SHORT_ADDR; + params1.m_dstAddr = Mac16Address ("ff:ff"); + params1.m_msduHandle = 0; + + Simulator::ScheduleNow (&LrWpanMac::McpsDataRequest, + dev->GetMac (), params1,p0); + } + +} + + +void +LrWpanDataIfsTestCase::IfsEnd (LrWpanDataIfsTestCase *testcase,Ptr dev, Time IfsTime) +{ + // take the time of the end of the IFS + testcase->m_endIfs = Simulator::Now (); +} + + void LrWpanDataIfsTestCase::DoRun () { @@ -133,6 +183,11 @@ LrWpanDataIfsTestCase::DoRun () // 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 + LogComponentEnableAll (LOG_PREFIX_TIME); + LogComponentEnableAll (LOG_PREFIX_FUNC); + LogComponentEnable ("LrWpanPhy", LOG_LEVEL_DEBUG); + LogComponentEnable ("LrWpanMac", LOG_LEVEL_DEBUG); + LogComponentEnable ("LrWpanCsmaCa", LOG_LEVEL_DEBUG); // Create 2 nodes, and a NetDevice for each one Ptr n0 = CreateObject (); @@ -159,8 +214,10 @@ LrWpanDataIfsTestCase::DoRun () n1->AddDevice (dev1); // Connect to trace files in the MAC layer - dev0->GetMac ()->TraceConnectWithoutContext ("MacStateValue", MakeBoundCallback (&LrWpanDataIfsTestCase::MacState, this, dev0)); + dev0->GetMac ()->TraceConnectWithoutContext ("IfsEnd", MakeBoundCallback (&LrWpanDataIfsTestCase::IfsEnd, this, dev0)); dev0->GetMac ()->TraceConnectWithoutContext ("MacRx", MakeBoundCallback (&LrWpanDataIfsTestCase::DataReceived, this, dev0)); + dev0->GetPhy ()->TraceConnectWithoutContext ("PhyRxBegin", MakeBoundCallback (&LrWpanDataIfsTestCase::PhyDataRxStart, this, dev0)); + dev1->GetMac ()->TraceConnectWithoutContext ("MacRx", MakeBoundCallback (&LrWpanDataIfsTestCase::DataReceived2, this, dev1)); Ptr sender0Mobility = CreateObject (); sender0Mobility->SetPosition (Vector (0,0,0)); @@ -174,6 +231,10 @@ LrWpanDataIfsTestCase::DoRun () cb0 = MakeBoundCallback (&LrWpanDataIfsTestCase::DataConfirm, this, dev0); dev0->GetMac ()->SetMcpsDataConfirmCallback (cb0); + McpsDataConfirmCallback cb1; + cb1 = MakeBoundCallback (&LrWpanDataIfsTestCase::DataConfirm1, this, dev1); + dev1->GetMac ()->SetMcpsDataConfirmCallback (cb1); + Ptr p0 = Create (2); McpsDataRequestParams params; params.m_dstPanId = 0; @@ -199,6 +260,7 @@ LrWpanDataIfsTestCase::DoRun () // 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"); + std::cout << "----------------------------------\n"; //////////////////////// LIFS /////////////////////////// @@ -213,9 +275,10 @@ LrWpanDataIfsTestCase::DoRun () // 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) + // LIFS = 40 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"); + std::cout << "----------------------------------\n"; //////////////////////// SIFS after ACK ////////////////// @@ -233,6 +296,7 @@ LrWpanDataIfsTestCase::DoRun () // 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"); + std::cout << "----------------------------------\n"; //////////////////////// LIFS after ACK ////////////////// @@ -248,9 +312,40 @@ LrWpanDataIfsTestCase::DoRun () // 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) + // LIFS = 40 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"); + std::cout << "----------------------------------\n"; + + /////////////////////// BCST frame with immediate BCST response ////////////////// + + // A packet is broadcasted and the receiving device respond with another broadcast. + // The devices are configured to not have any backoff delays in their CSMA/CA. + // In most cases, a device receive a packet after its IFS, however in this test, + // the receiving device of the reply broadcast will still be in its IFS when the + // broadcast is received (i.e. a PHY StartRX () occur before the end of IFS). + // This demonstrates that a device can start receiving a frame even during an IFS. + + // Makes the backoff delay period = 0 in the CSMA/CA + dev0->GetCsmaCa ()->SetMacMinBE (0); + dev1->GetCsmaCa ()->SetMacMinBE (0); + + p0 = Create (50); // 50 bytes of dummy data + params.m_dstPanId = 0; + params.m_srcAddrMode = SHORT_ADDR; + params.m_dstAddrMode = SHORT_ADDR; + params.m_dstAddr = Mac16Address ("ff:ff"); + params.m_msduHandle = 0; + + Simulator::ScheduleWithContext (1, Seconds (0.0), + &LrWpanMac::McpsDataRequest, + dev0->GetMac (), params, p0); + + Simulator::Run (); + + NS_TEST_ASSERT_MSG_GT (m_endIfs, m_phyStartRx, "Error, IFS end time should be greater than PHY start Rx time"); + + ////////////////////////////////////////////////////////////////////////////////// Simulator::Destroy ();