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