- 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.
This commit is contained in:
Sascha Jopen
2014-02-24 12:51:06 +01:00
parent 131f31f56a
commit f4b5e5e4e2
3 changed files with 75 additions and 45 deletions

View File

@@ -207,6 +207,7 @@ void
LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
McpsDataConfirmParams confirmParams;
confirmParams.m_msduHandle = params.m_msduHandle;
@@ -383,12 +384,14 @@ LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr<Packet> 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<Packet> 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<Packet> 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<Packet> 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<Packet> p, uint8_t lqi)
void
LrWpanMac::SendAck (uint8_t seqno)
{
NS_LOG_FUNCTION (this << static_cast<uint32_t> (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);
}
}

View File

@@ -413,6 +413,7 @@ private:
std::deque<TxQueueElement*> m_txQueue;
uint8_t m_retransmission;
EventId m_ackWaitTimeout;
EventId m_setMacState;
bool m_macRxOnWhenIdle;
};

View File

@@ -254,7 +254,8 @@ LrWpanPhy::StartRx (Ptr<SpectrumSignalParameters> spectrumRxParams)
Ptr<LrWpanSpectrumSignalParameters> lrWpanRxParams = DynamicCast<LrWpanSpectrumSignalParameters> (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<Packet> 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<LrWpanSpectrumSignalParameters> txParams = Create<LrWpanSpectrumSignalParameters> ();
txParams->duration = CalculateTxTime (p);
txParams->txPhy = GetObject<SpectrumPhy> ();
txParams->psd = m_txPsd;
txParams->txAntenna = m_antenna;
Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
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<LrWpanSpectrumSignalParameters> txParams = Create<LrWpanSpectrumSignalParameters> ();
txParams->duration = CalculateTxTime (p);
txParams->txPhy = GetObject<SpectrumPhy> ();
txParams->psd = m_txPsd;
txParams->txAntenna = m_antenna;
Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
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;