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( ®ionCommonRxBeaconSetup );
927
928 // Store downlink datarate
929 *outDr = US915_BEACON_CHANNEL_DR;
930 }
931