Line data Source code
1 : #include "LR11x0.h"
2 :
3 : #include "../../utils/CRC.h"
4 : #include "../../utils/Cryptography.h"
5 : #include "LR_common.h"
6 :
7 : #include <string.h>
8 : #include <math.h>
9 :
10 : #if !RADIOLIB_EXCLUDE_LR11X0
11 :
12 0 : int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) {
13 : // check maximum size
14 0 : if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
15 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
16 : }
17 0 : return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false));
18 : }
19 :
20 0 : int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
21 : // check maximum size
22 0 : if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
23 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
24 : }
25 :
26 : // the request contains the address and length
27 : uint8_t reqBuff[5] = {
28 0 : (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
29 0 : (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
30 : (uint8_t)len,
31 0 : };
32 :
33 : // build buffers - later we need to ensure endians are correct,
34 : // so there is probably no way to do this without copying buffers and iterating
35 : #if RADIOLIB_STATIC_ONLY
36 : uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
37 : #else
38 0 : uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
39 : #endif
40 :
41 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
42 :
43 : // convert endians
44 0 : if(data && (state == RADIOLIB_ERR_NONE)) {
45 0 : for(size_t i = 0; i < len; i++) {
46 0 : data[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)];
47 : }
48 : }
49 :
50 : #if !RADIOLIB_STATIC_ONLY
51 0 : delete[] rplBuff;
52 : #endif
53 :
54 0 : return(state);
55 : }
56 :
57 0 : int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) {
58 : // check maximum size
59 0 : if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
60 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
61 : }
62 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast<uint8_t*>(data), len));
63 : }
64 :
65 0 : int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) {
66 : // check maximum size
67 0 : if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
68 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
69 : }
70 :
71 : // build buffers
72 0 : size_t reqLen = 2*sizeof(uint8_t) + len;
73 : #if RADIOLIB_STATIC_ONLY
74 : uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
75 : #else
76 0 : uint8_t* reqBuff = new uint8_t[reqLen];
77 : #endif
78 :
79 : // set the offset and length
80 0 : reqBuff[0] = (uint8_t)offset;
81 0 : reqBuff[1] = (uint8_t)len;
82 :
83 : // send the request
84 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen);
85 : #if !RADIOLIB_STATIC_ONLY
86 0 : delete[] reqBuff;
87 : #endif
88 0 : return(state);
89 : }
90 :
91 0 : int16_t LR11x0::clearRxBuffer(void) {
92 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0));
93 : }
94 :
95 0 : int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) {
96 : uint8_t buff[12] = {
97 0 : (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
98 0 : (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF),
99 0 : (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF),
100 0 : };
101 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff)));
102 : }
103 :
104 0 : int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) {
105 0 : uint8_t buff[4] = { 0 };
106 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff));
107 :
108 : // pass the replies
109 0 : if(hw) { *hw = buff[0]; }
110 0 : if(device) { *device = buff[1]; }
111 0 : if(major) { *major = buff[2]; }
112 0 : if(minor) { *minor = buff[3]; }
113 :
114 0 : return(state);
115 : }
116 :
117 0 : int16_t LR11x0::getErrors(uint16_t* err) {
118 0 : uint8_t buff[2] = { 0 };
119 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff));
120 :
121 : // pass the replies
122 0 : if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
123 :
124 0 : return(state);
125 : }
126 :
127 0 : int16_t LR11x0::clearErrors(void) {
128 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0));
129 : }
130 :
131 0 : int16_t LR11x0::calibrate(uint8_t params) {
132 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1));
133 : }
134 :
135 0 : int16_t LR11x0::setRegMode(uint8_t mode) {
136 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1));
137 : }
138 :
139 0 : int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) {
140 : uint8_t buff[2] = {
141 0 : (uint8_t)floor((freqMin - 1.0f) / 4.0f),
142 0 : (uint8_t)ceil((freqMax + 1.0f) / 4.0f)
143 0 : };
144 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff)));
145 : }
146 :
147 0 : int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) {
148 0 : uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg };
149 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff)));
150 : }
151 :
152 3 : int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) {
153 : uint8_t buff[8] = {
154 3 : (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF),
155 3 : (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF),
156 3 : };
157 6 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff)));
158 : }
159 :
160 0 : int16_t LR11x0::setDioIrqParams(uint32_t irq) {
161 0 : return(setDioIrqParams(irq, this->gnss ? 0 : irq));
162 : }
163 :
164 6 : int16_t LR11x0::clearIrqState(uint32_t irq) {
165 6 : return(this->setU32(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, irq));
166 : }
167 :
168 0 : int16_t LR11x0::configLfClock(uint8_t setup) {
169 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1));
170 : }
171 :
172 0 : int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) {
173 : uint8_t buff[4] = {
174 0 : tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF),
175 0 : };
176 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff)));
177 : }
178 :
179 0 : int16_t LR11x0::reboot(bool stay) {
180 0 : uint8_t buff[1] = { (uint8_t)(stay*3) };
181 0 : return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false));
182 : }
183 :
184 0 : int16_t LR11x0::getVbat(float* vbat) {
185 0 : uint8_t buff[1] = { 0 };
186 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff));
187 :
188 : // pass the replies
189 0 : if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; }
190 :
191 0 : return(state);
192 : }
193 :
194 0 : int16_t LR11x0::getTemp(float* temp) {
195 0 : uint8_t buff[2] = { 0 };
196 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff));
197 :
198 : // pass the replies
199 0 : if(temp) {
200 0 : uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1];
201 0 : raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits
202 0 : *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35
203 : }
204 :
205 0 : return(state);
206 : }
207 :
208 0 : int16_t LR11x0::setFs(void) {
209 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0));
210 : }
211 :
212 3 : int16_t LR11x0::getRandomNumber(uint32_t* rnd) {
213 3 : uint8_t buff[4] = { 0 };
214 3 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff));
215 :
216 : // pass the replies
217 3 : if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; }
218 :
219 3 : return(state);
220 : }
221 :
222 0 : int16_t LR11x0::eraseInfoPage(void) {
223 : // only page 1 can be erased
224 0 : uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE };
225 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff)));
226 : }
227 :
228 0 : int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) {
229 : // check maximum size
230 0 : if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
231 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
232 : }
233 :
234 : // build buffers - later we need to ensure endians are correct,
235 : // so there is probably no way to do this without copying buffers and iterating
236 0 : size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t);
237 : #if RADIOLIB_STATIC_ONLY
238 : uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
239 : #else
240 0 : uint8_t* dataBuff = new uint8_t[buffLen];
241 : #endif
242 :
243 : // set the address
244 0 : dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE;
245 0 : dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF);
246 0 : dataBuff[2] = (uint8_t)(addr & 0xFF);
247 :
248 : // convert endians
249 0 : for(size_t i = 0; i < len; i++) {
250 0 : dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF);
251 0 : dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF);
252 0 : dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF);
253 0 : dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF);
254 : }
255 :
256 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen);
257 : #if !RADIOLIB_STATIC_ONLY
258 0 : delete[] dataBuff;
259 : #endif
260 0 : return(state);
261 : }
262 :
263 0 : int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) {
264 : // check maximum size
265 0 : if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
266 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
267 : }
268 :
269 : // the request contains the address and length
270 0 : uint8_t reqBuff[4] = {
271 : RADIOLIB_LR11X0_INFO_PAGE,
272 0 : (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF),
273 : (uint8_t)len,
274 0 : };
275 :
276 : // build buffers - later we need to ensure endians are correct,
277 : // so there is probably no way to do this without copying buffers and iterating
278 : #if RADIOLIB_STATIC_ONLY
279 : uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
280 : #else
281 0 : uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)];
282 : #endif
283 :
284 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff));
285 :
286 : // convert endians
287 0 : if(data && (state == RADIOLIB_ERR_NONE)) {
288 0 : for(size_t i = 0; i < len; i++) {
289 0 : data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)];
290 : }
291 : }
292 :
293 : #if !RADIOLIB_STATIC_ONLY
294 0 : delete[] rplBuff;
295 : #endif
296 :
297 0 : return(state);
298 : }
299 :
300 0 : int16_t LR11x0::getChipEui(uint8_t* eui) {
301 0 : RADIOLIB_ASSERT_PTR(eui);
302 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
303 : }
304 :
305 0 : int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) {
306 0 : RADIOLIB_ASSERT_PTR(eui);
307 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
308 : }
309 :
310 0 : int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) {
311 0 : RADIOLIB_ASSERT_PTR(pin);
312 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
313 : }
314 :
315 0 : int16_t LR11x0::enableSpiCrc(bool en) {
316 : // TODO implement this
317 : (void)en;
318 : // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected
319 : /*RadioLibCRCInstance.size = 8;
320 : RadioLibCRCInstance.poly = 0xA6;
321 : RadioLibCRCInstance.init = 0xFF;
322 : RadioLibCRCInstance.out = 0x00;
323 : RadioLibCRCInstance.refIn = true;
324 : RadioLibCRCInstance.refOut = true;*/
325 0 : return(RADIOLIB_ERR_UNSUPPORTED);
326 : }
327 :
328 0 : int16_t LR11x0::driveDiosInSleepMode(bool en) {
329 0 : if((this->versionDevice == RADIOLIB_LR11X0_DEVICE_LR1110) &&
330 0 : (this->versionCombined < 0x0306)) {
331 : RADIOLIB_DEBUG_BASIC_PRINTLN("driveDiosInSleepMode was not implemented in LR1110 < 0306\n");
332 0 : return(RADIOLIB_ERR_UNSUPPORTED);
333 : }
334 0 : uint8_t buff[1] = { (uint8_t)en };
335 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff)));
336 : }
337 :
338 0 : int16_t LR11x0::resetStats(void) {
339 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0));
340 : }
341 :
342 0 : int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) {
343 0 : uint8_t buff[8] = { 0 };
344 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff));
345 :
346 : // pass the replies
347 0 : if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; }
348 0 : if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; }
349 0 : if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; }
350 0 : if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
351 :
352 0 : return(state);
353 : }
354 :
355 69 : int16_t LR11x0::getPacketType(uint8_t* type) {
356 69 : uint8_t buff[1] = { 0 };
357 69 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff));
358 :
359 : // pass the replies
360 69 : if(type) { *type = buff[0]; }
361 :
362 69 : return(state);
363 : }
364 :
365 3 : int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) {
366 3 : uint8_t buff[2] = { 0 };
367 3 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff));
368 :
369 : // pass the replies
370 3 : if(len) { *len = buff[0]; }
371 3 : if(startOffset) { *startOffset = buff[1]; }
372 :
373 3 : return(state);
374 : }
375 :
376 0 : int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) {
377 0 : uint8_t buff[3] = { 0 };
378 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
379 :
380 : // pass the replies
381 0 : if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; }
382 0 : if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; }
383 0 : if(signalRssiPkt) { *signalRssiPkt = buff[2]; }
384 :
385 0 : return(state);
386 : }
387 :
388 0 : int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) {
389 0 : uint8_t buff[4] = { 0 };
390 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
391 :
392 : // pass the replies
393 0 : if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; }
394 0 : if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; }
395 0 : if(rxLen) { *rxLen = buff[2]; }
396 0 : if(stat) { *stat = buff[3]; }
397 :
398 0 : return(state);
399 : }
400 :
401 0 : int16_t LR11x0::getRssiInst(float* rssi) {
402 0 : uint8_t buff[1] = { 0 };
403 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff));
404 :
405 : // pass the replies
406 0 : if(rssi) { *rssi = (float)buff[0] / -2.0f; }
407 :
408 0 : return(state);
409 : }
410 :
411 0 : int16_t LR11x0::setGfskSyncWord(uint8_t* sync) {
412 0 : RADIOLIB_ASSERT_PTR(sync);
413 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN));
414 : }
415 :
416 0 : int16_t LR11x0::setLoRaPublicNetwork(bool pub) {
417 0 : uint8_t buff[1] = { (uint8_t)pub };
418 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff)));
419 : }
420 :
421 3 : int16_t LR11x0::setRx(uint32_t timeout) {
422 : uint8_t buff[3] = {
423 3 : (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
424 3 : };
425 6 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff)));
426 : }
427 :
428 0 : int16_t LR11x0::setTx(uint32_t timeout) {
429 : uint8_t buff[3] = {
430 0 : (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
431 0 : };
432 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff)));
433 : }
434 :
435 0 : int16_t LR11x0::setRfFrequency(uint32_t rfFreq) {
436 0 : return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, rfFreq));
437 : }
438 :
439 0 : int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) {
440 : uint8_t buff[7] = {
441 0 : (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode,
442 0 : (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
443 0 : };
444 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff)));
445 : }
446 :
447 0 : int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) {
448 : uint8_t buff[7] = {
449 : symNum, detPeak, detMin, cadExitMode,
450 0 : (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
451 0 : };
452 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff)));
453 : }
454 :
455 0 : int16_t LR11x0::setPacketType(uint8_t type) {
456 0 : uint8_t buff[1] = { type };
457 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff)));
458 : }
459 :
460 0 : int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
461 : // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
462 0 : if(this->ldroAuto) {
463 0 : float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
464 : // LDRO on SX128x seems to be working differently to sub-GHz LoRa, as it is always needed for SF > 10
465 : // if SX128x bandwidth is being used, we use this approach instead of the symbol time to preserve compatibility
466 0 : bool sx128xLdro = this->highFreq && ((bw >= RADIOLIB_LR11X0_LORA_BW_203_125) || (bw <= RADIOLIB_LR11X0_LORA_BW_812_50)) && (sf > 10);
467 0 : if((symbolLength >= 16.0f) || sx128xLdro) {
468 0 : this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED;
469 : } else {
470 0 : this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED;
471 : }
472 : } else {
473 0 : this->ldrOptimize = ldro;
474 : }
475 :
476 0 : uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize };
477 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
478 : }
479 :
480 0 : int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) {
481 : uint8_t buff[10] = {
482 0 : (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
483 0 : (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw,
484 0 : (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF),
485 0 : (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)
486 0 : };
487 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
488 : }
489 :
490 0 : int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) {
491 : uint8_t buff[5] = {
492 0 : (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF),
493 0 : (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh
494 0 : };
495 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff)));
496 : }
497 :
498 0 : int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) {
499 : // same as for LR-FHSS
500 0 : return(this->setModulationParamsLrFhss(br, sh));
501 : }
502 :
503 0 : int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) {
504 : uint8_t buff[6] = {
505 0 : (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
506 : hdrType, payloadLen, crcType, invertIQ
507 0 : };
508 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
509 : }
510 :
511 0 : int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) {
512 : uint8_t buff[9] = {
513 0 : (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF),
514 : preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten
515 0 : };
516 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
517 : }
518 :
519 0 : int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) {
520 : uint8_t buff[7] = {
521 0 : payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF),
522 0 : (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF),
523 0 : (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF),
524 0 : };
525 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff)));
526 : }
527 :
528 0 : int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) {
529 0 : uint8_t buff[2] = { (uint8_t)pwr, ramp };
530 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff)));
531 : }
532 :
533 0 : int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) {
534 0 : uint8_t buff[2] = { node, broadcast };
535 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff)));
536 : }
537 :
538 0 : int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) {
539 0 : uint8_t buff[1] = { mode };
540 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff)));
541 : }
542 :
543 0 : int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) {
544 : uint8_t buff[7] = {
545 0 : (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF),
546 0 : (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF),
547 : mode
548 0 : };
549 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff)));
550 : }
551 :
552 3 : int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) {
553 3 : uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel };
554 6 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff)));
555 : }
556 :
557 0 : int16_t LR11x0::stopTimeoutOnPreamble(bool stop) {
558 0 : uint8_t buff[1] = { (uint8_t)stop };
559 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff)));
560 : }
561 :
562 0 : int16_t LR11x0::setCad(void) {
563 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0));
564 : }
565 :
566 3 : int16_t LR11x0::setTxCw(void) {
567 3 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0));
568 : }
569 :
570 0 : int16_t LR11x0::setTxInfinitePreamble(void) {
571 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0));
572 : }
573 :
574 0 : int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) {
575 0 : uint8_t buff[1] = { symbolNum };
576 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff)));
577 : }
578 :
579 0 : int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) {
580 : uint8_t buff[5] = {
581 0 : (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF),
582 0 : (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen
583 0 : };
584 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff)));
585 : }
586 :
587 0 : int16_t LR11x0::setRangingReqAddr(uint32_t addr) {
588 0 : return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, addr));
589 : }
590 :
591 0 : int16_t LR11x0::getRangingResult(uint8_t type, float* res) {
592 0 : uint8_t reqBuff[1] = { type };
593 0 : uint8_t rplBuff[4] = { 0 };
594 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
595 0 : RADIOLIB_ASSERT(state);
596 :
597 0 : if(res) {
598 0 : if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) {
599 0 : uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3];
600 0 : *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000));
601 : } else {
602 0 : *res = (float)rplBuff[3]/2.0f;
603 : }
604 : }
605 :
606 0 : return(state);
607 : }
608 :
609 0 : int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) {
610 0 : return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, delay));
611 : }
612 :
613 0 : int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) {
614 : uint8_t buff[8] = {
615 0 : (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF),
616 0 : (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF),
617 0 : (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF),
618 0 : (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF)
619 0 : };
620 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff)));
621 :
622 : }
623 :
624 0 : int16_t LR11x0::setGfskWhitParams(uint16_t seed) {
625 : uint8_t buff[2] = {
626 0 : (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF)
627 0 : };
628 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff)));
629 : }
630 :
631 0 : int16_t LR11x0::setRangingParameter(uint8_t symbolNum) {
632 : // the first byte is reserved
633 0 : uint8_t buff[2] = { 0x00, symbolNum };
634 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff)));
635 : }
636 :
637 0 : int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) {
638 : uint8_t buff[11] = {
639 0 : (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4),
640 0 : (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4),
641 0 : (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4),
642 0 : (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4),
643 0 : (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4),
644 0 : (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4),
645 0 : (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4),
646 0 : (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4),
647 0 : (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4),
648 0 : (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF),
649 0 : };
650 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff)));
651 : }
652 :
653 0 : int16_t LR11x0::setLoRaSyncWord(uint8_t sync) {
654 0 : uint8_t buff[1] = { sync };
655 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff)));
656 : }
657 :
658 0 : int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) {
659 0 : return(this->setU32(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, sync));
660 : }
661 :
662 0 : int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) {
663 0 : return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len));
664 : }
665 :
666 0 : int16_t LR11x0::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
667 : // check if in explicit header mode
668 0 : if(this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) {
669 0 : return(RADIOLIB_ERR_WRONG_MODEM);
670 : }
671 :
672 0 : uint8_t buff[1] = { 0 };
673 0 : int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff));
674 :
675 : // pass the replies
676 0 : if(cr) { *cr = (buff[0] & 0x70) >> 4; }
677 0 : if(hasCRC) { *hasCRC = (buff[0] & RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED) != 0; }
678 :
679 0 : return(state);
680 : }
681 :
682 0 : int16_t LR11x0::bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len) {
683 0 : return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len));
684 : }
685 :
686 0 : int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len) {
687 : // check maximum size
688 : // TODO what is the actual maximum?
689 0 : if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) {
690 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
691 : }
692 :
693 : // build buffers
694 : #if RADIOLIB_STATIC_ONLY
695 : uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN];
696 : #else
697 0 : uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len];
698 : #endif
699 :
700 : // set the channel
701 0 : dataBuff[0] = chan;
702 0 : memcpy(&dataBuff[1], payload, len);
703 :
704 0 : int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len);
705 : #if !RADIOLIB_STATIC_ONLY
706 0 : delete[] dataBuff;
707 : #endif
708 0 : return(state);
709 : }
710 :
711 0 : int16_t LR11x0::bootEraseFlash(void) {
712 : // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds
713 0 : RadioLibTime_t timeout = this->mod->spiConfig.timeout;
714 0 : this->mod->spiConfig.timeout = 3000;
715 0 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false);
716 0 : this->mod->spiConfig.timeout = timeout;
717 0 : return(state);
718 : }
719 :
720 0 : int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) {
721 : // check maximum size
722 0 : if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
723 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
724 : }
725 0 : return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile));
726 : }
727 :
728 0 : int16_t LR11x0::bootGetHash(uint8_t hash[RADIOLIB_LR11X0_HASH_LEN]) {
729 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_HASH, false, hash, RADIOLIB_LR11X0_HASH_LEN));
730 : }
731 :
732 0 : int16_t LR11x0::bootReboot(bool stay) {
733 0 : uint8_t buff[1] = { (uint8_t)stay };
734 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff)));
735 : }
736 :
737 0 : int16_t LR11x0::bootGetPin(uint8_t* pin) {
738 0 : RADIOLIB_ASSERT_PTR(pin);
739 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN));
740 : }
741 :
742 0 : int16_t LR11x0::bootGetChipEui(uint8_t* eui) {
743 0 : RADIOLIB_ASSERT_PTR(eui);
744 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
745 : }
746 :
747 0 : int16_t LR11x0::bootGetJoinEui(uint8_t* eui) {
748 0 : RADIOLIB_ASSERT_PTR(eui);
749 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
750 : }
751 :
752 : #endif
|