Line data Source code
1 : #include "SX1268.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 paOptimizedTable[RADIOLIB_SX126X_PA_TABLE_LEN] = {
10 : { .paDutyCycle = 2, .hpMax = 1, .paVal = -3 },
11 : { .paDutyCycle = 2, .hpMax = 1, .paVal = -2 },
12 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 0 },
13 : { .paDutyCycle = 4, .hpMax = 1, .paVal = -1 },
14 : { .paDutyCycle = 2, .hpMax = 1, .paVal = 2 },
15 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 0 },
16 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 1 },
17 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 },
18 : { .paDutyCycle = 1, .hpMax = 3, .paVal = 3 },
19 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 5 },
20 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 9 },
21 : { .paDutyCycle = 4, .hpMax = 1, .paVal = 8 },
22 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 7 },
23 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 13 },
24 : { .paDutyCycle = 4, .hpMax = 1, .paVal = 11 },
25 : { .paDutyCycle = 1, .hpMax = 1, .paVal = 19 },
26 : { .paDutyCycle = 2, .hpMax = 1, .paVal = 19 },
27 : { .paDutyCycle = 4, .hpMax = 1, .paVal = 17 },
28 : { .paDutyCycle = 1, .hpMax = 6, .paVal = 12 },
29 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 16 },
30 : { .paDutyCycle = 4, .hpMax = 1, .paVal = 22 },
31 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 18 },
32 : { .paDutyCycle = 1, .hpMax = 2, .paVal = 21 },
33 : { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 },
34 : { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 },
35 : { .paDutyCycle = 2, .hpMax = 3, .paVal = 20 },
36 : { .paDutyCycle = 1, .hpMax = 6, .paVal = 20 },
37 : { .paDutyCycle = 1, .hpMax = 5, .paVal = 22 },
38 : { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 },
39 : { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 },
40 : { .paDutyCycle = 3, .hpMax = 7, .paVal = 22 },
41 : { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 },
42 : };
43 :
44 1 : SX1268::SX1268(Module* mod) : SX126x(mod) {
45 1 : chipType = RADIOLIB_SX1268_CHIP_TYPE;
46 1 : }
47 :
48 0 : int16_t SX1268::begin(const ConfigLoRa_t& cfg) {
49 0 : int16_t state = SX126x::begin(cfg.codingRate, cfg.syncWord, cfg.preambleLength);
50 0 : RADIOLIB_ASSERT(state);
51 :
52 : // configure publicly accessible settings
53 0 : state = setSpreadingFactor(cfg.spreadingFactor);
54 0 : RADIOLIB_ASSERT(state);
55 :
56 0 : state = setBandwidth(cfg.bandwidth);
57 0 : RADIOLIB_ASSERT(state);
58 :
59 0 : state = setFrequency(cfg.frequency);
60 0 : RADIOLIB_ASSERT(state);
61 :
62 0 : state = SX126x::fixPaClamping();
63 0 : RADIOLIB_ASSERT(state);
64 :
65 0 : state = setOutputPower(cfg.power);
66 0 : RADIOLIB_ASSERT(state);
67 :
68 0 : return(state);
69 : }
70 :
71 0 : int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
72 0 : ConfigLoRa_t cfg;
73 0 : cfg.frequency = freq;
74 0 : cfg.bandwidth = bw;
75 0 : cfg.spreadingFactor = sf;
76 0 : cfg.codingRate = cr;
77 0 : cfg.syncWord = syncWord;
78 0 : cfg.power = power;
79 0 : cfg.preambleLength = preambleLength;
80 0 : this->tcxoVoltage = tcxoVoltage;
81 0 : this->useRegulatorLDO = useRegulatorLDO;
82 0 : return(begin(cfg));
83 : }
84 :
85 0 : int16_t SX1268::beginFSK(const ConfigFSK_t& cfg) {
86 : // execute common part
87 0 : int16_t state = SX126x::beginFSK(cfg.bitRate, cfg.frequencyDeviation, cfg.receiverBandwidth, cfg.preambleLength);
88 0 : RADIOLIB_ASSERT(state);
89 :
90 : // configure publicly accessible settings
91 0 : state = setFrequency(cfg.frequency);
92 0 : RADIOLIB_ASSERT(state);
93 :
94 0 : state = SX126x::fixPaClamping();
95 0 : RADIOLIB_ASSERT(state);
96 :
97 0 : state = setOutputPower(cfg.power);
98 0 : RADIOLIB_ASSERT(state);
99 :
100 0 : return(state);
101 : }
102 :
103 0 : int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
104 0 : ConfigFSK_t cfg;
105 0 : cfg.frequency = freq;
106 0 : cfg.bitRate = br;
107 0 : cfg.frequencyDeviation = freqDev;
108 0 : cfg.receiverBandwidth = rxBw;
109 0 : cfg.power = power;
110 0 : cfg.preambleLength = preambleLength;
111 0 : this->tcxoVoltage = tcxoVoltage;
112 0 : this->useRegulatorLDO = useRegulatorLDO;
113 0 : return(beginFSK(cfg));
114 : }
115 :
116 0 : int16_t SX1268::beginBPSK(const ConfigBPSK_t& cfg) {
117 : // execute common part
118 0 : int16_t state = SX126x::beginBPSK(cfg.bitRate);
119 0 : RADIOLIB_ASSERT(state);
120 :
121 : // configure publicly accessible settings
122 0 : state = setFrequency(cfg.frequency);
123 0 : RADIOLIB_ASSERT(state);
124 :
125 0 : state = SX126x::fixPaClamping();
126 0 : RADIOLIB_ASSERT(state);
127 :
128 0 : state = setOutputPower(cfg.power);
129 0 : RADIOLIB_ASSERT(state);
130 :
131 0 : return(state);
132 : }
133 :
134 0 : int16_t SX1268::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
135 0 : ConfigBPSK_t cfg;
136 0 : cfg.frequency = freq;
137 0 : cfg.bitRate = br;
138 0 : cfg.power = power;
139 0 : this->tcxoVoltage = tcxoVoltage;
140 0 : this->useRegulatorLDO = useRegulatorLDO;
141 0 : return(beginBPSK(cfg));
142 : }
143 :
144 0 : int16_t SX1268::beginLRFHSS(const ConfigLRFHSS_t& cfg) {
145 : // execute common part
146 0 : int16_t state = SX126x::beginLRFHSS(cfg.bandwidth, cfg.codingRate, cfg.narrowGrid);
147 0 : RADIOLIB_ASSERT(state);
148 :
149 : // configure publicly accessible settings
150 0 : state = setFrequency(cfg.frequency);
151 0 : RADIOLIB_ASSERT(state);
152 :
153 0 : state = SX126x::fixPaClamping();
154 0 : RADIOLIB_ASSERT(state);
155 :
156 0 : state = setOutputPower(cfg.power);
157 0 : RADIOLIB_ASSERT(state);
158 :
159 0 : return(state);
160 : }
161 :
162 0 : int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
163 0 : ConfigLRFHSS_t cfg;
164 0 : cfg.frequency = freq;
165 0 : cfg.bandwidth = bw;
166 0 : cfg.codingRate = cr;
167 0 : cfg.narrowGrid = narrowGrid;
168 0 : cfg.power = power;
169 0 : this->tcxoVoltage = tcxoVoltage;
170 0 : this->useRegulatorLDO = useRegulatorLDO;
171 0 : return(beginLRFHSS(cfg));
172 : }
173 :
174 1 : int16_t SX1268::setFrequency(float freq) {
175 1 : return(setFrequency(freq, false));
176 : }
177 :
178 : /// \todo integers only (all modules - frequency, data rate, bandwidth etc.)
179 1 : int16_t SX1268::setFrequency(float freq, bool skipCalibration) {
180 1 : RADIOLIB_CHECK_RANGE(freq, 410.0f, 810.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
181 :
182 : // check if we need to recalibrate image
183 0 : if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
184 0 : int16_t state = this->calibrateImage(freq);
185 0 : RADIOLIB_ASSERT(state);
186 : }
187 :
188 : // set frequency
189 0 : return(SX126x::setFrequencyRaw(freq));
190 : }
191 :
192 1 : int16_t SX1268::setOutputPower(int8_t power) {
193 1 : return(setOutputPower(power, true));
194 : }
195 :
196 1 : int16_t SX1268::setOutputPower(int8_t power, bool optimize) {
197 : // check if power value is configurable
198 1 : int16_t state = checkOutputPower(power, NULL);
199 1 : RADIOLIB_ASSERT(state);
200 :
201 : // set PA config
202 1 : SX126x::paTableEntry_t* paTable = this->paOptTable ? this->paOptTable : const_cast<SX126x::paTableEntry_t*>(paOptimizedTable);
203 1 : int8_t paVal = optimize ? paTable[power + 9].paVal : power;
204 1 : uint8_t paDutyCycle = optimize ? paTable[power + 9].paDutyCycle : 0x04;
205 1 : uint8_t hpMax = optimize ? paTable[power + 9].hpMax : 0x07;
206 1 : return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1268));
207 : }
208 :
209 2 : int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) {
210 2 : if(clipped) {
211 0 : *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
212 : }
213 2 : RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
214 2 : return(RADIOLIB_ERR_NONE);
215 : }
216 :
217 1 : int16_t SX1268::setModem(ModemType_t modem) {
218 1 : switch(modem) {
219 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
220 0 : return(this->begin());
221 : } break;
222 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
223 0 : return(this->beginFSK());
224 : } break;
225 0 : case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
226 0 : return(this->beginLRFHSS());
227 : } break;
228 1 : default:
229 1 : return(RADIOLIB_ERR_WRONG_MODEM);
230 : }
231 : }
232 :
233 : #endif
|