From f4b5e5e4e279cf31ebc34f92b54f2cbeb0d661b9 Mon Sep 17 00:00:00 2001 From: Sascha Jopen Date: Mon, 24 Feb 2014 12:51:06 +0100 Subject: [PATCH] - Fixed error in MAC state machine when sending an ACK and enqueuing a data packet at the same time. - Fixed error when switching the PHY transceiver while a switch is already in progress. --- src/lr-wpan/model/lr-wpan-mac.cc | 36 ++++++++++---- src/lr-wpan/model/lr-wpan-mac.h | 1 + src/lr-wpan/model/lr-wpan-phy.cc | 83 ++++++++++++++++++-------------- 3 files changed, 75 insertions(+), 45 deletions(-) diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index 6f3ccee3e..f5e5e06f7 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -207,6 +207,7 @@ void LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr p) { NS_LOG_FUNCTION (this << p); + McpsDataConfirmParams confirmParams; confirmParams.m_msduHandle = params.m_msduHandle; @@ -383,12 +384,14 @@ LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr p) void LrWpanMac::CheckQueue () { + NS_LOG_FUNCTION (this); + // 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) + if (m_lrWpanMacState == MAC_IDLE && !m_txQueue.empty () && m_txPkt == 0 && !m_setMacState.IsRunning ()) { TxQueueElement *txQElement = m_txQueue.front (); m_txPkt = txQElement->txQPkt; - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); } } @@ -578,8 +581,10 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) // Currently we simply restart CSMA/CA after sending the ACK. m_csmaCa->Cancel (); } + // Cancel any pending MAC state change, ACKs have higher priority. + m_setMacState.Cancel (); ChangeMacState (MAC_IDLE); - Simulator::ScheduleNow (&LrWpanMac::SendAck, this, receivedMacHdr.GetSeqNum ()); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SendAck, this, receivedMacHdr.GetSeqNum ()); } if (receivedMacHdr.IsData () && !m_mcpsDataIndicationCallback.IsNull ()) @@ -606,7 +611,8 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) m_mcpsDataConfirmCallback (confirmParams); } RemoveFirstTxQElement (); - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); } else { @@ -614,11 +620,13 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) m_ackWaitTimeout.Cancel (); if (!PrepareRetransmission ()) { - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); } else { - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA); } } } @@ -634,6 +642,8 @@ LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr p, uint8_t lqi) void LrWpanMac::SendAck (uint8_t seqno) { + NS_LOG_FUNCTION (this << static_cast (seqno)); + NS_ASSERT (m_lrWpanMacState == MAC_IDLE); // Generate a corresponding ACK Frame. @@ -668,6 +678,8 @@ LrWpanMac::RemoveFirstTxQElement (void) void LrWpanMac::AckWaitTimeout (void) { + NS_LOG_FUNCTION (this); + // TODO: If we are a PAN coordinator and this was an indirect transmission, // we will not initiate a retransmission. Instead we wait for the data // being extracted after a new data request command. @@ -684,6 +696,8 @@ LrWpanMac::AckWaitTimeout (void) bool LrWpanMac::PrepareRetransmission (void) { + NS_LOG_FUNCTION (this); + if (m_retransmission >= m_macMaxFrameRetries) { // Maximum number of retransmissions has been reached. @@ -732,7 +746,8 @@ LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) Time waitTime = MicroSeconds (GetMacAckWaitDuration () * 1000 * 1000 / m_phy->GetDataOrSymbolRate (false)); NS_ASSERT (m_ackWaitTimeout.IsExpired()); m_ackWaitTimeout = Simulator::Schedule (waitTime, &LrWpanMac::AckWaitTimeout, this); - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_ACK_PENDING); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_ACK_PENDING); return; } else @@ -781,7 +796,8 @@ LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status) NS_FATAL_ERROR ("Transmission attempt failed with PHY status " << status); } - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + m_setMacState.Cancel (); + m_setMacState = Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); } void @@ -880,7 +896,7 @@ LrWpanMac::SetLrWpanMacState (LrWpanMacState macState) } else if (macState == MAC_CSMA) { - NS_ASSERT (m_lrWpanMacState == MAC_IDLE); + NS_ASSERT (m_lrWpanMacState == MAC_IDLE || m_lrWpanMacState == MAC_ACK_PENDING); ChangeMacState (MAC_CSMA); m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_RX_ON); @@ -907,7 +923,7 @@ LrWpanMac::SetLrWpanMacState (LrWpanMacState macState) // remove the copy of the packet that was just sent RemoveFirstTxQElement (); - Simulator::ScheduleNow (&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE); + ChangeMacState (MAC_IDLE); } } diff --git a/src/lr-wpan/model/lr-wpan-mac.h b/src/lr-wpan/model/lr-wpan-mac.h index 6868262a7..59ab180b5 100644 --- a/src/lr-wpan/model/lr-wpan-mac.h +++ b/src/lr-wpan/model/lr-wpan-mac.h @@ -413,6 +413,7 @@ private: std::deque m_txQueue; uint8_t m_retransmission; EventId m_ackWaitTimeout; + EventId m_setMacState; bool m_macRxOnWhenIdle; }; diff --git a/src/lr-wpan/model/lr-wpan-phy.cc b/src/lr-wpan/model/lr-wpan-phy.cc index b0f5ff166..a140a5e51 100644 --- a/src/lr-wpan/model/lr-wpan-phy.cc +++ b/src/lr-wpan/model/lr-wpan-phy.cc @@ -254,7 +254,8 @@ LrWpanPhy::StartRx (Ptr spectrumRxParams) Ptr lrWpanRxParams = DynamicCast (spectrumRxParams); - if (m_trxState == IEEE_802_15_4_PHY_RX_ON) + // Prevent PHY from receiving another packet while switching the transceiver state. + if (m_trxState == IEEE_802_15_4_PHY_RX_ON && !m_setTRXState.IsRunning ()) { if (lrWpanRxParams != 0) { @@ -407,47 +408,63 @@ LrWpanPhy::PdDataRequest (const uint32_t psduLength, Ptr p) return; } - if (m_trxState == IEEE_802_15_4_PHY_TX_ON) + // Prevent PHY from sending a packet while switching the transceiver state. + if (!m_setTRXState.IsRunning()) { - //send down - NS_ASSERT (m_channel); + if (m_trxState == IEEE_802_15_4_PHY_TX_ON) + { + //send down + NS_ASSERT (m_channel); - // Remove a possible LQI tag from a previous transmission of the packet. - LrWpanLqiTag lqiTag; - p->RemovePacketTag (lqiTag); + // Remove a possible LQI tag from a previous transmission of the packet. + LrWpanLqiTag lqiTag; + p->RemovePacketTag (lqiTag); - Ptr txParams = Create (); - txParams->duration = CalculateTxTime (p); - txParams->txPhy = GetObject (); - txParams->psd = m_txPsd; - txParams->txAntenna = m_antenna; - Ptr pb = CreateObject (); - pb->AddPacket (p); - txParams->packetBurst = pb; - m_channel->StartTx (txParams); - m_pdDataRequest = Simulator::Schedule (txParams->duration, &LrWpanPhy::EndTx, this); - ChangeTrxState (IEEE_802_15_4_PHY_BUSY_TX); - m_phyTxBeginTrace (p); - m_currentTxPacket.first = p; - m_currentTxPacket.second = false; - return; + Ptr txParams = Create (); + txParams->duration = CalculateTxTime (p); + txParams->txPhy = GetObject (); + txParams->psd = m_txPsd; + txParams->txAntenna = m_antenna; + Ptr pb = CreateObject (); + pb->AddPacket (p); + txParams->packetBurst = pb; + m_channel->StartTx (txParams); + m_pdDataRequest = Simulator::Schedule (txParams->duration, &LrWpanPhy::EndTx, this); + ChangeTrxState (IEEE_802_15_4_PHY_BUSY_TX); + m_phyTxBeginTrace (p); + m_currentTxPacket.first = p; + m_currentTxPacket.second = false; + return; + } + else if ((m_trxState == IEEE_802_15_4_PHY_RX_ON) + || (m_trxState == IEEE_802_15_4_PHY_TRX_OFF) + || (m_trxState == IEEE_802_15_4_PHY_BUSY_TX) ) + { + if (!m_pdDataConfirmCallback.IsNull ()) + { + m_pdDataConfirmCallback (m_trxState); + } + // Drop packet, hit PhyTxDrop trace + m_phyTxDropTrace (p); + return; + } + else + { + NS_FATAL_ERROR ("This should be unreachable, or else state " << m_trxState << " should be added as a case"); + } } - else if ((m_trxState == IEEE_802_15_4_PHY_RX_ON) - || (m_trxState == IEEE_802_15_4_PHY_TRX_OFF) - || (m_trxState == IEEE_802_15_4_PHY_BUSY_TX) ) + else { + // TODO: This error code is not covered by the standard. + // What is the correct behavior in this case? if (!m_pdDataConfirmCallback.IsNull ()) { - m_pdDataConfirmCallback (m_trxState); + m_pdDataConfirmCallback (IEEE_802_15_4_PHY_UNSPECIFIED); } // Drop packet, hit PhyTxDrop trace m_phyTxDropTrace (p); return; } - else - { - NS_FATAL_ERROR ("This should be unreachable, or else state " << m_trxState << " should be added as a case"); - } } void @@ -553,6 +570,7 @@ LrWpanPhy::PlmeSetTRXStateRequest (LrWpanPhyEnumeration state) else { NS_LOG_DEBUG ("Cancel m_setTRXState"); + // Keep the transceiver state as the old state before the switching attempt. m_setTRXState.Cancel(); } } @@ -627,8 +645,6 @@ LrWpanPhy::PlmeSetTRXStateRequest (LrWpanPhyEnumeration state) } m_trxStatePending = IEEE_802_15_4_PHY_TX_ON; - // Prevent PHY from receiving another packet while switching. - ChangeTrxState (IEEE_802_15_4_PHY_IDLE); // Delay for turnaround time // TODO: Does it also take aTurnaroundTime to switch the transceiver state, @@ -698,9 +714,6 @@ LrWpanPhy::PlmeSetTRXStateRequest (LrWpanPhyEnumeration state) // even when the transmitter is not busy? (6.9.1) m_trxStatePending = IEEE_802_15_4_PHY_RX_ON; - // Prevent PHY from sending another packet while switching. - ChangeTrxState (IEEE_802_15_4_PHY_IDLE); - Time setTime = Seconds ( (double) aTurnaroundTime / GetDataOrSymbolRate (false)); m_setTRXState = Simulator::Schedule (setTime, &LrWpanPhy::EndSetTRXState, this); return;