1 /*!
2  * \file      radio.c
3  *
4  * \brief     Radio driver API definition
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  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  *
21  * \author    Gregory Cristian ( Semtech )
22  */
23 #include <math.h>
24 #include <string.h>
25 #include "utilities.h"
26 #include "timer.h"
27 #include "delay.h"
28 #include "radio.h"
29 #include "sx126x.h"
30 #include "sx126x-board.h"
31 #include "board.h"
32 
33 /*!
34  * \brief Initializes the radio
35  *
36  * \param [IN] events Structure containing the driver callback functions
37  */
38 void RadioInit( RadioEvents_t *events );
39 
40 /*!
41  * Return current radio status
42  *
43  * \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
44  */
45 RadioState_t RadioGetStatus( void );
46 
47 /*!
48  * \brief Configures the radio with the given modem
49  *
50  * \param [IN] modem Modem to be used [0: FSK, 1: LoRa]
51  */
52 void RadioSetModem( RadioModems_t modem );
53 
54 /*!
55  * \brief Sets the channel frequency
56  *
57  * \param [IN] freq         Channel RF frequency
58  */
59 void RadioSetChannel( uint32_t freq );
60 
61 /*!
62  * \brief Checks if the channel is free for the given time
63  *
64  * \remark The FSK modem is always used for this task as we can select the Rx bandwidth at will.
65  *
66  * \param [IN] freq                Channel RF frequency in Hertz
67  * \param [IN] rxBandwidth         Rx bandwidth in Hertz
68  * \param [IN] rssiThresh          RSSI threshold in dBm
69  * \param [IN] maxCarrierSenseTime Max time in milliseconds while the RSSI is measured
70  *
71  * \retval isFree         [true: Channel is free, false: Channel is not free]
72  */
73 bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
74 
75 /*!
76  * \brief Generates a 32 bits random value based on the RSSI readings
77  *
78  * \remark This function sets the radio in LoRa modem mode and disables
79  *         all interrupts.
80  *         After calling this function either Radio.SetRxConfig or
81  *         Radio.SetTxConfig functions must be called.
82  *
83  * \retval randomValue    32 bits random value
84  */
85 uint32_t RadioRandom( void );
86 
87 /*!
88  * \brief Sets the reception parameters
89  *
90  * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa]
91  * \param [IN] bandwidth    Sets the bandwidth
92  *                          FSK : >= 2600 and <= 250000 Hz
93  *                          LoRa: [0: 125 kHz, 1: 250 kHz,
94  *                                 2: 500 kHz, 3: Reserved]
95  * \param [IN] datarate     Sets the Datarate
96  *                          FSK : 600..300000 bits/s
97  *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
98  *                                10: 1024, 11: 2048, 12: 4096  chips]
99  * \param [IN] coderate     Sets the coding rate (LoRa only)
100  *                          FSK : N/A ( set to 0 )
101  *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
102  * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
103  *                          FSK : >= 2600 and <= 250000 Hz
104  *                          LoRa: N/A ( set to 0 )
105  * \param [IN] preambleLen  Sets the Preamble length
106  *                          FSK : Number of bytes
107  *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
108  * \param [IN] symbTimeout  Sets the RxSingle timeout value
109  *                          FSK : timeout in number of bytes
110  *                          LoRa: timeout in symbols
111  * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
112  * \param [IN] payloadLen   Sets payload length when fixed length is used
113  * \param [IN] crcOn        Enables/Disables the CRC [0: OFF, 1: ON]
114  * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
115  *                          FSK : N/A ( set to 0 )
116  *                          LoRa: [0: OFF, 1: ON]
117  * \param [IN] HopPeriod    Number of symbols between each hop
118  *                          FSK : N/A ( set to 0 )
119  *                          LoRa: Number of symbols
120  * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
121  *                          FSK : N/A ( set to 0 )
122  *                          LoRa: [0: not inverted, 1: inverted]
123  * \param [IN] rxContinuous Sets the reception in continuous mode
124  *                          [false: single mode, true: continuous mode]
125  */
126 void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
127                           uint32_t datarate, uint8_t coderate,
128                           uint32_t bandwidthAfc, uint16_t preambleLen,
129                           uint16_t symbTimeout, bool fixLen,
130                           uint8_t payloadLen,
131                           bool crcOn, bool FreqHopOn, uint8_t HopPeriod,
132                           bool iqInverted, bool rxContinuous );
133 
134 /*!
135  * \brief Sets the transmission parameters
136  *
137  * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa]
138  * \param [IN] power        Sets the output power [dBm]
139  * \param [IN] fdev         Sets the frequency deviation (FSK only)
140  *                          FSK : [Hz]
141  *                          LoRa: 0
142  * \param [IN] bandwidth    Sets the bandwidth (LoRa only)
143  *                          FSK : 0
144  *                          LoRa: [0: 125 kHz, 1: 250 kHz,
145  *                                 2: 500 kHz, 3: Reserved]
146  * \param [IN] datarate     Sets the Datarate
147  *                          FSK : 600..300000 bits/s
148  *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
149  *                                10: 1024, 11: 2048, 12: 4096  chips]
150  * \param [IN] coderate     Sets the coding rate (LoRa only)
151  *                          FSK : N/A ( set to 0 )
152  *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
153  * \param [IN] preambleLen  Sets the preamble length
154  *                          FSK : Number of bytes
155  *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
156  * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
157  * \param [IN] crcOn        Enables disables the CRC [0: OFF, 1: ON]
158  * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
159  *                          FSK : N/A ( set to 0 )
160  *                          LoRa: [0: OFF, 1: ON]
161  * \param [IN] HopPeriod    Number of symbols between each hop
162  *                          FSK : N/A ( set to 0 )
163  *                          LoRa: Number of symbols
164  * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
165  *                          FSK : N/A ( set to 0 )
166  *                          LoRa: [0: not inverted, 1: inverted]
167  * \param [IN] timeout      Transmission timeout [ms]
168  */
169 void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
170                           uint32_t bandwidth, uint32_t datarate,
171                           uint8_t coderate, uint16_t preambleLen,
172                           bool fixLen, bool crcOn, bool FreqHopOn,
173                           uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
174 
175 /*!
176  * \brief Checks if the given RF frequency is supported by the hardware
177  *
178  * \param [IN] frequency RF frequency to be checked
179  * \retval isSupported [true: supported, false: unsupported]
180  */
181 bool RadioCheckRfFrequency( uint32_t frequency );
182 
183 /*!
184  * \brief Computes the packet time on air in ms for the given payload
185  *
186  * \Remark Can only be called once SetRxConfig or SetTxConfig have been called
187  *
188  * \param [IN] modem      Radio modem to be used [0: FSK, 1: LoRa]
189  * \param [IN] bandwidth    Sets the bandwidth
190  *                          FSK : >= 2600 and <= 250000 Hz
191  *                          LoRa: [0: 125 kHz, 1: 250 kHz,
192  *                                 2: 500 kHz, 3: Reserved]
193  * \param [IN] datarate     Sets the Datarate
194  *                          FSK : 600..300000 bits/s
195  *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
196  *                                10: 1024, 11: 2048, 12: 4096  chips]
197  * \param [IN] coderate     Sets the coding rate (LoRa only)
198  *                          FSK : N/A ( set to 0 )
199  *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
200  * \param [IN] preambleLen  Sets the Preamble length
201  *                          FSK : Number of bytes
202  *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
203  * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
204  * \param [IN] payloadLen   Sets payload length when fixed length is used
205  * \param [IN] crcOn        Enables/Disables the CRC [0: OFF, 1: ON]
206  *
207  * \retval airTime        Computed airTime (ms) for the given packet payload length
208  */
209 uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
210                               uint32_t datarate, uint8_t coderate,
211                               uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
212                               bool crcOn );
213 
214 /*!
215  * \brief Sends the buffer of size. Prepares the packet to be sent and sets
216  *        the radio in transmission
217  *
218  * \param [IN]: buffer     Buffer pointer
219  * \param [IN]: size       Buffer size
220  */
221 void RadioSend( uint8_t *buffer, uint8_t size );
222 
223 /*!
224  * \brief Sets the radio in sleep mode
225  */
226 void RadioSleep( void );
227 
228 /*!
229  * \brief Sets the radio in standby mode
230  */
231 void RadioStandby( void );
232 
233 /*!
234  * \brief Sets the radio in reception mode for the given time
235  * \param [IN] timeout Reception timeout [ms]
236  *                     [0: continuous, others timeout]
237  */
238 void RadioRx( uint32_t timeout );
239 
240 /*!
241  * \brief Start a Channel Activity Detection
242  */
243 void RadioStartCad( void );
244 
245 /*!
246  * \brief Sets the radio in continuous wave transmission mode
247  *
248  * \param [IN]: freq       Channel RF frequency
249  * \param [IN]: power      Sets the output power [dBm]
250  * \param [IN]: time       Transmission mode timeout [s]
251  */
252 void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time );
253 
254 /*!
255  * \brief Reads the current RSSI value
256  *
257  * \retval rssiValue Current RSSI value in [dBm]
258  */
259 int16_t RadioRssi( RadioModems_t modem );
260 
261 /*!
262  * \brief Writes the radio register at the specified address
263  *
264  * \param [IN]: addr Register address
265  * \param [IN]: data New register value
266  */
267 void RadioWrite( uint32_t addr, uint8_t data );
268 
269 /*!
270  * \brief Reads the radio register at the specified address
271  *
272  * \param [IN]: addr Register address
273  * \retval data Register value
274  */
275 uint8_t RadioRead( uint32_t addr );
276 
277 /*!
278  * \brief Writes multiple radio registers starting at address
279  *
280  * \param [IN] addr   First Radio register address
281  * \param [IN] buffer Buffer containing the new register's values
282  * \param [IN] size   Number of registers to be written
283  */
284 void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
285 
286 /*!
287  * \brief Reads multiple radio registers starting at address
288  *
289  * \param [IN] addr First Radio register address
290  * \param [OUT] buffer Buffer where to copy the registers data
291  * \param [IN] size Number of registers to be read
292  */
293 void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
294 
295 /*!
296  * \brief Sets the maximum payload length.
297  *
298  * \param [IN] modem      Radio modem to be used [0: FSK, 1: LoRa]
299  * \param [IN] max        Maximum payload length in bytes
300  */
301 void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max );
302 
303 /*!
304  * \brief Sets the network to public or private. Updates the sync byte.
305  *
306  * \remark Applies to LoRa modem only
307  *
308  * \param [IN] enable if true, it enables a public network
309  */
310 void RadioSetPublicNetwork( bool enable );
311 
312 /*!
313  * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
314  *
315  * \retval time Radio plus board wakeup time in ms.
316  */
317 uint32_t RadioGetWakeupTime( void );
318 
319 /*!
320  * \brief Process radio irq
321  */
322 void RadioIrqProcess( void );
323 
324 /*!
325  * \brief Sets the radio in reception mode with Max LNA gain for the given time
326  * \param [IN] timeout Reception timeout [ms]
327  *                     [0: continuous, others timeout]
328  */
329 void RadioRxBoosted( uint32_t timeout );
330 
331 /*!
332  * \brief Sets the Rx duty cycle management parameters
333  *
334  * \param [in]  rxTime        Structure describing reception timeout value
335  * \param [in]  sleepTime     Structure describing sleep timeout value
336  */
337 void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime );
338 
339 /*!
340  * \brief Add a register to the retention list
341  *
342  * \param [in] registerAddress The address of the register to be kept in retention
343  */
344 void RadioAddRegisterToRetentionList( uint16_t registerAddress );
345 
346 /*!
347  * Radio driver structure initialization
348  */
349 const struct Radio_s Radio =
350 {
351     RadioInit,
352     RadioGetStatus,
353     RadioSetModem,
354     RadioSetChannel,
355     RadioIsChannelFree,
356     RadioRandom,
357     RadioSetRxConfig,
358     RadioSetTxConfig,
359     RadioCheckRfFrequency,
360     RadioTimeOnAir,
361     RadioSend,
362     RadioSleep,
363     RadioStandby,
364     RadioRx,
365     RadioStartCad,
366     RadioSetTxContinuousWave,
367     RadioRssi,
368     RadioWrite,
369     RadioRead,
370     RadioWriteBuffer,
371     RadioReadBuffer,
372     RadioSetMaxPayloadLength,
373     RadioSetPublicNetwork,
374     RadioGetWakeupTime,
375     RadioIrqProcess,
376     // Available on SX126x only
377     RadioRxBoosted,
378     RadioSetRxDutyCycle
379 };
380 
381 /*
382  * Local types definition
383  */
384 
385 
386  /*!
387  * FSK bandwidth definition
388  */
389 typedef struct
390 {
391     uint32_t bandwidth;
392     uint8_t  RegValue;
393 }FskBandwidth_t;
394 
395 /*!
396  * Precomputed FSK bandwidth registers values
397  */
398 const FskBandwidth_t FskBandwidths[] =
399 {
400     { 4800  , 0x1F },
401     { 5800  , 0x17 },
402     { 7300  , 0x0F },
403     { 9700  , 0x1E },
404     { 11700 , 0x16 },
405     { 14600 , 0x0E },
406     { 19500 , 0x1D },
407     { 23400 , 0x15 },
408     { 29300 , 0x0D },
409     { 39000 , 0x1C },
410     { 46900 , 0x14 },
411     { 58600 , 0x0C },
412     { 78200 , 0x1B },
413     { 93800 , 0x13 },
414     { 117300, 0x0B },
415     { 156200, 0x1A },
416     { 187200, 0x12 },
417     { 234300, 0x0A },
418     { 312000, 0x19 },
419     { 373600, 0x11 },
420     { 467000, 0x09 },
421     { 500000, 0x00 }, // Invalid Bandwidth
422 };
423 
424 const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
425 
426 uint8_t MaxPayloadLength = 0xFF;
427 
428 uint32_t TxTimeout = 0;
429 uint32_t RxTimeout = 0;
430 
431 bool RxContinuous = false;
432 
433 
434 PacketStatus_t RadioPktStatus;
435 uint8_t RadioRxPayload[255];
436 
437 bool IrqFired = false;
438 
439 /*
440  * SX126x DIO IRQ callback functions prototype
441  */
442 
443 /*!
444  * \brief DIO 0 IRQ callback
445  */
446 void RadioOnDioIrq( void* context );
447 
448 /*!
449  * \brief Tx timeout timer callback
450  */
451 void RadioOnTxTimeoutIrq( void* context );
452 
453 /*!
454  * \brief Rx timeout timer callback
455  */
456 void RadioOnRxTimeoutIrq( void* context );
457 
458 /*
459  * Private global variables
460  */
461 
462 
463 /*!
464  * Holds the current network type for the radio
465  */
466 typedef struct
467 {
468     bool Previous;
469     bool Current;
470 }RadioPublicNetwork_t;
471 
472 static RadioPublicNetwork_t RadioPublicNetwork = { false };
473 
474 /*!
475  * Radio callbacks variable
476  */
477 static RadioEvents_t* RadioEvents;
478 
479 /*
480  * Public global variables
481  */
482 
483 /*!
484  * Radio hardware and global parameters
485  */
486 SX126x_t SX126x;
487 
488 /*!
489  * Tx and Rx timers
490  */
491 TimerEvent_t TxTimeoutTimer;
492 TimerEvent_t RxTimeoutTimer;
493 
494 /*!
495  * Returns the known FSK bandwidth registers value
496  *
497  * \param [IN] bandwidth Bandwidth value in Hz
498  * \retval regValue Bandwidth register value.
499  */
RadioGetFskBandwidthRegValue(uint32_t bandwidth)500 static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth )
501 {
502     uint8_t i;
503 
504     if( bandwidth == 0 )
505     {
506         return( 0x1F );
507     }
508 
509     for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ) - 1; i++ )
510     {
511         if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) )
512         {
513             return FskBandwidths[i+1].RegValue;
514         }
515     }
516     // ERROR: Value not found
517     while( 1 );
518 }
519 
RadioInit(RadioEvents_t * events)520 void RadioInit( RadioEvents_t *events )
521 {
522     RadioEvents = events;
523 
524     SX126xInit( RadioOnDioIrq );
525     SX126xSetStandby( STDBY_RC );
526     SX126xSetRegulatorMode( USE_DCDC );
527 
528     SX126xSetBufferBaseAddress( 0x00, 0x00 );
529     SX126xSetTxParams( 0, RADIO_RAMP_200_US );
530     SX126xSetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
531 
532     // Add registers to the retention list (4 is the maximum possible number)
533     RadioAddRegisterToRetentionList( REG_RX_GAIN );
534     RadioAddRegisterToRetentionList( REG_TX_MODULATION );
535 
536     // Initialize driver timeout timers
537     TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq );
538     TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq );
539 
540     IrqFired = false;
541 }
542 
RadioGetStatus(void)543 RadioState_t RadioGetStatus( void )
544 {
545     switch( SX126xGetOperatingMode( ) )
546     {
547         case MODE_TX:
548             return RF_TX_RUNNING;
549         case MODE_RX:
550             return RF_RX_RUNNING;
551         case MODE_CAD:
552             return RF_CAD;
553         default:
554             return RF_IDLE;
555     }
556 }
557 
RadioSetModem(RadioModems_t modem)558 void RadioSetModem( RadioModems_t modem )
559 {
560     switch( modem )
561     {
562     default:
563     case MODEM_FSK:
564         SX126xSetPacketType( PACKET_TYPE_GFSK );
565         // When switching to GFSK mode the LoRa SyncWord register value is reset
566         // Thus, we also reset the RadioPublicNetwork variable
567         RadioPublicNetwork.Current = false;
568         break;
569     case MODEM_LORA:
570         SX126xSetPacketType( PACKET_TYPE_LORA );
571         // Public/Private network register is reset when switching modems
572         if( RadioPublicNetwork.Current != RadioPublicNetwork.Previous )
573         {
574             RadioPublicNetwork.Current = RadioPublicNetwork.Previous;
575             RadioSetPublicNetwork( RadioPublicNetwork.Current );
576         }
577         break;
578     }
579 }
580 
RadioSetChannel(uint32_t freq)581 void RadioSetChannel( uint32_t freq )
582 {
583     SX126xSetRfFrequency( freq );
584 }
585 
RadioIsChannelFree(uint32_t freq,uint32_t rxBandwidth,int16_t rssiThresh,uint32_t maxCarrierSenseTime)586 bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime )
587 {
588     bool     status           = true;
589     int16_t  rssi             = 0;
590     uint32_t carrierSenseTime = 0;
591 
592     RadioSetModem( MODEM_FSK );
593 
594     RadioSetChannel( freq );
595 
596     // Set Rx bandwidth. Other parameters are not used.
597     RadioSetRxConfig( MODEM_FSK, rxBandwidth, 600, 0, rxBandwidth, 3, 0, false,
598                       0, false, 0, 0, false, true );
599     RadioRx( 0 );
600 
601     DelayMs( 1 );
602 
603     carrierSenseTime = TimerGetCurrentTime( );
604 
605     // Perform carrier sense for maxCarrierSenseTime
606     while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime )
607     {
608         rssi = RadioRssi( MODEM_FSK );
609 
610         if( rssi > rssiThresh )
611         {
612             status = false;
613             break;
614         }
615     }
616     RadioSleep( );
617     return status;
618 }
619 
RadioRandom(void)620 uint32_t RadioRandom( void )
621 {
622     uint32_t rnd = 0;
623 
624     /*
625      * Radio setup for random number generation
626      */
627     // Set LoRa modem ON
628     RadioSetModem( MODEM_LORA );
629 
630     // Disable LoRa modem interrupts
631     SX126xSetDioIrqParams( IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
632 
633     rnd = SX126xGetRandom( );
634 
635     return rnd;
636 }
637 
RadioSetRxConfig(RadioModems_t modem,uint32_t bandwidth,uint32_t datarate,uint8_t coderate,uint32_t bandwidthAfc,uint16_t preambleLen,uint16_t symbTimeout,bool fixLen,uint8_t payloadLen,bool crcOn,bool freqHopOn,uint8_t hopPeriod,bool iqInverted,bool rxContinuous)638 void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
639                          uint32_t datarate, uint8_t coderate,
640                          uint32_t bandwidthAfc, uint16_t preambleLen,
641                          uint16_t symbTimeout, bool fixLen,
642                          uint8_t payloadLen,
643                          bool crcOn, bool freqHopOn, uint8_t hopPeriod,
644                          bool iqInverted, bool rxContinuous )
645 {
646 
647     RxContinuous = rxContinuous;
648     if( rxContinuous == true )
649     {
650         symbTimeout = 0;
651     }
652     if( fixLen == true )
653     {
654         MaxPayloadLength = payloadLen;
655     }
656     else
657     {
658         MaxPayloadLength = 0xFF;
659     }
660 
661     switch( modem )
662     {
663         case MODEM_FSK:
664             SX126xSetStopRxTimerOnPreambleDetect( false );
665             SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK;
666 
667             SX126x.ModulationParams.Params.Gfsk.BitRate = datarate;
668             SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
669             SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth << 1 ); // SX126x badwidth is double sided
670 
671             SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK;
672             SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
673             SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS;
674             SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3; // convert byte into bit
675             SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
676             SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
677             SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
678             if( crcOn == true )
679             {
680                 SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT;
681             }
682             else
683             {
684                 SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
685             }
686             SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING;
687 
688             RadioStandby( );
689             RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
690             SX126xSetModulationParams( &SX126x.ModulationParams );
691             SX126xSetPacketParams( &SX126x.PacketParams );
692             SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
693             SX126xSetWhiteningSeed( 0x01FF );
694 
695             RxTimeout = ( uint32_t )symbTimeout * 8000UL / datarate;
696             break;
697 
698         case MODEM_LORA:
699             SX126xSetStopRxTimerOnPreambleDetect( false );
700             SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA;
701             SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate;
702             SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth];
703             SX126x.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate;
704 
705             if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
706             ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
707             {
708                 SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01;
709             }
710             else
711             {
712                 SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
713             }
714 
715             SX126x.PacketParams.PacketType = PACKET_TYPE_LORA;
716 
717             if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) ||
718                 ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) )
719             {
720                 if( preambleLen < 12 )
721                 {
722                     SX126x.PacketParams.Params.LoRa.PreambleLength = 12;
723                 }
724                 else
725                 {
726                     SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen;
727                 }
728             }
729             else
730             {
731                 SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen;
732             }
733 
734             SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen;
735 
736             SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength;
737             SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn;
738             SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted;
739 
740             RadioStandby( );
741             RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
742             SX126xSetModulationParams( &SX126x.ModulationParams );
743             SX126xSetPacketParams( &SX126x.PacketParams );
744             SX126xSetLoRaSymbNumTimeout( symbTimeout );
745 
746             // WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4
747             if( SX126x.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
748             {
749                 SX126xWriteRegister( REG_IQ_POLARITY, SX126xReadRegister( REG_IQ_POLARITY ) & ~( 1 << 2 ) );
750             }
751             else
752             {
753                 SX126xWriteRegister( REG_IQ_POLARITY, SX126xReadRegister( REG_IQ_POLARITY ) | ( 1 << 2 ) );
754             }
755             // WORKAROUND END
756 
757             // Timeout Max, Timeout handled directly in SetRx function
758             RxTimeout = 0xFFFF;
759 
760             break;
761     }
762 }
763 
RadioSetTxConfig(RadioModems_t modem,int8_t power,uint32_t fdev,uint32_t bandwidth,uint32_t datarate,uint8_t coderate,uint16_t preambleLen,bool fixLen,bool crcOn,bool freqHopOn,uint8_t hopPeriod,bool iqInverted,uint32_t timeout)764 void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
765                         uint32_t bandwidth, uint32_t datarate,
766                         uint8_t coderate, uint16_t preambleLen,
767                         bool fixLen, bool crcOn, bool freqHopOn,
768                         uint8_t hopPeriod, bool iqInverted, uint32_t timeout )
769 {
770 
771     switch( modem )
772     {
773         case MODEM_FSK:
774             SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK;
775             SX126x.ModulationParams.Params.Gfsk.BitRate = datarate;
776 
777             SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
778             SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth << 1 ); // SX126x badwidth is double sided
779             SX126x.ModulationParams.Params.Gfsk.Fdev = fdev;
780 
781             SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK;
782             SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
783             SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS;
784             SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3 ; // convert byte into bit
785             SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
786             SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
787 
788             if( crcOn == true )
789             {
790                 SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT;
791             }
792             else
793             {
794                 SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
795             }
796             SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING;
797 
798             RadioStandby( );
799             RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
800             SX126xSetModulationParams( &SX126x.ModulationParams );
801             SX126xSetPacketParams( &SX126x.PacketParams );
802             SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
803             SX126xSetWhiteningSeed( 0x01FF );
804             break;
805 
806         case MODEM_LORA:
807             SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA;
808             SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) datarate;
809             SX126x.ModulationParams.Params.LoRa.Bandwidth =  Bandwidths[bandwidth];
810             SX126x.ModulationParams.Params.LoRa.CodingRate= ( RadioLoRaCodingRates_t )coderate;
811 
812             if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
813             ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
814             {
815                 SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01;
816             }
817             else
818             {
819                 SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
820             }
821 
822             SX126x.PacketParams.PacketType = PACKET_TYPE_LORA;
823 
824             if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) ||
825                 ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) )
826             {
827                 if( preambleLen < 12 )
828                 {
829                     SX126x.PacketParams.Params.LoRa.PreambleLength = 12;
830                 }
831                 else
832                 {
833                     SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen;
834                 }
835             }
836             else
837             {
838                 SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen;
839             }
840 
841             SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen;
842             SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength;
843             SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn;
844             SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted;
845 
846             RadioStandby( );
847             RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
848             SX126xSetModulationParams( &SX126x.ModulationParams );
849             SX126xSetPacketParams( &SX126x.PacketParams );
850             break;
851     }
852 
853     // WORKAROUND - Modulation Quality with 500 kHz LoRa Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1
854     if( ( modem == MODEM_LORA ) && ( SX126x.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 ) )
855     {
856         SX126xWriteRegister( REG_TX_MODULATION, SX126xReadRegister( REG_TX_MODULATION ) & ~( 1 << 2 ) );
857     }
858     else
859     {
860         SX126xWriteRegister( REG_TX_MODULATION, SX126xReadRegister( REG_TX_MODULATION ) | ( 1 << 2 ) );
861     }
862     // WORKAROUND END
863 
864     SX126xSetRfTxPower( power );
865     TxTimeout = timeout;
866 }
867 
RadioCheckRfFrequency(uint32_t frequency)868 bool RadioCheckRfFrequency( uint32_t frequency )
869 {
870     return true;
871 }
872 
RadioGetLoRaBandwidthInHz(RadioLoRaBandwidths_t bw)873 static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw )
874 {
875     uint32_t bandwidthInHz = 0;
876 
877     switch( bw )
878     {
879     case LORA_BW_007:
880         bandwidthInHz = 7812UL;
881         break;
882     case LORA_BW_010:
883         bandwidthInHz = 10417UL;
884         break;
885     case LORA_BW_015:
886         bandwidthInHz = 15625UL;
887         break;
888     case LORA_BW_020:
889         bandwidthInHz = 20833UL;
890         break;
891     case LORA_BW_031:
892         bandwidthInHz = 31250UL;
893         break;
894     case LORA_BW_041:
895         bandwidthInHz = 41667UL;
896         break;
897     case LORA_BW_062:
898         bandwidthInHz = 62500UL;
899         break;
900     case LORA_BW_125:
901         bandwidthInHz = 125000UL;
902         break;
903     case LORA_BW_250:
904         bandwidthInHz = 250000UL;
905         break;
906     case LORA_BW_500:
907         bandwidthInHz = 500000UL;
908         break;
909     }
910 
911     return bandwidthInHz;
912 }
913 
RadioGetGfskTimeOnAirNumerator(uint32_t datarate,uint8_t coderate,uint16_t preambleLen,bool fixLen,uint8_t payloadLen,bool crcOn)914 static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
915                               uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
916                               bool crcOn )
917 {
918     const RadioAddressComp_t addrComp = RADIO_ADDRESSCOMP_FILT_OFF;
919     const uint8_t syncWordLength = 3;
920 
921     return ( preambleLen << 3 ) +
922            ( ( fixLen == false ) ? 8 : 0 ) +
923              ( syncWordLength << 3 ) +
924              ( ( payloadLen +
925                ( addrComp == RADIO_ADDRESSCOMP_FILT_OFF ? 0 : 1 ) +
926                ( ( crcOn == true ) ? 2 : 0 )
927                ) << 3
928              );
929 }
930 
RadioGetLoRaTimeOnAirNumerator(uint32_t bandwidth,uint32_t datarate,uint8_t coderate,uint16_t preambleLen,bool fixLen,uint8_t payloadLen,bool crcOn)931 static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
932                               uint32_t datarate, uint8_t coderate,
933                               uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
934                               bool crcOn )
935 {
936     int32_t crDenom           = coderate + 4;
937     bool    lowDatareOptimize = false;
938 
939     // Ensure that the preamble length is at least 12 symbols when using SF5 or
940     // SF6
941     if( ( datarate == 5 ) || ( datarate == 6 ) )
942     {
943         if( preambleLen < 12 )
944         {
945             preambleLen = 12;
946         }
947     }
948 
949     if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
950         ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
951     {
952         lowDatareOptimize = true;
953     }
954 
955     int32_t ceilDenominator;
956     int32_t ceilNumerator = ( payloadLen << 3 ) +
957                             ( crcOn ? 16 : 0 ) -
958                             ( 4 * datarate ) +
959                             ( fixLen ? 0 : 20 );
960 
961     if( datarate <= 6 )
962     {
963         ceilDenominator = 4 * datarate;
964     }
965     else
966     {
967         ceilNumerator += 8;
968 
969         if( lowDatareOptimize == true )
970         {
971             ceilDenominator = 4 * ( datarate - 2 );
972         }
973         else
974         {
975             ceilDenominator = 4 * datarate;
976         }
977     }
978 
979     if( ceilNumerator < 0 )
980     {
981         ceilNumerator = 0;
982     }
983 
984     // Perform integral ceil()
985     int32_t intermediate =
986         ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
987 
988     if( datarate <= 6 )
989     {
990         intermediate += 2;
991     }
992 
993     return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
994 }
995 
RadioTimeOnAir(RadioModems_t modem,uint32_t bandwidth,uint32_t datarate,uint8_t coderate,uint16_t preambleLen,bool fixLen,uint8_t payloadLen,bool crcOn)996 uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
997                               uint32_t datarate, uint8_t coderate,
998                               uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
999                               bool crcOn )
1000 {
1001     uint32_t numerator = 0;
1002     uint32_t denominator = 1;
1003 
1004     switch( modem )
1005     {
1006     case MODEM_FSK:
1007         {
1008             numerator   = 1000U * RadioGetGfskTimeOnAirNumerator( datarate, coderate,
1009                                                                   preambleLen, fixLen,
1010                                                                   payloadLen, crcOn );
1011             denominator = datarate;
1012         }
1013         break;
1014     case MODEM_LORA:
1015         {
1016             numerator   = 1000U * RadioGetLoRaTimeOnAirNumerator( bandwidth, datarate,
1017                                                                   coderate, preambleLen,
1018                                                                   fixLen, payloadLen, crcOn );
1019             denominator = RadioGetLoRaBandwidthInHz( Bandwidths[bandwidth] );
1020         }
1021         break;
1022     }
1023     // Perform integral ceil()
1024     return ( numerator + denominator - 1 ) / denominator;
1025 }
1026 
RadioSend(uint8_t * buffer,uint8_t size)1027 void RadioSend( uint8_t *buffer, uint8_t size )
1028 {
1029     SX126xSetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
1030                            IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
1031                            IRQ_RADIO_NONE,
1032                            IRQ_RADIO_NONE );
1033 
1034     if( SX126xGetPacketType( ) == PACKET_TYPE_LORA )
1035     {
1036         SX126x.PacketParams.Params.LoRa.PayloadLength = size;
1037     }
1038     else
1039     {
1040         SX126x.PacketParams.Params.Gfsk.PayloadLength = size;
1041     }
1042     SX126xSetPacketParams( &SX126x.PacketParams );
1043 
1044     SX126xSendPayload( buffer, size, 0 );
1045     TimerSetValue( &TxTimeoutTimer, TxTimeout );
1046     TimerStart( &TxTimeoutTimer );
1047 }
1048 
RadioSleep(void)1049 void RadioSleep( void )
1050 {
1051     SleepParams_t params = { 0 };
1052 
1053     params.Fields.WarmStart = 1;
1054     SX126xSetSleep( params );
1055 
1056     DelayMs( 2 );
1057 }
1058 
RadioStandby(void)1059 void RadioStandby( void )
1060 {
1061     SX126xSetStandby( STDBY_RC );
1062 }
1063 
RadioRx(uint32_t timeout)1064 void RadioRx( uint32_t timeout )
1065 {
1066     SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
1067                            IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
1068                            IRQ_RADIO_NONE,
1069                            IRQ_RADIO_NONE );
1070 
1071     if( timeout != 0 )
1072     {
1073         TimerSetValue( &RxTimeoutTimer, timeout );
1074         TimerStart( &RxTimeoutTimer );
1075     }
1076 
1077     if( RxContinuous == true )
1078     {
1079         SX126xSetRx( 0xFFFFFF ); // Rx Continuous
1080     }
1081     else
1082     {
1083         SX126xSetRx( RxTimeout << 6 );
1084     }
1085 }
1086 
RadioRxBoosted(uint32_t timeout)1087 void RadioRxBoosted( uint32_t timeout )
1088 {
1089     SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
1090                            IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
1091                            IRQ_RADIO_NONE,
1092                            IRQ_RADIO_NONE );
1093 
1094     if( timeout != 0 )
1095     {
1096         TimerSetValue( &RxTimeoutTimer, timeout );
1097         TimerStart( &RxTimeoutTimer );
1098     }
1099 
1100     if( RxContinuous == true )
1101     {
1102         SX126xSetRxBoosted( 0xFFFFFF ); // Rx Continuous
1103     }
1104     else
1105     {
1106         SX126xSetRxBoosted( RxTimeout << 6 );
1107     }
1108 }
1109 
RadioSetRxDutyCycle(uint32_t rxTime,uint32_t sleepTime)1110 void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime )
1111 {
1112     SX126xSetRxDutyCycle( rxTime, sleepTime );
1113 }
1114 
RadioAddRegisterToRetentionList(uint16_t registerAddress)1115 void RadioAddRegisterToRetentionList( uint16_t registerAddress )
1116 {
1117     uint8_t buffer[9];
1118 
1119     // Read the address and registers already added to the list
1120     SX126xReadRegisters( REG_RETENTION_LIST_BASE_ADDRESS, buffer, 9 );
1121 
1122     const uint8_t nbOfRegisters = buffer[0];
1123     uint8_t* registerList   = &buffer[1];
1124 
1125     // Check if the register given as parameter is already added to the list
1126     for( uint8_t i = 0; i < nbOfRegisters; i++ )
1127     {
1128         if( registerAddress == ( ( uint16_t ) registerList[2 * i] << 8 ) + registerList[2 * i + 1] )
1129         {
1130             return;
1131         }
1132     }
1133 
1134     if( nbOfRegisters < MAX_NB_REG_IN_RETENTION )
1135     {
1136         buffer[0] += 1;
1137         registerList[2 * nbOfRegisters]     = ( uint8_t )( registerAddress >> 8 );
1138         registerList[2 * nbOfRegisters + 1] = ( uint8_t )( registerAddress >> 0 );
1139 
1140         // Update radio with modified list
1141         SX126xWriteRegisters( REG_RETENTION_LIST_BASE_ADDRESS, buffer, 9 );
1142     }
1143 }
1144 
RadioStartCad(void)1145 void RadioStartCad( void )
1146 {
1147     SX126xSetDioIrqParams( IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
1148     SX126xSetCad( );
1149 }
1150 
RadioSetTxContinuousWave(uint32_t freq,int8_t power,uint16_t time)1151 void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
1152 {
1153     uint32_t timeout = ( uint32_t )time * 1000;
1154 
1155     SX126xSetRfFrequency( freq );
1156     SX126xSetRfTxPower( power );
1157     SX126xSetTxContinuousWave( );
1158 
1159     TimerSetValue( &TxTimeoutTimer, timeout );
1160     TimerStart( &TxTimeoutTimer );
1161 }
1162 
RadioRssi(RadioModems_t modem)1163 int16_t RadioRssi( RadioModems_t modem )
1164 {
1165     return SX126xGetRssiInst( );
1166 }
1167 
RadioWrite(uint32_t addr,uint8_t data)1168 void RadioWrite( uint32_t addr, uint8_t data )
1169 {
1170     SX126xWriteRegister( addr, data );
1171 }
1172 
RadioRead(uint32_t addr)1173 uint8_t RadioRead( uint32_t addr )
1174 {
1175     return SX126xReadRegister( addr );
1176 }
1177 
RadioWriteBuffer(uint32_t addr,uint8_t * buffer,uint8_t size)1178 void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
1179 {
1180     SX126xWriteRegisters( addr, buffer, size );
1181 }
1182 
RadioReadBuffer(uint32_t addr,uint8_t * buffer,uint8_t size)1183 void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
1184 {
1185     SX126xReadRegisters( addr, buffer, size );
1186 }
1187 
RadioSetMaxPayloadLength(RadioModems_t modem,uint8_t max)1188 void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max )
1189 {
1190     if( modem == MODEM_LORA )
1191     {
1192         SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength = max;
1193         SX126xSetPacketParams( &SX126x.PacketParams );
1194     }
1195     else
1196     {
1197         if( SX126x.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_VARIABLE_LENGTH )
1198         {
1199             SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength = max;
1200             SX126xSetPacketParams( &SX126x.PacketParams );
1201         }
1202     }
1203 }
1204 
RadioSetPublicNetwork(bool enable)1205 void RadioSetPublicNetwork( bool enable )
1206 {
1207     RadioPublicNetwork.Current = RadioPublicNetwork.Previous = enable;
1208 
1209     RadioSetModem( MODEM_LORA );
1210     if( enable == true )
1211     {
1212         // Change LoRa modem SyncWord
1213         SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PUBLIC_SYNCWORD >> 8 ) & 0xFF );
1214         SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PUBLIC_SYNCWORD & 0xFF );
1215     }
1216     else
1217     {
1218         // Change LoRa modem SyncWord
1219         SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF );
1220         SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF );
1221     }
1222 }
1223 
RadioGetWakeupTime(void)1224 uint32_t RadioGetWakeupTime( void )
1225 {
1226     return SX126xGetBoardTcxoWakeupTime( ) + RADIO_WAKEUP_TIME;
1227 }
1228 
RadioOnTxTimeoutIrq(void * context)1229 void RadioOnTxTimeoutIrq( void* context )
1230 {
1231     if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
1232     {
1233         RadioEvents->TxTimeout( );
1234     }
1235 }
1236 
RadioOnRxTimeoutIrq(void * context)1237 void RadioOnRxTimeoutIrq( void* context )
1238 {
1239     if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
1240     {
1241         RadioEvents->RxTimeout( );
1242     }
1243 }
1244 
RadioOnDioIrq(void * context)1245 void RadioOnDioIrq( void* context )
1246 {
1247     IrqFired = true;
1248 }
1249 
RadioIrqProcess(void)1250 void RadioIrqProcess( void )
1251 {
1252     CRITICAL_SECTION_BEGIN( );
1253     // Clear IRQ flag
1254     const bool isIrqFired = IrqFired;
1255     IrqFired = false;
1256     CRITICAL_SECTION_END( );
1257 
1258     if( isIrqFired == true )
1259     {
1260         uint16_t irqRegs = SX126xGetIrqStatus( );
1261         SX126xClearIrqStatus( irqRegs );
1262 
1263         // Check if DIO1 pin is High. If it is the case revert IrqFired to true
1264         CRITICAL_SECTION_BEGIN_REPEAT( );
1265         if( SX126xGetDio1PinState( ) == 1 )
1266         {
1267             IrqFired = true;
1268         }
1269         CRITICAL_SECTION_END( );
1270 
1271         if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE )
1272         {
1273             TimerStop( &TxTimeoutTimer );
1274             //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1275             SX126xSetOperatingMode( MODE_STDBY_RC );
1276             if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) )
1277             {
1278                 RadioEvents->TxDone( );
1279             }
1280         }
1281 
1282         if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE )
1283         {
1284             TimerStop( &RxTimeoutTimer );
1285 
1286             if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR )
1287             {
1288                 if( RxContinuous == false )
1289                 {
1290                     //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1291                     SX126xSetOperatingMode( MODE_STDBY_RC );
1292                 }
1293                 if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) )
1294                 {
1295                     RadioEvents->RxError( );
1296                 }
1297             }
1298             else
1299             {
1300                 uint8_t size;
1301 
1302                 if( RxContinuous == false )
1303                 {
1304                     //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1305                     SX126xSetOperatingMode( MODE_STDBY_RC );
1306 
1307                     // WORKAROUND - Implicit Header Mode Timeout Behavior, see DS_SX1261-2_V1.2 datasheet chapter 15.3
1308                     SX126xWriteRegister( REG_RTC_CTRL, 0x00 );
1309                     SX126xWriteRegister( REG_EVT_CLR, SX126xReadRegister( REG_EVT_CLR ) | ( 1 << 1 ) );
1310                     // WORKAROUND END
1311                 }
1312                 SX126xGetPayload( RadioRxPayload, &size , 255 );
1313                 SX126xGetPacketStatus( &RadioPktStatus );
1314                 if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
1315                 {
1316                     RadioEvents->RxDone( RadioRxPayload, size, RadioPktStatus.Params.LoRa.RssiPkt, RadioPktStatus.Params.LoRa.SnrPkt );
1317                 }
1318             }
1319         }
1320 
1321         if( ( irqRegs & IRQ_CAD_DONE ) == IRQ_CAD_DONE )
1322         {
1323             //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1324             SX126xSetOperatingMode( MODE_STDBY_RC );
1325             if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
1326             {
1327                 RadioEvents->CadDone( ( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ) );
1328             }
1329         }
1330 
1331         if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT )
1332         {
1333             if( SX126xGetOperatingMode( ) == MODE_TX )
1334             {
1335                 TimerStop( &TxTimeoutTimer );
1336                 //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1337                 SX126xSetOperatingMode( MODE_STDBY_RC );
1338                 if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
1339                 {
1340                     RadioEvents->TxTimeout( );
1341                 }
1342             }
1343             else if( SX126xGetOperatingMode( ) == MODE_RX )
1344             {
1345                 TimerStop( &RxTimeoutTimer );
1346                 //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1347                 SX126xSetOperatingMode( MODE_STDBY_RC );
1348                 if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
1349                 {
1350                     RadioEvents->RxTimeout( );
1351                 }
1352             }
1353         }
1354 
1355         if( ( irqRegs & IRQ_PREAMBLE_DETECTED ) == IRQ_PREAMBLE_DETECTED )
1356         {
1357             //__NOP( );
1358         }
1359 
1360         if( ( irqRegs & IRQ_SYNCWORD_VALID ) == IRQ_SYNCWORD_VALID )
1361         {
1362             //__NOP( );
1363         }
1364 
1365         if( ( irqRegs & IRQ_HEADER_VALID ) == IRQ_HEADER_VALID )
1366         {
1367             //__NOP( );
1368         }
1369 
1370         if( ( irqRegs & IRQ_HEADER_ERROR ) == IRQ_HEADER_ERROR )
1371         {
1372             TimerStop( &RxTimeoutTimer );
1373             if( RxContinuous == false )
1374             {
1375                 //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
1376                 SX126xSetOperatingMode( MODE_STDBY_RC );
1377             }
1378             if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
1379             {
1380                 RadioEvents->RxTimeout( );
1381             }
1382         }
1383     }
1384 }
1385