Line data Source code
1 : #include "Module.h"
2 :
3 : // the following is probably only needed on non-Arduino builds
4 : #include <stdio.h>
5 : #include <string.h>
6 :
7 : #if defined(RADIOLIB_BUILD_ARDUINO)
8 : #include "hal/Arduino/ArduinoHal.h"
9 :
10 : Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
11 : this->hal = new ArduinoHal();
12 : }
13 :
14 : Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
15 : this->hal = new ArduinoHal(spi, spiSettings);
16 : }
17 : #endif
18 :
19 63 : Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
20 63 : this->hal = hal;
21 63 : }
22 :
23 0 : Module::Module(const Module& mod) {
24 0 : *this = mod;
25 0 : }
26 :
27 1 : Module& Module::operator=(const Module& mod) {
28 1 : this->hal = mod.hal;
29 1 : memcpy(&this->spiConfig, reinterpret_cast<void*>(&(const_cast<Module&>(mod)).spiConfig), sizeof(SPIConfig_t));
30 1 : this->csPin = mod.csPin;
31 1 : this->irqPin = mod.irqPin;
32 1 : this->rstPin = mod.rstPin;
33 1 : this->gpioPin = mod.gpioPin;
34 :
35 1 : memcpy(this->rfSwitchPins, mod.rfSwitchPins, Module::RFSWITCH_MAX_PINS*sizeof(this->rfSwitchPins[0]));
36 1 : this->rfSwitchTable = mod.rfSwitchTable;
37 :
38 : #if RADIOLIB_INTERRUPT_TIMING
39 : this->TimerSetupCb = mod.TimerSetupCb;
40 : this->TimerFlag = mod.TimerFlag;
41 : this->prevTimingLen = mod.prevTimingLen;
42 : #endif
43 :
44 1 : return(*this);
45 : }
46 :
47 : static volatile const char rlb_info[] = RADIOLIB_INFO;
48 7 : void Module::init() {
49 7 : this->hal->init();
50 7 : this->hal->pinMode(csPin, this->hal->GpioModeOutput);
51 7 : this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh);
52 : RADIOLIB_DEBUG_BASIC_PRINTLN(RADIOLIB_INFO);
53 7 : RADIOLIB_VALUE_USED(rlb_info);
54 7 : }
55 :
56 7 : void Module::term() {
57 : // stop hardware interfaces (if they were initialized by the library)
58 7 : this->hal->term();
59 7 : }
60 :
61 404 : int16_t Module::SPIgetRegValue(uint32_t reg, uint8_t msb, uint8_t lsb) {
62 404 : if((msb > 7) || (lsb > 7) || (lsb > msb)) {
63 6 : return(RADIOLIB_ERR_INVALID_BIT_RANGE);
64 : }
65 :
66 398 : uint8_t rawValue = SPIreadRegister(reg);
67 398 : uint8_t maskedValue = rawValue & ((0b11111111 << lsb) & (0b11111111 >> (7 - msb)));
68 398 : return(maskedValue);
69 : }
70 :
71 232 : int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask, bool force) {
72 232 : if((msb > 7) || (lsb > 7) || (lsb > msb)) {
73 6 : return(RADIOLIB_ERR_INVALID_BIT_RANGE);
74 : }
75 :
76 : // read the current value
77 226 : uint8_t currentValue = SPIreadRegister(reg);
78 226 : uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb)));
79 :
80 : // check if we actually need to update the register
81 226 : if((currentValue & mask) == (value & mask) && !force) {
82 24 : return(RADIOLIB_ERR_NONE);
83 : }
84 :
85 : // update the register
86 202 : uint8_t newValue = (currentValue & ~mask) | (value & mask);
87 202 : SPIwriteRegister(reg, newValue);
88 :
89 : #if RADIOLIB_SPI_PARANOID
90 : // check register value each millisecond until check interval is reached
91 : // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE)
92 202 : RadioLibTime_t start = this->hal->micros();
93 : #if RADIOLIB_DEBUG_SPI
94 : uint8_t readValue = 0x00;
95 : #endif
96 527 : while(this->hal->micros() - start < ((RadioLibTime_t)checkInterval * 1000UL)) {
97 327 : uint8_t val = SPIreadRegister(reg);
98 327 : if((val & checkMask) == (newValue & checkMask)) {
99 : // check passed, we can stop the loop
100 2 : return(RADIOLIB_ERR_NONE);
101 : }
102 : #if RADIOLIB_DEBUG_SPI
103 : readValue = val;
104 : #endif
105 : }
106 :
107 : // check failed, print debug info
108 : RADIOLIB_DEBUG_SPI_PRINTLN();
109 : RADIOLIB_DEBUG_SPI_PRINTLN("address:\t0x%X", reg);
110 : RADIOLIB_DEBUG_SPI_PRINTLN("bits:\t\t%d %d", msb, lsb);
111 : RADIOLIB_DEBUG_SPI_PRINTLN("value:\t\t0x%X", value);
112 : RADIOLIB_DEBUG_SPI_PRINTLN("current:\t0x%X", currentValue);
113 : RADIOLIB_DEBUG_SPI_PRINTLN("mask:\t\t0x%X", mask);
114 : RADIOLIB_DEBUG_SPI_PRINTLN("new:\t\t0x%X", newValue);
115 : RADIOLIB_DEBUG_SPI_PRINTLN("read:\t\t0x%X", readValue);
116 :
117 200 : return(RADIOLIB_ERR_SPI_WRITE_FAILED);
118 : #else
119 : return(RADIOLIB_ERR_NONE);
120 : #endif
121 : }
122 :
123 33 : void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inBytes) {
124 33 : if(!this->spiConfig.stream) {
125 0 : SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], reg, NULL, inBytes, numBytes);
126 : } else {
127 : uint8_t cmd[6];
128 33 : uint8_t* cmdPtr = cmd;
129 99 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
130 66 : *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF;
131 : }
132 66 : for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
133 33 : *(cmdPtr++) = (reg >> 8*i) & 0xFF;
134 : }
135 33 : SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true);
136 : }
137 33 : }
138 :
139 2547 : uint8_t Module::SPIreadRegister(uint32_t reg) {
140 2547 : uint8_t resp = 0;
141 2547 : if(!spiConfig.stream) {
142 106 : SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], reg, NULL, &resp, 1);
143 : } else {
144 : uint8_t cmd[6];
145 2441 : uint8_t* cmdPtr = cmd;
146 7280 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
147 4839 : *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF;
148 : }
149 4925 : for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
150 2484 : *(cmdPtr++) = (reg >> 8*i) & 0xFF;
151 : }
152 2441 : SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true);
153 : }
154 2547 : return(resp);
155 : }
156 :
157 6 : void Module::SPIwriteRegisterBurst(uint32_t reg, const uint8_t* data, size_t numBytes) {
158 6 : if(!spiConfig.stream) {
159 0 : SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, data, NULL, numBytes);
160 : } else {
161 : uint8_t cmd[6];
162 6 : uint8_t* cmdPtr = cmd;
163 18 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
164 12 : *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF;
165 : }
166 12 : for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
167 6 : *(cmdPtr++) = (reg >> 8*i) & 0xFF;
168 : }
169 6 : SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true);
170 : }
171 6 : }
172 :
173 226 : void Module::SPIwriteRegister(uint32_t reg, uint8_t data) {
174 226 : if(!spiConfig.stream) {
175 5 : SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, &data, NULL, 1);
176 : } else {
177 : uint8_t cmd[6];
178 221 : uint8_t* cmdPtr = cmd;
179 658 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
180 437 : *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF;
181 : }
182 447 : for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
183 226 : *(cmdPtr++) = (reg >> 8*i) & 0xFF;
184 : }
185 221 : SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true);
186 : }
187 226 : }
188 :
189 111 : void Module::SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
190 : // prepare the buffers
191 111 : size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes;
192 : #if RADIOLIB_STATIC_ONLY
193 : uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
194 : uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
195 : #else
196 111 : uint8_t* buffOut = new uint8_t[buffLen];
197 111 : uint8_t* buffIn = new uint8_t[buffLen];
198 : #endif
199 111 : uint8_t* buffOutPtr = buffOut;
200 :
201 : // copy the command
202 : // TODO properly handle variable commands and addresses
203 111 : if(this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] <= 8) {
204 111 : *(buffOutPtr++) = reg | cmd;
205 : } else {
206 0 : *(buffOutPtr++) = (reg >> 8) | cmd;
207 0 : *(buffOutPtr++) = reg & 0xFF;
208 : }
209 :
210 : // copy the data
211 111 : if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) {
212 5 : memcpy(buffOutPtr, dataOut, numBytes);
213 : } else {
214 106 : memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes);
215 : }
216 :
217 : // do the transfer
218 111 : this->hal->spiBeginTransaction();
219 111 : this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
220 111 : this->hal->spiTransfer(buffOut, buffLen, buffIn);
221 111 : this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
222 111 : this->hal->spiEndTransaction();
223 :
224 : // copy the data
225 111 : if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) {
226 106 : memcpy(dataIn, &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8], numBytes);
227 : }
228 :
229 : // print debug information
230 : #if RADIOLIB_DEBUG_SPI
231 : const uint8_t* debugBuffPtr = NULL;
232 : if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) {
233 : RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg);
234 : debugBuffPtr = &buffOut[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8];
235 : } else if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) {
236 : RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg);
237 : debugBuffPtr = &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8];
238 : }
239 : for(size_t n = 0; n < numBytes; n++) {
240 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]);
241 : }
242 : RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
243 : #endif
244 :
245 : #if !RADIOLIB_STATIC_ONLY
246 111 : delete[] buffOut;
247 111 : delete[] buffIn;
248 : #endif
249 111 : }
250 :
251 156 : int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
252 : uint8_t cmdBuf[2];
253 156 : uint8_t* cmdPtr = cmdBuf;
254 468 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
255 312 : *(cmdPtr++) = (cmd >> 8*i) & 0xFF;
256 : }
257 312 : return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
258 : }
259 :
260 156 : int16_t Module::SPIreadStream(const uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
261 : // send the command
262 156 : int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio);
263 156 : RADIOLIB_ASSERT(state);
264 :
265 : #if !RADIOLIB_SPI_PARANOID
266 : (void)verify;
267 : return(RADIOLIB_ERR_NONE);
268 : #else
269 :
270 : // check the status
271 0 : if(verify && (this->spiConfig.checkStatusCb != nullptr)) {
272 0 : state = this->spiConfig.checkStatusCb(this);
273 : }
274 :
275 0 : return(state);
276 : #endif
277 : }
278 :
279 335 : int16_t Module::SPIwriteStream(uint16_t cmd, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
280 : uint8_t cmdBuf[2];
281 335 : uint8_t* cmdPtr = cmdBuf;
282 1005 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
283 670 : *(cmdPtr++) = (cmd >> 8*i) & 0xFF;
284 : }
285 670 : return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
286 : }
287 :
288 335 : int16_t Module::SPIwriteStream(const uint8_t* cmd, uint8_t cmdLen, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
289 : // send the command
290 335 : int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio);
291 335 : RADIOLIB_ASSERT(state);
292 :
293 : #if !RADIOLIB_SPI_PARANOID
294 : (void)verify;
295 : return(RADIOLIB_ERR_NONE);
296 : #else
297 :
298 : // check the status
299 0 : if(verify && (this->spiConfig.checkStatusCb != nullptr)) {
300 0 : state = this->spiConfig.checkStatusCb(this);
301 : }
302 :
303 0 : return(state);
304 : #endif
305 : }
306 :
307 30 : int16_t Module::SPIcheckStream() {
308 30 : int16_t state = RADIOLIB_ERR_NONE;
309 :
310 : #if RADIOLIB_SPI_PARANOID
311 : // get the status
312 30 : uint8_t spiStatus = 0;
313 : uint8_t cmdBuf[2];
314 30 : uint8_t* cmdPtr = cmdBuf;
315 90 : for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
316 60 : *(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF;
317 : }
318 30 : state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true);
319 30 : RADIOLIB_ASSERT(state);
320 :
321 : // translate to RadioLib status code
322 0 : if(this->spiConfig.parseStatusCb != nullptr) {
323 0 : this->spiConfig.err = this->spiConfig.parseStatusCb(spiStatus);
324 : }
325 : #endif
326 :
327 0 : return(state);
328 : }
329 :
330 3236 : int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) {
331 : // prepare the output buffer
332 3236 : int16_t state = RADIOLIB_ERR_NONE;
333 3236 : size_t buffLen = cmdLen + numBytes;
334 3236 : if(!write) {
335 2674 : buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8);
336 : }
337 : #if RADIOLIB_STATIC_ONLY
338 : uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
339 : #else
340 3236 : uint8_t* buffOut = new uint8_t[buffLen];
341 : #endif
342 3236 : uint8_t* buffOutPtr = buffOut;
343 :
344 : // copy the command
345 12384 : for(uint8_t n = 0; n < cmdLen; n++) {
346 9148 : *(buffOutPtr++) = cmd[n];
347 : }
348 :
349 : // copy the data
350 3236 : if(write) {
351 562 : memcpy(buffOutPtr, dataOut, numBytes);
352 : } else {
353 2674 : memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8));
354 : }
355 :
356 : // ensure GPIO is low
357 3236 : if(waitForGpio) {
358 3154 : if(this->gpioPin == RADIOLIB_NC) {
359 0 : this->hal->delay(50);
360 : } else {
361 3154 : RadioLibTime_t start = this->hal->millis();
362 3154 : while(this->hal->digitalRead(this->gpioPin)) {
363 0 : this->hal->yield();
364 :
365 0 : if(this->hal->millis() >= start + this->spiConfig.timeout) {
366 : RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
367 : #if !RADIOLIB_STATIC_ONLY
368 0 : delete[] buffOut;
369 : #endif
370 0 : return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
371 : }
372 :
373 : }
374 : }
375 : }
376 :
377 : // prepare the input buffer
378 : #if RADIOLIB_STATIC_ONLY
379 : uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE];
380 : #else
381 3236 : uint8_t* buffIn = new uint8_t[buffLen];
382 : #endif
383 :
384 : // do the transfer
385 3236 : this->hal->spiBeginTransaction();
386 3236 : this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
387 3236 : this->hal->spiTransfer(buffOut, buffLen, buffIn);
388 3236 : this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
389 3236 : this->hal->spiEndTransaction();
390 :
391 : // wait for GPIO to go high and then low
392 3236 : if(waitForGpio) {
393 3154 : if(this->gpioPin == RADIOLIB_NC) {
394 0 : this->hal->delay(1);
395 : } else {
396 3154 : this->hal->delayMicroseconds(1);
397 3154 : RadioLibTime_t start = this->hal->millis();
398 3154 : while(this->hal->digitalRead(this->gpioPin)) {
399 0 : this->hal->yield();
400 :
401 0 : if(this->hal->millis() >= start + this->spiConfig.timeout) {
402 : RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?");
403 :
404 : // do not return yet to display the debug output
405 0 : state = RADIOLIB_ERR_SPI_CMD_TIMEOUT;
406 0 : break;
407 : }
408 :
409 : }
410 : }
411 : }
412 :
413 : // parse status (only if GPIO did not timeout)
414 3236 : if((state == RADIOLIB_ERR_NONE) && (this->spiConfig.parseStatusCb != nullptr) && (buffLen > this->spiConfig.statusPos)) {
415 3188 : state = this->spiConfig.parseStatusCb(buffIn[this->spiConfig.statusPos]);
416 : }
417 :
418 : // copy the data
419 3236 : if(!write) {
420 : // skip the status bytes if present
421 2674 : memcpy(dataIn, &buffIn[cmdLen + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8)], numBytes);
422 : }
423 :
424 : // print debug information
425 : #if RADIOLIB_DEBUG_SPI
426 : RADIOLIB_DEBUG_SPI_PRINTLN("LEN\t%d", buffLen);
427 : // print command byte(s)
428 : RADIOLIB_DEBUG_SPI_PRINT("CMD");
429 : if(write) {
430 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("W\t");
431 : } else {
432 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("R\t");
433 : }
434 : size_t n = 0;
435 : for(; n < cmdLen; n++) {
436 : // tab character intentionally omitted here
437 : // command is a single number so this is easier to parse
438 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X", cmd[n]);
439 : }
440 : RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
441 :
442 : // print data bytes
443 : RADIOLIB_DEBUG_SPI_PRINT("SI\t");
444 : for(n = 0; n < cmdLen; n++) {
445 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t");
446 : }
447 : // initialization of n to 0 is skipped here, because we want to skip the command bytes
448 : for(; n < buffLen; n++) {
449 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffOut[n]);
450 : }
451 : RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
452 : RADIOLIB_DEBUG_SPI_PRINT("SO\t");
453 : for(n = 0; n < buffLen; n++) {
454 : RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffIn[n]);
455 : }
456 : RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG("");
457 : // if there is enough data to evaluate the status byte, print it as well
458 : if(buffLen > this->spiConfig.statusPos) {
459 : RADIOLIB_DEBUG_SPI_PRINTLN("STAT\t%02X", buffIn[this->spiConfig.statusPos]);
460 : }
461 : #endif
462 :
463 : #if !RADIOLIB_STATIC_ONLY
464 3236 : delete[] buffOut;
465 3236 : delete[] buffIn;
466 : #endif
467 :
468 3236 : return(state);
469 : }
470 :
471 0 : void Module::waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len) {
472 : #if RADIOLIB_INTERRUPT_TIMING
473 : (void)start;
474 : if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) {
475 : prevTimingLen = len;
476 : this->TimerSetupCb(len);
477 : }
478 : this->TimerFlag = false;
479 : while(!this->TimerFlag) {
480 : this->hal->yield();
481 : }
482 : #else
483 0 : while(this->hal->micros() - start < len) {
484 0 : this->hal->yield();
485 : }
486 : #endif
487 0 : }
488 :
489 : #if RADIOLIB_DEBUG
490 : void Module::regdump(const char* level, uint16_t start, size_t len) {
491 : #if RADIOLIB_STATIC_ONLY
492 : uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE];
493 : #else
494 : uint8_t* buff = new uint8_t[len];
495 : #endif
496 : SPIreadRegisterBurst(start, len, buff);
497 : rlb_hexdump(level, buff, len, start);
498 : #if !RADIOLIB_STATIC_ONLY
499 : delete[] buff;
500 : #endif
501 : }
502 : #endif
503 :
504 0 : void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
505 : // This can be on the stack, setRfSwitchTable copies the contents
506 0 : const uint32_t pins[] = {
507 : rxEn, txEn, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC,
508 0 : };
509 :
510 : // This must be static, since setRfSwitchTable stores a reference.
511 : static const RfSwitchMode_t table[] = {
512 0 : { MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow} },
513 0 : { MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow} },
514 0 : { MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh} },
515 : END_OF_MODE_TABLE,
516 0 : };
517 0 : setRfSwitchTable(pins, table);
518 0 : }
519 :
520 0 : void Module::setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]) {
521 0 : memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins));
522 0 : this->rfSwitchTable = table;
523 0 : for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) {
524 0 : this->hal->pinMode(pins[i], this->hal->GpioModeOutput);
525 : }
526 0 : }
527 :
528 154 : const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const {
529 154 : const RfSwitchMode_t *row = this->rfSwitchTable;
530 154 : while(row && row->mode != MODE_END_OF_TABLE) {
531 0 : if(row->mode == mode) {
532 0 : return row;
533 : }
534 0 : ++row;
535 : }
536 154 : return nullptr;
537 : }
538 :
539 154 : void Module::setRfSwitchState(uint8_t mode) {
540 154 : const RfSwitchMode_t *row = findRfSwitchMode(mode);
541 154 : if(!row) {
542 : // RF switch control is disabled or does not have this mode
543 154 : return;
544 : }
545 :
546 : // set pins
547 0 : const uint32_t *value = &row->values[0];
548 0 : for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) {
549 0 : uint32_t pin = this->rfSwitchPins[i];
550 0 : if(!(pin & RFSWITCH_PIN_FLAG)) {
551 0 : this->hal->digitalWrite(pin, *value);
552 : }
553 0 : ++value;
554 : }
555 : }
|