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