signetlabdei / lorawan

An ns-3 module for simulation of LoRaWAN networks
GNU General Public License v2.0
190 stars 132 forks source link

Some question about ACK_TIMEOUT and waitingTime #77

Closed QiuYukang closed 4 years ago

QiuYukang commented 4 years ago

Hi! I have two questions while reading the source code:

1. The first quastion is about ACK_TIMEOUT in lora end device

In EndDeviceLorawanMac::Send method in file end-device-lorawan-mac.cc, I see this:

Time netxTxDelay = GetNextTransmissionDelay ();
  if (netxTxDelay != Seconds (0))
    {
      // Add the ACK_TIMEOUT random delay if it is a retransmission.
      if (m_retxParams.waitingAck)
        {
          double ack_timeout = m_uniformRV->GetValue (1,3);
          netxTxDelay = netxTxDelay + Seconds (ack_timeout);
        }
      postponeTransmission (netxTxDelay, packet);
      return;
    }

It seems like you only calculated the ACK_TIMEOUT but didn't actually use it. Instead of using ack_timeout, you determine whether a retransmission is required when the second recieve window is closed, just like this codes in ClassAEndDeviceLorawanMac::CloseSecondReceiveWindow method in file class-a-end-device-lorawan-mac.cc:

if (m_retxParams.waitingAck)
    {
      NS_LOG_DEBUG ("No reception initiated by PHY: rescheduling transmission.");
      if (m_retxParams.retxLeft > 0 )
        {
          NS_LOG_INFO ("We have " << unsigned(m_retxParams.retxLeft) << " retransmissions left: rescheduling transmission.");
          this->Send (m_retxParams.packet);
        }

      else if (m_retxParams.retxLeft == 0 && m_phy->GetObject<EndDeviceLoraPhy> ()->GetState () != EndDeviceLoraPhy::RX)
        {
          uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
          m_requiredTxCallback (txs, false, m_retxParams.firstAttempt, m_retxParams.packet);
          NS_LOG_DEBUG ("Failure: no more retransmissions left. Used " << unsigned(txs) << " transmissions.");

          // Reset retransmission parameters
          resetRetransmissionParameters ();
        }

      else
        {
          NS_ABORT_MSG ("The number of retransmissions left is negative ! ");
        }
    }

Shouldn't we use ack_timeout to deciding whether to decide whether to retransmit the frame or not?

2. The second question is about the calculation of waitingTime when the end device try to send a frame

In ClassAEndDeviceLorawanMac::GetNextClassTransmissionDelay method in file class-a-end-device-lorawan-mac.cc, I see this:

  if (!m_closeFirstWindow.IsExpired () || !m_closeSecondWindow.IsExpired () || !m_secondReceiveWindow.IsExpired () )
    {
      NS_LOG_WARN ("Attempting to send when there are receive windows:" <<
                   " Transmission postponed.");

      //Calculate the duration of a single symbol for the second receive window DR
      double tSym = pow (2, GetSfFromDataRate (GetSecondReceiveWindowDataRate ())) / GetBandwidthFromDataRate ( GetSecondReceiveWindowDataRate ());

      Time endSecondRxWindow = (m_receiveDelay2 + Seconds (m_receiveWindowDurationInSymbols*tSym));
      waitingTime = std::max (waitingTime, endSecondRxWindow);
    }

  return waitingTime;

Why should the end device wait as long as m_receiveDelay2 + Seconds (m_receiveWindowDurationInSymbols*tSym)? since at this time the second receive window may has been open for a while.

If you are free, hope to answer me, thank you very much!

DvdMgr commented 4 years ago

Hi, thanks for your questions!

Ack Timeout

I think the issue here is that this is not a "timeout" in the conventional sense. Unfortunately, the standard as of v1.1 uses the following terminology we decided to stick with:

If an end-device does not receive a frame with the ACK bit set in one of the two receive windows immediately following the uplink transmission it may resend the same frame with the same payload and frame counter again at least ACK_TIMEOUT seconds after the second reception window.

So, I think the best term here would be backoff: ACK_TIMEOUT is an additional delay devices must respect before they can re-transmit their frame. It's worth noticing that from the latest Regional Parameters document, this variable was renamed:

RETRANSMIT_TIMEOUT was known as ACK_TIMEOUT in versions prior to 1.0.4 of LoRaWAN specification. It is renamed in version 1.0.4 and subsequent versions of the LoRaWAN specification to better reflect its intended use.

As for the code: the ack_timeout value is actually used, when it's summed to nextTxDelay to decide when to postpone the transmission.

waitingTime

It looks like you are right on this one - the returned waitingTime should simply be the maximum between the passed waitingTime and the time remaining until the m_closeSecondWindow event. Do you have the time to open a pull request fixing this?

QiuYukang commented 4 years ago

Thank you very much! I have opened a pull request to fix calculation of waitingTime.

ACK_TIMEOUT

I checked the standard documentation and it does as you said, also I see the following description in section 19.1 in versions prior to 1.1 of LoRaWAN specification:

If an end-device does not receive a frame with the ACK bit set in one of the two receive 2410 windows immediately following the uplink transmission it may resend the same frame with the same payload and frame counter again at least ACK_TIMEOUT seconds after the second reception window. This resend must be done on another channel and must obey the duty cycle limitation as any other normal transmission. If this time the end-device receives the ACK downlink during its first receive window, as soon as the ACK frame is demodulated, the end-device is free to transmit a new frame on a new channel. Uplink timing diagram for confirmed data messages

This means the end device should be ACK_TIMEOUT seconds after opening the second receive window to determine if a frame needs to be retransmitted, which seems to be inconsistent with the current code?

DvdMgr commented 4 years ago

I see what you mean.

So, as of now, in the code we sum the output of GetNextTransmissionDelay () with the ACK_TIMEOUT to get when we should re-transmit. For Class A EDs, GetNextTransmissionDelay computes the maximum between the end of the next receive window and the duty cycle, so we are waiting additional ACK_TIMEOUT seconds after the first time we are allowed to transmit according to duty cycle. Instead, we should compute the maximum between (first moment we are allowed to transmit according to duty cycle) and (startRxWindow2 + ACK_TIMEOUT).

I think this solution would better represent the contents of the standard, what do you think?

QiuYukang commented 4 years ago

Yes, I quite agree with you!

DvdMgr commented 4 years ago

Ok then: if you have some time to fix this, pull requests are welcome as usual - if you can't make it let me know, I can probably tackle this in the upcoming weeks!

QiuYukang commented 4 years ago

I'll try it and if I can't fix this, I'll let you know as soon as possible.

DvdMgr commented 4 years ago

The corresponding merge request is now on develop, thank you!