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