RadioLibSmol/src/modules/SX127x.cpp
2018-12-26 11:36:30 +01:00

1187 lines
32 KiB
C++

#include "SX127x.h"
SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT) {
_mod = mod;
}
int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
DEBUG_PRINTLN_STR("No SX127x found!");
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN_STR("Found SX127x!");
}
// check active modem
int16_t state;
if(getActiveModem() != SX127X_LORA) {
// set LoRa mode
state = setActiveModem(SX127X_LORA);
if(state != ERR_NONE) {
return(state);
}
}
// set LoRa sync word
state = SX127x::setSyncWord(syncWord);
if(state != ERR_NONE) {
return(state);
}
// set over current protection
state = SX127x::setCurrentLimit(currentLimit);
if(state != ERR_NONE) {
return(state);
}
// set preamble length
state = SX127x::setPreambleLength(preambleLength);
// initalize internal variables
_dataRate = 0.0;
return(state);
}
int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
DEBUG_PRINTLN_STR("No SX127x found!");
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN_STR("Found SX127x!");
}
// check currently active modem
int16_t state;
if(getActiveModem() != SX127X_FSK_OOK) {
// set FSK mode
state = setActiveModem(SX127X_FSK_OOK);
if(state != ERR_NONE) {
return(state);
}
}
// set bit rate
state = SX127x::setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
// set frequency deviation
state = SX127x::setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
// set receiver bandwidth
state = SX127x::setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
// set over current protection
state = SX127x::setCurrentLimit(currentLimit);
if(state != ERR_NONE) {
return(state);
}
// default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library
uint8_t syncWord[] = {0x2D, 0x01};
state = setSyncWord(syncWord, 2);
if(state != ERR_NONE) {
return(state);
}
// disable address filtering
state = disableAddressFiltering();
return(state);
}
int16_t SX127x::transmit(String& str, uint8_t addr) {
return(SX127x::transmit(str.c_str(), addr));
}
int16_t SX127x::transmit(const char* str, uint8_t addr) {
return(SX127x::transmit((uint8_t*)str, strlen(str), addr));
}
int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// check packet length
if(len >= 256) {
return(ERR_PACKET_TOO_LONG);
}
// calculate timeout
uint16_t base = 1;
float symbolLength = (float)(base << _sf) / (float)_bw;
float de = 0;
if(symbolLength >= 16.0) {
de = 1;
}
float ih = (float)_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_1, 0, 0);
float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
float n_pre = (float)((_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB));
float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0);
uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1.5);
// set DIO mapping
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set packet length
state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
// set FIFO pointers
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX);
// write packet to FIFO
_mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len);
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
// wait for packet transmission or timeout
uint32_t start = millis();
while(!digitalRead(_mod->int0())) {
if(millis() - start > timeout) {
clearIRQFlags();
return(ERR_TX_TIMEOUT);
}
}
uint32_t elapsed = millis() - start;
// update data rate
_dataRate = (len*8.0)/((float)elapsed/1000.0);
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
} else if(modem == SX127X_FSK_OOK) {
// check packet length
if(len >= 64) {
return(ERR_PACKET_TOO_LONG);
}
// set DIO mapping
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set packet length
_mod->SPIwriteRegister(SX127X_REG_FIFO, len);
// check address filtering
uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
_mod->SPIwriteRegister(SX127X_REG_FIFO, addr);
}
// write packet to FIFO
_mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len);
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
// wait for transmission end or timeout (150 % of expected time-on-air)
uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500.0);
uint32_t start = millis();
while(!digitalRead(_mod->int0())) {
if(millis() - start > timeout) {
clearIRQFlags();
return(ERR_TX_TIMEOUT);
}
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
return(ERR_UNKNOWN);
}
int16_t SX127x::receive(String& str, size_t len) {
// create temporary array to store received data
char* data = new char[len + 1];
int16_t state = SX127x::receive((uint8_t*)data, len);
// if packet was received successfully, copy data into String
if(state == ERR_NONE) {
str = String(data);
}
delete[] data;
return(state);
}
int16_t SX127x::receive(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4);
// clear interrupt flags
clearIRQFlags();
// set FIFO pointers
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX);
// set mode to receive
state |= setMode(SX127X_RXSINGLE);
if(state != ERR_NONE) {
return(state);
}
// wait for packet reception or timeout
while(!digitalRead(_mod->int0())) {
if(digitalRead(_mod->int1())) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
// check integrity CRC
if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
return(ERR_CRC_MISMATCH);
}
// get packet length
size_t length = len;
if(_sf != 6) {
length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES);
}
// read packet data
if(len == 0) {
// argument 'len' equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
_mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
// add terminating null
if(len == 0) {
data[length] = 0;
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
} else if(modem == SX127X_FSK_OOK) {
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set mode to receive
state |= setMode(SX127X_RX);
if(state != ERR_NONE) {
return(state);
}
// wait for packet reception or timeout (150 % of expected time-one-air)
size_t maxLen = len;
if(len == 0) {
maxLen = 0xFF;
}
uint32_t timeout = (uint32_t)((((float)(maxLen * 8)) / (_br * 1000.0)) * 1500.0);
uint32_t start = millis();
while(!digitalRead(_mod->int0())) {
if(millis() - start > timeout) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
// get packet length
size_t length = _mod->SPIreadRegister(SX127X_REG_FIFO);
// check address filtering
uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
_mod->SPIreadRegister(SX127X_REG_FIFO);
}
// read packet data
if(len == 0) {
// argument len equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
_mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
// add terminating null
if(len == 0) {
data[length] = 0;
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
return(ERR_UNKNOWN);
}
int16_t SX127x::scanChannel() {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
// clear interrupt flags
clearIRQFlags();
// set mode to CAD
state |= setMode(SX127X_CAD);
if(state != ERR_NONE) {
return(state);
}
// wait for channel activity detected or timeout
while(!digitalRead(_mod->int0())) {
if(digitalRead(_mod->int1())) {
clearIRQFlags();
return(PREAMBLE_DETECTED);
}
}
// clear interrupt flags
clearIRQFlags();
return(CHANNEL_FREE);
}
int16_t SX127x::sleep() {
// set mode to sleep
return(setMode(SX127X_SLEEP));
}
int16_t SX127x::standby() {
// set mode to standby
return(setMode(SX127X_STANDBY));
}
int16_t SX127x::transmitDirect(uint32_t FRF) {
// check modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// user requested to start transmitting immediately (required for RTTY)
if(FRF != 0) {
_mod->SPIwriteRegister(SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
_mod->SPIwriteRegister(SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
_mod->SPIwriteRegister(SX127X_REG_FRF_LSB, FRF & 0x0000FF);
return(setMode(SX127X_TX));
}
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
// start transmitting
return(setMode(SX127X_TX));
}
int16_t SX127x::receiveDirect() {
// check modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
// start receiving
return(setMode(SX127X_RX));
}
int16_t SX127x::directMode() {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
// set DIO mapping
state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO1_CONT_DCLK | SX127X_DIO2_CONT_DATA, 5, 2);
// set continuous mode
state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_CONTINUOUS, 6, 6);
return(state);
}
int16_t SX127x::packetMode() {
// check modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET, 6, 6));
}
int16_t SX127x::startReceive() {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4);
// clear interrupt flags
clearIRQFlags();
// set FIFO pointers
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX);
if(state != ERR_NONE) {
return(state);
}
// set mode to continuous reception
return(setMode(SX127X_RXCONTINUOUS));
} else if(modem == SX127X_FSK_OOK) {
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set mode to receive
return(setMode(SX127X_RX));
}
return(ERR_UNKNOWN);
}
void SX127x::setDio0Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->int0()), func, RISING);
}
void SX127x::setDio1Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->int1()), func, RISING);
}
int16_t SX127x::startTransmit(String& str, uint8_t addr) {
return(SX127x::startTransmit(str.c_str(), addr));
}
int16_t SX127x::startTransmit(const char* str, uint8_t addr) {
return(SX127x::startTransmit((uint8_t*)str, strlen(str), addr));
}
int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// check packet length
if(len >= 256) {
return(ERR_PACKET_TOO_LONG);
}
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// set DIO mapping
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set packet length
state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
// set FIFO pointers
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX);
// write packet to FIFO
_mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len);
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
return(ERR_NONE);
} else if(modem == SX127X_FSK_OOK) {
// set DIO mapping
_mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
// clear interrupt flags
clearIRQFlags();
// set packet length
_mod->SPIwriteRegister(SX127X_REG_FIFO, len);
// check address filtering
uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
_mod->SPIwriteRegister(SX127X_REG_FIFO, addr);
}
// write packet to FIFO
_mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len);
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
return(ERR_NONE);
}
return(ERR_UNKNOWN);
}
int16_t SX127x::readData(String& str, size_t len) {
// create temporary array to store received data
char* data = new char[len];
int16_t state = SX127x::readData((uint8_t*)data, len);
// if packet was received successfully, copy data into String
if(state == ERR_NONE) {
str = String(data);
}
delete[] data;
return(state);
}
int16_t SX127x::readData(uint8_t* data, size_t len) {
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// check integrity CRC
if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
return(ERR_CRC_MISMATCH);
}
// get packet length
size_t length = len;
if(_sf != 6) {
length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES);
}
// read packet data
if(len == 0) {
// argument len equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
_mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
// add terminating null
if(len == 0) {
data[length] = 0;
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
} else if(modem == SX127X_FSK_OOK) {
// get packet length
size_t length = _mod->SPIreadRegister(SX127X_REG_FIFO);
// check address filtering
uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
_mod->SPIreadRegister(SX127X_REG_FIFO);
}
// read packet data
if(len == 0) {
// argument len equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
_mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
// add terminating null
if(len == 0) {
data[length] = 0;
}
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
return(ERR_UNKNOWN);
}
int16_t SX127x::setSyncWord(uint8_t syncWord) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// set mode to standby
setMode(SX127X_STANDBY);
// write register
return(_mod->SPIsetRegValue(SX127X_REG_SYNC_WORD, syncWord));
}
int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
// check allowed range
if(!(((currentLimit >= 45) && (currentLimit <= 240)) || (currentLimit == 0))) {
return(ERR_INVALID_CURRENT_LIMIT);
}
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
// set OCP limit
uint8_t raw;
if(currentLimit == 0) {
// limit set to 0, disable OCP
state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_OFF, 5, 5);
} else if(currentLimit <= 120) {
raw = (currentLimit - 45) / 5;
state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_ON | raw, 5, 0);
} else if(currentLimit <= 240) {
raw = (currentLimit + 30) / 10;
state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_ON | raw, 5, 0);
}
return(state);
}
int16_t SX127x::setPreambleLength(uint16_t preambleLength) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// check allowed range
if(preambleLength < 6) {
return(ERR_INVALID_PREAMBLE_LENGTH);
}
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
// set preamble length
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8);
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF);
return(state);
}
float SX127x::getFrequencyError(bool autoCorrect) {
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// get raw frequency error
uint32_t raw = (uint32_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16;
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8;
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB);
uint32_t base = (uint32_t)2 << 23;
float error;
// check the first bit
if(raw & 0x80000) {
// frequency error is negative
raw |= (uint32_t)0xFFF00000;
raw = ~raw + 1;
error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0) * -1.0;
} else {
error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0);
}
if(autoCorrect) {
// adjust LoRa modem data rate
float ppmOffset = 0.95 * (error/32.0);
_mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset);
}
return(error);
} else if(modem == SX127X_FSK_OOK) {
// get raw frequency error
uint16_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8;
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB_FSK);
uint32_t base = 1;
float error;
// check the first bit
if(raw & 0x8000) {
// frequency error is negative
raw |= (uint32_t)0xFFF00000;
raw = ~raw + 1;
error = (float)raw * (32000000.0 / (float)(base << 19)) * -1.0;
} else {
error = (float)raw * (32000000.0 / (float)(base << 19));
}
return(error);
}
return(ERR_UNKNOWN);
}
float SX127x::getSNR() {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(0);
}
// get SNR value
int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE);
return(rawSNR / 4.0);
}
float SX127x::getDataRate() {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(0);
}
return(_dataRate);
}
int16_t SX127x::setBitRate(float br) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// check allowed bitrate
if((br < 1.2) || (br > 300.0)) {
return(ERR_INVALID_BIT_RATE);
}
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
// set bit rate
uint16_t bitRate = 32000 / br;
state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0);
state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0);
// TODO: fractional part of bit rate setting
if(state == ERR_NONE) {
SX127x::_br = br;
}
return(state);
}
int16_t SX127x::setFrequencyDeviation(float freqDev) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// check frequency deviation range
if(!((freqDev + _br/2.0 <= 250.0) && (freqDev <= 200.0))) {
return(ERR_INVALID_FREQUENCY_DEVIATION);
}
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
// set allowed frequency deviation
uint32_t base = 1;
uint32_t FDEV = (freqDev * (base << 19)) / 32000;
state = _mod->SPIsetRegValue(SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
state |= _mod->SPIsetRegValue(SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
return(state);
}
int16_t SX127x::setRxBandwidth(float rxBw) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// check allowed bandwidth values
uint8_t bwMant, bwExp;
if(abs(rxBw - 2.6) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 7;
} else if(abs(rxBw - 3.1) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 7;
} else if(abs(rxBw - 3.9) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 7;
} else if(abs(rxBw - 5.2) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 6;
} else if(abs(rxBw - 6.3) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 6;
} else if(abs(rxBw - 7.8) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 6;
} else if(abs(rxBw - 10.4) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 5;
} else if(abs(rxBw - 12.5) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 5;
} else if(abs(rxBw - 15.6) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 5;
} else if(abs(rxBw - 20.8) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 4;
} else if(abs(rxBw - 25.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 4;
} else if(abs(rxBw - 31.3) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 4;
} else if(abs(rxBw - 41.7) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 3;
} else if(abs(rxBw - 50.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 3;
} else if(abs(rxBw - 62.5) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 3;
} else if(abs(rxBw - 83.3) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 2;
} else if(abs(rxBw - 100.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 2;
} else if(abs(rxBw - 125.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 2;
} else if(abs(rxBw - 166.7) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_24;
bwExp = 1;
} else if(abs(rxBw - 200.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_20;
bwExp = 1;
} else if(abs(rxBw - 250.0) <= 0.001) {
bwMant = SX127X_RX_BW_MANT_16;
bwExp = 1;
} else {
return(ERR_INVALID_RX_BANDWIDTH);
}
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
// set Rx bandwidth during AFC
state = _mod->SPIsetRegValue(SX127X_REG_AFC_BW, bwMant | bwExp, 4, 0);
if(state != ERR_NONE) {
return(state);
}
// set Rx bandwidth
state = _mod->SPIsetRegValue(SX127X_REG_RX_BW, bwMant | bwExp, 4, 0);
if(state == ERR_NONE) {
SX127x::_rxBw = rxBw;
}
return(state);
}
int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// check constraints
if(len > 8) {
return(ERR_INVALID_SYNC_WORD);
}
// sync word must not contain value 0x00
for(uint8_t i = 0; i < len; i++) {
if(syncWord[i] == 0x00) {
return(ERR_INVALID_SYNC_WORD);
}
}
// enable sync word recognition
int16_t state = _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_SYNC_ON, 4, 4);
state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len, 2, 0);
if(state != ERR_NONE) {
return(state);
}
// set sync word
_mod->SPIwriteRegisterBurst(SX127X_SYNC_VALUE_1, syncWord, len);
return(ERR_NONE);
}
int16_t SX127x::setNodeAddress(uint8_t nodeAddr) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// enable address filtering (node only)
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE, 2, 1);
if(state != ERR_NONE) {
return(state);
}
// set node address
return(_mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, nodeAddr));
}
int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// enable address filtering (node + broadcast)
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
if(state != ERR_NONE) {
return(state);
}
// set broadcast address
return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, broadAddr));
}
int16_t SX127x::disableAddressFiltering() {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// disable address filtering
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_OFF, 2, 1);
if(state != ERR_NONE) {
return(state);
}
// set node address to default (0x00)
state = _mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, 0x00);
if(state != ERR_NONE) {
return(state);
}
// set broadcast address to default (0x00)
return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00));
}
int16_t SX127x::setFrequencyRaw(float newFreq) {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
// calculate register values
uint32_t base = 1;
uint32_t FRF = (newFreq * (base << 19)) / 32.0;
// write registers
state |= _mod->SPIsetRegValue(SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
state |= _mod->SPIsetRegValue(SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
state |= _mod->SPIsetRegValue(SX127X_REG_FRF_LSB, FRF & 0x0000FF);
return(state);
}
int16_t SX127x::config() {
// turn off frequency hopping
int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF);
return(state);
}
int16_t SX127x::configFSK() {
// set FSK modulation
int16_t state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5);
if(state != ERR_NONE) {
return(state);
}
// set RSSI threshold
state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD);
if(state != ERR_NONE) {
return(state);
}
// reset FIFO flag
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN);
// set packet configuration
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON, 7, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5);
if(state != ERR_NONE) {
return(state);
}
// set FIFO threshold
state = _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_FIFO_THRESH, 5, 0);
if(state != ERR_NONE) {
return(state);
}
// disable Rx timeouts
state = _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_1, SX127X_TIMEOUT_RX_RSSI_OFF);
state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_2, SX127X_TIMEOUT_RX_PREAMBLE_OFF);
state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_3, SX127X_TIMEOUT_SIGNAL_SYNC_OFF);
if(state != ERR_NONE) {
return(state);
}
// enable preamble detector and set preamble length
state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_1_BYTE | SX127X_PREAMBLE_DETECTOR_TOL);
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, SX127X_PREAMBLE_SIZE_MSB);
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, SX127X_PREAMBLE_SIZE_LSB);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
bool SX127x::findChip(uint8_t ver) {
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION);
if(version == ver) {
flagFound = true;
} else {
#ifdef KITELIB_DEBUG
Serial.print(F("SX127x not found! ("));
Serial.print(i + 1);
Serial.print(F(" of 10 tries) SX127X_REG_VERSION == "));
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
Serial.print(buffHex);
Serial.print(F(", expected 0x00"));
Serial.print(ver, HEX);
Serial.println();
#endif
delay(1000);
i++;
}
}
return(flagFound);
}
int16_t SX127x::setMode(uint8_t mode) {
return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0, 5));
}
int16_t SX127x::getActiveModem() {
return(_mod->SPIgetRegValue(SX127X_REG_OP_MODE, 7, 7));
}
int16_t SX127x::setActiveModem(uint8_t modem) {
// set mode to SLEEP
int16_t state = setMode(SX127X_SLEEP);
// set LoRa mode
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, modem, 7, 7, 5);
// set mode to STANDBY
state |= setMode(SX127X_STANDBY);
return(state);
}
void SX127x::clearIRQFlags() {
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS, 0b11111111);
} else if(modem == SX127X_FSK_OOK) {
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_1, 0b11111111);
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, 0b11111111);
}
}
#ifdef KITELIB_DEBUG
void SX127x::regDump() {
Serial.println();
Serial.println(F("ADDR\tVALUE"));
for(uint16_t addr = 0x01; addr <= 0x70; addr++) {
if(addr <= 0x0F) {
Serial.print(F("0x0"));
} else {
Serial.print(F("0x"));
}
Serial.print(addr, HEX);
Serial.print('\t');
uint8_t val = _mod->SPIreadRegister(addr);
if(val <= 0x0F) {
Serial.print(F("0x0"));
} else {
Serial.print(F("0x"));
}
Serial.println(val, HEX);
delay(50);
}
}
#endif