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