lr-wpan: IFS bug fix (it also solves #238)

This commit is contained in:
Alberto Gallegos
2021-03-31 10:51:03 +00:00
committed by Tommaso Pecorella
parent 894d786e24
commit 74532df514
3 changed files with 184 additions and 54 deletions

View File

@@ -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<Packet> 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<Packet> 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<Packet> 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_txQueue.size());
NS_LOG_DEBUG ("Transmit Queue Size: " << m_txQueue.size ());
}
void

View File

@@ -1059,7 +1059,7 @@ private:
* the mac layer wait an Interframe Space (IFS) time and triggers this function
* to continue with the MAC flow.
*/
void IfsWaitTimeout (void);
void IfsWaitTimeout (Time ifsTime);
/**
* Check for remaining retransmissions for the packet currently being sent.
* Drop the packet, if there are no retransmissions left.
@@ -1089,6 +1089,10 @@ private:
*/
PendingAddrFields GetPendingAddrFields (void);
/**
* The trace source is fired at the end of any Interframe Space (IFS).
*/
TracedCallback<Time> m_macIfsEndTrace;
/**
* The trace source fired when packets are considered as successfully sent
* or the transmission has been given up.

View File

@@ -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<LrWpanNetDevice> dev,
McpsDataConfirmParams params);
static void DataConfirm1 (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> dev,
McpsDataConfirmParams params);
static void DataReceived (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> dev,
Ptr<const Packet>);
static void MacState (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> dev,
LrWpanMacState oldValue,
LrWpanMacState newValue);
static void PhyDataRxStart (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> dev,
Ptr<const Packet>);
static void DataReceived2 (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> dev,
Ptr<const Packet>);
static void IfsEnd (LrWpanDataIfsTestCase *testcase,
Ptr<LrWpanNetDevice> 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<LrWpanNetDevice> 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<LrWpanNetDevice> 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<LrWpanNetDevice> dev, Ptr<const Packet> p)
{
// Callback for Data received in the Dev0
Ptr<Packet> 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<LrWpanNetDevice> 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<LrWpanNetDevice> dev, Ptr<const Packet>)
{
//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<LrWpanNetDevice> dev, Ptr<const Packet> p)
{
// Callback for Data received in the Dev1
Ptr<Packet> 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<Packet> p0 = Create<Packet> (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<LrWpanNetDevice> 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<Node> n0 = CreateObject <Node> ();
@@ -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<ConstantPositionMobilityModel> sender0Mobility = CreateObject<ConstantPositionMobilityModel> ();
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<Packet> p0 = Create<Packet> (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<Packet> (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 ();