STM32CubeWL
STM32CubeWL copied to clipboard
LmHandlerJoin can only be called a fixed number of times if no join occurs
Hi,
I've been working on evaluating different scenarios for a device which is not able to join a network immidiately and during my tests I found out that LmHandlerJoin can only be called a fixed number of times ( 13 ). And I'm not quite sure why. My join callback looks like the one below:
static void OnJoinRequest(LmHandlerJoinParams_t *joinParams)
{
if ( joinParams != NULL )
{
if ( joinParams->Status == LORAMAC_HANDLER_SUCCESS )
{
ALOG ( "Network join success!" );
}
else
{
ALOG ( "Network join failed!" );
ALOGP( "Restarting join process, retry %d ", ( ++retries ) );
LmHandlerJoin(lmhandler_activation_type);
}
}
}
and the log looks like this
0:029 APP : Starting join process.
7:755 APP : Network join failed!
7:755 APP : Restarting join process, retry 1
15:479 APP : Network join failed!
15:479 APP : Restarting join process, retry 2
23:203 APP : Network join failed!
23:203 APP : Restarting join process, retry 3
30:926 APP : Network join failed!
30:926 APP : Restarting join process, retry 4
38:650 APP : Network join failed!
38:650 APP : Restarting join process, retry 5
46:374 APP : Network join failed!
46:374 APP : Restarting join process, retry 6
54:097 APP : Network join failed!
54:097 APP : Restarting join process, retry 7
61:821 APP : Network join failed!
61:821 APP : Restarting join process, retry 8
69:544 APP : Network join failed!
69:544 APP : Restarting join process, retry 9
77:268 APP : Network join failed!
77:268 APP : Restarting join process, retry 10
84:992 APP : Network join failed!
84:992 APP : Restarting join process, retry 11
92:715 APP : Network join failed!
92:715 APP : Restarting join process, retry 12
Is this a restriction of the stack itself ? I don't quite understand the reasoning behind this, if the reason is to restrict some rogue device from spamming the network, you can always perform a reboot and continue spamming. The restriction is not time-dependant either because I've tested calling LmHandlerJoin with increasing timeout ( varying from tens of seconds to tens of minutes + some random interval ) with the same effect.
ST Internal Reference: 121059
@asob
According to the LoRaWAN specification V1.0.4, the LoRaWAN stack shall limit the aggregated time on air during the first hour following power-up or reset to 36 s. A join request frame consists of the following fields:
join request: MHDR (1 byte) | joinEUI (8 byte) | devEUI (8 byte) | devNonce (2 byte) | MIC (4 byte)
In total a join request frame consists of 23 byte not taking into account additional PHY layer overhead like PHY preamble, PHY header and PHY crc. Transmitting 23 byte with SF12 results in approximately 1.5 s time on air. So if you don't consider the PHY layer overhead, the LoRaWAN stack allows to send approximately (36 s) / (1.5 s / message) = 24 message within the first hour following power-up or reset. Taking the PHY layer overhead into account, it might be possible that you run into the aggregated air time limit of 36 s within the first hour. If you exceed the aggregated time on air limit, the LoRaWAN stack will refuse the join request transmission, and OnJoinRequest
will not be called. Since OnJoinRequest
will not be called, your join process stops.
Possible solution: Use a periodic timer and trigger a new join request when the timer elapses.
UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_JoinProcess), UTIL_SEQ_RFU, JoinProcess);
UTIL_TIMER_Create(&JoinTimer, 10000, UTIL_TIMER_PERIODIC, OnJoinTimerEvent, NULL);
UTIL_TIMER_Start(&JoinTimer);
static void OnJoinTimerEvent(void *context) {
UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_JoinProcess), CFG_SEQ_Prio_0);
}
static void JoinProcess(void) {
ALOGP( "Restarting join process, retry %d ", ( ++retries ) );
LmHandlerJoin(lmhandler_activation_type);
}
static void OnJoinRequest(LmHandlerJoinParams_t *joinParams)
{
if ( joinParams != NULL )
{
if ( joinParams->Status == LORAMAC_HANDLER_SUCCESS )
{
UTIL_TIMER_Stop(&JoinTimer);
ALOG ( "Network join success!" );
}
else
{
ALOG ( "Network join failed!" );
}
}
}
Best regards Roman Jasmann
Hi @asob,
2 configurations parameters are important to understood your situation:
- The used region (Duty-cycle enabled or not)
- The default datarate
if you are in EU868 + default datarate 0, this limitation is defined in the LoRaMAC to be compliant with the ETSI regulations:
In the specification LoRaWAN 1.0.3 Regional Parameters:
2.2.2 EU863-870 ISM Band channel frequencies In order to access the physical medium the ETSI regulations impose some restrictions such maximum time the transmitter can be on or the maximum time a transmitter can transmit per hour. The ETSI regulations allow the choice of using either a duty-cycle limitation or a so called Listen Before Talk Adaptive Frequency Agility (LBT AFA) transmissions management. The current LoRaWAN specification exclusively uses duty-cycled limited transmissions to comply with the ETSI regulations. ... The JoinReq message transmit duty-cycle SHALL follow the rules described in chapter “Retransmissions back-off” of the LoRaWAN specification document.
So, if some multiple Join Request are not accepted by the Network Server (Gateway missing or wrong channel plan, wrong device configuration in NS, ...), the Mac will abort the next transmit due to 'LORAMAC_STATUS_NO_CHANNEL_FOUND' status.
These aborted Tx are generated by the RegionCommon.c/RegionCommonUpdateBandTimeOff() function code (implementation of the chapter "7 Retransmissions back-off" in Link Layer 1.0.3 specification): ... // Apply a special calculation if the device is not joined. if( joined == false ) { SysTime_t backoffTimeRange = { .Seconds = 0, .SubSeconds = 0, }; // Get the backoff time range based on the duty cycle definition if( dutyCycle == BACKOFF_DC_1_HOUR ) { backoffTimeRange.Seconds = BACKOFF_DUTY_CYCLE_1_HOUR_IN_S; } else if( dutyCycle == BACKOFF_DC_10_HOURS ) { backoffTimeRange.Seconds = BACKOFF_DUTY_CYCLE_10_HOURS_IN_S; } else { backoffTimeRange.Seconds = BACKOFF_DUTY_CYCLE_24_HOURS_IN_S; } // Calculate the time to wait. if( elapsedTimeSinceStartup.Seconds > BACKOFF_DUTY_CYCLE_24_HOURS_IN_S ) { backoffTimeRange.Seconds += BACKOFF_24_HOURS_IN_S * ( ( ( elapsedTimeSinceStartup.Seconds - BACKOFF_DUTY_CYCLE_24_HOURS_IN_S ) / BACKOFF_24_HOURS_IN_S ) + 1 ); } // Calculate the time difference between now and the next range backoffTimeRange = SysTimeSub( backoffTimeRange, elapsedTimeSinceStartup ); minTimeToWait = SysTimeToMs( backoffTimeRange ); }
In your case, the 13 first join requests consume all the TimeCredit available (the Join Channels are at 1% of duty cycle), and the next join req can only be done one hour later.
As described in the "Retransmissions back-off" chapter, the device will try to join several times at the beginning of each hour, for 10 hours, and then will have to wait 24 hours before trying again.
Hope this will help you. Please allow me thus to close this thread.
With regards,