1 /*!
2  * \file      RegionKR920.c
3  *
4  * \brief     Region implementation for KR920
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 "RegionKR920.h"
34 
35 // Definitions
36 #define CHANNELS_MASK_SIZE                1
37 
38 /*!
39  * Specifies the reception bandwidth to be used while executing the LBT
40  * Max channel bandwidth is 200 kHz
41  */
42 #define KR920_LBT_RX_BANDWIDTH            200000
43 
44 /*
45  * Non-volatile module context.
46  */
47 static RegionNvmDataGroup1_t* RegionNvmGroup1;
48 static RegionNvmDataGroup2_t* RegionNvmGroup2;
49 static Band_t* RegionBands;
50 
51 // Static functions
GetMaxEIRP(uint32_t freq)52 static int8_t GetMaxEIRP( uint32_t freq )
53 {
54     if( freq >= 922100000 )
55     {// Limit to 14dBm
56         return KR920_DEFAULT_MAX_EIRP_HIGH;
57     }
58     // Limit to 10dBm
59     return KR920_DEFAULT_MAX_EIRP_LOW;
60 }
61 
VerifyRfFreq(uint32_t freq)62 static bool VerifyRfFreq( uint32_t freq )
63 {
64     uint32_t tmpFreq = freq;
65 
66     // Check radio driver support
67     if( Radio.CheckRfFrequency( tmpFreq ) == false )
68     {
69         return false;
70     }
71 
72     // Verify if the frequency is valid. The frequency must be in a specified
73     // range and can be set to specific values.
74     if( ( tmpFreq >= 920900000 ) && ( tmpFreq <=923300000 ) )
75     {
76         // Range ok, check for specific value
77         tmpFreq -= 920900000;
78         if( ( tmpFreq % 200000 ) == 0 )
79         {
80             return true;
81         }
82     }
83     return false;
84 }
85 
GetTimeOnAir(int8_t datarate,uint16_t pktLen)86 static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
87 {
88     int8_t phyDr = DataratesKR920[datarate];
89     uint32_t bandwidth = RegionCommonGetBandwidth( datarate, BandwidthsKR920 );
90 
91     return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
92 }
93 
RegionKR920GetPhyParam(GetPhyParams_t * getPhy)94 PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy )
95 {
96     PhyParam_t phyParam = { 0 };
97 
98     switch( getPhy->Attribute )
99     {
100         case PHY_MIN_RX_DR:
101         {
102             phyParam.Value = KR920_RX_MIN_DATARATE;
103             break;
104         }
105         case PHY_MIN_TX_DR:
106         {
107             phyParam.Value = KR920_TX_MIN_DATARATE;
108             break;
109         }
110         case PHY_DEF_TX_DR:
111         {
112             phyParam.Value = KR920_DEFAULT_DATARATE;
113             break;
114         }
115         case PHY_NEXT_LOWER_TX_DR:
116         {
117             RegionCommonGetNextLowerTxDrParams_t nextLowerTxDrParams =
118             {
119                 .CurrentDr = getPhy->Datarate,
120                 .MaxDr = ( int8_t )KR920_TX_MAX_DATARATE,
121                 .MinDr = ( int8_t )KR920_TX_MIN_DATARATE,
122                 .NbChannels = KR920_MAX_NB_CHANNELS,
123                 .ChannelsMask = RegionNvmGroup2->ChannelsMask,
124                 .Channels = RegionNvmGroup2->Channels,
125             };
126             phyParam.Value = RegionCommonGetNextLowerTxDr( &nextLowerTxDrParams );
127             break;
128         }
129         case PHY_MAX_TX_POWER:
130         {
131             phyParam.Value = KR920_MAX_TX_POWER;
132             break;
133         }
134         case PHY_DEF_TX_POWER:
135         {
136             phyParam.Value = KR920_DEFAULT_TX_POWER;
137             break;
138         }
139         case PHY_DEF_ADR_ACK_LIMIT:
140         {
141             phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_LIMIT;
142             break;
143         }
144         case PHY_DEF_ADR_ACK_DELAY:
145         {
146             phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_DELAY;
147             break;
148         }
149         case PHY_MAX_PAYLOAD:
150         {
151             phyParam.Value = MaxPayloadOfDatarateKR920[getPhy->Datarate];
152             break;
153         }
154         case PHY_DUTY_CYCLE:
155         {
156             phyParam.Value = KR920_DUTY_CYCLE_ENABLED;
157             break;
158         }
159         case PHY_MAX_RX_WINDOW:
160         {
161             phyParam.Value = KR920_MAX_RX_WINDOW;
162             break;
163         }
164         case PHY_RECEIVE_DELAY1:
165         {
166             phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY1;
167             break;
168         }
169         case PHY_RECEIVE_DELAY2:
170         {
171             phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY2;
172             break;
173         }
174         case PHY_JOIN_ACCEPT_DELAY1:
175         {
176             phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY1;
177             break;
178         }
179         case PHY_JOIN_ACCEPT_DELAY2:
180         {
181             phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY2;
182             break;
183         }
184         case PHY_RETRANSMIT_TIMEOUT:
185         {
186             phyParam.Value = ( REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT + randr( -REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND, REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND ) );
187             break;
188         }
189         case PHY_DEF_DR1_OFFSET:
190         {
191             phyParam.Value = REGION_COMMON_DEFAULT_RX1_DR_OFFSET;
192             break;
193         }
194         case PHY_DEF_RX2_FREQUENCY:
195         {
196             phyParam.Value = KR920_RX_WND_2_FREQ;
197             break;
198         }
199         case PHY_DEF_RX2_DR:
200         {
201             phyParam.Value = KR920_RX_WND_2_DR;
202             break;
203         }
204         case PHY_CHANNELS_MASK:
205         {
206             phyParam.ChannelsMask = RegionNvmGroup2->ChannelsMask;
207             break;
208         }
209         case PHY_CHANNELS_DEFAULT_MASK:
210         {
211             phyParam.ChannelsMask = RegionNvmGroup2->ChannelsDefaultMask;
212             break;
213         }
214         case PHY_MAX_NB_CHANNELS:
215         {
216             phyParam.Value = KR920_MAX_NB_CHANNELS;
217             break;
218         }
219         case PHY_CHANNELS:
220         {
221             phyParam.Channels = RegionNvmGroup2->Channels;
222             break;
223         }
224         case PHY_DEF_UPLINK_DWELL_TIME:
225         {
226             phyParam.Value = KR920_DEFAULT_UPLINK_DWELL_TIME;
227             break;
228         }
229         case PHY_DEF_DOWNLINK_DWELL_TIME:
230         {
231             phyParam.Value = REGION_COMMON_DEFAULT_DOWNLINK_DWELL_TIME;
232             break;
233         }
234         case PHY_DEF_MAX_EIRP:
235         {
236             // We set the higher maximum EIRP as default value.
237             // The reason for this is, that the frequency may
238             // change during a channel selection for the next uplink.
239             // The value has to be recalculated in the TX configuration.
240             phyParam.fValue = KR920_DEFAULT_MAX_EIRP_HIGH;
241             break;
242         }
243         case PHY_DEF_ANTENNA_GAIN:
244         {
245             phyParam.fValue = KR920_DEFAULT_ANTENNA_GAIN;
246             break;
247         }
248         case PHY_BEACON_CHANNEL_FREQ:
249         {
250             phyParam.Value = KR920_BEACON_CHANNEL_FREQ;
251             break;
252         }
253         case PHY_BEACON_FORMAT:
254         {
255             phyParam.BeaconFormat.BeaconSize = KR920_BEACON_SIZE;
256             phyParam.BeaconFormat.Rfu1Size = KR920_RFU1_SIZE;
257             phyParam.BeaconFormat.Rfu2Size = KR920_RFU2_SIZE;
258             break;
259         }
260         case PHY_BEACON_CHANNEL_DR:
261         {
262             phyParam.Value = KR920_BEACON_CHANNEL_DR;
263             break;
264         }
265         case PHY_PING_SLOT_CHANNEL_FREQ:
266         {
267             phyParam.Value = KR920_PING_SLOT_CHANNEL_FREQ;
268             break;
269         }
270         case PHY_PING_SLOT_CHANNEL_DR:
271         {
272             phyParam.Value = KR920_PING_SLOT_CHANNEL_DR;
273             break;
274         }
275         case PHY_SF_FROM_DR:
276         {
277             phyParam.Value = DataratesKR920[getPhy->Datarate];
278             break;
279         }
280         case PHY_BW_FROM_DR:
281         {
282             phyParam.Value = RegionCommonGetBandwidth( getPhy->Datarate, BandwidthsKR920 );
283             break;
284         }
285         default:
286         {
287             break;
288         }
289     }
290 
291     return phyParam;
292 }
293 
RegionKR920SetBandTxDone(SetBandTxDoneParams_t * txDone)294 void RegionKR920SetBandTxDone( SetBandTxDoneParams_t* txDone )
295 {
296     RegionCommonSetBandTxDone( &RegionBands[RegionNvmGroup2->Channels[txDone->Channel].Band],
297                                txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
298 }
299 
RegionKR920InitDefaults(InitDefaultsParams_t * params)300 void RegionKR920InitDefaults( InitDefaultsParams_t* params )
301 {
302     Band_t bands[KR920_MAX_NB_BANDS] =
303     {
304         KR920_BAND0
305     };
306 
307     switch( params->Type )
308     {
309         case INIT_TYPE_DEFAULTS:
310         {
311             if( ( params->NvmGroup1 == NULL ) || ( params->NvmGroup2 == NULL ) )
312             {
313                 return;
314             }
315 
316             RegionNvmGroup1 = (RegionNvmDataGroup1_t*) params->NvmGroup1;
317             RegionNvmGroup2 = (RegionNvmDataGroup2_t*) params->NvmGroup2;
318             RegionBands = (Band_t*) params->Bands;
319 
320             // Initialize bands
321             memcpy1( ( uint8_t* )RegionBands, ( uint8_t* )bands, sizeof( Band_t ) * KR920_MAX_NB_BANDS );
322 
323             // Default channels
324             RegionNvmGroup2->Channels[0] = ( ChannelParams_t ) KR920_LC1;
325             RegionNvmGroup2->Channels[1] = ( ChannelParams_t ) KR920_LC2;
326             RegionNvmGroup2->Channels[2] = ( ChannelParams_t ) KR920_LC3;
327 
328             // Default ChannelsMask
329             RegionNvmGroup2->ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
330 
331             // Update the channels mask
332             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
333             break;
334         }
335         case INIT_TYPE_RESET_TO_DEFAULT_CHANNELS:
336         {
337             // Reset Channels Rx1Frequency to default 0
338             RegionNvmGroup2->Channels[0].Rx1Frequency = 0;
339             RegionNvmGroup2->Channels[1].Rx1Frequency = 0;
340             RegionNvmGroup2->Channels[2].Rx1Frequency = 0;
341             // Update the channels mask
342             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
343             break;
344         }
345         case INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS:
346         {
347             // Restore channels default mask
348             RegionNvmGroup2->ChannelsMask[0] |= RegionNvmGroup2->ChannelsDefaultMask[0];
349             break;
350         }
351         default:
352         {
353             break;
354         }
355     }
356 }
357 
RegionKR920Verify(VerifyParams_t * verify,PhyAttribute_t phyAttribute)358 bool RegionKR920Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
359 {
360     switch( phyAttribute )
361     {
362         case PHY_FREQUENCY:
363         {
364             return VerifyRfFreq( verify->Frequency );
365         }
366         case PHY_TX_DR:
367         {
368             return RegionCommonValueInRange( verify->DatarateParams.Datarate, KR920_TX_MIN_DATARATE, KR920_TX_MAX_DATARATE );
369         }
370         case PHY_DEF_TX_DR:
371         {
372             return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
373         }
374         case PHY_RX_DR:
375         {
376             return RegionCommonValueInRange( verify->DatarateParams.Datarate, KR920_RX_MIN_DATARATE, KR920_RX_MAX_DATARATE );
377         }
378         case PHY_DEF_TX_POWER:
379         case PHY_TX_POWER:
380         {
381             // Remark: switched min and max!
382             return RegionCommonValueInRange( verify->TxPower, KR920_MAX_TX_POWER, KR920_MIN_TX_POWER );
383         }
384         case PHY_DUTY_CYCLE:
385         {
386             return KR920_DUTY_CYCLE_ENABLED;
387         }
388         default:
389             return false;
390     }
391 }
392 
RegionKR920ApplyCFList(ApplyCFListParams_t * applyCFList)393 void RegionKR920ApplyCFList( ApplyCFListParams_t* applyCFList )
394 {
395     ChannelParams_t newChannel;
396     ChannelAddParams_t channelAdd;
397     ChannelRemoveParams_t channelRemove;
398 
399     // Setup default datarate range
400     newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
401 
402     // Size of the optional CF list
403     if( applyCFList->Size != 16 )
404     {
405         return;
406     }
407 
408     // Last byte CFListType must be 0 to indicate the CFList contains a list of frequencies
409     if( applyCFList->Payload[15] != 0 )
410     {
411         return;
412     }
413 
414     // Last byte is RFU, don't take it into account
415     for( uint8_t i = 0, chanIdx = KR920_NUMB_DEFAULT_CHANNELS; chanIdx < KR920_MAX_NB_CHANNELS; i+=3, chanIdx++ )
416     {
417         if( chanIdx < ( KR920_NUMB_CHANNELS_CF_LIST + KR920_NUMB_DEFAULT_CHANNELS ) )
418         {
419             // Channel frequency
420             newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
421             newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
422             newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
423             newChannel.Frequency *= 100;
424 
425             // Initialize alternative frequency to 0
426             newChannel.Rx1Frequency = 0;
427         }
428         else
429         {
430             newChannel.Frequency = 0;
431             newChannel.DrRange.Value = 0;
432             newChannel.Rx1Frequency = 0;
433         }
434 
435         if( newChannel.Frequency != 0 )
436         {
437             channelAdd.NewChannel = &newChannel;
438             channelAdd.ChannelId = chanIdx;
439 
440             // Try to add all channels
441             RegionKR920ChannelAdd( &channelAdd );
442         }
443         else
444         {
445             channelRemove.ChannelId = chanIdx;
446 
447             RegionKR920ChannelsRemove( &channelRemove );
448         }
449     }
450 }
451 
RegionKR920ChanMaskSet(ChanMaskSetParams_t * chanMaskSet)452 bool RegionKR920ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
453 {
454     switch( chanMaskSet->ChannelsMaskType )
455     {
456         case CHANNELS_MASK:
457         {
458             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
459             break;
460         }
461         case CHANNELS_DEFAULT_MASK:
462         {
463             RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
464             break;
465         }
466         default:
467             return false;
468     }
469     return true;
470 }
471 
RegionKR920ComputeRxWindowParameters(int8_t datarate,uint8_t minRxSymbols,uint32_t rxError,RxConfigParams_t * rxConfigParams)472 void RegionKR920ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
473 {
474     uint32_t tSymbolInUs = 0;
475 
476     // Get the datarate, perform a boundary check
477     rxConfigParams->Datarate = MIN( datarate, KR920_RX_MAX_DATARATE );
478     rxConfigParams->Bandwidth = RegionCommonGetBandwidth( rxConfigParams->Datarate, BandwidthsKR920 );
479 
480     tSymbolInUs = RegionCommonComputeSymbolTimeLoRa( DataratesKR920[rxConfigParams->Datarate], BandwidthsKR920[rxConfigParams->Datarate] );
481 
482     RegionCommonComputeRxWindowParameters( tSymbolInUs, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
483 }
484 
RegionKR920RxConfig(RxConfigParams_t * rxConfig,int8_t * datarate)485 bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
486 {
487     int8_t dr = rxConfig->Datarate;
488     int8_t phyDr = 0;
489     uint32_t frequency = rxConfig->Frequency;
490 
491     if( Radio.GetStatus( ) != RF_IDLE )
492     {
493         return false;
494     }
495 
496     if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
497     {
498         // Apply window 1 frequency
499         frequency = RegionNvmGroup2->Channels[rxConfig->Channel].Frequency;
500         // Apply the alternative RX 1 window frequency, if it is available
501         if( RegionNvmGroup2->Channels[rxConfig->Channel].Rx1Frequency != 0 )
502         {
503             frequency = RegionNvmGroup2->Channels[rxConfig->Channel].Rx1Frequency;
504         }
505     }
506 
507     // Read the physical datarate from the datarates table
508     phyDr = DataratesKR920[dr];
509 
510     Radio.SetChannel( frequency );
511 
512     // Radio configuration
513     Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
514     Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateKR920[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
515 
516     *datarate = (uint8_t) dr;
517     return true;
518 }
519 
RegionKR920TxConfig(TxConfigParams_t * txConfig,int8_t * txPower,TimerTime_t * txTimeOnAir)520 bool RegionKR920TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
521 {
522     int8_t phyDr = DataratesKR920[txConfig->Datarate];
523     int8_t txPowerLimited = RegionCommonLimitTxPower( txConfig->TxPower, RegionBands[RegionNvmGroup2->Channels[txConfig->Channel].Band].TxMaxPower );
524     uint32_t bandwidth = RegionCommonGetBandwidth( txConfig->Datarate, BandwidthsKR920 );
525     float maxEIRP = GetMaxEIRP( RegionNvmGroup2->Channels[txConfig->Channel].Frequency );
526     int8_t phyTxPower = 0;
527 
528     // Take the minimum between the maxEIRP and txConfig->MaxEirp.
529     // The value of txConfig->MaxEirp could have changed during runtime, e.g. due to a MAC command.
530     maxEIRP = MIN( txConfig->MaxEirp, maxEIRP );
531 
532     // Calculate physical TX power
533     phyTxPower = RegionCommonComputeTxPower( txPowerLimited, maxEIRP, txConfig->AntennaGain );
534 
535     // Setup the radio frequency
536     Radio.SetChannel( RegionNvmGroup2->Channels[txConfig->Channel].Frequency );
537 
538     Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
539 
540     // Setup maximum payload lenght of the radio driver
541     Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
542     // Update time-on-air
543     *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
544 
545     *txPower = txPowerLimited;
546     return true;
547 }
548 
RegionKR920LinkAdrReq(LinkAdrReqParams_t * linkAdrReq,int8_t * drOut,int8_t * txPowOut,uint8_t * nbRepOut,uint8_t * nbBytesParsed)549 uint8_t RegionKR920LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
550 {
551     uint8_t status = 0x07;
552     RegionCommonLinkAdrParams_t linkAdrParams = { 0 };
553     uint8_t nextIndex = 0;
554     uint8_t bytesProcessed = 0;
555     uint16_t chMask = 0;
556     GetPhyParams_t getPhy;
557     PhyParam_t phyParam;
558     RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
559 
560     while( bytesProcessed < linkAdrReq->PayloadSize )
561     {
562         // Get ADR request parameters
563         nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
564 
565         if( nextIndex == 0 )
566             break; // break loop, since no more request has been found
567 
568         // Update bytes processed
569         bytesProcessed += nextIndex;
570 
571         // Revert status, as we only check the last ADR request for the channel mask KO
572         status = 0x07;
573 
574         // Setup temporary channels mask
575         chMask = linkAdrParams.ChMask;
576 
577         // Verify channels mask
578         if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
579         {
580             status &= 0xFE; // Channel mask KO
581         }
582         else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
583                 ( linkAdrParams.ChMaskCtrl >= 7 ) )
584         {
585             // RFU
586             status &= 0xFE; // Channel mask KO
587         }
588         else
589         {
590             for( uint8_t i = 0; i < KR920_MAX_NB_CHANNELS; i++ )
591             {
592                 if( linkAdrParams.ChMaskCtrl == 6 )
593                 {
594                     if( RegionNvmGroup2->Channels[i].Frequency != 0 )
595                     {
596                         chMask |= 1 << i;
597                     }
598                 }
599                 else
600                 {
601                     if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
602                         ( RegionNvmGroup2->Channels[i].Frequency == 0 ) )
603                     {// Trying to enable an undefined channel
604                         status &= 0xFE; // Channel mask KO
605                     }
606                 }
607             }
608         }
609     }
610 
611     // Get the minimum possible datarate
612     getPhy.Attribute = PHY_MIN_TX_DR;
613     getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
614     phyParam = RegionKR920GetPhyParam( &getPhy );
615 
616     linkAdrVerifyParams.Status = status;
617     linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
618     linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
619     linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
620     linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
621     linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
622     linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
623     linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
624     linkAdrVerifyParams.NbChannels = KR920_MAX_NB_CHANNELS;
625     linkAdrVerifyParams.ChannelsMask = &chMask;
626     linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
627     linkAdrVerifyParams.MaxDatarate = KR920_TX_MAX_DATARATE;
628     linkAdrVerifyParams.Channels = RegionNvmGroup2->Channels;
629     linkAdrVerifyParams.MinTxPower = KR920_MIN_TX_POWER;
630     linkAdrVerifyParams.MaxTxPower = KR920_MAX_TX_POWER;
631     linkAdrVerifyParams.Version = linkAdrReq->Version;
632 
633     // Verify the parameters and update, if necessary
634     status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
635 
636     // Update channelsMask if everything is correct
637     if( status == 0x07 )
638     {
639         // Set the channels mask to a default value
640         memset1( ( uint8_t* ) RegionNvmGroup2->ChannelsMask, 0, sizeof( RegionNvmGroup2->ChannelsMask ) );
641         // Update the channels mask
642         RegionNvmGroup2->ChannelsMask[0] = chMask;
643     }
644 
645     // Update status variables
646     *drOut = linkAdrParams.Datarate;
647     *txPowOut = linkAdrParams.TxPower;
648     *nbRepOut = linkAdrParams.NbRep;
649     *nbBytesParsed = bytesProcessed;
650 
651     return status;
652 }
653 
RegionKR920RxParamSetupReq(RxParamSetupReqParams_t * rxParamSetupReq)654 uint8_t RegionKR920RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
655 {
656     uint8_t status = 0x07;
657 
658     // Verify radio frequency
659     if( VerifyRfFreq( rxParamSetupReq->Frequency ) == false )
660     {
661         status &= 0xFE; // Channel frequency KO
662     }
663 
664     // Verify datarate
665     if( RegionCommonValueInRange( rxParamSetupReq->Datarate, KR920_RX_MIN_DATARATE, KR920_RX_MAX_DATARATE ) == false )
666     {
667         status &= 0xFD; // Datarate KO
668     }
669 
670     // Verify datarate offset
671     if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, KR920_MIN_RX1_DR_OFFSET, KR920_MAX_RX1_DR_OFFSET ) == false )
672     {
673         status &= 0xFB; // Rx1DrOffset range KO
674     }
675 
676     return status;
677 }
678 
RegionKR920NewChannelReq(NewChannelReqParams_t * newChannelReq)679 int8_t RegionKR920NewChannelReq( NewChannelReqParams_t* newChannelReq )
680 {
681     uint8_t status = 0x03;
682     ChannelAddParams_t channelAdd;
683     ChannelRemoveParams_t channelRemove;
684 
685     if( newChannelReq->NewChannel->Frequency == 0 )
686     {
687         channelRemove.ChannelId = newChannelReq->ChannelId;
688 
689         // Remove
690         if( RegionKR920ChannelsRemove( &channelRemove ) == false )
691         {
692             status &= 0xFC;
693         }
694     }
695     else
696     {
697         channelAdd.NewChannel = newChannelReq->NewChannel;
698         channelAdd.ChannelId = newChannelReq->ChannelId;
699 
700         switch( RegionKR920ChannelAdd( &channelAdd ) )
701         {
702             case LORAMAC_STATUS_OK:
703             {
704                 break;
705             }
706             case LORAMAC_STATUS_FREQUENCY_INVALID:
707             {
708                 status &= 0xFE;
709                 break;
710             }
711             case LORAMAC_STATUS_DATARATE_INVALID:
712             {
713                 status &= 0xFD;
714                 break;
715             }
716             case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
717             {
718                 status &= 0xFC;
719                 break;
720             }
721             default:
722             {
723                 status &= 0xFC;
724                 break;
725             }
726         }
727     }
728 
729     return status;
730 }
731 
RegionKR920TxParamSetupReq(TxParamSetupReqParams_t * txParamSetupReq)732 int8_t RegionKR920TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
733 {
734     // Do not accept the request
735     return -1;
736 }
737 
RegionKR920DlChannelReq(DlChannelReqParams_t * dlChannelReq)738 int8_t RegionKR920DlChannelReq( DlChannelReqParams_t* dlChannelReq )
739 {
740     uint8_t status = 0x03;
741 
742     // Verify if the frequency is supported
743     if( VerifyRfFreq( dlChannelReq->Rx1Frequency ) == false )
744     {
745         status &= 0xFE;
746     }
747 
748     // Verify if an uplink frequency exists
749     if( RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Frequency == 0 )
750     {
751         status &= 0xFD;
752     }
753 
754     // Apply Rx1 frequency, if the status is OK
755     if( status == 0x03 )
756     {
757         RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
758     }
759 
760     return status;
761 }
762 
RegionKR920AlternateDr(int8_t currentDr,AlternateDrType_t type)763 int8_t RegionKR920AlternateDr( int8_t currentDr, AlternateDrType_t type )
764 {
765     return currentDr;
766 }
767 
RegionKR920NextChannel(NextChanParams_t * nextChanParams,uint8_t * channel,TimerTime_t * time,TimerTime_t * aggregatedTimeOff)768 LoRaMacStatus_t RegionKR920NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
769 {
770     uint8_t channelNext = 0;
771     uint8_t nbEnabledChannels = 0;
772     uint8_t nbRestrictedChannels = 0;
773     uint8_t enabledChannels[KR920_MAX_NB_CHANNELS] = { 0 };
774     RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
775     RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
776     LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
777     uint16_t joinChannels = KR920_JOIN_CHANNELS;
778 
779     if( RegionCommonCountChannels( RegionNvmGroup2->ChannelsMask, 0, 1 ) == 0 )
780     { // Reactivate default channels
781         RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
782     }
783 
784     // Search how many channels are enabled
785     countChannelsParams.Joined = nextChanParams->Joined;
786     countChannelsParams.Datarate = nextChanParams->Datarate;
787     countChannelsParams.ChannelsMask = RegionNvmGroup2->ChannelsMask;
788     countChannelsParams.Channels = RegionNvmGroup2->Channels;
789     countChannelsParams.Bands = RegionBands;
790     countChannelsParams.MaxNbChannels = KR920_MAX_NB_CHANNELS;
791     countChannelsParams.JoinChannels = &joinChannels;
792 
793     identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
794     identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
795     identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
796     identifyChannelsParam.MaxBands = KR920_MAX_NB_BANDS;
797 
798     identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
799     identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
800     identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
801 
802     identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
803 
804     status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
805                                            &nbEnabledChannels, &nbRestrictedChannels, time );
806 
807     if( status == LORAMAC_STATUS_OK )
808     {
809         for( uint8_t  i = 0, j = randr( 0, nbEnabledChannels - 1 ); i < KR920_MAX_NB_CHANNELS; i++ )
810         {
811             channelNext = enabledChannels[j];
812             j = ( j + 1 ) % nbEnabledChannels;
813 
814             // Perform carrier sense for KR920_CARRIER_SENSE_TIME
815             // If the channel is free, we can stop the LBT mechanism
816             if( Radio.IsChannelFree( RegionNvmGroup2->Channels[channelNext].Frequency, KR920_LBT_RX_BANDWIDTH, KR920_RSSI_FREE_TH, KR920_CARRIER_SENSE_TIME ) == true )
817             {
818                 // Free channel found
819                 *channel = channelNext;
820                 return LORAMAC_STATUS_OK;
821             }
822         }
823         // Even if one or more channels are available according to the channel plan, no free channel
824         // was found during the LBT procedure.
825         status = LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
826     }
827     else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
828     {
829         // Datarate not supported by any channel, restore defaults
830         RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
831     }
832     return status;
833 }
834 
RegionKR920ChannelAdd(ChannelAddParams_t * channelAdd)835 LoRaMacStatus_t RegionKR920ChannelAdd( ChannelAddParams_t* channelAdd )
836 {
837     bool drInvalid = false;
838     bool freqInvalid = false;
839     uint8_t id = channelAdd->ChannelId;
840 
841     if( id < KR920_NUMB_DEFAULT_CHANNELS )
842     {
843         return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
844     }
845 
846     if( id >= KR920_MAX_NB_CHANNELS )
847     {
848         return LORAMAC_STATUS_PARAMETER_INVALID;
849     }
850 
851     // Validate the datarate range
852     if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, KR920_TX_MIN_DATARATE, KR920_TX_MAX_DATARATE ) == false )
853     {
854         drInvalid = true;
855     }
856     if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, KR920_TX_MIN_DATARATE, KR920_TX_MAX_DATARATE ) == false )
857     {
858         drInvalid = true;
859     }
860     if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
861     {
862         drInvalid = true;
863     }
864 
865     // Check frequency
866     if( freqInvalid == false )
867     {
868         if( VerifyRfFreq( channelAdd->NewChannel->Frequency ) == false )
869         {
870             freqInvalid = true;
871         }
872     }
873 
874     // Check status
875     if( ( drInvalid == true ) && ( freqInvalid == true ) )
876     {
877         return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
878     }
879     if( drInvalid == true )
880     {
881         return LORAMAC_STATUS_DATARATE_INVALID;
882     }
883     if( freqInvalid == true )
884     {
885         return LORAMAC_STATUS_FREQUENCY_INVALID;
886     }
887 
888     memcpy1( ( uint8_t* ) &(RegionNvmGroup2->Channels[id]), ( uint8_t* ) channelAdd->NewChannel, sizeof( RegionNvmGroup2->Channels[id] ) );
889     RegionNvmGroup2->Channels[id].Band = 0;
890     RegionNvmGroup2->ChannelsMask[0] |= ( 1 << id );
891     return LORAMAC_STATUS_OK;
892 }
893 
RegionKR920ChannelsRemove(ChannelRemoveParams_t * channelRemove)894 bool RegionKR920ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
895 {
896     uint8_t id = channelRemove->ChannelId;
897 
898     if( id < KR920_NUMB_DEFAULT_CHANNELS )
899     {
900         return false;
901     }
902 
903     // Remove the channel from the list of channels
904     RegionNvmGroup2->Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
905 
906     return RegionCommonChanDisable( RegionNvmGroup2->ChannelsMask, id, KR920_MAX_NB_CHANNELS );
907 }
908 
RegionKR920ApplyDrOffset(uint8_t downlinkDwellTime,int8_t dr,int8_t drOffset)909 uint8_t RegionKR920ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
910 {
911     int8_t datarate = dr - drOffset;
912 
913     if( datarate < 0 )
914     {
915         datarate = DR_0;
916     }
917     return datarate;
918 }
919 
RegionKR920RxBeaconSetup(RxBeaconSetup_t * rxBeaconSetup,uint8_t * outDr)920 void RegionKR920RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr )
921 {
922     RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup;
923 
924     regionCommonRxBeaconSetup.Datarates = DataratesKR920;
925     regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency;
926     regionCommonRxBeaconSetup.BeaconSize = KR920_BEACON_SIZE;
927     regionCommonRxBeaconSetup.BeaconDatarate = KR920_BEACON_CHANNEL_DR;
928     regionCommonRxBeaconSetup.BeaconChannelBW = KR920_BEACON_CHANNEL_BW;
929     regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime;
930     regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout;
931 
932     RegionCommonRxBeaconSetup( &regionCommonRxBeaconSetup );
933 
934     // Store downlink datarate
935     *outDr = KR920_BEACON_CHANNEL_DR;
936 }
937