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 if( dlChannelReq->ChannelId >= ( CHANNELS_MASK_SIZE * 16 ) )
747 {
748 return 0;
749 }
750
751 // Verify if the frequency is supported
752 if( VerifyRfFreq( dlChannelReq->Rx1Frequency ) == false )
753 {
754 status &= 0xFE;
755 }
756
757 // Verify if an uplink frequency exists
758 if( RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Frequency == 0 )
759 {
760 status &= 0xFD;
761 }
762
763 // Apply Rx1 frequency, if the status is OK
764 if( status == 0x03 )
765 {
766 RegionNvmGroup2->Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
767 }
768
769 return status;
770 }
771
RegionCN779AlternateDr(int8_t currentDr,AlternateDrType_t type)772 int8_t RegionCN779AlternateDr( int8_t currentDr, AlternateDrType_t type )
773 {
774 return currentDr;
775 }
776
RegionCN779NextChannel(NextChanParams_t * nextChanParams,uint8_t * channel,TimerTime_t * time,TimerTime_t * aggregatedTimeOff)777 LoRaMacStatus_t RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
778 {
779 uint8_t nbEnabledChannels = 0;
780 uint8_t nbRestrictedChannels = 0;
781 uint8_t enabledChannels[CN779_MAX_NB_CHANNELS] = { 0 };
782 RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
783 RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
784 LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
785 uint16_t joinChannels = CN779_JOIN_CHANNELS;
786
787 if( RegionCommonCountChannels( RegionNvmGroup2->ChannelsMask, 0, 1 ) == 0 )
788 { // Reactivate default channels
789 RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
790 }
791
792 // Search how many channels are enabled
793 countChannelsParams.Joined = nextChanParams->Joined;
794 countChannelsParams.Datarate = nextChanParams->Datarate;
795 countChannelsParams.ChannelsMask = RegionNvmGroup2->ChannelsMask;
796 countChannelsParams.Channels = RegionNvmGroup2->Channels;
797 countChannelsParams.Bands = RegionBands;
798 countChannelsParams.MaxNbChannels = CN779_MAX_NB_CHANNELS;
799 countChannelsParams.JoinChannels = &joinChannels;
800
801 identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
802 identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
803 identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
804 identifyChannelsParam.MaxBands = CN779_MAX_NB_BANDS;
805
806 identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
807 identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
808 identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
809
810 identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
811
812 status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
813 &nbEnabledChannels, &nbRestrictedChannels, time );
814
815 if( status == LORAMAC_STATUS_OK )
816 {
817 // We found a valid channel
818 *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
819 }
820 else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
821 {
822 // Datarate not supported by any channel, restore defaults
823 RegionNvmGroup2->ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
824 }
825 return status;
826 }
827
RegionCN779ChannelAdd(ChannelAddParams_t * channelAdd)828 LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd )
829 {
830 bool drInvalid = false;
831 bool freqInvalid = false;
832 uint8_t id = channelAdd->ChannelId;
833
834 if( id < CN779_NUMB_DEFAULT_CHANNELS )
835 {
836 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
837 }
838
839 if( id >= CN779_MAX_NB_CHANNELS )
840 {
841 return LORAMAC_STATUS_PARAMETER_INVALID;
842 }
843
844 // Validate the datarate range
845 if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE ) == false )
846 {
847 drInvalid = true;
848 }
849 if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE ) == false )
850 {
851 drInvalid = true;
852 }
853 if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
854 {
855 drInvalid = true;
856 }
857
858 // Check frequency
859 if( freqInvalid == false )
860 {
861 if( VerifyRfFreq( channelAdd->NewChannel->Frequency ) == false )
862 {
863 freqInvalid = true;
864 }
865 }
866
867 // Check status
868 if( ( drInvalid == true ) && ( freqInvalid == true ) )
869 {
870 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
871 }
872 if( drInvalid == true )
873 {
874 return LORAMAC_STATUS_DATARATE_INVALID;
875 }
876 if( freqInvalid == true )
877 {
878 return LORAMAC_STATUS_FREQUENCY_INVALID;
879 }
880
881 memcpy1( ( uint8_t* ) &(RegionNvmGroup2->Channels[id]), ( uint8_t* ) channelAdd->NewChannel, sizeof( RegionNvmGroup2->Channels[id] ) );
882 RegionNvmGroup2->Channels[id].Band = 0;
883 RegionNvmGroup2->ChannelsMask[0] |= ( 1 << id );
884 return LORAMAC_STATUS_OK;
885 }
886
RegionCN779ChannelsRemove(ChannelRemoveParams_t * channelRemove)887 bool RegionCN779ChannelsRemove( ChannelRemoveParams_t* channelRemove )
888 {
889 uint8_t id = channelRemove->ChannelId;
890
891 if( id < CN779_NUMB_DEFAULT_CHANNELS )
892 {
893 return false;
894 }
895
896 // Remove the channel from the list of channels
897 RegionNvmGroup2->Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
898
899 return RegionCommonChanDisable( RegionNvmGroup2->ChannelsMask, id, CN779_MAX_NB_CHANNELS );
900 }
901
RegionCN779ApplyDrOffset(uint8_t downlinkDwellTime,int8_t dr,int8_t drOffset)902 uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
903 {
904 int8_t datarate = dr - drOffset;
905
906 if( datarate < 0 )
907 {
908 datarate = DR_0;
909 }
910 return datarate;
911 }
912
RegionCN779RxBeaconSetup(RxBeaconSetup_t * rxBeaconSetup,uint8_t * outDr)913 void RegionCN779RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr )
914 {
915 RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup;
916
917 regionCommonRxBeaconSetup.Datarates = DataratesCN779;
918 regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency;
919 regionCommonRxBeaconSetup.BeaconSize = CN779_BEACON_SIZE;
920 regionCommonRxBeaconSetup.BeaconDatarate = CN779_BEACON_CHANNEL_DR;
921 regionCommonRxBeaconSetup.BeaconChannelBW = CN779_BEACON_CHANNEL_BW;
922 regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime;
923 regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout;
924
925 RegionCommonRxBeaconSetup( ®ionCommonRxBeaconSetup );
926
927 // Store downlink datarate
928 *outDr = CN779_BEACON_CHANNEL_DR;
929 }
930