#include "Module.h" #if defined(RADIOLIB_BUILD_ARDUINO) Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { _spi = &RADIOLIB_DEFAULT_SPI; _initInterface = true; // this is Arduino build, pre-set callbacks setCb_pinMode(::pinMode); setCb_digitalRead(::digitalRead); setCb_digitalWrite(::digitalWrite); #if !defined(RADIOLIB_TONE_UNSUPPORTED) setCb_tone(::tone); setCb_noTone(::noTone); #endif setCb_attachInterrupt(::attachInterrupt); setCb_detachInterrupt(::detachInterrupt); #if !defined(RADIOLIB_YIELD_UNSUPPORTED) setCb_yield(::yield); #endif setCb_delay(::delay); setCb_delayMicroseconds(::delayMicroseconds); setCb_millis(::millis); setCb_micros(::micros); setCb_SPIbegin(&Module::SPIbegin); setCb_SPIbeginTransaction(&Module::beginTransaction); setCb_SPItransfer(&Module::transfer); setCb_SPIendTransaction(&Module::endTransaction); setCb_SPIend(&Module::end); } Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings): _cs(cs), _irq(irq), _rst(rst), _gpio(gpio), _spiSettings(spiSettings) { _spi = &spi; _initInterface = false; // this is Arduino build, pre-set callbacks setCb_pinMode(::pinMode); setCb_digitalRead(::digitalRead); setCb_digitalWrite(::digitalWrite); #if !defined(RADIOLIB_TONE_UNSUPPORTED) setCb_tone(::tone); setCb_noTone(::noTone); #endif setCb_attachInterrupt(::attachInterrupt); setCb_detachInterrupt(::detachInterrupt); #if !defined(RADIOLIB_YIELD_UNSUPPORTED) setCb_yield(::yield); #endif setCb_delay(::delay); setCb_delayMicroseconds(::delayMicroseconds); setCb_millis(::millis); setCb_micros(::micros); setCb_SPIbegin(&Module::SPIbegin); setCb_SPIbeginTransaction(&Module::beginTransaction); setCb_SPItransfer(&Module::transfer); setCb_SPIendTransaction(&Module::endTransaction); setCb_SPIend(&Module::end); } #else Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { // not an Arduino build, it's up to the user to set all callbacks } #endif Module::Module(const Module& mod) { *this = mod; } Module& Module::operator=(const Module& mod) { this->SPIreadCommand = mod.SPIreadCommand; this->SPIwriteCommand = mod.SPIwriteCommand; this->_cs = mod.getCs(); this->_irq = mod.getIrq(); this->_rst = mod.getRst(); this->_gpio = mod.getGpio(); return(*this); } void Module::init() { this->pinMode(_cs, OUTPUT); this->digitalWrite(_cs, HIGH); if(_initInterface) { (this->*cb_SPIbegin)(); } } void Module::term() { // stop hardware interfaces (if they were initialized by the library) if(!_initInterface) { return; } if(_spi != nullptr) { this->SPIend(); } } int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } uint8_t rawValue = SPIreadRegister(reg); uint8_t maskedValue = rawValue & ((0b11111111 << lsb) & (0b11111111 >> (7 - msb))); return(maskedValue); } int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } uint8_t currentValue = SPIreadRegister(reg); uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb))); uint8_t newValue = (currentValue & ~mask) | (value & mask); SPIwriteRegister(reg, newValue); #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) uint32_t start = this->micros(); uint8_t readValue = 0x00; while(this->micros() - start < (checkInterval * 1000)) { readValue = SPIreadRegister(reg); if((readValue & checkMask) == (newValue & checkMask)) { // check passed, we can stop the loop return(RADIOLIB_ERR_NONE); } } // check failed, print debug info RADIOLIB_DEBUG_PRINTLN(); RADIOLIB_DEBUG_PRINT(F("address:\t0x")); RADIOLIB_DEBUG_PRINTLN(reg, HEX); RADIOLIB_DEBUG_PRINT(F("bits:\t\t")); RADIOLIB_DEBUG_PRINT(msb); RADIOLIB_DEBUG_PRINT(' '); RADIOLIB_DEBUG_PRINTLN(lsb); RADIOLIB_DEBUG_PRINT(F("value:\t\t0b")); RADIOLIB_DEBUG_PRINTLN(value, BIN); RADIOLIB_DEBUG_PRINT(F("current:\t0b")); RADIOLIB_DEBUG_PRINTLN(currentValue, BIN); RADIOLIB_DEBUG_PRINT(F("mask:\t\t0b")); RADIOLIB_DEBUG_PRINTLN(mask, BIN); RADIOLIB_DEBUG_PRINT(F("new:\t\t0b")); RADIOLIB_DEBUG_PRINTLN(newValue, BIN); RADIOLIB_DEBUG_PRINT(F("read:\t\t0b")); RADIOLIB_DEBUG_PRINTLN(readValue, BIN); RADIOLIB_DEBUG_PRINTLN(); return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else return(RADIOLIB_ERR_NONE); #endif } void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); } uint8_t Module::SPIreadRegister(uint8_t reg) { uint8_t resp = 0; SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); return(resp); } void Module::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes) { SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); } void Module::SPIwriteRegister(uint8_t reg, uint8_t data) { SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); } void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start SPI transaction this->SPIbeginTransaction(); // pull CS low this->digitalWrite(_cs, LOW); // send SPI register address with access command this->SPItransfer(reg | cmd); #if defined(RADIOLIB_VERBOSE) if(cmd == SPIwriteCommand) { RADIOLIB_VERBOSE_PRINT('W'); } else if(cmd == SPIreadCommand) { RADIOLIB_VERBOSE_PRINT('R'); } RADIOLIB_VERBOSE_PRINT('\t') RADIOLIB_VERBOSE_PRINT(reg, HEX); RADIOLIB_VERBOSE_PRINT('\t'); #endif // send data or get response if(cmd == SPIwriteCommand) { if(dataOut != NULL) { for(size_t n = 0; n < numBytes; n++) { this->SPItransfer(dataOut[n]); RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } } } else if (cmd == SPIreadCommand) { if(dataIn != NULL) { for(size_t n = 0; n < numBytes; n++) { dataIn[n] = this->SPItransfer(0x00); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } } } RADIOLIB_VERBOSE_PRINTLN(); // release CS this->digitalWrite(_cs, HIGH); // end SPI transaction this->SPIendTransaction(); } void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) { if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) { return; } cb_pinMode(pin, mode); } void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) { if((pin == RADIOLIB_NC) || (cb_digitalWrite == nullptr)) { return; } cb_digitalWrite(pin, value); } RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { if((pin == RADIOLIB_NC) || (cb_digitalRead == nullptr)) { return((RADIOLIB_PIN_STATUS)0); } return(cb_digitalRead(pin)); } void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) { return; } cb_tone(pin, value, duration); #else if(pin == RADIOLIB_NC) { return; } #if defined(ESP32) // ESP32 tone() emulation ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); #else (void)value; (void)duration; #endif #endif } void Module::noTone(RADIOLIB_PIN_TYPE pin) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if((pin == RADIOLIB_NC) || (cb_noTone == nullptr)) { return; } #if defined(ARDUINO_ARCH_STM32) cb_noTone(pin, false); #else cb_noTone(pin); #endif #else if(pin == RADIOLIB_NC) { return; } #if defined(ESP32) // ESP32 tone() emulation ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); #endif #endif } void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) { if((interruptNum == RADIOLIB_NC) || (cb_attachInterrupt == nullptr)) { return; } cb_attachInterrupt(interruptNum, userFunc, mode); } void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { if((interruptNum == RADIOLIB_NC) || (cb_detachInterrupt == nullptr)) { return; } cb_detachInterrupt(interruptNum); } void Module::yield() { if(cb_yield == nullptr) { return; } #if !defined(RADIOLIB_YIELD_UNSUPPORTED) cb_yield(); #endif } void Module::delay(uint32_t ms) { if(cb_delay == nullptr) { return; } cb_delay(ms); } void Module::delayMicroseconds(uint32_t us) { if(cb_delayMicroseconds == nullptr) { return; } cb_delayMicroseconds(us); } uint32_t Module::millis() { if(cb_millis == nullptr) { return(0); } return(cb_millis()); } uint32_t Module::micros() { if(cb_micros == nullptr) { return(0); } return(cb_micros()); } void Module::begin() { if(cb_SPIbegin == nullptr) { return; } (this->*cb_SPIbegin)(); } void Module::beginTransaction() { if(cb_SPIbeginTransaction == nullptr) { return; } (this->*cb_SPIbeginTransaction)(); } uint8_t Module::transfer(uint8_t b) { if(cb_SPItransfer == nullptr) { return(0xFF); } return((this->*cb_SPItransfer)(b)); } void Module::endTransaction() { if(cb_SPIendTransaction == nullptr) { return; } (this->*cb_SPIendTransaction)(); } void Module::end() { if(cb_SPIend == nullptr) { return; } (this->*cb_SPIend)(); } #if defined(RADIOLIB_BUILD_ARDUINO) void Module::SPIbegin() { _spi->begin(); } void Module::SPIbeginTransaction() { _spi->beginTransaction(_spiSettings); } uint8_t Module::SPItransfer(uint8_t b) { return(_spi->transfer(b)); } void Module::SPIendTransaction() { _spi->endTransaction(); } void Module::SPIend() { _spi->end(); } #endif 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; } void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _useRfSwitch = true; _rxEn = rxEn; _txEn = txEn; this->pinMode(rxEn, OUTPUT); this->pinMode(txEn, OUTPUT); } void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { // check RF switch control is enabled if(!_useRfSwitch) { return; } // set pins this->digitalWrite(_rxEn, rxPinState); this->digitalWrite(_txEn, txPinState); }