1 /*!
2 * \file RegionIN865.c
3 *
4 * \brief Region implementation for IN865
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 "RegionIN865.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
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 < 865000000 ) || ( freq > 867000000 ) )
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 = DataratesIN865[datarate];
64 uint32_t bandwidth = RegionCommonGetBandwidth( datarate, BandwidthsIN865 );
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
RegionIN865GetPhyParam(GetPhyParams_t * getPhy)78 PhyParam_t RegionIN865GetPhyParam( 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 = IN865_RX_MIN_DATARATE;
87 break;
88 }
89 case PHY_MIN_TX_DR:
90 {
91 phyParam.Value = IN865_TX_MIN_DATARATE;
92 break;
93 }
94 case PHY_DEF_TX_DR:
95 {
96 phyParam.Value = IN865_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 )IN865_TX_MAX_DATARATE,
105 .MinDr = ( int8_t )IN865_TX_MIN_DATARATE,
106 .NbChannels = IN865_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 = IN865_MAX_TX_POWER;
116 break;
117 }
118 case PHY_DEF_TX_POWER:
119 {
120 phyParam.Value = IN865_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 = MaxPayloadOfDatarateIN865[getPhy->Datarate];
136 break;
137 }
138 case PHY_DUTY_CYCLE:
139 {
140 phyParam.Value = IN865_DUTY_CYCLE_ENABLED;
141 break;
142 }
143 case PHY_MAX_RX_WINDOW:
144 {
145 phyParam.Value = IN865_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 = IN865_RX_WND_2_FREQ;
181 break;
182 }
183 case PHY_DEF_RX2_DR:
184 {
185 phyParam.Value = IN865_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 = IN865_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 = IN865_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 = IN865_DEFAULT_MAX_EIRP;
221 break;
222 }
223 case PHY_DEF_ANTENNA_GAIN:
224 {
225 phyParam.fValue = IN865_DEFAULT_ANTENNA_GAIN;
226 break;
227 }
228 case PHY_BEACON_CHANNEL_FREQ:
229 {
230 phyParam.Value = IN865_BEACON_CHANNEL_FREQ;
231 break;
232 }
233 case PHY_BEACON_FORMAT:
234 {
235 phyParam.BeaconFormat.BeaconSize = IN865_BEACON_SIZE;
236 phyParam.BeaconFormat.Rfu1Size = IN865_RFU1_SIZE;
237 phyParam.BeaconFormat.Rfu2Size = IN865_RFU2_SIZE;
238 break;
239 }
240 case PHY_BEACON_CHANNEL_DR:
241 {
242 phyParam.Value = IN865_BEACON_CHANNEL_DR;
243 break;
244 }
245 case PHY_PING_SLOT_CHANNEL_FREQ:
246 {
247 phyParam.Value = IN865_PING_SLOT_CHANNEL_FREQ;
248 break;
249 }
250 case PHY_PING_SLOT_CHANNEL_DR:
251 {
252 phyParam.Value = IN865_PING_SLOT_CHANNEL_DR;
253 break;
254 }
255 case PHY_SF_FROM_DR:
256 {
257 phyParam.Value = DataratesIN865[getPhy->Datarate];
258 break;
259 }
260 case PHY_BW_FROM_DR:
261 {
262 phyParam.Value = RegionCommonGetBandwidth( getPhy->Datarate, BandwidthsIN865 );
263 break;
264 }
265 default:
266 {
267 break;
268 }
269 }
270
271 return phyParam;
272 }
273
RegionIN865SetBandTxDone(SetBandTxDoneParams_t * txDone)274 void RegionIN865SetBandTxDone( SetBandTxDoneParams_t* txDone )
275 {
276 RegionCommonSetBandTxDone( &RegionBands[RegionNvmGroup2->Channels[txDone->Channel].Band],
277 txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
278 }
279
RegionIN865InitDefaults(InitDefaultsParams_t * params)280 void RegionIN865InitDefaults( InitDefaultsParams_t* params )
281 {
282 Band_t bands[IN865_MAX_NB_BANDS] =
283 {
284 IN865_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 // Initialize bands
301 memcpy1( ( uint8_t* )RegionBands, ( uint8_t* )bands, sizeof( Band_t ) * IN865_MAX_NB_BANDS );
302
303 // Default channels
304 RegionNvmGroup2->Channels[0] = ( ChannelParams_t ) IN865_LC1;
305 RegionNvmGroup2->Channels[1] = ( ChannelParams_t ) IN865_LC2;
306 RegionNvmGroup2->Channels[2] = ( ChannelParams_t ) IN865_LC3;
307
308 // Initialize the channels default mask
309 RegionNvmGroup2->ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
310
311 // Default ChannelsMask
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 // Default ChannelsMask
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
RegionIN865Verify(VerifyParams_t * verify,PhyAttribute_t phyAttribute)338 bool RegionIN865Verify( 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 if( verify->DatarateParams.Datarate == DR_6 )
349 {// DR_6 is not supported by this region
350 return false;
351 }
352 else
353 {
354 return RegionCommonValueInRange( verify->DatarateParams.Datarate, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE );
355 }
356 }
357 case PHY_DEF_TX_DR:
358 {
359 return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
360 }
361 case PHY_RX_DR:
362 {
363 if( verify->DatarateParams.Datarate == DR_6 )
364 {// DR_6 is not supported by this region
365 return false;
366 }
367 else
368 {
369 return RegionCommonValueInRange( verify->DatarateParams.Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE );
370 }
371 }
372 case PHY_DEF_TX_POWER:
373 case PHY_TX_POWER:
374 {
375 // Remark: switched min and max!
376 return RegionCommonValueInRange( verify->TxPower, IN865_MAX_TX_POWER, IN865_MIN_TX_POWER );
377 }
378 case PHY_DUTY_CYCLE:
379 {
380 return IN865_DUTY_CYCLE_ENABLED;
381 }
382 default:
383 return false;
384 }
385 }
386
RegionIN865ApplyCFList(ApplyCFListParams_t * applyCFList)387 void RegionIN865ApplyCFList( ApplyCFListParams_t* applyCFList )
388 {
389 ChannelParams_t newChannel;
390 ChannelAddParams_t channelAdd;
391 ChannelRemoveParams_t channelRemove;
392
393 // Setup default datarate range
394 newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
395
396 // Size of the optional CF list
397 if( applyCFList->Size != 16 )
398 {
399 return;
400 }
401
402 // Last byte CFListType must be 0 to indicate the CFList contains a list of frequencies
403 if( applyCFList->Payload[15] != 0 )
404 {
405 return;
406 }
407
408 // Last byte is RFU, don't take it into account
409 for( uint8_t i = 0, chanIdx = IN865_NUMB_DEFAULT_CHANNELS; chanIdx < IN865_MAX_NB_CHANNELS; i+=3, chanIdx++ )
410 {
411 if( chanIdx < ( IN865_NUMB_CHANNELS_CF_LIST + IN865_NUMB_DEFAULT_CHANNELS ) )
412 {
413 // Channel frequency
414 newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
415 newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
416 newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
417 newChannel.Frequency *= 100;
418
419 // Initialize alternative frequency to 0
420 newChannel.Rx1Frequency = 0;
421 }
422 else
423 {
424 newChannel.Frequency = 0;
425 newChannel.DrRange.Value = 0;
426 newChannel.Rx1Frequency = 0;
427 }
428
429 if( newChannel.Frequency != 0 )
430 {
431 channelAdd.NewChannel = &newChannel;
432 channelAdd.ChannelId = chanIdx;
433
434 // Try to add all channels
435 RegionIN865ChannelAdd( &channelAdd );
436 }
437 else
438 {
439 channelRemove.ChannelId = chanIdx;
440
441 RegionIN865ChannelsRemove( &channelRemove );
442 }
443 }
444 }
445
RegionIN865ChanMaskSet(ChanMaskSetParams_t * chanMaskSet)446 bool RegionIN865ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
447 {
448 switch( chanMaskSet->ChannelsMaskType )
449 {
450 case CHANNELS_MASK:
451 {
452 RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
453 break;
454 }
455 case CHANNELS_DEFAULT_MASK:
456 {
457 RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
458 break;
459 }
460 default:
461 return false;
462 }
463 return true;
464 }
465
RegionIN865ComputeRxWindowParameters(int8_t datarate,uint8_t minRxSymbols,uint32_t rxError,RxConfigParams_t * rxConfigParams)466 void RegionIN865ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
467 {
468 uint32_t tSymbolInUs = 0;
469
470 // Get the datarate, perform a boundary check
471 rxConfigParams->Datarate = MIN( datarate, IN865_RX_MAX_DATARATE );
472 rxConfigParams->Bandwidth = RegionCommonGetBandwidth( rxConfigParams->Datarate, BandwidthsIN865 );
473
474 if( rxConfigParams->Datarate == DR_7 )
475 { // FSK
476 tSymbolInUs = RegionCommonComputeSymbolTimeFsk( DataratesIN865[rxConfigParams->Datarate] );
477 }
478 else
479 { // LoRa
480 tSymbolInUs = RegionCommonComputeSymbolTimeLoRa( DataratesIN865[rxConfigParams->Datarate], BandwidthsIN865[rxConfigParams->Datarate] );
481 }
482
483 RegionCommonComputeRxWindowParameters( tSymbolInUs, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
484 }
485
RegionIN865RxConfig(RxConfigParams_t * rxConfig,int8_t * datarate)486 bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
487 {
488 RadioModems_t modem;
489 int8_t dr = rxConfig->Datarate;
490 int8_t phyDr = 0;
491 uint32_t frequency = rxConfig->Frequency;
492
493 if( Radio.GetStatus( ) != RF_IDLE )
494 {
495 return false;
496 }
497
498 if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
499 {
500 // Apply window 1 frequency
501 frequency = RegionNvmGroup2->Channels[rxConfig->Channel].Frequency;
502 // Apply the alternative RX 1 window frequency, if it is available
503 if( RegionNvmGroup2->Channels[rxConfig->Channel].Rx1Frequency != 0 )
504 {
505 frequency = RegionNvmGroup2->Channels[rxConfig->Channel].Rx1Frequency;
506 }
507 }
508
509 // Read the physical datarate from the datarates table
510 phyDr = DataratesIN865[dr];
511
512 Radio.SetChannel( frequency );
513
514 // Radio configuration
515 if( dr == DR_7 )
516 {
517 modem = MODEM_FSK;
518 Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
519 }
520 else
521 {
522 modem = MODEM_LORA;
523 Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
524 }
525
526 Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateIN865[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
527
528 *datarate = (uint8_t) dr;
529 return true;
530 }
531
RegionIN865TxConfig(TxConfigParams_t * txConfig,int8_t * txPower,TimerTime_t * txTimeOnAir)532 bool RegionIN865TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
533 {
534 RadioModems_t modem;
535 int8_t phyDr = DataratesIN865[txConfig->Datarate];
536 int8_t txPowerLimited = RegionCommonLimitTxPower( txConfig->TxPower, RegionBands[RegionNvmGroup2->Channels[txConfig->Channel].Band].TxMaxPower );
537 uint32_t bandwidth = RegionCommonGetBandwidth( txConfig->Datarate, BandwidthsIN865 );
538 int8_t phyTxPower = 0;
539
540 // Calculate physical TX power
541 phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
542
543 // Setup the radio frequency
544 Radio.SetChannel( RegionNvmGroup2->Channels[txConfig->Channel].Frequency );
545
546 if( txConfig->Datarate == DR_7 )
547 { // High Speed FSK channel
548 modem = MODEM_FSK;
549 Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
550 }
551 else
552 {
553 modem = MODEM_LORA;
554 Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
555 }
556
557 // Update time-on-air
558 *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
559
560 // Setup maximum payload lenght of the radio driver
561 Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
562
563 *txPower = txPowerLimited;
564 return true;
565 }
566
RegionIN865LinkAdrReq(LinkAdrReqParams_t * linkAdrReq,int8_t * drOut,int8_t * txPowOut,uint8_t * nbRepOut,uint8_t * nbBytesParsed)567 uint8_t RegionIN865LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
568 {
569 uint8_t status = 0x07;
570 RegionCommonLinkAdrParams_t linkAdrParams = { 0 };
571 uint8_t nextIndex = 0;
572 uint8_t bytesProcessed = 0;
573 uint16_t chMask = 0;
574 GetPhyParams_t getPhy;
575 PhyParam_t phyParam;
576 RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
577
578 while( bytesProcessed < linkAdrReq->PayloadSize )
579 {
580 // Get ADR request parameters
581 nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
582
583 if( nextIndex == 0 )
584 break; // break loop, since no more request has been found
585
586 // Update bytes processed
587 bytesProcessed += nextIndex;
588
589 // Revert status, as we only check the last ADR request for the channel mask KO
590 status = 0x07;
591
592 // Setup temporary channels mask
593 chMask = linkAdrParams.ChMask;
594
595 // Verify channels mask
596 if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
597 {
598 status &= 0xFE; // Channel mask KO
599 }
600 else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
601 ( linkAdrParams.ChMaskCtrl >= 7 ) )
602 {
603 // RFU
604 status &= 0xFE; // Channel mask KO
605 }
606 else
607 {
608 for( uint8_t i = 0; i < IN865_MAX_NB_CHANNELS; i++ )
609 {
610 if( linkAdrParams.ChMaskCtrl == 6 )
611 {
612 if( RegionNvmGroup2->Channels[i].Frequency != 0 )
613 {
614 chMask |= 1 << i;
615 }
616 }
617 else
618 {
619 if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
620 ( RegionNvmGroup2->Channels[i].Frequency == 0 ) )
621 {// Trying to enable an undefined channel
622 status &= 0xFE; // Channel mask KO
623 }
624 }
625 }
626 }
627 }
628
629 if( linkAdrParams.Datarate != DR_6 )
630 {
631 // Get the minimum possible datarate
632 getPhy.Attribute = PHY_MIN_TX_DR;
633 getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
634 phyParam = RegionIN865GetPhyParam( &getPhy );
635
636 linkAdrVerifyParams.Status = status;
637 linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
638 linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
639 linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
640 linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
641 linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
642 linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
643 linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
644 linkAdrVerifyParams.NbChannels = IN865_MAX_NB_CHANNELS;
645 linkAdrVerifyParams.ChannelsMask = &chMask;
646 linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
647 linkAdrVerifyParams.MaxDatarate = IN865_TX_MAX_DATARATE;
648 linkAdrVerifyParams.Channels = RegionNvmGroup2->Channels;
649 linkAdrVerifyParams.MinTxPower = IN865_MIN_TX_POWER;
650 linkAdrVerifyParams.MaxTxPower = IN865_MAX_TX_POWER;
651 linkAdrVerifyParams.Version = linkAdrReq->Version;
652
653 // Verify the parameters and update, if necessary
654 status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
655 }
656 else
657 {// DR_6 is not supported by this region
658 status &= 0xFD; // Datarate KO
659 }
660
661 // Update channelsMask if everything is correct
662 if( status == 0x07 )
663 {
664 // Set the channels mask to a default value
665 memset1( ( uint8_t* ) RegionNvmGroup2->ChannelsMask, 0, sizeof( RegionNvmGroup2->ChannelsMask ) );
666 // Update the channels mask
667 RegionNvmGroup2->ChannelsMask[0] = chMask;
668 }
669
670 // Update status variables
671 *drOut = linkAdrParams.Datarate;
672 *txPowOut = linkAdrParams.TxPower;
673 *nbRepOut = linkAdrParams.NbRep;
674 *nbBytesParsed = bytesProcessed;
675
676 return status;
677 }
678
RegionIN865RxParamSetupReq(RxParamSetupReqParams_t * rxParamSetupReq)679 uint8_t RegionIN865RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
680 {
681 uint8_t status = 0x07;
682
683 // Verify radio frequency
684 if( VerifyRfFreq( rxParamSetupReq->Frequency ) == false )
685 {
686 status &= 0xFE; // Channel frequency KO
687 }
688
689 // Verify datarate
690 if( ( RegionCommonValueInRange( rxParamSetupReq->Datarate, IN865_RX_MIN_DATARATE, IN865_RX_MAX_DATARATE ) == false ) ||
691 // DR_6 is not supported by this region
692 ( rxParamSetupReq->Datarate == DR_6 ) )
693 {
694 status &= 0xFD; // Datarate KO
695 }
696
697 // Verify datarate offset
698 if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, IN865_MIN_RX1_DR_OFFSET, IN865_MAX_RX1_DR_OFFSET ) == false )
699 {
700 status &= 0xFB; // Rx1DrOffset range KO
701 }
702
703 return status;
704 }
705
RegionIN865NewChannelReq(NewChannelReqParams_t * newChannelReq)706 int8_t RegionIN865NewChannelReq( NewChannelReqParams_t* newChannelReq )
707 {
708 uint8_t status = 0x03;
709 ChannelAddParams_t channelAdd;
710 ChannelRemoveParams_t channelRemove;
711
712 if( newChannelReq->NewChannel->Frequency == 0 )
713 {
714 channelRemove.ChannelId = newChannelReq->ChannelId;
715
716 // Remove
717 if( RegionIN865ChannelsRemove( &channelRemove ) == false )
718 {
719 status &= 0xFC;
720 }
721 }
722 else
723 {
724 channelAdd.NewChannel = newChannelReq->NewChannel;
725 channelAdd.ChannelId = newChannelReq->ChannelId;
726
727 switch( RegionIN865ChannelAdd( &channelAdd ) )
728 {
729 case LORAMAC_STATUS_OK:
730 {
731 break;
732 }
733 case LORAMAC_STATUS_FREQUENCY_INVALID:
734 {
735 status &= 0xFE;
736 break;
737 }
738 case LORAMAC_STATUS_DATARATE_INVALID:
739 {
740 status &= 0xFD;
741 break;
742 }
743 case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
744 {
745 status &= 0xFC;
746 break;
747 }
748 default:
749 {
750 status &= 0xFC;
751 break;
752 }
753 }
754 }
755
756 return status;
757 }
758
RegionIN865TxParamSetupReq(TxParamSetupReqParams_t * txParamSetupReq)759 int8_t RegionIN865TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
760 {
761 // Do not accept the request
762 return -1;
763 }
764
RegionIN865DlChannelReq(DlChannelReqParams_t * dlChannelReq)765 int8_t RegionIN865DlChannelReq( DlChannelReqParams_t* dlChannelReq )
766 {
767 uint8_t status = 0x03;
768
769 // Verify if the frequency is supported
770 if( VerifyRfFreq( dlChannelReq->Rx1Frequency ) == false )
771 {
772 status &= 0xFE;
773 }
774
775 // Verify if an uplink frequency exists
776 if( RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Frequency == 0 )
777 {
778 status &= 0xFD;
779 }
780
781 // Apply Rx1 frequency, if the status is OK
782 if( status == 0x03 )
783 {
784 RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
785 }
786
787 return status;
788 }
789
RegionIN865AlternateDr(int8_t currentDr,AlternateDrType_t type)790 int8_t RegionIN865AlternateDr( int8_t currentDr, AlternateDrType_t type )
791 {
792 return currentDr;
793 }
794
RegionIN865NextChannel(NextChanParams_t * nextChanParams,uint8_t * channel,TimerTime_t * time,TimerTime_t * aggregatedTimeOff)795 LoRaMacStatus_t RegionIN865NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
796 {
797 uint8_t nbEnabledChannels = 0;
798 uint8_t nbRestrictedChannels = 0;
799 uint8_t enabledChannels[IN865_MAX_NB_CHANNELS] = { 0 };
800 RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
801 RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
802 LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
803 uint16_t joinChannels = IN865_JOIN_CHANNELS;
804
805 if( RegionCommonCountChannels( RegionNvmGroup2->ChannelsMask, 0, 1 ) == 0 )
806 { // Reactivate default channels
807 RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
808 }
809
810 // Search how many channels are enabled
811 countChannelsParams.Joined = nextChanParams->Joined;
812 countChannelsParams.Datarate = nextChanParams->Datarate;
813 countChannelsParams.ChannelsMask = RegionNvmGroup2->ChannelsMask;
814 countChannelsParams.Channels = RegionNvmGroup2->Channels;
815 countChannelsParams.Bands = RegionBands;
816 countChannelsParams.MaxNbChannels = IN865_MAX_NB_CHANNELS;
817 countChannelsParams.JoinChannels = &joinChannels;
818
819 identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
820 identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
821 identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
822 identifyChannelsParam.MaxBands = IN865_MAX_NB_BANDS;
823
824 identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
825 identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
826 identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
827
828 identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
829
830 status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
831 &nbEnabledChannels, &nbRestrictedChannels, time );
832
833 if( status == LORAMAC_STATUS_OK )
834 {
835 // We found a valid channel
836 *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
837 }
838 else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
839 {
840 // Datarate not supported by any channel, restore defaults
841 RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
842 }
843 return status;
844 }
845
RegionIN865ChannelAdd(ChannelAddParams_t * channelAdd)846 LoRaMacStatus_t RegionIN865ChannelAdd( ChannelAddParams_t* channelAdd )
847 {
848 bool drInvalid = false;
849 bool freqInvalid = false;
850 uint8_t id = channelAdd->ChannelId;
851
852 if( id < IN865_NUMB_DEFAULT_CHANNELS )
853 {
854 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
855 }
856
857 if( id >= IN865_MAX_NB_CHANNELS )
858 {
859 return LORAMAC_STATUS_PARAMETER_INVALID;
860 }
861
862 // Validate the datarate range
863 if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE ) == false )
864 {
865 drInvalid = true;
866 }
867 if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, IN865_TX_MIN_DATARATE, IN865_TX_MAX_DATARATE ) == false )
868 {
869 drInvalid = true;
870 }
871 if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
872 {
873 drInvalid = true;
874 }
875
876 // Check frequency
877 if( freqInvalid == false )
878 {
879 if( VerifyRfFreq( channelAdd->NewChannel->Frequency ) == false )
880 {
881 freqInvalid = true;
882 }
883 }
884
885 // Check status
886 if( ( drInvalid == true ) && ( freqInvalid == true ) )
887 {
888 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
889 }
890 if( drInvalid == true )
891 {
892 return LORAMAC_STATUS_DATARATE_INVALID;
893 }
894 if( freqInvalid == true )
895 {
896 return LORAMAC_STATUS_FREQUENCY_INVALID;
897 }
898
899 memcpy1( ( uint8_t* ) &(RegionNvmGroup2->Channels[id]), ( uint8_t* ) channelAdd->NewChannel, sizeof( RegionNvmGroup2->Channels[id] ) );
900 RegionNvmGroup2->Channels[id].Band = 0;
901 RegionNvmGroup2->ChannelsMask[0] |= ( 1 << id );
902 return LORAMAC_STATUS_OK;
903 }
904
RegionIN865ChannelsRemove(ChannelRemoveParams_t * channelRemove)905 bool RegionIN865ChannelsRemove( ChannelRemoveParams_t* channelRemove )
906 {
907 uint8_t id = channelRemove->ChannelId;
908
909 if( id < IN865_NUMB_DEFAULT_CHANNELS )
910 {
911 return false;
912 }
913
914 // Remove the channel from the list of channels
915 RegionNvmGroup2->Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
916
917 return RegionCommonChanDisable( RegionNvmGroup2->ChannelsMask, id, IN865_MAX_NB_CHANNELS );
918 }
919
RegionIN865ApplyDrOffset(uint8_t downlinkDwellTime,int8_t dr,int8_t drOffset)920 uint8_t RegionIN865ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
921 {
922 int8_t datarate = EffectiveRx1DrOffsetIN865[dr][drOffset];
923
924 if( ( datarate < 0 ) || ( dr == DR_6 ) )
925 {
926 datarate = DR_0;
927 }
928 return datarate;
929 }
930
RegionIN865RxBeaconSetup(RxBeaconSetup_t * rxBeaconSetup,uint8_t * outDr)931 void RegionIN865RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr )
932 {
933 RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup;
934
935 regionCommonRxBeaconSetup.Datarates = DataratesIN865;
936 regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency;
937 regionCommonRxBeaconSetup.BeaconSize = IN865_BEACON_SIZE;
938 regionCommonRxBeaconSetup.BeaconDatarate = IN865_BEACON_CHANNEL_DR;
939 regionCommonRxBeaconSetup.BeaconChannelBW = IN865_BEACON_CHANNEL_BW;
940 regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime;
941 regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout;
942
943 RegionCommonRxBeaconSetup( ®ionCommonRxBeaconSetup );
944
945 // Store downlink datarate
946 *outDr = IN865_BEACON_CHANNEL_DR;
947 }
948