1 /*!
2  * \file      RegionAU915.c
3  *
4  * \brief     Region implementation for AU915
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
18  *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
19  *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
20  *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
21  *              embedded.connectivity.solutions===============
22  *
23  * \endcode
24  *
25  * \author    Miguel Luis ( Semtech )
26  *
27  * \author    Gregory Cristian ( Semtech )
28  *
29  * \author    Daniel Jaeckle ( STACKFORCE )
30 */
31 #include "radio.h"
32 #include "RegionCommon.h"
33 #include "RegionAU915.h"
34 #include "RegionBaseUS.h"
35 
36 // Definitions
37 #define CHANNELS_MASK_SIZE              6
38 
39 // A mask to select only valid 500KHz channels
40 #define CHANNELS_MASK_500KHZ_MASK       0x00FF
41 
42 /*
43  * Non-volatile module context.
44  */
45 static RegionNvmDataGroup1_t* RegionNvmGroup1;
46 static RegionNvmDataGroup2_t* RegionNvmGroup2;
47 static Band_t* RegionBands;
48 
VerifyRfFreq(uint32_t freq)49 static bool VerifyRfFreq( uint32_t freq )
50 {
51     // Check radio driver support
52     if( Radio.CheckRfFrequency( freq ) == false )
53     {
54         return false;
55     }
56 
57     // Rx frequencies
58     if( ( freq < AU915_FIRST_RX1_CHANNEL ) ||
59         ( freq > AU915_LAST_RX1_CHANNEL ) ||
60         ( ( ( freq - ( uint32_t ) AU915_FIRST_RX1_CHANNEL ) % ( uint32_t ) AU915_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
61     {
62         return false;
63     }
64 
65     // Tx frequencies for 125kHz
66     // Also includes the range for 500kHz channels
67     if( ( freq < 915200000 ) ||  ( freq > 927800000 ) )
68     {
69         return false;
70     }
71     return true;
72 }
73 
GetTimeOnAir(int8_t datarate,uint16_t pktLen)74 static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
75 {
76     int8_t phyDr = DataratesAU915[datarate];
77     uint32_t bandwidth = RegionCommonGetBandwidth( datarate, BandwidthsAU915 );
78 
79     return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
80 }
81 
RegionAU915GetPhyParam(GetPhyParams_t * getPhy)82 PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
83 {
84     PhyParam_t phyParam = { 0 };
85 
86     switch( getPhy->Attribute )
87     {
88         case PHY_MIN_RX_DR:
89         {
90             if( getPhy->DownlinkDwellTime == 0)
91             {
92                 phyParam.Value = AU915_RX_MIN_DATARATE;
93             }
94             else
95             {
96                 phyParam.Value = AU915_DWELL_LIMIT_DATARATE;
97             }
98             break;
99         }
100         case PHY_MIN_TX_DR:
101         {
102             if( getPhy->UplinkDwellTime == 0)
103             {
104                 phyParam.Value = AU915_TX_MIN_DATARATE;
105             }
106             else
107             {
108                 phyParam.Value = AU915_DWELL_LIMIT_DATARATE;
109             }
110             break;
111         }
112         case PHY_DEF_TX_DR:
113         {
114             phyParam.Value = AU915_DEFAULT_DATARATE;
115             break;
116         }
117         case PHY_NEXT_LOWER_TX_DR:
118         {
119             RegionCommonGetNextLowerTxDrParams_t nextLowerTxDrParams =
120             {
121                 .CurrentDr = getPhy->Datarate,
122                 .MaxDr = ( int8_t )AU915_TX_MAX_DATARATE,
123                 .MinDr = ( int8_t )( ( getPhy->UplinkDwellTime == 0 ) ? AU915_TX_MIN_DATARATE : AU915_DWELL_LIMIT_DATARATE ),
124                 .NbChannels = AU915_MAX_NB_CHANNELS,
125                 .ChannelsMask = RegionNvmGroup2->ChannelsMask,
126                 .Channels = RegionNvmGroup2->Channels,
127             };
128             phyParam.Value = RegionCommonGetNextLowerTxDr( &nextLowerTxDrParams );
129             break;
130         }
131         case PHY_MAX_TX_POWER:
132         {
133             phyParam.Value = AU915_MAX_TX_POWER;
134             break;
135         }
136         case PHY_DEF_TX_POWER:
137         {
138             phyParam.Value = AU915_DEFAULT_TX_POWER;
139             break;
140         }
141         case PHY_DEF_ADR_ACK_LIMIT:
142         {
143             phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_LIMIT;
144             break;
145         }
146         case PHY_DEF_ADR_ACK_DELAY:
147         {
148             phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_DELAY;
149             break;
150         }
151         case PHY_MAX_PAYLOAD:
152         {
153             if( getPhy->UplinkDwellTime == 0 )
154             {
155                 phyParam.Value = MaxPayloadOfDatarateDwell0AU915[getPhy->Datarate];
156             }
157             else
158             {
159                 phyParam.Value = MaxPayloadOfDatarateDwell1AU915[getPhy->Datarate];
160             }
161             break;
162         }
163         case PHY_DUTY_CYCLE:
164         {
165             phyParam.Value = AU915_DUTY_CYCLE_ENABLED;
166             break;
167         }
168         case PHY_MAX_RX_WINDOW:
169         {
170             phyParam.Value = AU915_MAX_RX_WINDOW;
171             break;
172         }
173         case PHY_RECEIVE_DELAY1:
174         {
175             phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY1;
176             break;
177         }
178         case PHY_RECEIVE_DELAY2:
179         {
180             phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY2;
181             break;
182         }
183         case PHY_JOIN_ACCEPT_DELAY1:
184         {
185             phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY1;
186             break;
187         }
188         case PHY_JOIN_ACCEPT_DELAY2:
189         {
190             phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY2;
191             break;
192         }
193         case PHY_RETRANSMIT_TIMEOUT:
194         {
195             phyParam.Value = ( REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT + randr( -REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND, REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND ) );
196             break;
197         }
198         case PHY_DEF_DR1_OFFSET:
199         {
200             phyParam.Value = REGION_COMMON_DEFAULT_RX1_DR_OFFSET;
201             break;
202         }
203         case PHY_DEF_RX2_FREQUENCY:
204         {
205             phyParam.Value = AU915_RX_WND_2_FREQ;
206             break;
207         }
208         case PHY_DEF_RX2_DR:
209         {
210             phyParam.Value = AU915_RX_WND_2_DR;
211             break;
212         }
213         case PHY_CHANNELS_MASK:
214         {
215             phyParam.ChannelsMask = RegionNvmGroup2->ChannelsMask;
216             break;
217         }
218         case PHY_CHANNELS_DEFAULT_MASK:
219         {
220             phyParam.ChannelsMask = RegionNvmGroup2->ChannelsDefaultMask;
221             break;
222         }
223         case PHY_MAX_NB_CHANNELS:
224         {
225             phyParam.Value = AU915_MAX_NB_CHANNELS;
226             break;
227         }
228         case PHY_CHANNELS:
229         {
230             phyParam.Channels = RegionNvmGroup2->Channels;
231             break;
232         }
233         case PHY_DEF_UPLINK_DWELL_TIME:
234         {
235             phyParam.Value = AU915_DEFAULT_UPLINK_DWELL_TIME;
236             break;
237         }
238         case PHY_DEF_DOWNLINK_DWELL_TIME:
239         {
240             phyParam.Value = REGION_COMMON_DEFAULT_DOWNLINK_DWELL_TIME;
241             break;
242         }
243         case PHY_DEF_MAX_EIRP:
244         {
245             phyParam.fValue = AU915_DEFAULT_MAX_EIRP;
246             break;
247         }
248         case PHY_DEF_ANTENNA_GAIN:
249         {
250             phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN;
251             break;
252         }
253         case PHY_BEACON_CHANNEL_FREQ:
254         {
255             phyParam.Value = RegionBaseUSCalcDownlinkFrequency( getPhy->Channel,
256                                                                 AU915_BEACON_CHANNEL_FREQ,
257                                                                 AU915_BEACON_CHANNEL_STEPWIDTH );
258             break;
259         }
260         case PHY_BEACON_FORMAT:
261         {
262             phyParam.BeaconFormat.BeaconSize = AU915_BEACON_SIZE;
263             phyParam.BeaconFormat.Rfu1Size = AU915_RFU1_SIZE;
264             phyParam.BeaconFormat.Rfu2Size = AU915_RFU2_SIZE;
265             break;
266         }
267         case PHY_BEACON_CHANNEL_DR:
268         {
269             phyParam.Value = AU915_BEACON_CHANNEL_DR;
270             break;
271         }
272         case PHY_BEACON_NB_CHANNELS:
273         {
274             phyParam.Value = AU915_BEACON_NB_CHANNELS;
275             break;
276         }
277         case PHY_PING_SLOT_CHANNEL_FREQ:
278         {
279             phyParam.Value = RegionBaseUSCalcDownlinkFrequency( getPhy->Channel,
280                                                                 AU915_PING_SLOT_CHANNEL_FREQ,
281                                                                 AU915_BEACON_CHANNEL_STEPWIDTH );
282             break;
283         }
284         case PHY_PING_SLOT_CHANNEL_DR:
285         {
286             phyParam.Value = AU915_PING_SLOT_CHANNEL_DR;
287             break;
288         }
289         case PHY_PING_SLOT_NB_CHANNELS:
290         {
291             phyParam.Value = AU915_BEACON_NB_CHANNELS;
292             break;
293         }
294         case PHY_SF_FROM_DR:
295         {
296             phyParam.Value = DataratesAU915[getPhy->Datarate];
297             break;
298         }
299         case PHY_BW_FROM_DR:
300         {
301             phyParam.Value = RegionCommonGetBandwidth( getPhy->Datarate, BandwidthsAU915 );
302             break;
303         }
304         default:
305         {
306             break;
307         }
308     }
309 
310     return phyParam;
311 }
312 
RegionAU915SetBandTxDone(SetBandTxDoneParams_t * txDone)313 void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone )
314 {
315     RegionCommonSetBandTxDone( &RegionBands[RegionNvmGroup2->Channels[txDone->Channel].Band],
316                                txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
317 }
318 
RegionAU915InitDefaults(InitDefaultsParams_t * params)319 void RegionAU915InitDefaults( InitDefaultsParams_t* params )
320 {
321     Band_t bands[AU915_MAX_NB_BANDS] =
322     {
323         AU915_BAND0
324     };
325 
326     switch( params->Type )
327     {
328         case INIT_TYPE_DEFAULTS:
329         {
330             if( ( params->NvmGroup1 == NULL ) || ( params->NvmGroup2 == NULL ) )
331             {
332                 return;
333             }
334 
335             RegionNvmGroup1 = (RegionNvmDataGroup1_t*) params->NvmGroup1;
336             RegionNvmGroup2 = (RegionNvmDataGroup2_t*) params->NvmGroup2;
337             RegionBands = (Band_t*) params->Bands;
338 
339             // Initialize 8 bit channel groups index
340             RegionNvmGroup1->JoinChannelGroupsCurrentIndex = 0;
341 
342             // Initialize the join trials counter
343             RegionNvmGroup1->JoinTrialsCounter = 0;
344 
345             // Default bands
346             memcpy1( ( uint8_t* )RegionBands, ( uint8_t* )bands, sizeof( Band_t ) * AU915_MAX_NB_BANDS );
347 
348             // Channels
349             for( uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++ )
350             {
351                 // 125 kHz channels
352                 RegionNvmGroup2->Channels[i].Frequency = 915200000 + i * 200000;
353                 RegionNvmGroup2->Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
354                 RegionNvmGroup2->Channels[i].Band = 0;
355             }
356             for( uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++ )
357             {
358                 // 500 kHz channels
359                 RegionNvmGroup2->Channels[i].Frequency = 915900000 + ( i - ( AU915_MAX_NB_CHANNELS - 8 ) ) * 1600000;
360                 RegionNvmGroup2->Channels[i].DrRange.Value = ( DR_6 << 4 ) | DR_6;
361                 RegionNvmGroup2->Channels[i].Band = 0;
362             }
363 
364             // Initialize channels default mask
365             RegionNvmGroup2->ChannelsDefaultMask[0] = 0xFFFF;
366             RegionNvmGroup2->ChannelsDefaultMask[1] = 0xFFFF;
367             RegionNvmGroup2->ChannelsDefaultMask[2] = 0xFFFF;
368             RegionNvmGroup2->ChannelsDefaultMask[3] = 0xFFFF;
369             RegionNvmGroup2->ChannelsDefaultMask[4] = 0x00FF;
370             RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;
371 
372             // Copy channels default mask
373             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
374 
375             // Copy into channels mask remaining
376             RegionCommonChanMaskCopy( RegionNvmGroup1->ChannelsMaskRemaining, RegionNvmGroup2->ChannelsMask, CHANNELS_MASK_SIZE );
377             break;
378         }
379         case INIT_TYPE_RESET_TO_DEFAULT_CHANNELS:
380         {
381             // Intentional fallthrough
382         }
383         case INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS:
384         {
385             // Copy channels default mask
386             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
387 
388             for( uint8_t i = 0; i < CHANNELS_MASK_SIZE; i++ )
389             { // Copy-And the channels mask
390                 RegionNvmGroup1->ChannelsMaskRemaining[i] &= RegionNvmGroup2->ChannelsMask[i];
391             }
392             break;
393         }
394         default:
395         {
396             break;
397         }
398     }
399 }
400 
RegionAU915Verify(VerifyParams_t * verify,PhyAttribute_t phyAttribute)401 bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
402 {
403     switch( phyAttribute )
404     {
405         case PHY_FREQUENCY:
406         {
407             return VerifyRfFreq( verify->Frequency );
408         }
409         case PHY_TX_DR:
410         case PHY_DEF_TX_DR:
411         {
412             if( verify->DatarateParams.UplinkDwellTime == 0 )
413             {
414                 return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE );
415             }
416             else
417             {
418                 return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_DWELL_LIMIT_DATARATE, AU915_TX_MAX_DATARATE );
419             }
420         }
421         case PHY_RX_DR:
422         {
423             if( verify->DatarateParams.UplinkDwellTime == 0 )
424             {
425                 return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE );
426             }
427             else
428             {
429                 return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_DWELL_LIMIT_DATARATE, AU915_RX_MAX_DATARATE );
430             }
431         }
432         case PHY_DEF_TX_POWER:
433         case PHY_TX_POWER:
434         {
435             // Remark: switched min and max!
436             return RegionCommonValueInRange( verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER );
437         }
438         case PHY_DUTY_CYCLE:
439         {
440             return AU915_DUTY_CYCLE_ENABLED;
441         }
442         default:
443             return false;
444     }
445 }
446 
RegionAU915ApplyCFList(ApplyCFListParams_t * applyCFList)447 void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList )
448 {
449     // Size of the optional CF list must be 16 byte
450     if( applyCFList->Size != 16 )
451     {
452         return;
453     }
454 
455     // Last byte CFListType must be 0x01 to indicate the CFList contains a series of ChMask fields
456     if( applyCFList->Payload[15] != 0x01 )
457     {
458         return;
459     }
460 
461     // ChMask0 - ChMask4 must be set (every ChMask has 16 bit)
462     for( uint8_t chMaskItr = 0, cntPayload = 0; chMaskItr <= 4; chMaskItr++, cntPayload+=2 )
463     {
464         RegionNvmGroup2->ChannelsMask[chMaskItr] = (uint16_t) (0x00FF & applyCFList->Payload[cntPayload]);
465         RegionNvmGroup2->ChannelsMask[chMaskItr] |= (uint16_t) (applyCFList->Payload[cntPayload+1] << 8);
466         if( chMaskItr == 4 )
467         {
468             RegionNvmGroup2->ChannelsMask[chMaskItr] = RegionNvmGroup2->ChannelsMask[chMaskItr] & CHANNELS_MASK_500KHZ_MASK;
469         }
470         // Set the channel mask to the remaining
471         RegionNvmGroup1->ChannelsMaskRemaining[chMaskItr] &= RegionNvmGroup2->ChannelsMask[chMaskItr];
472     }
473 }
474 
RegionAU915ChanMaskSet(ChanMaskSetParams_t * chanMaskSet)475 bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
476 {
477     switch( chanMaskSet->ChannelsMaskType )
478     {
479         case CHANNELS_MASK:
480         {
481             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, chanMaskSet->ChannelsMaskIn, CHANNELS_MASK_SIZE );
482 
483             RegionNvmGroup2->ChannelsDefaultMask[4] = RegionNvmGroup2->ChannelsDefaultMask[4] & CHANNELS_MASK_500KHZ_MASK;
484             RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;
485 
486             for( uint8_t i = 0; i < 6; i++ )
487             { // Copy-And the channels mask
488                 RegionNvmGroup1->ChannelsMaskRemaining[i] &= RegionNvmGroup2->ChannelsMask[i];
489             }
490             break;
491         }
492         case CHANNELS_DEFAULT_MASK:
493         {
494             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, CHANNELS_MASK_SIZE );
495             break;
496         }
497         default:
498             return false;
499     }
500     return true;
501 }
502 
RegionAU915ComputeRxWindowParameters(int8_t datarate,uint8_t minRxSymbols,uint32_t rxError,RxConfigParams_t * rxConfigParams)503 void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
504 {
505     uint32_t tSymbolInUs = 0;
506 
507     // Get the datarate, perform a boundary check
508     rxConfigParams->Datarate = MIN( datarate, AU915_RX_MAX_DATARATE );
509     rxConfigParams->Bandwidth = RegionCommonGetBandwidth( rxConfigParams->Datarate, BandwidthsAU915 );
510 
511     tSymbolInUs = RegionCommonComputeSymbolTimeLoRa( DataratesAU915[rxConfigParams->Datarate], BandwidthsAU915[rxConfigParams->Datarate] );
512 
513     RegionCommonComputeRxWindowParameters( tSymbolInUs, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
514 }
515 
RegionAU915RxConfig(RxConfigParams_t * rxConfig,int8_t * datarate)516 bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
517 {
518     int8_t dr = rxConfig->Datarate;
519     int8_t phyDr = 0;
520     uint32_t frequency = rxConfig->Frequency;
521 
522     if( Radio.GetStatus( ) != RF_IDLE )
523     {
524         return false;
525     }
526 
527     if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
528     {
529         // Apply window 1 frequency
530         frequency = AU915_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * AU915_STEPWIDTH_RX1_CHANNEL;
531     }
532 
533     // Read the physical datarate from the datarates table
534     phyDr = DataratesAU915[dr];
535 
536     Radio.SetChannel( frequency );
537 
538     // Radio configuration
539     Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
540 
541     Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateDwell0AU915[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
542 
543     *datarate = (uint8_t) dr;
544     return true;
545 }
546 
RegionAU915TxConfig(TxConfigParams_t * txConfig,int8_t * txPower,TimerTime_t * txTimeOnAir)547 bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
548 {
549     int8_t phyDr = DataratesAU915[txConfig->Datarate];
550     int8_t txPowerLimited = RegionCommonLimitTxPower( txConfig->TxPower, RegionBands[RegionNvmGroup2->Channels[txConfig->Channel].Band].TxMaxPower );
551     uint32_t bandwidth = RegionCommonGetBandwidth( txConfig->Datarate, BandwidthsAU915 );
552     int8_t phyTxPower = 0;
553 
554     // Calculate physical TX power
555     phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
556 
557     // Setup the radio frequency
558     Radio.SetChannel( RegionNvmGroup2->Channels[txConfig->Channel].Frequency );
559 
560     Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
561 
562     // Setup maximum payload lenght of the radio driver
563     Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
564     // Update time-on-air
565     *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
566 
567     *txPower = txPowerLimited;
568     return true;
569 }
570 
RegionAU915LinkAdrReq(LinkAdrReqParams_t * linkAdrReq,int8_t * drOut,int8_t * txPowOut,uint8_t * nbRepOut,uint8_t * nbBytesParsed)571 uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
572 {
573     uint8_t status = 0x07;
574     RegionCommonLinkAdrParams_t linkAdrParams = { 0 };
575     uint8_t nextIndex = 0;
576     uint8_t bytesProcessed = 0;
577     uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
578     GetPhyParams_t getPhy;
579     PhyParam_t phyParam;
580     RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
581 
582     // Initialize local copy of channels mask
583     RegionCommonChanMaskCopy( channelsMask, RegionNvmGroup2->ChannelsMask, 6 );
584 
585     while( bytesProcessed < linkAdrReq->PayloadSize )
586     {
587         nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
588 
589         if( nextIndex == 0 )
590             break; // break loop, since no more request has been found
591 
592         // Update bytes processed
593         bytesProcessed += nextIndex;
594 
595         // Revert status, as we only check the last ADR request for the channel mask KO
596         status = 0x07;
597 
598         if( linkAdrParams.ChMaskCtrl == 6 )
599         {
600             // Enable all 125 kHz channels
601             channelsMask[0] = 0xFFFF;
602             channelsMask[1] = 0xFFFF;
603             channelsMask[2] = 0xFFFF;
604             channelsMask[3] = 0xFFFF;
605             // Apply chMask to channels 64 to 71
606             channelsMask[4] = linkAdrParams.ChMask & CHANNELS_MASK_500KHZ_MASK;
607         }
608         else if( linkAdrParams.ChMaskCtrl == 7 )
609         {
610             // Disable all 125 kHz channels
611             channelsMask[0] = 0x0000;
612             channelsMask[1] = 0x0000;
613             channelsMask[2] = 0x0000;
614             channelsMask[3] = 0x0000;
615             // Apply chMask to channels 64 to 71
616             channelsMask[4] = linkAdrParams.ChMask & CHANNELS_MASK_500KHZ_MASK;
617         }
618         else if( linkAdrParams.ChMaskCtrl == 5 )
619         {
620             // Start value for comparision
621             uint8_t bitMask = 1;
622 
623             // cntChannelMask for channelsMask[0] until channelsMask[3]
624             uint8_t cntChannelMask = 0;
625 
626             // i will be 1, 2, 3, ..., 7
627             for( uint8_t i = 0; i <= 7; i++ )
628             {
629                 // 8 MSBs of ChMask are RFU
630                 // Checking if the ChMask is set, then true
631                 if( ( ( linkAdrParams.ChMask & 0x00FF ) & ( bitMask << i ) ) != 0 )
632                 {
633                     if( ( i % 2 ) == 0 )
634                     {
635                         // Enable a bank of 8 125kHz channels, 8 LSBs
636                         channelsMask[cntChannelMask] |= 0x00FF;
637                         // Enable the corresponding 500kHz channel
638                         channelsMask[4] |= ( bitMask << i );
639                     }
640                     else
641                     {
642                         // Enable a bank of 8 125kHz channels, 8 MSBs
643                         channelsMask[cntChannelMask] |= 0xFF00;
644                         // Enable the corresponding 500kHz channel
645                         channelsMask[4] |= ( bitMask << i );
646                         // cntChannelMask increment for uneven i
647                         cntChannelMask++;
648                     }
649                 }
650                 // ChMask is not set
651                 else
652                 {
653                     if( ( i % 2 ) == 0 )
654                     {
655                         // Disable a bank of 8 125kHz channels, 8 LSBs
656                         channelsMask[cntChannelMask] &= 0xFF00;
657                         // Disable the corresponding 500kHz channel
658                         channelsMask[4] &= ~( bitMask << i );
659                     }
660                     else
661                     {
662                         // Enable a bank of 8 125kHz channels, 8 MSBs
663                         channelsMask[cntChannelMask] &= 0x00FF;
664                         // Disable the corresponding 500kHz channel
665                         channelsMask[4] &= ~( bitMask << i );
666                         // cntChannelMask increment for uneven i
667                         cntChannelMask++;
668                     }
669                 }
670             }
671         }
672         else
673         {
674             channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
675         }
676     }
677 
678     // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
679     if( ( linkAdrParams.Datarate < DR_6 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
680     {
681         status &= 0xFE; // Channel mask KO
682     }
683 
684     // Get the minimum possible datarate
685     getPhy.Attribute = PHY_MIN_TX_DR;
686     getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
687     phyParam = RegionAU915GetPhyParam( &getPhy );
688 
689     linkAdrVerifyParams.Status = status;
690     linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
691     linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
692     linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
693     linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
694     linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
695     linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
696     linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
697     linkAdrVerifyParams.NbChannels = AU915_MAX_NB_CHANNELS;
698     linkAdrVerifyParams.ChannelsMask = channelsMask;
699     linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
700     linkAdrVerifyParams.MaxDatarate = AU915_TX_MAX_DATARATE;
701     linkAdrVerifyParams.Channels = RegionNvmGroup2->Channels;
702     linkAdrVerifyParams.MinTxPower = AU915_MIN_TX_POWER;
703     linkAdrVerifyParams.MaxTxPower = AU915_MAX_TX_POWER;
704     linkAdrVerifyParams.Version = linkAdrReq->Version;
705 
706     // Verify the parameters and update, if necessary
707     status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
708 
709     // Update channelsMask if everything is correct
710     if( status == 0x07 )
711     {
712         // Copy Mask
713         RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, channelsMask, 6 );
714 
715         RegionNvmGroup1->ChannelsMaskRemaining[0] &= RegionNvmGroup2->ChannelsMask[0];
716         RegionNvmGroup1->ChannelsMaskRemaining[1] &= RegionNvmGroup2->ChannelsMask[1];
717         RegionNvmGroup1->ChannelsMaskRemaining[2] &= RegionNvmGroup2->ChannelsMask[2];
718         RegionNvmGroup1->ChannelsMaskRemaining[3] &= RegionNvmGroup2->ChannelsMask[3];
719         RegionNvmGroup1->ChannelsMaskRemaining[4] = RegionNvmGroup2->ChannelsMask[4];
720         RegionNvmGroup1->ChannelsMaskRemaining[5] = RegionNvmGroup2->ChannelsMask[5];
721     }
722 
723     // Update status variables
724     *drOut = linkAdrParams.Datarate;
725     *txPowOut = linkAdrParams.TxPower;
726     *nbRepOut = linkAdrParams.NbRep;
727     *nbBytesParsed = bytesProcessed;
728 
729     return status;
730 }
731 
RegionAU915RxParamSetupReq(RxParamSetupReqParams_t * rxParamSetupReq)732 uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
733 {
734     uint8_t status = 0x07;
735 
736     // Verify radio frequency
737     if( VerifyRfFreq( rxParamSetupReq->Frequency ) == false )
738     {
739         status &= 0xFE; // Channel frequency KO
740     }
741 
742     // Verify datarate
743     if( RegionCommonValueInRange( rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE ) == false )
744     {
745         status &= 0xFD; // Datarate KO
746     }
747     if( ( rxParamSetupReq->Datarate == DR_7 ) ||
748         ( rxParamSetupReq->Datarate > DR_13 ) )
749     {
750         status &= 0xFD; // Datarate KO
751     }
752 
753     // Verify datarate offset
754     if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET ) == false )
755     {
756         status &= 0xFB; // Rx1DrOffset range KO
757     }
758 
759     return status;
760 }
761 
RegionAU915NewChannelReq(NewChannelReqParams_t * newChannelReq)762 int8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq )
763 {
764     // Do not accept the request
765     return -1;
766 }
767 
RegionAU915TxParamSetupReq(TxParamSetupReqParams_t * txParamSetupReq)768 int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
769 {
770     // Accept the request
771     return 0;
772 }
773 
RegionAU915DlChannelReq(DlChannelReqParams_t * dlChannelReq)774 int8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq )
775 {
776     // Do not accept the request
777     return -1;
778 }
779 
RegionAU915AlternateDr(int8_t currentDr,AlternateDrType_t type)780 int8_t RegionAU915AlternateDr( int8_t currentDr, AlternateDrType_t type )
781 {
782     // Alternates the data rate according to the channel sequence:
783     // Eight times a 125kHz DR_2 and then one 500kHz DR_6 channel
784     if( type == ALTERNATE_DR )
785     {
786         RegionNvmGroup1->JoinTrialsCounter++;
787     }
788     else
789     {
790         RegionNvmGroup1->JoinTrialsCounter--;
791     }
792 
793     if( RegionNvmGroup1->JoinTrialsCounter % 9 == 0 )
794     {
795         // Use DR_6 every 9th times.
796         currentDr = DR_6;
797     }
798     else
799     {
800         currentDr = DR_2;
801     }
802     return currentDr;
803 }
804 
RegionAU915NextChannel(NextChanParams_t * nextChanParams,uint8_t * channel,TimerTime_t * time,TimerTime_t * aggregatedTimeOff)805 LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
806 {
807     uint8_t nbEnabledChannels = 0;
808     uint8_t nbRestrictedChannels = 0;
809     uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = { 0 };
810     RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
811     RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
812     LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
813 
814     // Count 125kHz channels
815     if( RegionCommonCountChannels( RegionNvmGroup1->ChannelsMaskRemaining, 0, 4 ) == 0 )
816     { // Reactivate default channels
817         RegionCommonChanMaskCopy( RegionNvmGroup1->ChannelsMaskRemaining, RegionNvmGroup2->ChannelsMask, 4  );
818 
819         RegionNvmGroup1->JoinChannelGroupsCurrentIndex = 0;
820     }
821     // Check other channels
822     if( nextChanParams->Datarate >= DR_6 )
823     {
824         if( ( RegionNvmGroup1->ChannelsMaskRemaining[4] & CHANNELS_MASK_500KHZ_MASK ) == 0 )
825         {
826             RegionNvmGroup1->ChannelsMaskRemaining[4] = RegionNvmGroup2->ChannelsMask[4];
827         }
828     }
829 
830     // Search how many channels are enabled
831     countChannelsParams.Joined = nextChanParams->Joined;
832     countChannelsParams.Datarate = nextChanParams->Datarate;
833     countChannelsParams.ChannelsMask = RegionNvmGroup1->ChannelsMaskRemaining;
834     countChannelsParams.Channels = RegionNvmGroup2->Channels;
835     countChannelsParams.Bands = RegionBands;
836     countChannelsParams.MaxNbChannels = AU915_MAX_NB_CHANNELS;
837     countChannelsParams.JoinChannels = NULL;
838 
839     identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
840     identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
841     identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
842     identifyChannelsParam.MaxBands = AU915_MAX_NB_BANDS;
843 
844     identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
845     identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
846     identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
847 
848     identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
849 
850     status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
851                                            &nbEnabledChannels, &nbRestrictedChannels, time );
852 
853     if( status == LORAMAC_STATUS_OK )
854     {
855         if( nextChanParams->Joined == true )
856         {
857             // Choose randomly on of the remaining channels
858             *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
859         }
860         else
861         {
862             // For rapid network acquisition in mixed gateway channel plan environments, the device
863             // follow a random channel selection sequence. It probes alternating one out of a
864             // group of eight 125 kHz channels followed by probing one 500 kHz channel each pass.
865             // Each time a 125 kHz channel will be selected from another group.
866 
867             // 125kHz Channels (0 - 63) DR2
868             if( nextChanParams->Datarate == DR_2 )
869             {
870                 if( RegionBaseUSComputeNext125kHzJoinChannel( ( uint16_t* ) RegionNvmGroup1->ChannelsMaskRemaining,
871                     &RegionNvmGroup1->JoinChannelGroupsCurrentIndex, channel ) == LORAMAC_STATUS_PARAMETER_INVALID )
872                 {
873                     return LORAMAC_STATUS_PARAMETER_INVALID;
874                 }
875             }
876             // 500kHz Channels (64 - 71) DR6
877             else
878             {
879                 // Choose the next available channel
880                 uint8_t i = 0;
881                 while( ( ( RegionNvmGroup1->ChannelsMaskRemaining[4] & CHANNELS_MASK_500KHZ_MASK ) & ( 1 << i ) ) == 0 )
882                 {
883                     i++;
884                 }
885                 *channel = 64 + i;
886             }
887         }
888 
889         // Disable the channel in the mask
890         RegionCommonChanDisable( RegionNvmGroup1->ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS );
891     }
892     return status;
893 }
894 
RegionAU915ChannelAdd(ChannelAddParams_t * channelAdd)895 LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd )
896 {
897     return LORAMAC_STATUS_PARAMETER_INVALID;
898 }
899 
RegionAU915ChannelsRemove(ChannelRemoveParams_t * channelRemove)900 bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
901 {
902     return LORAMAC_STATUS_PARAMETER_INVALID;
903 }
904 
RegionAU915ApplyDrOffset(uint8_t downlinkDwellTime,int8_t dr,int8_t drOffset)905 uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
906 {
907     int8_t datarate = DatarateOffsetsAU915[dr][drOffset];
908 
909     if( datarate < 0 )
910     {
911         if( downlinkDwellTime == 0 )
912         {
913             datarate = AU915_TX_MIN_DATARATE;
914         }
915         else
916         {
917             datarate = AU915_DWELL_LIMIT_DATARATE;
918         }
919     }
920     return datarate;
921 }
922 
RegionAU915RxBeaconSetup(RxBeaconSetup_t * rxBeaconSetup,uint8_t * outDr)923 void RegionAU915RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr )
924 {
925     RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup;
926 
927     regionCommonRxBeaconSetup.Datarates = DataratesAU915;
928     regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency;
929     regionCommonRxBeaconSetup.BeaconSize = AU915_BEACON_SIZE;
930     regionCommonRxBeaconSetup.BeaconDatarate = AU915_BEACON_CHANNEL_DR;
931     regionCommonRxBeaconSetup.BeaconChannelBW = AU915_BEACON_CHANNEL_BW;
932     regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime;
933     regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout;
934 
935     RegionCommonRxBeaconSetup( &regionCommonRxBeaconSetup );
936 
937     // Store downlink datarate
938     *outDr = AU915_BEACON_CHANNEL_DR;
939 }
940