Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct ChannelCheckTimerEvent to send when tx NOT running #8

Closed
wants to merge 1 commit into from
Closed

Conversation

jmalangoni
Copy link

ChannelCheckTimerEvent should call LoRaMacSendFrameOnChannel when free channel found and MAC_TX_RUNNING bit is NOT set

@jmalangoni jmalangoni changed the title S Correct ChannelCheckTimerEvent to send when tx NOT running Jul 9, 2015
@mluis1
Copy link
Contributor

mluis1 commented Jul 9, 2015

I'm sorry, but, I think that the implementation is correct.

The LoRaMacState variable reflects the current MAC layer state.

The MAC_TX_RUNNING state indicates that a Class A transmission cycle is running.
Class A transmission cycle is composed of the radio transmission plus the opening of the 2 reception windows.
Due to the duty cycle enforcement a channel may not be immediately available when the application tries to send a frame. But the MAC transmission cycle is started.
So, the OnChannelCheckTimerEvent is there to check time to time when a channel becomes available and when it is the case the MAC layer can instruct the radio to transmit the frame.

Could you please explain why you think the implementation is incorrect?

@jmalangoni
Copy link
Author

I found that when a channel that is otherwise free to use (e.g. it is supported by the active bands, duty cycle restriction checks out ok, etc) has too high of a noise level (i think the Lib's current limit is around -90 rssi), the channelcheck event will call and reschedule itself as intended until the channel is free AND the noise ceiling is met. i believe the intention is then that the channelcheck event will send on the channel if it passes the mac_tx_running check, but it never does because the check currently only passes if the transmit/receive sequence has started, which doesn't happen at that stage yet. by setting the check to pass only if the transmit/receive sequence has NOT started, the channelcheck event will successfully start and complete the transmit/receive cycle.

hope this helps, I'm only on my phone now but I'm happy to provide more info if needed later

On July 9, 2015 3:15:15 PM GMT+03:00, Miguel Luis notifications@github.com wrote:

I'm sorry, but, I think that the implementation is correct.

The LoRaMacState variable reflects the current MAC layer state.

The MAC_TX_RUNNING state indicates that a Class A transmission cycle is
running.
Class A transmission cycle is composed of the radio transmission plus
the opening of the 2 reception windows.
Due to the duty cycle enforcement a channel may not be immediately
available when the application tries to send a frame. But the MAC
transmission cycle is started.
So, the OnChannelCheckTimerEvent is there to check time to time when a
channel becomes available and when it is the case the MAC layer can
instruct the radio to transmit the frame.

Could you please explain why you think the implementation is incorrect?


Reply to this email directly or view it on GitHub:
#8 (comment)

@mluis1
Copy link
Contributor

mluis1 commented Jul 9, 2015

Ok, I see your point.

The issue is that the patch may solve the problem at the first check before the MAC layer state is in MAC_TX_RUNNING but, it will produce an issue when the MAC layer is in MAC_TX_RUNNING state.

I think that this issue needs further investigation.

While we haven't found a better solution we could as a temporary solution remove the channel free check. The MAC layer is now respecting the ETSI duty cycle enforcement thus there is no need to check if the channel is free or not.

            // GitHub pull request #8 temporary solution
            //if( Radio.IsChannelFree( MODEM_LORA, Channels[channelNext].Frequency, RSSI_FREE_TH ) == true )
            {
                // Free channel found
                Channel = channelNext;

                LoRaMacState &= ~MAC_CHANNEL_CHECK;
                TimerStop( &ChannelCheckTimer );
                return 0;
            }

If you agree could you please resubmit a patch with this change.

@Mobiak
Copy link

Mobiak commented Jul 9, 2015

Timer ChannelCheckTimer is started only by the function LoRaMacSetNextChannel() if there is no free channel.
On the timer event it checks again if there is a channel free, if not restart timer but if there is one free it has to send the message.
The flag MAC_TX_RUNNING is set in the function LoRaMacSendFrameOnChannel() called just after, for the first time, or has been set before if it's a repetition for confirmed or unconfirmed frame. This flag is removed when the emission is done, and set only in the function LoRaMacSendFrameOnChannel(). His role is only to say if an emission is already running, locking new emission called by function LoRaMacSendOnChannel() or LoRaMacSend(). To avoid any problem, the function LoRaMacSendFrameOnChannel() should be used only by the LoRaMac layer, and not directly available for others.

So why not just remove the check of MAC_TX_RUNNING in function OnChannelCheckTimerEvent() and lock LoRaMacSendFrameOnChannel for other layer?

@jmalangoni
Copy link
Author

@mluis1 :

Can the ChannelCheckTimer event ever actually fire after the MAC state transitions into MAC_TX_RUNNING?

As far as I can tell, the ChannelCheckTimer event is only used to check if a channel is free after a transmission is denied due to no free channels being available, which means that the transmit/receive cycle is never initiated until the event's last callback.

But even if this is true, I think you're right and this needs additional investigation, because LoRaMacSendOnChannel and its own calls like LoRaMacPrepareFrame are never invoked in the sequence (ChannelCheckTimer event "skips" ahead to LoRaMacSendFrameOnChannel) which means the actual frame being sent might be the last one prepared, not the present one requested.

So I would not only agree with your above suggestion of removing the RSSI check but also suggest removing the use of ChannelCheckTimer and its callback until a better solution is found.

@mluis1
Copy link
Contributor

mluis1 commented Jul 9, 2015

We can't simply remove the ChannelCheckTimer. The duty cycle enforcement and acknowledgement retries relies on it. Once the MAC layer is in MAC_TX_RUNNING state it will try to send the last requested frame up until a channel becomes available.

The LoRaMacSendFrameOnChannel must be kept accessible to the upper layers for test purposes. Example radio coverage test.

When I get some time I will try to figure out a better solution that suits every one.

@daniwebCH
Copy link

I think that the stack keeps the LoRaMacEventFlags.Bits.Tx as long as the RX window is not ended.
As up to now (ClassA and ClassB) had a RX end window calling static void OnRadioRxTimeout( void ) with consequent reset of the flag.
Since now in ClassC we do not have this event, because we plan to stay forever in RX the flag is not changed.

For my device I temporary patched on this way, but I'm not sure if it is a clean solution because I do not have time to fully investigate on the code. by addind the stuff commentedwith ///DWY-ADDED-CLASSC-PATCH-TEST
I changed OnRadioTxDone function of LoRaMac.c:

if( IsRxWindowsEnabled == true )
{
TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
TimerStart( &RxWindowTimer1 );
if( LoRaMacDeviceClass != CLASS_C )
{
TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
TimerStart( &RxWindowTimer2 );
}
else ///DWY-ADDED-CLASSC-PATCH-TEST
{ ///DWY-ADDED-CLASSC-PATCH-TEST
LoRaMacEventFlags.Bits.Tx = 1; ///DWY-ADDED-CLASSC-PATCH-TEST
} ///DWY-ADDED-CLASSC-PATCH-TEST
}
else

Mobiak pushed a commit to Mobiak/LoRaMac-node that referenced this pull request Sep 7, 2015
Add define for RX1 and RX2 windows.
Add some documentation.
Add delay between two emission of the same unconfirmed frame.
Add timer to manage join request.

Remove check of MAC_TX_RUNNING in OnChannelCheckTimerEvent() to correct temporary PullRequest Lora-net#8.
Remove MacStateCheckTimer.

Rename and reorganize function OnMacStateCheckTimerEvent().

Class C :
 Open Rx2 when Class C device join a fake network LoRaMacInitNwkIds(), for a real connection it's manage by LoRaMacEndOfTxRxManager().
 Continuous Rx2 is open after handling information.

Change LoRaMacEventInfoStatus_t gestion :
 add more information about each case.

Change LoRaMacState gestion :
 MAC_TX_RUNNING
  is set at the beginning of an emission cycle.
  is reset at the end of an emission cycle.

Change LoRaMacEventFlags_t gestion :
 Tx is for all emission, successful, with error or on timeout.
 Rx is for all reception, successful (data or not), with error or on timeout.
 RxData is only for reception with data.

Change gestion for UnConfirmed and Confirmed frame
 Unconfirmed :
  Reset ChannelsNbRepCounter before sending the frame for the first time in LoRaMacSendOnChannel.
  Add function LoRaMacManageUnconfirmedUplink to manage emission counter and end of emission.
  For multiple emission, the next one is done after the end of a cycle, Rx1 with error or Rx2 for ClassA and Rx1 for ClassC.
 Confirmed :
  Add function LoRaMacManageConfirmedUplink to manage end of emission cycle, successful or unsuccessful.
  Move the launch of AckTimeoutTimer. It was generating error when there was a reception on Rx1 with a Mic error, RxWindow2Timer was stop so it didn't launch the AckTimeoutTimer to send again the confirmed frame (For Class A devices).
  AckTimeoutTimer is now launch after an emission of a Confirmed frame, for Class A and C device.

Why is the LoRaWan implemantation use a timer to notified the upper layer only when every operation is finished ?
A timer add a delay between the last operation and the notification. It become impossible to use real time application in this case.
Wouldn't it be better to use the timer callback as a function called after each radio event. In this way, every information would be forwarded to users and they will have to choose which to use or ignore.

The utilisation of the structure LoRaMacEventFlags_t and more precisely the Bits.Tx can generate some error with class C devices. It was working well with class A because for every reception the device has to have an emission before. But for class C it can receive message without emission and the field Bits.Tx will be true. Just try the case where a class C device receive a frame, the mic is wrong, field Bits.Tx become true. Now imagine the previous configuration was NodeAckRequested false, and ChannelsNbRepCounter is inferior to ChannelsNbRep, the device will enter this part of the code and try to send a previous frame again, or there is no previous frame to send again:

    else
    {
        LoRaMacEventFlags.Bits.Tx = 0;
        // Sends the same frame again
        if( LoRaMacSetNextChannel( ) == 0 )
        {
            LoRaMacSendFrameOnChannel( Channels[Channel] );
        }
    }

My point is, various field of LoRaMacEventsFlags should be used accordingly to their name to differenciate every case, Tx for an emission (succesful or unsuccessful), Rx for every reception successfull/failed/timeout. I think others are used as they should.
Reorganisation of the code to follow this idea would reorganised the timer callback OnMacStateCheckTimerEvent to differenciate emission and reception.

Actual gestion of confirmed frame can generate issue in Class C device. The timer AckTimeoutTimer is launched in OnRxWindow2TimerEvent, with a time between 1 and 3 seconds. If the delay is 1 second, Rx1 will not open and the device will send the frame again. The issue will occured if the gateway try to answer the confirmed frame on Rx1 in this case. Class C device should try to send again if nothing is received after Rx1.
@mluis1 mluis1 closed this Oct 30, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants