Line data Source code
1 : #include "SX1262.h"
2 : #include <math.h>
3 :
4 : #if !RADIOLIB_EXCLUDE_SX126X
5 :
6 : // this is a lookup table for optimized PA configuration
7 : // it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628
8 : // see also https://github.com/radiolib-org/power-tests
9 : static const SX126x::paTableEntry_t paOptTable[32] = {
10 : { .paDutyCycle = 2, .hpMax = 2, .paVal = -5 },
11 : { .paDutyCycle = 2, .hpMax = 1, .paVal = 0 },
12 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 3 },
13 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 0 },
14 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 6 },
15 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 },
16 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 2 },
17 : { .paDutyCycle = 4, .hpMax = 1, .paVal = 6 },
18 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 11 },
19 : { .paDutyCycle = 2, .hpMax = 1, .paVal = 11 },
20 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 14 },
21 : { .paDutyCycle = 2, .hpMax = 1, .paVal = 14 },
22 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 20 },
23 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 22 },
24 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 11 },
25 : { .paDutyCycle = 3, .hpMax = 1, .paVal = 21 },
26 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 17 },
27 : { .paDutyCycle = 4, .hpMax = 2, .paVal = 13 },
28 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 20 },
29 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 22 },
30 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 },
31 : { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 },
32 : { .paDutyCycle = 1, .hpMax = 4, .paVal = 19 },
33 : { .paDutyCycle = 1, .hpMax = 4, .paVal = 20 },
34 : { .paDutyCycle = 3, .hpMax = 3, .paVal = 20 },
35 : { .paDutyCycle = 2, .hpMax = 5, .paVal = 19 },
36 : { .paDutyCycle = 1, .hpMax = 6, .paVal = 22 },
37 : { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 },
38 : { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 },
39 : { .paDutyCycle = 3, .hpMax = 6, .paVal = 22 },
40 : { .paDutyCycle = 4, .hpMax = 6, .paVal = 22 },
41 : { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 },
42 : };
43 :
44 :
45 2 : SX1262::SX1262(Module* mod) : SX126x(mod) {
46 2 : chipType = RADIOLIB_SX1262_CHIP_TYPE;
47 2 : }
48 :
49 0 : int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
50 : // execute common part
51 0 : int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO);
52 0 : RADIOLIB_ASSERT(state);
53 :
54 : // configure publicly accessible settings
55 0 : state = setSpreadingFactor(sf);
56 0 : RADIOLIB_ASSERT(state);
57 :
58 0 : state = setBandwidth(bw);
59 0 : RADIOLIB_ASSERT(state);
60 :
61 0 : state = setFrequency(freq);
62 0 : RADIOLIB_ASSERT(state);
63 :
64 0 : state = SX126x::fixPaClamping();
65 0 : RADIOLIB_ASSERT(state);
66 :
67 0 : state = setOutputPower(power);
68 0 : RADIOLIB_ASSERT(state);
69 :
70 0 : return(state);
71 : }
72 :
73 0 : int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
74 : // execute common part
75 0 : int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO);
76 0 : RADIOLIB_ASSERT(state);
77 :
78 : // configure publicly accessible settings
79 0 : state = setFrequency(freq);
80 0 : RADIOLIB_ASSERT(state);
81 :
82 0 : state = SX126x::fixPaClamping();
83 0 : RADIOLIB_ASSERT(state);
84 :
85 0 : state = setOutputPower(power);
86 0 : RADIOLIB_ASSERT(state);
87 :
88 0 : return(state);
89 : }
90 :
91 0 : int16_t SX1262::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
92 : // execute common part
93 0 : int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO);
94 0 : RADIOLIB_ASSERT(state);
95 :
96 : // configure publicly accessible settings
97 0 : state = setFrequency(freq);
98 0 : RADIOLIB_ASSERT(state);
99 :
100 0 : state = SX126x::fixPaClamping();
101 0 : RADIOLIB_ASSERT(state);
102 :
103 0 : state = setOutputPower(power);
104 0 : RADIOLIB_ASSERT(state);
105 :
106 0 : return(state);
107 : }
108 :
109 0 : int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
110 : // execute common part
111 0 : int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);
112 0 : RADIOLIB_ASSERT(state);
113 :
114 : // configure publicly accessible settings
115 0 : state = setFrequency(freq);
116 0 : RADIOLIB_ASSERT(state);
117 :
118 0 : state = SX126x::fixPaClamping();
119 0 : RADIOLIB_ASSERT(state);
120 :
121 0 : state = setOutputPower(power);
122 0 : RADIOLIB_ASSERT(state);
123 :
124 0 : return(state);
125 : }
126 :
127 2 : int16_t SX1262::setFrequency(float freq) {
128 2 : return(setFrequency(freq, false));
129 : }
130 :
131 2 : int16_t SX1262::setFrequency(float freq, bool skipCalibration) {
132 2 : RADIOLIB_CHECK_RANGE(freq, 150.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
133 :
134 : // check if we need to recalibrate image
135 0 : if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
136 0 : int16_t state = this->calibrateImage(freq);
137 0 : RADIOLIB_ASSERT(state);
138 : }
139 :
140 : // set frequency
141 0 : return(SX126x::setFrequencyRaw(freq));
142 : }
143 :
144 1 : int16_t SX1262::setOutputPower(int8_t power) {
145 1 : return(setOutputPower(power, true));
146 : }
147 :
148 1 : int16_t SX1262::setOutputPower(int8_t power, bool optimize) {
149 : // check if power value is configurable
150 1 : int16_t state = checkOutputPower(power, NULL);
151 1 : RADIOLIB_ASSERT(state);
152 :
153 : // set PA config
154 1 : int8_t paVal = optimize ? paOptTable[power + 9].paVal : power;
155 1 : uint8_t paDutyCycle = optimize ? paOptTable[power + 9].paDutyCycle : 0x04;
156 1 : uint8_t hpMax = optimize ? paOptTable[power + 9].hpMax : 0x07;
157 1 : return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1262));
158 : }
159 :
160 2 : int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) {
161 2 : if(clipped) {
162 0 : *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
163 : }
164 2 : RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
165 2 : return(RADIOLIB_ERR_NONE);
166 : }
167 :
168 2 : int16_t SX1262::setModem(ModemType_t modem) {
169 2 : switch(modem) {
170 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
171 0 : return(this->begin());
172 : } break;
173 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
174 0 : return(this->beginFSK());
175 : } break;
176 0 : case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
177 0 : return(this->beginLRFHSS());
178 : } break;
179 2 : default:
180 2 : return(RADIOLIB_ERR_WRONG_MODEM);
181 : }
182 : }
183 :
184 : #endif
|