-
Notifications
You must be signed in to change notification settings - Fork 79
Expand file tree
/
Copy pathradio.c
More file actions
2416 lines (2171 loc) · 87.5 KB
/
radio.c
File metadata and controls
2416 lines (2171 loc) · 87.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*!
* \file radio.c
*
* \brief Radio driver API implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file radio.c
* @author MCD Application Team
* @brief Radio driver API definition
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include "radio.h"
#include "wl_lr_fhss.h"
#include "timer.h"
#include "radio_fw.h"
#include "radio_driver.h"
#include "radio_conf.h"
#include "mw_log_conf.h"
/* Private typedef -----------------------------------------------------------*/
/*!
* Radio hardware and global parameters
*/
typedef struct SubgRf_s
{
RadioModems_t Modem;
bool RxContinuous;
uint32_t TxTimeout;
uint32_t RxTimeout;
struct
{
bool Previous;
bool Current;
} PublicNetwork;
PacketParams_t PacketParams;
PacketStatus_t PacketStatus;
ModulationParams_t ModulationParams;
RadioIrqMasks_t RadioIrq;
uint8_t AntSwitchPaSelect;
uint32_t RxDcPreambleDetectTimeout; /* 0:RxDutyCycle is off, otherwise on with 2*rxTime + sleepTime (See STM32WL Errata: RadioSetRxDutyCycle)*/
#if( RADIO_LR_FHSS_IS_ON == 1 )
struct
{
uint32_t rf_freq_in_hz;
int8_t tx_rf_pwr_in_dbm;
bool is_lr_fhss_on;
uint16_t hop_sequence_id;
wl_lr_fhss_params_t lr_fhss_params;
wl_lr_fhss_state_t lr_fhss_state;
} lr_fhss;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
} SubgRf_t;
/* Private macro -------------------------------------------------------------*/
#define RADIO_BIT_MASK(__n) (~(1<<__n))
/**
* \brief Calculates ceiling division of ( X / N )
*
* \param [in] X numerator
* \param [in] N denominator
*
*/
#ifndef DIVC
#define DIVC( X, N ) ( ( ( X ) + ( N ) - 1 ) / ( N ) )
#endif
/**
* \brief Calculates rounding division of ( X / N )
*
* \param [in] X numerator
* \param [in] N denominator
*
*/
#ifndef DIVR
#define DIVR( X, N ) ( ( ( X ) + ( ((X)>0?(N):(N))>>1 ) ) / ( N ) )
#endif
/* Private define ------------------------------------------------------------*/
/* */
/*can be overridden in radio_conf.h*/
#ifndef RADIO_LR_FHSS_IS_ON
#define RADIO_LR_FHSS_IS_ON 0
#endif /* !RADIO_LR_FHSS_IS_ON */
/*can be overridden in radio_conf.h*/
#ifndef XTAL_FREQ
#define XTAL_FREQ 32000000UL
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_IRQ_PROCESS_INIT
#define RADIO_IRQ_PROCESS_INIT()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_IRQ_PROCESS
#define RADIO_IRQ_PROCESS() RadioIrqProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_RX_TIMEOUT_PROCESS
#define RADIO_RX_TIMEOUT_PROCESS() RadioOnRxTimeoutProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_TX_TIMEOUT_PROCESS
#define RADIO_TX_TIMEOUT_PROCESS() RadioOnTxTimeoutProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef IRQ_TX_DBG
#define IRQ_TX_DBG ((uint16_t) 0)
#endif
/*can be overridden in radio_conf.h*/
#ifndef IRQ_RX_DBG
#define IRQ_RX_DBG ((uint16_t) 0)
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_SIGFOX_ENABLE
#define RADIO_SIGFOX_ENABLE 1
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_GENERIC_CONFIG_ENABLE
#define RADIO_GENERIC_CONFIG_ENABLE 1
#endif
/*can be overridden in radio_conf.h*/
#ifndef DBG_GPIO_RADIO_RX
#define DBG_GPIO_RADIO_RX(set_rst)
#endif
/*can be overridden in radio_conf.h*/
#ifndef DBG_GPIO_RADIO_TX
#define DBG_GPIO_RADIO_TX(set_rst)
#endif
#define RADIO_BUF_SIZE 255
/* Private function prototypes -----------------------------------------------*/
/*!
* \brief Initializes the radio
*
* \param [in] events Structure containing the driver callback functions
*/
static void RadioInit( RadioEvents_t *events );
/*!
* Return current radio status
*
* \return status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
static RadioState_t RadioGetStatus( void );
/*!
* \brief Configures the radio with the given modem
*
* \param [in] modem Modem to be used [0: FSK, 1: LoRa]
*/
static void RadioSetModem( RadioModems_t modem );
/*!
* \brief Sets the channel frequency
*
* \param [in] freq Channel RF frequency
*/
static void RadioSetChannel( uint32_t freq );
/*!
* \brief Checks if the channel is free for the given time
*
* \remark The FSK modem is always used for this task as we can select the Rx bandwidth at will.
*
* \param [in] freq Channel RF frequency in Hertz
* \param [in] rxBandwidth Rx bandwidth in Hertz
* \param [in] rssiThresh RSSI threshold in dBm
* \param [in] maxCarrierSenseTime Max time in milliseconds while the RSSI is measured
*
* \retval isFree [true: Channel is free, false: Channel is not free]
*/
static bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \brief Generates a 32 bits random value based on the RSSI readings
*
* \remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \retval randomValue 32 bits random value
*/
static uint32_t RadioRandom( void );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \param [in] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
static void 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 );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] power Sets the output power [dBm]
* \param [in] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \param [in] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \param [in] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] timeout Transmission timeout [ms]
*/
static void 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 );
/*!
* \brief Checks if the given RF frequency is supported by the hardware
*
* \param [in] frequency RF frequency to be checked
* \retval isSupported [true: supported, false: unsupported]
*/
static bool RadioCheckRfFrequency( uint32_t frequency );
/*!
* \brief Computes the packet time on air in ms for the given payload
*
* \remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
static uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \param [in] buffer Buffer pointer
* \param [in] size Buffer size
*
* \retval status (OK, ERROR, ...)
*/
static radio_status_t RadioSend( uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the radio in sleep mode
*/
static void RadioSleep( void );
/*!
* \brief Sets the radio in standby mode
*/
static void RadioStandby( void );
/*!
* \brief Sets the radio in reception mode for the given time
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
static void RadioRx( uint32_t timeout );
/*!
* \brief Start a Channel Activity Detection
*/
static void RadioStartCad( void );
/*!
* \brief Sets the radio in continuous wave transmission mode
*
* \param [in] freq Channel RF frequency
* \param [in] power Sets the output power [dBm]
* \param [in] time Transmission mode timeout [s]
*/
static void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time );
/*!
* \brief Reads the current RSSI value
*
* \retval rssiValue Current RSSI value in [dBm]
*/
static int16_t RadioRssi( RadioModems_t modem );
/*!
* \brief Writes the radio register at the specified address
*
* \param [in] addr Register address
* \param [in] data New register value
*/
static void RadioWrite( uint16_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [in] addr Register address
* \retval data Register value
*/
static uint8_t RadioRead( uint16_t addr );
/*!
* \brief Writes multiple radio registers starting at address
*
* \param [in] addr First Radio register address
* \param [in] buffer Buffer containing the new register's values
* \param [in] size Number of registers to be written
*/
static void RadioWriteRegisters( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
* \param [in] addr First Radio register address
* \param [out] buffer Buffer where to copy the registers data
* \param [in] size Number of registers to be read
*/
static void RadioReadRegisters( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] max Maximum payload length in bytes
*/
static void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max );
/*!
* \brief Sets the network to public or private. Updates the sync byte.
*
* \remark Applies to LoRa modem only
*
* \param [in] enable if true, it enables a public network
*/
static void RadioSetPublicNetwork( bool enable );
/*!
* \brief Gets the time required for the board plus radio to get out of sleep.[ms]
*
* \retval time Radio plus board wakeup time in ms.
*/
static uint32_t RadioGetWakeupTime( void );
/*!
* \brief Process radio irq
*/
static void RadioIrqProcess( void );
/*!
* \brief Sets the radio in reception mode with Max LNA gain for the given time
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
static void RadioRxBoosted( uint32_t timeout );
/*!
* \brief Sets the Rx duty cycle management parameters
*
* \param [in] rxTime Structure describing reception timeout value
* \param [in] sleepTime Structure describing sleep timeout value
*/
static void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime );
/*!
* \brief radio IRQ callback
*
* \param [in] radioIrq mask of radio irq
*/
static void RadioOnDioIrq( RadioIrqMasks_t radioIrq );
/*!
* \brief Tx timeout timer callback
*
* \param [in] context context of the interrupt
*/
static void RadioOnTxTimeoutIrq( void *context );
/*!
* \brief Rx timeout timer callback
*
* \param [in] context context of the interrupt
*/
static void RadioOnRxTimeoutIrq( void *context );
/*!
* \brief Rx timeout timer process
*/
static void RadioOnRxTimeoutProcess( void );
/*!
* \brief Tx timeout timer process
*/
static void RadioOnTxTimeoutProcess( void );
#if( RADIO_LR_FHSS_IS_ON == 1 )
static uint32_t prbs31_val = 0xAA;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
#if (RADIO_SIGFOX_ENABLE == 1)
/*!
* @brief D-BPSK to BPSK
*
* @param [out] outBuffer buffer with frame encoded
* @param [in] inBuffer buffer with frame to encode
* @param [in] size size of the payload to encode
*/
static void payload_integration( uint8_t *outBuffer, uint8_t *inBuffer, uint8_t size );
#endif /*RADIO_SIGFOX_ENABLE == 1*/
/*!
* \brief Sets the Transmitter in continuous PRBS mode
*/
static void RadioTxPrbs( void );
/*!
* \brief Sets the Transmitter in continuous un-modulated Carrier mode at power dBm
*
* \param [in] power Tx power in dBm
*/
static void RadioTxCw( int8_t power );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
* \param [in] rxContinuous Sets the reception in continuous mode
* [0: single mode, otherwise continuous mode]
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \return 0 when no parameters error, -1 otherwise
*/
static int32_t RadioSetRxGenericConfig( GenericModems_t modem, RxConfigGeneric_t *config,
uint32_t rxContinuous, uint32_t symbTimeout );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK or GENERIC_BPSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
bpsk field to be used if modem =GENERIC_BPSK
* \param [in] power Sets the output power [dBm]
* \param [in] timeout Transmission timeout [ms]
* \return 0 when no parameters error, -1 otherwise
*/
static int32_t RadioSetTxGenericConfig( GenericModems_t modem, TxConfigGeneric_t *config,
int8_t power, uint32_t timeout );
/*!
* \brief Configure the radio LR-FHSS modem parameters
*
* \param [in] cfg_params LR-FHSS modem configuration parameters
*
* \returns Operation status
*/
static radio_status_t RadioLrFhssSetCfg( const radio_lr_fhss_cfg_params_t *cfg_params );
/*!
* \brief Get the time on air in millisecond for LR-FHSS packet
*
* \param [in] params Pointer to LR-FHSS time on air parameters
* \param [out] time_on_air_in_ms time on air parameters results in ms
*
* \returns Time-on-air value in ms for LR-FHSS packet
*/
static radio_status_t RadioLrFhssGetTimeOnAirInMs( const radio_lr_fhss_time_on_air_params_t *params, uint32_t *time_on_air_in_ms );
/*!
* \brief Convert the bandwidth enum to Hz value
*
* \param [in] bw RF frequency to be checked
* \retval bandwidthInHz bandwidth value in Hertz
*/
static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw );
/*!
* \brief Computes the time on air GFSK numerator
*
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \retval numerator time on air GFSK numerator
*/
static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
/*!
* \brief Computes the time on air LoRa numerator
*
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \retval numerator time on air LoRa numerator
*/
static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
#if( RADIO_LR_FHSS_IS_ON == 1 )
static uint32_t GetNextFreqIdx( uint32_t max );
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
/* Private variables ---------------------------------------------------------*/
/*!
* Radio driver structure initialization
*/
const struct Radio_s Radio =
{
RadioInit,
RadioGetStatus,
RadioSetModem,
RadioSetChannel,
RadioIsChannelFree,
RadioRandom,
RadioSetRxConfig,
RadioSetTxConfig,
RadioCheckRfFrequency,
RadioTimeOnAir,
RadioSend,
RadioSleep,
RadioStandby,
RadioRx,
RadioStartCad,
RadioSetTxContinuousWave,
RadioRssi,
RadioWrite,
RadioRead,
RadioWriteRegisters,
RadioReadRegisters,
RadioSetMaxPayloadLength,
RadioSetPublicNetwork,
RadioGetWakeupTime,
RadioIrqProcess,
RadioRxBoosted,
RadioSetRxDutyCycle,
RadioTxPrbs,
RadioTxCw,
RadioSetRxGenericConfig,
RadioSetTxGenericConfig,
RFW_TransmitLongPacket,
RFW_ReceiveLongPacket,
/* LrFhss extended radio functions */
RadioLrFhssSetCfg,
RadioLrFhssGetTimeOnAirInMs
};
const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
static uint8_t MaxPayloadLength = RADIO_BUF_SIZE;
static uint8_t RadioBuffer[RADIO_BUF_SIZE];
/*
* Radio callbacks variable
*/
static RadioEvents_t *RadioEvents;
/*!
* Radio hardware and global parameters
*/
SubgRf_t SubgRf;
/*!
* Tx and Rx timers
*/
TimerEvent_t TxTimeoutTimer;
TimerEvent_t RxTimeoutTimer;
/* Private functions ---------------------------------------------------------*/
static void RadioInit( RadioEvents_t *events )
{
RadioEvents = events;
SubgRf.RxContinuous = false;
SubgRf.TxTimeout = 0;
SubgRf.RxTimeout = 0;
/*See STM32WL Errata: RadioSetRxDutyCycle*/
SubgRf.RxDcPreambleDetectTimeout = 0;
#if( RADIO_LR_FHSS_IS_ON == 1 )
SubgRf.lr_fhss.is_lr_fhss_on = false;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
SUBGRF_Init( RadioOnDioIrq );
/*SubgRf.publicNetwork set to false*/
SubgRf.PublicNetwork.Current = false;
SubgRf.PublicNetwork.Previous = false;
RADIO_IRQ_PROCESS_INIT();
SUBGRF_SetRegulatorMode( );
SUBGRF_SetBufferBaseAddress( 0x00, 0x00 );
SUBGRF_SetTxParams( RFO_LP, 0, RADIO_RAMP_200_US );
SUBGRF_SetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
RadioSleep();
// Initialize driver timeout timers
TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq );
TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq );
TimerStop( &TxTimeoutTimer );
TimerStop( &RxTimeoutTimer );
}
static RadioState_t RadioGetStatus( void )
{
switch( SUBGRF_GetOperatingMode( ) )
{
case MODE_TX:
return RF_TX_RUNNING;
case MODE_RX:
return RF_RX_RUNNING;
case MODE_CAD:
return RF_CAD;
default:
return RF_IDLE;
}
}
static void RadioSetModem( RadioModems_t modem )
{
SubgRf.Modem = modem;
RFW_SetRadioModem( modem );
switch( modem )
{
default:
case MODEM_MSK:
SUBGRF_SetPacketType( PACKET_TYPE_GMSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_FSK:
SUBGRF_SetPacketType( PACKET_TYPE_GFSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_LORA:
SUBGRF_SetPacketType( PACKET_TYPE_LORA );
// Public/Private network register is reset when switching modems
if( SubgRf.PublicNetwork.Current != SubgRf.PublicNetwork.Previous )
{
SubgRf.PublicNetwork.Current = SubgRf.PublicNetwork.Previous;
RadioSetPublicNetwork( SubgRf.PublicNetwork.Current );
}
break;
case MODEM_BPSK:
SUBGRF_SetPacketType( PACKET_TYPE_BPSK );
// When switching to BPSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_TX:
SUBGRF_SetPacketType( PACKET_TYPE_BPSK );
// When switching to BPSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_SIGFOX_RX:
SUBGRF_SetPacketType( PACKET_TYPE_GFSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
#endif /*RADIO_SIGFOX_ENABLE == 1*/
}
}
static void RadioSetChannel( uint32_t freq )
{
SUBGRF_SetRfFrequency( freq );
}
static bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime )
{
bool status = true;
int16_t rssi = 0;
uint32_t carrierSenseTime = 0;
RadioStandby( );
RadioSetModem( MODEM_FSK );
RadioSetChannel( freq );
// Set Rx bandwidth. Other parameters are not used.
RadioSetRxConfig( MODEM_FSK, rxBandwidth, 600, 0, rxBandwidth, 3, 0, false,
0, false, 0, 0, false, true );
RadioRx( 0 );
RADIO_DELAY_MS( RadioGetWakeupTime( ) );
carrierSenseTime = TimerGetCurrentTime( );
// Perform carrier sense for maxCarrierSenseTime
while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime )
{
rssi = RadioRssi( MODEM_FSK );
if( rssi > rssiThresh )
{
status = false;
break;
}
}
RadioStandby( );
return status;
}
static uint32_t RadioRandom( void )
{
uint32_t rnd = 0;
/*
* Radio setup for random number generation
*/
// Disable modem interrupts
SUBGRF_SetDioIrqParams( IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
rnd = SUBGRF_GetRandom();
return rnd;
}
static void 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 )
{
#if (RADIO_SIGFOX_ENABLE == 1)
uint8_t modReg;
#endif
//Disabled, too much influence on RX timing
/*
MW_LOG( TS_ON, VLEVEL_M,
"Setting RX Config: modem=%s, bandwidth=%u, datarate=%u, coderate=%u bandwithAfc=%u, preambleLen=%u, symbTimeout=%u, fixLen=%u, payloadLen=%u, crcOn=%u, freqHopOn=%u, hopPeriod=%u, iqInverted=%u, rxContinuous=%u\r\n",
modem == MODEM_FSK ? "MODEM_FSK" : (modem == MODEM_LORA ? "MODEM_LORA" : "?"),
(unsigned)bandwidth, (unsigned)datarate, (unsigned)coderate,
(unsigned)bandwidthAfc, (unsigned)preambleLen,
(unsigned)symbTimeout, (unsigned)fixLen, (unsigned)payloadLen,
(unsigned)crcOn, (unsigned)freqHopOn, (unsigned)hopPeriod,
(unsigned)iqInverted, (unsigned)rxContinuous
);
*/
SubgRf.RxContinuous = rxContinuous;
RFW_DeInit();
if( rxContinuous == true )
{
symbTimeout = 0;
}
if( fixLen == true )
{
MaxPayloadLength = payloadLen;
}
else
{
MaxPayloadLength = 0xFF;
}
switch( modem )
{
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_RX:
SUBGRF_SetStopRxTimerOnPreambleDetect( true );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_05;
SubgRf.ModulationParams.Params.Gfsk.Fdev = 800;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( bandwidth );
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_OFF;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = 2 << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
SubgRf.PacketParams.Params.Gfsk.HeaderType = RADIO_PACKET_FIXED_LENGTH;
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
SubgRf.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREE_OFF;
RadioSetModem( MODEM_SIGFOX_RX );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( ( uint8_t[] ){0xB2, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } );
SUBGRF_SetWhiteningSeed( 0x01FF );
/* NO gfo reset (better sensitivity). Reg 0x8b8, bit4 = 0 */
modReg= RadioRead(SUBGHZ_AGCGFORSTCFGR);
modReg&=RADIO_BIT_MASK(4);
RadioWrite(SUBGHZ_AGCGFORSTCFGR, modReg);
/* Lower the threshold of cfo_reset */
RadioWrite(SUBGHZ_AGCGFORSTPOWTHR, 0x4 );
/* Bigger rssi_len (stability AGC). Reg 0x89b, bits[2 :4] = 0x1 */
modReg= RadioRead(SUBGHZ_AGCRSSICTL0R);
modReg&=( RADIO_BIT_MASK(2) & RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
RadioWrite(SUBGHZ_AGCRSSICTL0R, (modReg| (0x1<<3) ) );
/* Bigger afc_pbl_len (better frequency correction). Reg 0x6d1, bits[3 :4] = 0x3 */
modReg= RadioRead(SUBGHZ_GAFCR);
modReg&=( RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
RadioWrite(SUBGHZ_GAFCR, (modReg| (0x3<<3) ));
/* Use of new bit synchronizer (to avoid CRC errors during PER for payloads with a small amount of transitions). Reg 0x6ac, bits[4 :6] = 0x5 */
modReg= RadioRead(SUBGHZ_GBSYNCR);
modReg&=( RADIO_BIT_MASK(4) & RADIO_BIT_MASK(5) & RADIO_BIT_MASK(6) );
RadioWrite(SUBGHZ_GBSYNCR, (modReg| (0x5<<4) ));
/*timeout unused when SubgRf.RxContinuous*/
SubgRf.RxTimeout = ( uint32_t )(( symbTimeout * 8 * 1000 ) /datarate);
break;
#endif /*RADIO_SIGFOX_ENABLE == 1*/
case MODEM_FSK:
SUBGRF_SetStopRxTimerOnPreambleDetect( false );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( bandwidth );
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
if( crcOn == true )
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
}
SubgRf.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING;
RadioStandby( );
RadioSetModem( MODEM_FSK );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
SUBGRF_SetWhiteningSeed( 0x01FF );
/*timeout unused when SubgRf.RxContinuous*/
SubgRf.RxTimeout = ( uint32_t )(( symbTimeout * 8 * 1000 ) /datarate);
break;
case MODEM_LORA:
SUBGRF_SetStopRxTimerOnPreambleDetect( false );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_LORA;
SubgRf.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate;
SubgRf.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth];
SubgRf.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate;
if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01;
}
else