2023-04-22 16:11:00 +00:00
|
|
|
#include "Module.h"
|
|
|
|
|
|
|
|
|
|
// the following is probably only needed on non-Arduino builds
|
2023-04-11 02:51:29 +00:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2018-03-05 16:08:42 +00:00
|
|
|
|
2023-04-22 18:19:36 +00:00
|
|
|
#if defined(RADIOLIB_DEBUG)
|
|
|
|
|
// needed for debug print
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-11-14 10:33:35 +00:00
|
|
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
2023-04-11 02:51:29 +00:00
|
|
|
#include "ArduinoHal.h"
|
2023-04-22 18:19:36 +00:00
|
|
|
|
2023-04-22 16:50:12 +00:00
|
|
|
Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
|
2023-04-22 16:11:00 +00:00
|
|
|
this->hal = new ArduinoHal();
|
2018-07-11 16:15:54 +00:00
|
|
|
}
|
|
|
|
|
|
2023-04-22 16:50:12 +00:00
|
|
|
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) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal = new ArduinoHal(spi, spiSettings);
|
2021-11-14 10:33:35 +00:00
|
|
|
}
|
2019-09-07 13:30:57 +00:00
|
|
|
#endif
|
2018-03-05 16:08:42 +00:00
|
|
|
|
2023-04-22 16:50:12 +00:00
|
|
|
Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal = hal;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-05 08:05:54 +00:00
|
|
|
Module::Module(const Module& mod) {
|
|
|
|
|
*this = mod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Module& Module::operator=(const Module& mod) {
|
|
|
|
|
this->SPIreadCommand = mod.SPIreadCommand;
|
|
|
|
|
this->SPIwriteCommand = mod.SPIwriteCommand;
|
2023-04-22 16:50:12 +00:00
|
|
|
this->csPin = mod.csPin;
|
|
|
|
|
this->irqPin = mod.irqPin;
|
|
|
|
|
this->rstPin = mod.rstPin;
|
|
|
|
|
this->gpioPin = mod.gpioPin;
|
2020-07-05 08:05:54 +00:00
|
|
|
return(*this);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-14 10:33:35 +00:00
|
|
|
void Module::init() {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->init();
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->pinMode(csPin, this->hal->GpioModeOutput);
|
|
|
|
|
this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh);
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-14 10:33:35 +00:00
|
|
|
void Module::term() {
|
2020-05-12 14:00:13 +00:00
|
|
|
// stop hardware interfaces (if they were initialized by the library)
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->term();
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-19 11:41:49 +00:00
|
|
|
int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) {
|
2018-03-05 16:08:42 +00:00
|
|
|
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
|
2021-11-14 10:33:35 +00:00
|
|
|
return(RADIOLIB_ERR_INVALID_BIT_RANGE);
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2018-03-05 16:08:42 +00:00
|
|
|
uint8_t rawValue = SPIreadRegister(reg);
|
|
|
|
|
uint8_t maskedValue = rawValue & ((0b11111111 << lsb) & (0b11111111 >> (7 - msb)));
|
|
|
|
|
return(maskedValue);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 11:41:49 +00:00
|
|
|
int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) {
|
2018-07-23 09:19:34 +00:00
|
|
|
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
|
2021-11-14 10:33:35 +00:00
|
|
|
return(RADIOLIB_ERR_INVALID_BIT_RANGE);
|
2018-07-23 09:19:34 +00:00
|
|
|
}
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2018-07-23 09:19:34 +00:00
|
|
|
uint8_t currentValue = SPIreadRegister(reg);
|
|
|
|
|
uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb)));
|
|
|
|
|
uint8_t newValue = (currentValue & ~mask) | (value & mask);
|
|
|
|
|
SPIwriteRegister(reg, newValue);
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2021-02-12 20:03:49 +00:00
|
|
|
#if defined(RADIOLIB_SPI_PARANOID)
|
|
|
|
|
// check register value each millisecond until check interval is reached
|
|
|
|
|
// some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE)
|
2023-04-11 02:51:29 +00:00
|
|
|
uint32_t start = this->hal->micros();
|
2021-02-12 20:03:49 +00:00
|
|
|
uint8_t readValue = 0x00;
|
2023-04-11 02:51:29 +00:00
|
|
|
while(this->hal->micros() - start < (checkInterval * 1000)) {
|
2021-02-12 20:03:49 +00:00
|
|
|
readValue = SPIreadRegister(reg);
|
2021-04-15 17:34:53 +00:00
|
|
|
if((readValue & checkMask) == (newValue & checkMask)) {
|
2021-02-12 20:03:49 +00:00
|
|
|
// check passed, we can stop the loop
|
2021-11-14 10:33:35 +00:00
|
|
|
return(RADIOLIB_ERR_NONE);
|
2021-02-12 20:03:49 +00:00
|
|
|
}
|
2018-10-31 16:44:47 +00:00
|
|
|
}
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2021-02-12 20:03:49 +00:00
|
|
|
// check failed, print debug info
|
|
|
|
|
RADIOLIB_DEBUG_PRINTLN();
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg);
|
|
|
|
|
RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb);
|
2023-04-12 16:43:43 +00:00
|
|
|
RADIOLIB_DEBUG_PRINT("value:\t\t0x%X", value);
|
|
|
|
|
RADIOLIB_DEBUG_PRINT("current:\t0x%X", currentValue);
|
|
|
|
|
RADIOLIB_DEBUG_PRINT("mask:\t\t0x%X", mask);
|
|
|
|
|
RADIOLIB_DEBUG_PRINT("new:\t\t0x%X", newValue);
|
2023-04-12 16:44:12 +00:00
|
|
|
RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue);
|
2021-02-12 20:03:49 +00:00
|
|
|
|
2021-11-14 10:33:35 +00:00
|
|
|
return(RADIOLIB_ERR_SPI_WRITE_FAILED);
|
2021-02-12 20:03:49 +00:00
|
|
|
#else
|
2021-11-14 10:33:35 +00:00
|
|
|
return(RADIOLIB_ERR_NONE);
|
2021-02-12 20:03:49 +00:00
|
|
|
#endif
|
2018-07-23 09:19:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) {
|
2023-02-19 13:22:30 +00:00
|
|
|
if(!SPIstreamType) {
|
|
|
|
|
SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes);
|
|
|
|
|
} else {
|
|
|
|
|
uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
|
|
|
|
|
SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, 5000);
|
|
|
|
|
}
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-19 11:41:49 +00:00
|
|
|
uint8_t Module::SPIreadRegister(uint16_t reg) {
|
2019-11-23 09:10:53 +00:00
|
|
|
uint8_t resp = 0;
|
2023-02-19 13:22:30 +00:00
|
|
|
if(!SPIstreamType) {
|
|
|
|
|
SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
|
|
|
|
|
} else {
|
|
|
|
|
uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
|
|
|
|
|
SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, 5000);
|
|
|
|
|
}
|
2019-03-22 18:01:56 +00:00
|
|
|
return(resp);
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) {
|
2023-02-19 13:22:30 +00:00
|
|
|
if(!SPIstreamType) {
|
|
|
|
|
SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes);
|
|
|
|
|
} else {
|
|
|
|
|
uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
|
|
|
|
|
SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, 5000);
|
|
|
|
|
}
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-19 11:41:49 +00:00
|
|
|
void Module::SPIwriteRegister(uint16_t reg, uint8_t data) {
|
2023-02-19 13:22:30 +00:00
|
|
|
if(!SPIstreamType) {
|
|
|
|
|
SPItransfer(SPIwriteCommand, reg, &data, NULL, 1);
|
|
|
|
|
} else {
|
|
|
|
|
uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
|
|
|
|
|
SPItransferStream(cmd, 3, true, &data, NULL, 1, true, 5000);
|
|
|
|
|
}
|
2019-03-22 18:01:56 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
|
2019-03-22 18:01:56 +00:00
|
|
|
// start SPI transaction
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiBeginTransaction();
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2019-03-22 18:01:56 +00:00
|
|
|
// pull CS low
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2019-03-22 18:01:56 +00:00
|
|
|
// send SPI register address with access command
|
2023-02-19 11:41:49 +00:00
|
|
|
if(this->SPIaddrWidth <= 8) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiTransfer(reg | cmd);
|
2023-02-19 11:41:49 +00:00
|
|
|
} else {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiTransfer((reg >> 8) | cmd);
|
|
|
|
|
this->hal->spiTransfer(reg & 0xFF);
|
2023-02-19 11:41:49 +00:00
|
|
|
}
|
2023-02-19 13:22:30 +00:00
|
|
|
|
2021-11-14 10:33:35 +00:00
|
|
|
#if defined(RADIOLIB_VERBOSE)
|
2020-01-06 16:20:18 +00:00
|
|
|
if(cmd == SPIwriteCommand) {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("W");
|
2020-01-06 16:20:18 +00:00
|
|
|
} else if(cmd == SPIreadCommand) {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("R");
|
2020-01-06 16:20:18 +00:00
|
|
|
}
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("\t%X\t", reg);
|
2020-01-06 16:20:18 +00:00
|
|
|
#endif
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2019-03-22 18:01:56 +00:00
|
|
|
// send data or get response
|
|
|
|
|
if(cmd == SPIwriteCommand) {
|
2020-07-04 11:43:39 +00:00
|
|
|
if(dataOut != NULL) {
|
|
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiTransfer(dataOut[n]);
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]);
|
2020-07-04 11:43:39 +00:00
|
|
|
}
|
2019-03-22 18:01:56 +00:00
|
|
|
}
|
|
|
|
|
} else if (cmd == SPIreadCommand) {
|
2020-07-04 11:43:39 +00:00
|
|
|
if(dataIn != NULL) {
|
|
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-04-11 02:51:29 +00:00
|
|
|
dataIn[n] = this->hal->spiTransfer(0x00);
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]);
|
2020-07-04 11:43:39 +00:00
|
|
|
}
|
2019-03-22 18:01:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-28 08:30:50 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINTLN();
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2019-03-22 18:01:56 +00:00
|
|
|
// release CS
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
|
2019-05-13 13:03:09 +00:00
|
|
|
|
2019-03-22 18:01:56 +00:00
|
|
|
// end SPI transaction
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiEndTransaction();
|
2018-03-05 16:08:42 +00:00
|
|
|
}
|
2019-12-01 07:12:04 +00:00
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
|
2023-02-19 15:59:03 +00:00
|
|
|
return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify));
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
|
2023-02-19 15:59:03 +00:00
|
|
|
// send the command
|
|
|
|
|
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, 5000);
|
|
|
|
|
RADIOLIB_ASSERT(state);
|
|
|
|
|
|
|
|
|
|
// check the status
|
|
|
|
|
if(verify) {
|
|
|
|
|
state = this->SPIcheckStream();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(state);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
|
2023-02-19 15:59:03 +00:00
|
|
|
return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify));
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
|
2023-02-19 15:59:03 +00:00
|
|
|
// send the command
|
|
|
|
|
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, 5000);
|
|
|
|
|
RADIOLIB_ASSERT(state);
|
|
|
|
|
|
|
|
|
|
// check the status
|
|
|
|
|
if(verify) {
|
|
|
|
|
state = this->SPIcheckStream();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int16_t Module::SPIcheckStream() {
|
|
|
|
|
int16_t state = RADIOLIB_ERR_NONE;
|
|
|
|
|
|
|
|
|
|
#if defined(RADIOLIB_SPI_PARANOID)
|
|
|
|
|
// get the status
|
|
|
|
|
uint8_t spiStatus = 0;
|
|
|
|
|
uint8_t cmd = this->SPIstatusCommand;
|
|
|
|
|
state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000);
|
|
|
|
|
RADIOLIB_ASSERT(state);
|
|
|
|
|
|
|
|
|
|
// translate to RadioLib status code
|
|
|
|
|
if(this->SPIparseStatusCb != nullptr) {
|
|
|
|
|
this->SPIstreamError = this->SPIparseStatusCb(spiStatus);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return(state);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) {
|
2023-02-19 11:32:17 +00:00
|
|
|
#if defined(RADIOLIB_VERBOSE)
|
|
|
|
|
uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ensure GPIO is low
|
2023-04-11 02:51:29 +00:00
|
|
|
uint32_t start = this->hal->millis();
|
2023-04-22 16:50:12 +00:00
|
|
|
while(this->hal->digitalRead(this->gpioPin)) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->yield();
|
|
|
|
|
if(this->hal->millis() - start >= timeout) {
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
|
2023-04-24 16:25:09 +00:00
|
|
|
RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?");
|
2023-02-19 11:32:17 +00:00
|
|
|
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 21:17:34 +00:00
|
|
|
// pull NSS low
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
|
2023-03-30 21:17:34 +00:00
|
|
|
|
2023-02-19 11:32:17 +00:00
|
|
|
// start transfer
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiBeginTransaction();
|
2023-02-19 11:32:17 +00:00
|
|
|
|
|
|
|
|
// send command byte(s)
|
|
|
|
|
for(uint8_t n = 0; n < cmdLen; n++) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiTransfer(cmd[n]);
|
2023-02-19 11:32:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// variable to save error during SPI transfer
|
|
|
|
|
int16_t state = RADIOLIB_ERR_NONE;
|
|
|
|
|
|
|
|
|
|
// send/receive all bytes
|
|
|
|
|
if(write) {
|
2023-02-25 12:20:30 +00:00
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-02-19 11:32:17 +00:00
|
|
|
// send byte
|
2023-04-11 02:51:29 +00:00
|
|
|
uint8_t in = this->hal->spiTransfer(dataOut[n]);
|
2023-02-19 11:32:17 +00:00
|
|
|
#if defined(RADIOLIB_VERBOSE)
|
|
|
|
|
debugBuff[n] = in;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// check status
|
|
|
|
|
if(this->SPIparseStatusCb != nullptr) {
|
|
|
|
|
state = this->SPIparseStatusCb(in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// skip the first byte for read-type commands (status-only)
|
2023-04-11 02:51:29 +00:00
|
|
|
uint8_t in = this->hal->spiTransfer(this->SPInopCommand);
|
2023-02-19 11:32:17 +00:00
|
|
|
#if defined(RADIOLIB_VERBOSE)
|
|
|
|
|
debugBuff[0] = in;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// check status
|
|
|
|
|
if(this->SPIparseStatusCb != nullptr) {
|
|
|
|
|
state = this->SPIparseStatusCb(in);
|
|
|
|
|
} else {
|
|
|
|
|
state = RADIOLIB_ERR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read the data
|
|
|
|
|
if(state == RADIOLIB_ERR_NONE) {
|
2023-02-25 12:20:30 +00:00
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-04-11 02:51:29 +00:00
|
|
|
dataIn[n] = this->hal->spiTransfer(this->SPInopCommand);
|
2023-02-19 11:32:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stop transfer
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->spiEndTransaction();
|
2023-04-22 16:50:12 +00:00
|
|
|
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
|
2023-02-19 11:32:17 +00:00
|
|
|
|
|
|
|
|
// wait for GPIO to go high and then low
|
|
|
|
|
if(waitForGpio) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->delayMicroseconds(1);
|
|
|
|
|
uint32_t start = this->hal->millis();
|
2023-04-22 16:50:12 +00:00
|
|
|
while(this->hal->digitalRead(this->gpioPin)) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->yield();
|
|
|
|
|
if(this->hal->millis() - start >= timeout) {
|
2023-02-19 11:32:17 +00:00
|
|
|
state = RADIOLIB_ERR_SPI_CMD_TIMEOUT;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// print debug output
|
|
|
|
|
#if defined(RADIOLIB_VERBOSE)
|
|
|
|
|
// print command byte(s)
|
|
|
|
|
RADIOLIB_VERBOSE_PRINT("CMD\t");
|
|
|
|
|
for(uint8_t n = 0; n < cmdLen; n++) {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]);
|
2023-02-19 11:32:17 +00:00
|
|
|
}
|
|
|
|
|
RADIOLIB_VERBOSE_PRINTLN();
|
|
|
|
|
|
|
|
|
|
// print data bytes
|
|
|
|
|
RADIOLIB_VERBOSE_PRINT("DAT");
|
|
|
|
|
if(write) {
|
|
|
|
|
RADIOLIB_VERBOSE_PRINT("W\t");
|
2023-02-25 12:20:30 +00:00
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]);
|
2023-02-19 11:32:17 +00:00
|
|
|
}
|
|
|
|
|
RADIOLIB_VERBOSE_PRINTLN();
|
|
|
|
|
} else {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]);
|
2023-02-19 11:32:17 +00:00
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
for(size_t n = 0; n < numBytes; n++) {
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]);
|
2023-02-19 11:32:17 +00:00
|
|
|
}
|
|
|
|
|
RADIOLIB_VERBOSE_PRINTLN();
|
|
|
|
|
}
|
|
|
|
|
RADIOLIB_VERBOSE_PRINTLN();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return(state);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 16:03:34 +00:00
|
|
|
void Module::waitForMicroseconds(uint32_t start, uint32_t len) {
|
|
|
|
|
#if defined(RADIOLIB_INTERRUPT_TIMING)
|
|
|
|
|
(void)start;
|
2023-04-22 16:50:12 +00:00
|
|
|
if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) {
|
2022-11-18 16:03:34 +00:00
|
|
|
_prevTimingLen = len;
|
|
|
|
|
this->TimerSetupCb(len);
|
|
|
|
|
}
|
|
|
|
|
this->TimerFlag = false;
|
|
|
|
|
while(!this->TimerFlag) {
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->yield();
|
2021-11-14 10:33:35 +00:00
|
|
|
}
|
2023-04-10 07:06:40 +00:00
|
|
|
#else
|
2023-04-11 02:51:29 +00:00
|
|
|
while(this->hal->micros() - start < len) {
|
|
|
|
|
this->hal->yield();
|
2021-11-14 10:33:35 +00:00
|
|
|
}
|
2023-04-10 07:06:40 +00:00
|
|
|
#endif
|
2021-11-14 10:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-14 18:59:16 +00:00
|
|
|
uint8_t Module::flipBits(uint8_t b) {
|
|
|
|
|
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
|
|
|
|
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
|
|
|
|
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t Module::flipBits16(uint16_t i) {
|
|
|
|
|
i = (i & 0xFF00) >> 8 | (i & 0x00FF) << 8;
|
|
|
|
|
i = (i & 0xF0F0) >> 4 | (i & 0x0F0F) << 4;
|
|
|
|
|
i = (i & 0xCCCC) >> 2 | (i & 0x3333) << 2;
|
|
|
|
|
i = (i & 0xAAAA) >> 1 | (i & 0x5555) << 1;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) {
|
2022-08-18 18:48:51 +00:00
|
|
|
size_t rem_len = len;
|
2023-03-05 18:14:14 +00:00
|
|
|
for(size_t i = 0; i < len; i+=16) {
|
2022-07-03 09:05:56 +00:00
|
|
|
char str[80];
|
2023-03-01 20:50:40 +00:00
|
|
|
sprintf(str, "%07" PRIx32 " ", i+offset);
|
2022-08-18 18:48:51 +00:00
|
|
|
size_t line_len = 16;
|
|
|
|
|
if(rem_len < line_len) {
|
|
|
|
|
line_len = rem_len;
|
|
|
|
|
}
|
2023-03-05 18:14:14 +00:00
|
|
|
for(size_t j = 0; j < line_len; j+=width) {
|
2023-02-25 12:20:30 +00:00
|
|
|
if(width > 1) {
|
|
|
|
|
int m = 0;
|
|
|
|
|
int step = width/2;
|
|
|
|
|
if(be) {
|
|
|
|
|
step *= -1;
|
|
|
|
|
}
|
|
|
|
|
for(int32_t k = width - 1; k >= -width + 1; k+=step) {
|
|
|
|
|
sprintf(&str[8 + (j+m)*3], "%02x ", data[i+j+k+m]);
|
|
|
|
|
m++;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(&str[8 + (j)*3], "%02x ", data[i+j]);
|
|
|
|
|
}
|
2022-07-03 09:05:56 +00:00
|
|
|
}
|
2022-09-18 14:20:16 +00:00
|
|
|
for(size_t j = line_len; j < 16; j++) {
|
2022-08-18 18:48:51 +00:00
|
|
|
sprintf(&str[8 + j*3], " ");
|
|
|
|
|
}
|
2022-07-03 09:05:56 +00:00
|
|
|
str[56] = '|';
|
|
|
|
|
str[57] = ' ';
|
2022-09-18 14:20:16 +00:00
|
|
|
for(size_t j = 0; j < line_len; j++) {
|
2022-07-03 09:05:56 +00:00
|
|
|
char c = data[i+j];
|
|
|
|
|
if((c < ' ') || (c > '~')) {
|
|
|
|
|
c = '.';
|
|
|
|
|
}
|
|
|
|
|
sprintf(&str[58 + j], "%c", c);
|
|
|
|
|
}
|
2022-09-18 14:20:16 +00:00
|
|
|
for(size_t j = line_len; j < 16; j++) {
|
2022-08-18 18:48:51 +00:00
|
|
|
sprintf(&str[58 + j], " ");
|
|
|
|
|
}
|
2023-04-09 21:47:44 +00:00
|
|
|
RADIOLIB_DEBUG_PRINT(str);
|
|
|
|
|
RADIOLIB_DEBUG_PRINTLN();
|
2022-08-18 18:48:51 +00:00
|
|
|
rem_len -= 16;
|
2022-07-03 09:05:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-25 12:20:30 +00:00
|
|
|
void Module::regdump(uint16_t start, size_t len) {
|
2022-07-04 13:30:37 +00:00
|
|
|
#if defined(RADIOLIB_STATIC_ONLY)
|
|
|
|
|
uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE];
|
|
|
|
|
#else
|
|
|
|
|
uint8_t* buff = new uint8_t[len];
|
|
|
|
|
#endif
|
|
|
|
|
SPIreadRegisterBurst(start, len, buff);
|
2023-02-25 12:20:30 +00:00
|
|
|
hexdump(buff, len, start);
|
2022-07-04 13:30:37 +00:00
|
|
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
|
|
|
|
delete[] buff;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 12:51:07 +00:00
|
|
|
#if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO)
|
|
|
|
|
// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50
|
|
|
|
|
size_t Module::serialPrintf(const char* format, ...) {
|
|
|
|
|
va_list arg;
|
|
|
|
|
va_start(arg, format);
|
|
|
|
|
char temp[64];
|
|
|
|
|
char* buffer = temp;
|
|
|
|
|
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
if (len > sizeof(temp) - 1) {
|
|
|
|
|
buffer = new char[len + 1];
|
|
|
|
|
if (!buffer) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
va_start(arg, format);
|
|
|
|
|
vsnprintf(buffer, len + 1, format, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
}
|
|
|
|
|
len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len);
|
|
|
|
|
if (buffer != temp) {
|
|
|
|
|
delete[] buffer;
|
|
|
|
|
}
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-04-16 19:39:00 +00:00
|
|
|
void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
// This can be on the stack, setRfSwitchTable copies the contents
|
2023-04-16 19:39:00 +00:00
|
|
|
const uint32_t pins[] = {
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
rxEn, txEn, RADIOLIB_NC,
|
|
|
|
|
};
|
2023-04-22 16:50:12 +00:00
|
|
|
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
// This must be static, since setRfSwitchTable stores a reference.
|
2023-04-11 02:51:29 +00:00
|
|
|
static const RfSwitchMode_t table[] = {
|
2023-04-22 16:50:12 +00:00
|
|
|
{ MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow} },
|
|
|
|
|
{ MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow} },
|
|
|
|
|
{ MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh} },
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
END_OF_MODE_TABLE,
|
|
|
|
|
};
|
|
|
|
|
setRfSwitchTable(pins, table);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-16 19:39:00 +00:00
|
|
|
void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) {
|
2023-04-22 16:50:12 +00:00
|
|
|
memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins));
|
|
|
|
|
this->rfSwitchTable = table;
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++)
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->pinMode(pins[i], this->hal->GpioModeOutput);
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const {
|
2023-04-22 16:50:12 +00:00
|
|
|
const RfSwitchMode_t *row = this->rfSwitchTable;
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
while (row && row->mode != MODE_END_OF_TABLE) {
|
|
|
|
|
if (row->mode == mode)
|
|
|
|
|
return row;
|
|
|
|
|
++row;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
2020-06-18 14:31:38 +00:00
|
|
|
}
|
|
|
|
|
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
void Module::setRfSwitchState(uint8_t mode) {
|
|
|
|
|
const RfSwitchMode_t *row = findRfSwitchMode(mode);
|
|
|
|
|
if(!row) {
|
|
|
|
|
// RF switch control is disabled or does not have this mode
|
2020-06-18 14:31:38 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set pins
|
2023-04-16 19:39:00 +00:00
|
|
|
const uint32_t *value = &row->values[0];
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) {
|
2023-04-22 16:50:12 +00:00
|
|
|
uint32_t pin = this->rfSwitchPins[i];
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
if (pin != RADIOLIB_NC)
|
2023-04-11 02:51:29 +00:00
|
|
|
this->hal->digitalWrite(pin, *value);
|
[MOD] Generalize rfswitch pin handling
This defines operation modes (IDLE, RX and TX) and allows defining up to
to three pins to be controlled. For each mode a value can be specified
for each pin a table.
Compared to the previous handling, this:
- Allows up to three pins instead of only two.
- Gives more control over output pin values (e.g. to simply change
polarity or support more complex control logic).
In addition, the modes are treated as opaque by the Module code,
allowing radio classes to define their own modes if needed.
Some notes regarding the implementation:
- The number of pins is limited at three, since most boards seem to need
only two pins and only the Nucleo STM32WL55 board needs three. If
more pins are needed in the future, the setRfSwitchTable()
can be overloaded to accept either a 3-element or e.g. 4-element pins
array, to allow new and old code to work as-is.
Note that there is a RFSWITCH_MAX_PINS constant defined, but it is
not recommended for sketches to use this constant when defining
a rfswitch pins array, to prevent issues when this value is ever
increased and such an array gets extra zero elements (that will be
interpreted as pin 0).
Note that this is not a problem for the RfSwitchMode_t values array,
since any extra values in there will only be used if a valid pin was
set in the pins array.
- The pins array is passed by reference, so the compiler complains if
the array passed is not the expected size. Since a reference to an
array without a length is not supported (at least not by the gcc
7 used by the AVR core - gcc 10 for STM32 seems to accept it), the
table array is passed as a pointer instead (but because arrays and
pointers are reasonably interchangeable, the caller does not see the
difference).
- The existing setRfSwitchPins() method is still supported as before.
Internally it creates a table with the right values and pins and
passes those to setRfSwitchTable.
- For easier review, this commit does not modify all calls to
setRfSwitchState() in all radio modules yet, but has a compatibility
wrapper to delay this change until the next commit. Similarly, the
setRfSwitchTable() method is now defined on Module only, a wrapper
for it will be defined in all radios that already have the
setRfSwitchPins() wrapper in another commit.
- To allow future radios to define any number of modes, the modes table
does not have a fixed length, but instead is terminated by a special
value. This is a bit fragile (if the terminator is omitted, the code
will read past the end of the array), but rather flexible. One
alternative to this approach would be to make setRfSwitchTable
a template that deduces the array size from a template argument and
then stores the size explicitly, but using templates probably reduces
code clarity.
2022-12-06 16:52:18 +00:00
|
|
|
++value;
|
|
|
|
|
}
|
2020-06-18 14:31:38 +00:00
|
|
|
}
|