This commit is contained in:
Mark Qvist 2025-01-04 21:05:11 +01:00
parent 217db4bcd3
commit eb168d4734
6 changed files with 346 additions and 703 deletions

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#include "Boards.h" #include "Boards.h"
#if MODEM == SX1262 #if MODEM == SX1262
@ -24,19 +21,19 @@
#define OP_TX_6X 0x83 #define OP_TX_6X 0x83
#define OP_RX_6X 0x82 #define OP_RX_6X 0x82
#define OP_PA_CONFIG_6X 0x95 #define OP_PA_CONFIG_6X 0x95
#define OP_SET_IRQ_FLAGS_6X 0x08 // also provides info such as #define OP_SET_IRQ_FLAGS_6X 0x08 // Also provides info such as
// preamble detection, etc for // preamble detection, etc for
// knowing when it's safe to switch // knowing when it's safe to switch
// antenna modes // antenna modes
#define OP_CLEAR_IRQ_STATUS_6X 0x02 #define OP_CLEAR_IRQ_STATUS_6X 0x02
#define OP_GET_IRQ_STATUS_6X 0x12 #define OP_GET_IRQ_STATUS_6X 0x12
#define OP_RX_BUFFER_STATUS_6X 0x13 #define OP_RX_BUFFER_STATUS_6X 0x13
#define OP_PACKET_STATUS_6X 0x14 // get snr & rssi of last packet #define OP_PACKET_STATUS_6X 0x14 // Get snr & rssi of last packet
#define OP_CURRENT_RSSI_6X 0x15 #define OP_CURRENT_RSSI_6X 0x15
#define OP_MODULATION_PARAMS_6X 0x8B // bw, sf, cr, etc. #define OP_MODULATION_PARAMS_6X 0x8B // BW, SF, CR, etc.
#define OP_PACKET_PARAMS_6X 0x8C // crc, preamble, payload length, etc. #define OP_PACKET_PARAMS_6X 0x8C // CRC, preamble, payload length, etc.
#define OP_STATUS_6X 0xC0 #define OP_STATUS_6X 0xC0
#define OP_TX_PARAMS_6X 0x8E // set dbm, etc #define OP_TX_PARAMS_6X 0x8E // Set dbm, etc
#define OP_PACKET_TYPE_6X 0x8A #define OP_PACKET_TYPE_6X 0x8A
#define OP_BUFFER_BASE_ADDR_6X 0x8F #define OP_BUFFER_BASE_ADDR_6X 0x8F
#define OP_READ_REGISTER_6X 0x1D #define OP_READ_REGISTER_6X 0x1D
@ -63,7 +60,7 @@
#define OP_FIFO_WRITE_6X 0x0E #define OP_FIFO_WRITE_6X 0x0E
#define OP_FIFO_READ_6X 0x1E #define OP_FIFO_READ_6X 0x1E
#define REG_OCP_6X 0x08E7 #define REG_OCP_6X 0x08E7
#define REG_LNA_6X 0x08AC // no agc in sx1262 #define REG_LNA_6X 0x08AC // No agc in sx1262
#define REG_SYNC_WORD_MSB_6X 0x0740 #define REG_SYNC_WORD_MSB_6X 0x0740
#define REG_SYNC_WORD_LSB_6X 0x0741 #define REG_SYNC_WORD_LSB_6X 0x0741
#define REG_PAYLOAD_LENGTH_6X 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98 #define REG_PAYLOAD_LENGTH_6X 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98
@ -118,10 +115,7 @@ sx126x::sx126x() :
_packet({0}), _packet({0}),
_preinit_done(false), _preinit_done(false),
_onReceive(NULL) _onReceive(NULL)
{ { setTimeout(0); }
// overide Stream timeout value
setTimeout(0);
}
bool sx126x::preInit() { bool sx126x::preInit() {
pinMode(_ss, OUTPUT); pinMode(_ss, OUTPUT);
@ -133,7 +127,7 @@ bool sx126x::preInit() {
SPI.begin(); SPI.begin();
#endif #endif
// check version (retry for up to 2 seconds) // Check version (retry for up to 2 seconds)
// TODO: Actually read version registers, not syncwords // TODO: Actually read version registers, not syncwords
long start = millis(); long start = millis();
uint8_t syncmsb; uint8_t syncmsb;
@ -154,31 +148,24 @@ bool sx126x::preInit() {
return true; return true;
} }
uint8_t ISR_VECT sx126x::readRegister(uint16_t address) uint8_t ISR_VECT sx126x::readRegister(uint16_t address) {
{
return singleTransfer(OP_READ_REGISTER_6X, address, 0x00); return singleTransfer(OP_READ_REGISTER_6X, address, 0x00);
} }
void sx126x::writeRegister(uint16_t address, uint8_t value) void sx126x::writeRegister(uint16_t address, uint8_t value) {
{
singleTransfer(OP_WRITE_REGISTER_6X, address, value); singleTransfer(OP_WRITE_REGISTER_6X, address, value);
} }
uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value) uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value) {
{
waitOnBusy(); waitOnBusy();
uint8_t response; uint8_t response;
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings); SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode); SPI.transfer(opcode);
SPI.transfer((address & 0xFF00) >> 8); SPI.transfer((address & 0xFF00) >> 8);
SPI.transfer(address & 0x00FF); SPI.transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER_6X) { if (opcode == OP_READ_REGISTER_6X) { SPI.transfer(0x00); }
SPI.transfer(0x00);
}
response = SPI.transfer(value); response = SPI.transfer(value);
SPI.endTransaction(); SPI.endTransaction();
@ -187,15 +174,12 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
return response; return response;
} }
void sx126x::rxAntEnable() void sx126x::rxAntEnable() {
{ if (_rxen != -1) { digitalWrite(_rxen, HIGH); }
if (_rxen != -1) {
digitalWrite(_rxen, HIGH);
}
} }
void sx126x::loraMode() { void sx126x::loraMode() {
// enable lora mode on the SX1262 chip // Enable lora mode on the SX1262 chip
uint8_t mode = MODE_LONG_RANGE_MODE_6X; uint8_t mode = MODE_LONG_RANGE_MODE_6X;
executeOpcode(OP_PACKET_TYPE_6X, &mode, 1); executeOpcode(OP_PACKET_TYPE_6X, &mode, 1);
} }
@ -203,141 +187,90 @@ void sx126x::loraMode() {
void sx126x::waitOnBusy() { void sx126x::waitOnBusy() {
unsigned long time = millis(); unsigned long time = millis();
if (_busy != -1) { if (_busy != -1) {
while (digitalRead(_busy) == HIGH) while (digitalRead(_busy) == HIGH) {
{ if (millis() >= (time + 100)) { break; }
if (millis() >= (time + 100)) {
break;
}
// do nothing
} }
} }
} }
void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) {
{
waitOnBusy(); waitOnBusy();
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings); SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode); SPI.transfer(opcode);
for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); }
for (int i = 0; i < size; i++)
{
SPI.transfer(buffer[i]);
}
SPI.endTransaction(); SPI.endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) {
{
waitOnBusy(); waitOnBusy();
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings); SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode); SPI.transfer(opcode);
SPI.transfer(0x00); SPI.transfer(0x00);
for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); }
for (int i = 0; i < size; i++)
{
buffer[i] = SPI.transfer(0x00);
}
SPI.endTransaction(); SPI.endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
void sx126x::writeBuffer(const uint8_t* buffer, size_t size) void sx126x::writeBuffer(const uint8_t* buffer, size_t size) {
{
waitOnBusy(); waitOnBusy();
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings); SPI.beginTransaction(_spiSettings);
SPI.transfer(OP_FIFO_WRITE_6X); SPI.transfer(OP_FIFO_WRITE_6X);
SPI.transfer(_fifo_tx_addr_ptr); SPI.transfer(_fifo_tx_addr_ptr);
for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); _fifo_tx_addr_ptr++; }
for (int i = 0; i < size; i++)
{
SPI.transfer(buffer[i]);
_fifo_tx_addr_ptr++;
}
SPI.endTransaction(); SPI.endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
void sx126x::readBuffer(uint8_t* buffer, size_t size) void sx126x::readBuffer(uint8_t* buffer, size_t size) {
{
waitOnBusy(); waitOnBusy();
digitalWrite(_ss, LOW); digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings); SPI.beginTransaction(_spiSettings);
SPI.transfer(OP_FIFO_READ_6X); SPI.transfer(OP_FIFO_READ_6X);
SPI.transfer(_fifo_rx_addr_ptr); SPI.transfer(_fifo_rx_addr_ptr);
SPI.transfer(0x00); SPI.transfer(0x00);
for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); }
for (int i = 0; i < size; i++)
{
buffer[i] = SPI.transfer(0x00);
}
SPI.endTransaction(); SPI.endTransaction();
digitalWrite(_ss, HIGH); digitalWrite(_ss, HIGH);
} }
void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) { void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
// because there is no access to these registers on the sx1262, we have // Because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all. // to set all these parameters at once or not at all.
uint8_t buf[8]; uint8_t buf[8];
buf[0] = sf; buf[0] = sf;
buf[1] = bw; buf[1] = bw;
buf[2] = cr; buf[2] = cr;
// low data rate toggle buf[3] = ldro; // Low data rate toggle
buf[3] = ldro; buf[4] = 0x00; // Unused params in LoRa mode
// unused params in LoRa mode
buf[4] = 0x00;
buf[5] = 0x00; buf[5] = 0x00;
buf[6] = 0x00; buf[6] = 0x00;
buf[7] = 0x00; buf[7] = 0x00;
executeOpcode(OP_MODULATION_PARAMS_6X, buf, 8); executeOpcode(OP_MODULATION_PARAMS_6X, buf, 8);
} }
void sx126x::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) { void sx126x::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
// because there is no access to these registers on the sx1262, we have // Because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all. // to set all these parameters at once or not at all.
uint8_t buf[9]; uint8_t buf[9];
buf[0] = uint8_t((preamble & 0xFF00) >> 8); buf[0] = uint8_t((preamble & 0xFF00) >> 8);
buf[1] = uint8_t((preamble & 0x00FF)); buf[1] = uint8_t((preamble & 0x00FF));
buf[2] = headermode; buf[2] = headermode;
buf[3] = length; buf[3] = length;
buf[4] = crc; buf[4] = crc;
// standard IQ setting (no inversion) buf[5] = 0x00; // standard IQ setting (no inversion)
buf[5] = 0x00; buf[6] = 0x00; // unused params
// unused params
buf[6] = 0x00;
buf[7] = 0x00; buf[7] = 0x00;
buf[8] = 0x00; buf[8] = 0x00;
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9); executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
} }
void sx126x::reset(void) { void sx126x::reset(void) {
if (_reset != -1) { if (_reset != -1) {
pinMode(_reset, OUTPUT); pinMode(_reset, OUTPUT);
// perform reset
digitalWrite(_reset, LOW); digitalWrite(_reset, LOW);
delay(10); delay(10);
digitalWrite(_reset, HIGH); digitalWrite(_reset, HIGH);
@ -350,7 +283,7 @@ void sx126x::calibrate(void) {
uint8_t mode_byte = MODE_STDBY_RC_6X; uint8_t mode_byte = MODE_STDBY_RC_6X;
executeOpcode(OP_STANDBY_6X, &mode_byte, 1); executeOpcode(OP_STANDBY_6X, &mode_byte, 1);
// calibrate RC64k, RC13M, PLL, ADC and image // Calibrate RC64k, RC13M, PLL, ADC and image
uint8_t calibrate = MASK_CALIBRATE_ALL; uint8_t calibrate = MASK_CALIBRATE_ALL;
executeOpcode(OP_CALIBRATE_6X, &calibrate, 1); executeOpcode(OP_CALIBRATE_6X, &calibrate, 1);
@ -360,55 +293,25 @@ void sx126x::calibrate(void) {
void sx126x::calibrate_image(long frequency) { void sx126x::calibrate_image(long frequency) {
uint8_t image_freq[2] = {0}; uint8_t image_freq[2] = {0};
if (frequency >= 430E6 && frequency <= 440E6) { image_freq[0] = 0x6B; image_freq[1] = 0x6F; }
if (frequency >= 430E6 && frequency <= 440E6) { else if (frequency >= 470E6 && frequency <= 510E6) { image_freq[0] = 0x75; image_freq[1] = 0x81; }
image_freq[0] = 0x6B; else if (frequency >= 779E6 && frequency <= 787E6) { image_freq[0] = 0xC1; image_freq[1] = 0xC5; }
image_freq[1] = 0x6F; else if (frequency >= 863E6 && frequency <= 870E6) { image_freq[0] = 0xD7; image_freq[1] = 0xDB; }
} else if (frequency >= 902E6 && frequency <= 928E6) { image_freq[0] = 0xE1; image_freq[1] = 0xE9; }
else if (frequency >= 470E6 && frequency <= 510E6) {
image_freq[0] = 0x75;
image_freq[1] = 0x81;
}
else if (frequency >= 779E6 && frequency <= 787E6) {
image_freq[0] = 0xC1;
image_freq[1] = 0xC5;
}
else if (frequency >= 863E6 && frequency <= 870E6) {
image_freq[0] = 0xD7;
image_freq[1] = 0xDB;
}
else if (frequency >= 902E6 && frequency <= 928E6) {
image_freq[0] = 0xE1;
image_freq[1] = 0xE9;
}
executeOpcode(OP_CALIBRATE_IMAGE_6X, image_freq, 2); executeOpcode(OP_CALIBRATE_IMAGE_6X, image_freq, 2);
waitOnBusy(); waitOnBusy();
} }
int sx126x::begin(long frequency) int sx126x::begin(long frequency) {
{
reset(); reset();
if (_busy != -1) { if (_busy != -1) { pinMode(_busy, INPUT); }
pinMode(_busy, INPUT); if (!_preinit_done) { if (!preInit()) { return false; } }
} if (_rxen != -1) { pinMode(_rxen, OUTPUT); }
if (!_preinit_done) {
if (!preInit()) {
return false;
}
}
if (_rxen != -1) {
pinMode(_rxen, OUTPUT);
}
calibrate(); calibrate();
calibrate_image(frequency); calibrate_image(frequency);
enableTCXO(); enableTCXO();
loraMode(); loraMode();
standby(); standby();
@ -422,18 +325,11 @@ int sx126x::begin(long frequency)
#endif #endif
rxAntEnable(); rxAntEnable();
setFrequency(frequency); setFrequency(frequency);
// set output power to 2 dBm
setTxPower(2); setTxPower(2);
enableCrc(); enableCrc();
writeRegister(REG_LNA_6X, 0x96); // Set LNA boost
// set LNA boost uint8_t basebuf[2] = {0}; // Set base addresses
writeRegister(REG_LNA_6X, 0x96);
// set base addresses
uint8_t basebuf[2] = {0};
executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2); executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
setModulationParams(_sf, _bw, _cr, _ldro); setModulationParams(_sf, _bw, _cr, _ldro);
@ -442,26 +338,12 @@ int sx126x::begin(long frequency)
return 1; return 1;
} }
void sx126x::end() void sx126x::end() { sleep(); SPI.end(); _preinit_done = false; }
{
// put in sleep mode
sleep();
// stop SPI int sx126x::beginPacket(int implicitHeader) {
SPI.end();
_preinit_done = false;
}
int sx126x::beginPacket(int implicitHeader)
{
standby(); standby();
if (implicitHeader) { implicitHeaderMode(); }
if (implicitHeader) { else { explicitHeaderMode(); }
implicitHeaderMode();
} else {
explicitHeaderMode();
}
_payloadLength = 0; _payloadLength = 0;
_fifo_tx_addr_ptr = 0; _fifo_tx_addr_ptr = 0;
@ -470,24 +352,19 @@ int sx126x::beginPacket(int implicitHeader)
return 1; return 1;
} }
int sx126x::endPacket() int sx126x::endPacket() {
{
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
uint8_t timeout[3] = {0}; // Put in single TX mode
// put in single TX mode
uint8_t timeout[3] = {0};
executeOpcode(OP_TX_6X, timeout, 3); executeOpcode(OP_TX_6X, timeout, 3);
uint8_t buf[2]; uint8_t buf[2];
buf[0] = 0x00; buf[0] = 0x00;
buf[1] = 0x00; buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
// Wait for TX done
bool timed_out = false; bool timed_out = false;
uint32_t w_timeout = millis()+LORA_MODEM_TIMEOUT_MS; uint32_t w_timeout = millis()+LORA_MODEM_TIMEOUT_MS;
// wait for TX done
while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0)) { while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0)) {
buf[0] = 0x00; buf[0] = 0x00;
buf[1] = 0x00; buf[1] = 0x00;
@ -497,32 +374,24 @@ int sx126x::endPacket()
if (!(millis() < w_timeout)) { timed_out = true; } if (!(millis() < w_timeout)) { timed_out = true; }
// clear IRQ's // Clear IRQs
uint8_t mask[2]; uint8_t mask[2];
mask[0] = 0x00; mask[0] = 0x00;
mask[1] = IRQ_TX_DONE_MASK_6X; mask[1] = IRQ_TX_DONE_MASK_6X;
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2); executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2);
if (timed_out) { return 0; } else { return 1; }
if (timed_out) {
return 0;
} else {
return 1;
}
} }
uint8_t sx126x::modemStatus() { uint8_t sx126x::modemStatus() {
// imitate the register status from the sx1276 / 78 // Imitate the register status from the sx1276 / 78
uint8_t buf[2] = {0}; uint8_t buf[2] = {0};
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
uint8_t clearbuf[2] = {0}; uint8_t clearbuf[2] = {0};
uint8_t byte = 0x00; uint8_t byte = 0x00;
if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) { if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) {
byte = byte | 0x01 | 0x04; byte = byte | 0x01 | 0x04;
// clear register after reading clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X; // Clear register after reading
clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
} }
if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) { if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) {
@ -530,7 +399,6 @@ uint8_t sx126x::modemStatus() {
} }
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2); executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
return byte; return byte;
} }
@ -555,7 +423,7 @@ uint8_t sx126x::packetRssiRaw() {
} }
int ISR_VECT sx126x::packetRssi() { int ISR_VECT sx126x::packetRssi() {
// may need more calculations here // TODO: May need more calculations here
uint8_t buf[3] = {0}; uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3); executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
int pkt_rssi = -buf[0] / 2; int pkt_rssi = -buf[0] / 2;
@ -563,7 +431,7 @@ int ISR_VECT sx126x::packetRssi() {
} }
int ISR_VECT sx126x::packetRssi(uint8_t pkt_snr_raw) { int ISR_VECT sx126x::packetRssi(uint8_t pkt_snr_raw) {
// may need more calculations here // TODO: May need more calculations here
uint8_t buf[3] = {0}; uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3); executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
int pkt_rssi = -buf[0] / 2; int pkt_rssi = -buf[0] / 2;
@ -582,50 +450,33 @@ float ISR_VECT sx126x::packetSnr() {
return float(buf[1]) * 0.25; return float(buf[1]) * 0.25;
} }
long sx126x::packetFrequencyError() long sx126x::packetFrequencyError() {
{ // TODO: Implement this, no idea how to check it on the sx1262
// todo: implement this, no idea how to check it on the sx1262
const float fError = 0.0; const float fError = 0.0;
return static_cast<long>(fError); return static_cast<long>(fError);
} }
size_t sx126x::write(uint8_t byte) size_t sx126x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
{ size_t sx126x::write(const uint8_t *buffer, size_t size) {
return write(&byte, sizeof(byte)); if ((_payloadLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - _payloadLength; }
}
size_t sx126x::write(const uint8_t *buffer, size_t size)
{
if ((_payloadLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - _payloadLength;
}
// write data
writeBuffer(buffer, size); writeBuffer(buffer, size);
_payloadLength = _payloadLength + size; _payloadLength = _payloadLength + size;
return size; return size;
} }
int ISR_VECT sx126x::available() int ISR_VECT sx126x::available() {
{
uint8_t buf[2] = {0}; uint8_t buf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, buf, 2); executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, buf, 2);
return buf[0] - _packetIndex; return buf[0] - _packetIndex;
} }
int ISR_VECT sx126x::read() int ISR_VECT sx126x::read(){
{ if (!available()) { return -1; }
if (!available()) {
return -1;
}
// if received new packet
if (_packetIndex == 0) { if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0}; uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2); executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int size = rxbuf[0]; int size = rxbuf[0];
_fifo_rx_addr_ptr = rxbuf[1]; _fifo_rx_addr_ptr = rxbuf[1];
readBuffer(_packet, size); readBuffer(_packet, size);
} }
@ -634,19 +485,13 @@ int ISR_VECT sx126x::read()
return byte; return byte;
} }
int sx126x::peek() int sx126x::peek() {
{ if (!available()) { return -1; }
if (!available()) {
return -1;
}
// if received new packet
if (_packetIndex == 0) { if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0}; uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2); executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int size = rxbuf[0]; int size = rxbuf[0];
_fifo_rx_addr_ptr = rxbuf[1]; _fifo_rx_addr_ptr = rxbuf[1];
readBuffer(_packet, size); readBuffer(_packet, size);
} }
@ -654,41 +499,29 @@ int sx126x::peek()
return b; return b;
} }
void sx126x::flush() void sx126x::flush() { }
{
}
void sx126x::onReceive(void(*callback)(int)) void sx126x::onReceive(void(*callback)(int)){
{
_onReceive = callback; _onReceive = callback;
if (callback) { if (callback) {
pinMode(_dio0, INPUT); pinMode(_dio0, INPUT);
uint8_t buf[8]; // Set preamble and header detection irqs, plus dio0 mask
// set preamble and header detection irqs, plus dio0 mask buf[0] = 0xFF; // Set irq masks, enable all
uint8_t buf[8];
// set irq masks, enable all
buf[0] = 0xFF;
buf[1] = 0xFF; buf[1] = 0xFF;
buf[2] = 0x00; // Set dio0 masks
// set dio0 masks
buf[2] = 0x00;
buf[3] = IRQ_RX_DONE_MASK_6X; buf[3] = IRQ_RX_DONE_MASK_6X;
buf[4] = 0x00; // Set dio1 masks
// set dio1 masks
buf[4] = 0x00;
buf[5] = 0x00; buf[5] = 0x00;
buf[6] = 0x00; // Set dio2 masks
// set dio2 masks
buf[6] = 0x00;
buf[7] = 0x00; buf[7] = 0x00;
executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8); executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8);
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
#endif #endif
attachInterrupt(digitalPinToInterrupt(_dio0), sx126x::onDio0Rise, RISING); attachInterrupt(digitalPinToInterrupt(_dio0), sx126x::onDio0Rise, RISING);
} else { } else {
detachInterrupt(digitalPinToInterrupt(_dio0)); detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT #ifdef SPI_HAS_NOTUSINGINTERRUPT
@ -697,40 +530,24 @@ void sx126x::onReceive(void(*callback)(int))
} }
} }
void sx126x::receive(int size) void sx126x::receive(int size) {
{
if (size > 0) { if (size > 0) {
implicitHeaderMode(); implicitHeaderMode();
// tell radio payload length
_payloadLength = size; _payloadLength = size;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
} else { } else { explicitHeaderMode(); }
explicitHeaderMode();
}
if (_rxen != -1) { if (_rxen != -1) { rxAntEnable(); }
rxAntEnable(); uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // Continuous mode
}
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode
executeOpcode(OP_RX_6X, mode, 3); executeOpcode(OP_RX_6X, mode, 3);
} }
void sx126x::standby() void sx126x::standby() {
{ uint8_t byte = MODE_STDBY_XOSC_6X; // STDBY_XOSC
// STDBY_XOSC
uint8_t byte = MODE_STDBY_XOSC_6X;
// STDBY_RC
// uint8_t byte = MODE_STDBY_RC_6X;
executeOpcode(OP_STANDBY_6X, &byte, 1); executeOpcode(OP_STANDBY_6X, &byte, 1);
} }
void sx126x::sleep() void sx126x::sleep() { uint8_t byte = 0x00; executeOpcode(OP_SLEEP_6X, &byte, 1); }
{
uint8_t byte = 0x00;
executeOpcode(OP_SLEEP_6X, &byte, 1);
}
void sx126x::enableTCXO() { void sx126x::enableTCXO() {
#if HAS_TCXO #if HAS_TCXO
@ -755,78 +572,60 @@ void sx126x::enableTCXO() {
void sx126x::disableTCXO() { } void sx126x::disableTCXO() { }
void sx126x::setTxPower(int level, int outputPin) { void sx126x::setTxPower(int level, int outputPin) {
// currently no low power mode for SX1262 implemented, assuming PA boost // Currently no low power mode for SX1262 implemented, assuming PA boost
// WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2 // WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
// RegTxClampConfig = @address 0x08D8 // RegTxClampConfig = @address 0x08D8
writeRegister(0x08D8, readRegister(0x08D8) | (0x0F << 1)); writeRegister(0x08D8, readRegister(0x08D8) | (0x0F << 1));
uint8_t pa_buf[4]; uint8_t pa_buf[4];
pa_buf[0] = 0x04; // PADutyCycle needs to be 0x04 to achieve 22dBm output, but can be lowered for better efficiency at lower outputs pa_buf[0] = 0x04; // PADutyCycle needs to be 0x04 to achieve 22dBm output, but can be lowered for better efficiency at lower outputs
pa_buf[1] = 0x07; // HPMax at 0x07 is maximum supported for SX1262 pa_buf[1] = 0x07; // HPMax at 0x07 is maximum supported for SX1262
pa_buf[2] = 0x00; // DeviceSel 0x00 for SX1262 (0x01 for SX1261) pa_buf[2] = 0x00; // DeviceSel 0x00 for SX1262 (0x01 for SX1261)
pa_buf[3] = 0x01; // PALut always 0x01 (reserved according to datasheet) pa_buf[3] = 0x01; // PALut always 0x01 (reserved according to datasheet)
executeOpcode(OP_PA_CONFIG_6X, pa_buf, 4); // set pa_config for high power executeOpcode(OP_PA_CONFIG_6X, pa_buf, 4); // set pa_config for high power
if (level > 22) { level = 22; } if (level > 22) { level = 22; }
else if (level < -9) { level = -9; } else if (level < -9) { level = -9; }
writeRegister(REG_OCP_6X, OCP_TUNED); // Use board-specific tuned OCP writeRegister(REG_OCP_6X, OCP_TUNED); // Use board-specific tuned OCP
uint8_t tx_buf[2]; uint8_t tx_buf[2];
tx_buf[0] = level; tx_buf[0] = level;
tx_buf[1] = 0x02; // PA ramping time - 40 microseconds tx_buf[1] = 0x02; // PA ramping time - 40 microseconds
executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2); executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2);
_txp = level; _txp = level;
} }
uint8_t sx126x::getTxPower() { uint8_t sx126x::getTxPower() { return _txp; }
return _txp;
}
void sx126x::setFrequency(long frequency) { void sx126x::setFrequency(long frequency) {
_frequency = frequency; _frequency = frequency;
uint8_t buf[4]; uint8_t buf[4];
uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_6X); uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_6X);
buf[0] = ((freq >> 24) & 0xFF); buf[0] = ((freq >> 24) & 0xFF);
buf[1] = ((freq >> 16) & 0xFF); buf[1] = ((freq >> 16) & 0xFF);
buf[2] = ((freq >> 8) & 0xFF); buf[2] = ((freq >> 8) & 0xFF);
buf[3] = (freq & 0xFF); buf[3] = (freq & 0xFF);
executeOpcode(OP_RF_FREQ_6X, buf, 4); executeOpcode(OP_RF_FREQ_6X, buf, 4);
} }
uint32_t sx126x::getFrequency() { uint32_t sx126x::getFrequency() {
// we can't read the frequency on the sx1262 / 80 // We can't read the frequency on the sx1262 / 80
uint32_t frequency = _frequency; uint32_t frequency = _frequency;
return frequency; return frequency;
} }
void sx126x::setSpreadingFactor(int sf) void sx126x::setSpreadingFactor(int sf) {
{ if (sf < 5) { sf = 5; }
if (sf < 5) { else if (sf > 12) { sf = 12; }
sf = 5;
} else if (sf > 12) {
sf = 12;
}
_sf = sf; _sf = sf;
handleLowDataRate(); handleLowDataRate();
setModulationParams(sf, _bw, _cr, _ldro); setModulationParams(sf, _bw, _cr, _ldro);
} }
long sx126x::getSignalBandwidth() long sx126x::getSignalBandwidth() {
{
int bw = _bw; int bw = _bw;
switch (bw) { switch (bw) {
case 0x00: return 7.8E3; case 0x00: return 7.8E3;
@ -844,96 +643,52 @@ long sx126x::getSignalBandwidth()
} }
void sx126x::handleLowDataRate(){ void sx126x::handleLowDataRate(){
if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16) { if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16) { _ldro = 0x01; }
_ldro = 0x01; else { _ldro = 0x00; }
} else {
_ldro = 0x00;
}
} }
void sx126x::optimizeModemSensitivity(){ // TODO: check if there's anything the sx1262 can do here
// todo: check if there's anything the sx1262 can do here void sx126x::optimizeModemSensitivity(){ }
}
void sx126x::setSignalBandwidth(long sbw) void sx126x::setSignalBandwidth(long sbw) {
{ if (sbw <= 7.8E3) { _bw = 0x00; }
if (sbw <= 7.8E3) { else if (sbw <= 10.4E3) { _bw = 0x08; }
_bw = 0x00; else if (sbw <= 15.6E3) { _bw = 0x01; }
} else if (sbw <= 10.4E3) { else if (sbw <= 20.8E3) { _bw = 0x09; }
_bw = 0x08; else if (sbw <= 31.25E3) { _bw = 0x02; }
} else if (sbw <= 15.6E3) { else if (sbw <= 41.7E3) { _bw = 0x0A; }
_bw = 0x01; else if (sbw <= 62.5E3) { _bw = 0x03; }
} else if (sbw <= 20.8E3) { else if (sbw <= 125E3) { _bw = 0x04; }
_bw = 0x09; else if (sbw <= 250E3) { _bw = 0x05; }
} else if (sbw <= 31.25E3) { else { _bw = 0x06; }
_bw = 0x02;
} else if (sbw <= 41.7E3) {
_bw = 0x0A;
} else if (sbw <= 62.5E3) {
_bw = 0x03;
} else if (sbw <= 125E3) {
_bw = 0x04;
} else if (sbw <= 250E3) {
_bw = 0x05;
} else /*if (sbw <= 250E3)*/ {
_bw = 0x06;
}
handleLowDataRate(); handleLowDataRate();
setModulationParams(_sf, _bw, _cr, _ldro); setModulationParams(_sf, _bw, _cr, _ldro);
optimizeModemSensitivity(); optimizeModemSensitivity();
} }
void sx126x::setCodingRate4(int denominator) void sx126x::setCodingRate4(int denominator) {
{ if (denominator < 5) { denominator = 5; }
if (denominator < 5) { else if (denominator > 8) { denominator = 8; }
denominator = 5;
} else if (denominator > 8) {
denominator = 8;
}
int cr = denominator - 4; int cr = denominator - 4;
_cr = cr; _cr = cr;
setModulationParams(_sf, _bw, cr, _ldro); setModulationParams(_sf, _bw, cr, _ldro);
} }
void sx126x::setPreambleLength(long length) void sx126x::setPreambleLength(long length) {
{
_preambleLength = length; _preambleLength = length;
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode); setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
} }
void sx126x::setSyncWord(uint16_t sw) void sx126x::setSyncWord(uint16_t sw) {
{ // TODO: Why was this hardcoded instead of using the config value?
// TODO: Fix
// writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8); // writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8);
// writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF); // writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF);
writeRegister(REG_SYNC_WORD_MSB_6X, 0x14); writeRegister(REG_SYNC_WORD_MSB_6X, 0x14);
writeRegister(REG_SYNC_WORD_LSB_6X, 0x24); writeRegister(REG_SYNC_WORD_LSB_6X, 0x24);
} }
void sx126x::enableCrc() void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen) {
{
_crcMode = 1;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void sx126x::disableCrc()
{
_crcMode = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
byte sx126x::random()
{
return readRegister(REG_RANDOM_GEN_6X);
}
void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen)
{
_ss = ss; _ss = ss;
_reset = reset; _reset = reset;
_dio0 = dio0; _dio0 = dio0;
@ -941,13 +696,7 @@ void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen)
_rxen = rxen; _rxen = rxen;
} }
void sx126x::setSPIFrequency(uint32_t frequency) void sx126x::dumpRegisters(Stream& out) {
{
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
}
void sx126x::dumpRegisters(Stream& out)
{
for (int i = 0; i < 128; i++) { for (int i = 0; i < 128; i++) {
out.print("0x"); out.print("0x");
out.print(i, HEX); out.print(i, HEX);
@ -956,49 +705,29 @@ void sx126x::dumpRegisters(Stream& out)
} }
} }
void sx126x::explicitHeaderMode() void ISR_VECT sx126x::handleDio0Rise() {
{
_implicitHeaderMode = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void sx126x::implicitHeaderMode()
{
_implicitHeaderMode = 1;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void ISR_VECT sx126x::handleDio0Rise()
{
uint8_t buf[2]; uint8_t buf[2];
buf[0] = 0x00; buf[0] = 0x00;
buf[1] = 0x00; buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2); executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2);
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) { if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) {
// received a packet
_packetIndex = 0; _packetIndex = 0;
uint8_t rxbuf[2] = {0}; // Read packet length
// read packet length
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2); executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int packetLength = rxbuf[0]; int packetLength = rxbuf[0];
if (_onReceive) { _onReceive(packetLength); }
if (_onReceive) {
_onReceive(packetLength);
}
} }
} }
void ISR_VECT sx126x::onDio0Rise() void ISR_VECT sx126x::onDio0Rise() { sx126x_modem.handleDio0Rise(); }
{ void sx126x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
sx126x_modem.handleDio0Rise(); void sx126x::enableCrc() { _crcMode = 1; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
} void sx126x::disableCrc() { _crcMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx126x::explicitHeaderMode() { _implicitHeaderMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx126x::implicitHeaderMode() { _implicitHeaderMode = 1; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
byte sx126x::random() { return readRegister(REG_RANDOM_GEN_6X); }
sx126x sx126x_modem; sx126x sx126x_modem;

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX126X_H #ifndef SX126X_H
#define SX126X_H #define SX126X_H

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#include "Boards.h" #include "Boards.h"
#if MODEM == SX1276 #if MODEM == SX1276
@ -81,10 +78,7 @@ extern SPIClass SPI;
sx127x::sx127x() : sx127x::sx127x() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
_frequency(0), _frequency(0), _packetIndex(0), _preinit_done(false), _onReceive(NULL) { setTimeout(0); }
_packetIndex(0),
_preinit_done(false),
_onReceive(NULL) { setTimeout(0); }
void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
void sx127x::setPins(int ss, int reset, int dio0, int busy) { _ss = ss; _reset = reset; _dio0 = dio0; _busy = busy; } void sx127x::setPins(int ss, int reset, int dio0, int busy) { _ss = ss; _reset = reset; _dio0 = dio0; _busy = busy; }
@ -123,7 +117,6 @@ bool sx127x::preInit() {
} }
if (version != 0x12) { return false; } if (version != 0x12) { return false; }
_preinit_done = true; _preinit_done = true;
return true; return true;
} }
@ -144,8 +137,6 @@ uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) {
int sx127x::begin(long frequency) { int sx127x::begin(long frequency) {
if (_reset != -1) { if (_reset != -1) {
pinMode(_reset, OUTPUT); pinMode(_reset, OUTPUT);
// Perform reset
digitalWrite(_reset, LOW); digitalWrite(_reset, LOW);
delay(10); delay(10);
digitalWrite(_reset, HIGH); digitalWrite(_reset, HIGH);
@ -153,19 +144,16 @@ int sx127x::begin(long frequency) {
} }
if (_busy != -1) { pinMode(_busy, INPUT); } if (_busy != -1) { pinMode(_busy, INPUT); }
if (!_preinit_done) { if (!preInit()) { return false; } }
if (!_preinit_done) {
if (!preInit()) { return false; }
}
sleep(); sleep();
setFrequency(frequency); setFrequency(frequency);
// set base addresses // Set base addresses
writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0); writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0);
writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0); writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0);
// set LNA boost and auto AGC // Set LNA boost and auto AGC
writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03); writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03);
writeRegister(REG_MODEM_CONFIG_3_7X, 0x04); writeRegister(REG_MODEM_CONFIG_3_7X, 0x04);
@ -178,20 +166,13 @@ int sx127x::begin(long frequency) {
return 1; return 1;
} }
void sx127x::end() { void sx127x::end() { sleep(); SPI.end(); _preinit_done = false; }
sleep();
SPI.end();
_preinit_done = false;
}
int sx127x::beginPacket(int implicitHeader) { int sx127x::beginPacket(int implicitHeader) {
standby(); standby();
if (implicitHeader) { if (implicitHeader) { implicitHeaderMode(); }
implicitHeaderMode(); else { explicitHeaderMode(); }
} else {
explicitHeaderMode();
}
// Reset FIFO address and payload length // Reset FIFO address and payload length
writeRegister(REG_FIFO_ADDR_PTR_7X, 0); writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
@ -253,9 +234,8 @@ int ISR_VECT sx127x::packetRssi() {
if (_frequency < 820E6) pkt_rssi -= 7; if (_frequency < 820E6) pkt_rssi -= 7;
if (pkt_snr < 0) { if (pkt_snr < 0) { pkt_rssi += pkt_snr; }
pkt_rssi += pkt_snr; else {
} else {
// Slope correction is (16/15)*pkt_rssi, // Slope correction is (16/15)*pkt_rssi,
// this estimation looses one floating point // this estimation looses one floating point
// operation, and should be precise enough. // operation, and should be precise enough.
@ -264,13 +244,9 @@ int ISR_VECT sx127x::packetRssi() {
return pkt_rssi; return pkt_rssi;
} }
uint8_t ISR_VECT sx127x::packetSnrRaw() { uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); }
return readRegister(REG_PKT_SNR_VALUE_7X);
}
float ISR_VECT sx127x::packetSnr() { float ISR_VECT sx127x::packetSnr() { return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; }
return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25;
}
long sx127x::packetFrequencyError() { long sx127x::packetFrequencyError() {
int32_t freqError = 0; int32_t freqError = 0;
@ -294,15 +270,11 @@ size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
size_t sx127x::write(const uint8_t *buffer, size_t size) { size_t sx127x::write(const uint8_t *buffer, size_t size) {
int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X); int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X);
if ((currentLength + size) > MAX_PKT_LENGTH) { if ((currentLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; }
size = MAX_PKT_LENGTH - currentLength;
}
for (size_t i = 0; i < size; i++) {
writeRegister(REG_FIFO_7X, buffer[i]);
}
for (size_t i = 0; i < size; i++) { writeRegister(REG_FIFO_7X, buffer[i]); }
writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size); writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size);
return size; return size;
} }

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX1276_H #ifndef SX1276_H
#define SX1276_H #define SX1276_H

View File

@ -1,12 +1,11 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva
// Obviously still under the MIT license.
#include "sx128x.h"
#include "Boards.h" #include "Boards.h"
#if MODEM == SX1280
#include "sx128x.h"
#define MCU_1284P 0x91 #define MCU_1284P 0x91
#define MCU_2560 0x92 #define MCU_2560 0x92
#define MCU_ESP32 0x81 #define MCU_ESP32 0x81
@ -44,19 +43,19 @@
#define OP_STANDBY_8X 0x80 #define OP_STANDBY_8X 0x80
#define OP_TX_8X 0x83 #define OP_TX_8X 0x83
#define OP_RX_8X 0x82 #define OP_RX_8X 0x82
#define OP_SET_IRQ_FLAGS_8X 0x8D // also provides info such as #define OP_SET_IRQ_FLAGS_8X 0x8D // Also provides info such as
// preamble detection, etc for // preamble detection, etc for
// knowing when it's safe to switch // knowing when it's safe to switch
// antenna modes // antenna modes
#define OP_CLEAR_IRQ_STATUS_8X 0x97 #define OP_CLEAR_IRQ_STATUS_8X 0x97
#define OP_GET_IRQ_STATUS_8X 0x15 #define OP_GET_IRQ_STATUS_8X 0x15
#define OP_RX_BUFFER_STATUS_8X 0x17 #define OP_RX_BUFFER_STATUS_8X 0x17
#define OP_PACKET_STATUS_8X 0x1D // get snr & rssi of last packet #define OP_PACKET_STATUS_8X 0x1D // Get snr & rssi of last packet
#define OP_CURRENT_RSSI_8X 0x1F #define OP_CURRENT_RSSI_8X 0x1F
#define OP_MODULATION_PARAMS_8X 0x8B // bw, sf, cr, etc. #define OP_MODULATION_PARAMS_8X 0x8B // BW, SF, CR, etc.
#define OP_PACKET_PARAMS_8X 0x8C // crc, preamble, payload length, etc. #define OP_PACKET_PARAMS_8X 0x8C // CRC, preamble, payload length, etc.
#define OP_STATUS_8X 0xC0 #define OP_STATUS_8X 0xC0
#define OP_TX_PARAMS_8X 0x8E // set dbm, etc #define OP_TX_PARAMS_8X 0x8E // Set dbm, etc
#define OP_PACKET_TYPE_8X 0x8A #define OP_PACKET_TYPE_8X 0x8A
#define OP_BUFFER_BASE_ADDR_8X 0x8F #define OP_BUFFER_BASE_ADDR_8X 0x8F
#define OP_READ_REGISTER_8X 0x19 #define OP_READ_REGISTER_8X 0x19
@ -93,24 +92,8 @@ extern SPIClass SPI;
sx128x::sx128x() : sx128x::sx128x() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _rxen(pin_rxen), _busy(LORA_DEFAULT_BUSY_PIN), _txen(pin_txen), _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _rxen(pin_rxen), _busy(LORA_DEFAULT_BUSY_PIN), _txen(pin_txen),
_frequency(0), _frequency(0), _txp(0), _sf(0x05), _bw(0x34), _cr(0x01), _packetIndex(0), _implicitHeaderMode(0), _payloadLength(255), _crcMode(0), _fifo_tx_addr_ptr(0),
_txp(0), _fifo_rx_addr_ptr(0), _rxPacketLength(0), _preinit_done(false), _tcxo(false) { setTimeout(0); }
_sf(0x05),
_bw(0x34),
_cr(0x01),
_packetIndex(0),
_implicitHeaderMode(0),
_payloadLength(255),
_crcMode(0),
_fifo_tx_addr_ptr(0),
_fifo_rx_addr_ptr(0),
_rxPacketLength(0),
_preinit_done(false),
_tcxo(false)
{
// overide Stream timeout value
setTimeout(0);
}
bool ISR_VECT sx128x::getPacketValidity() { bool ISR_VECT sx128x::getPacketValidity() {
uint8_t buf[2]; uint8_t buf[2];
@ -472,23 +455,17 @@ float ISR_VECT sx128x::packetSnr() {
} }
long sx128x::packetFrequencyError() { long sx128x::packetFrequencyError() {
// TODO: implement this, page 120 of sx1280 datasheet // TODO: Implement this, page 120 of sx1280 datasheet
int32_t freqError = 0; int32_t freqError = 0;
const float fError = 0.0; const float fError = 0.0;
return static_cast<long>(fError); return static_cast<long>(fError);
} }
void sx128x::flush() { } void sx128x::flush() { }
int ISR_VECT sx128x::available() { return _rxPacketLength - _packetIndex; } int ISR_VECT sx128x::available() { return _rxPacketLength - _packetIndex; }
size_t sx128x::write(uint8_t byte) { return write(&byte, sizeof(byte)); } size_t sx128x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
size_t sx128x::write(const uint8_t *buffer, size_t size) { size_t sx128x::write(const uint8_t *buffer, size_t size) {
if ((_payloadLength + size) > MAX_PKT_LENGTH) { if ((_payloadLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - _payloadLength; }
size = MAX_PKT_LENGTH - _payloadLength;
}
writeBuffer(buffer, size); writeBuffer(buffer, size);
_payloadLength = _payloadLength + size; _payloadLength = _payloadLength + size;
return size; return size;
@ -716,7 +693,7 @@ void sx128x::setTxPower(int level, int outputPin) {
} }
tx_buf[0] = reg_value + 18; tx_buf[0] = reg_value + 18;
tx_buf[1] = 0xE0; // ramping time - 20 microseconds tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2);
// T3S3 SX1280 PA // T3S3 SX1280 PA
@ -795,7 +772,7 @@ void sx128x::setTxPower(int level, int outputPin) {
break; break;
} }
tx_buf[0] = reg_value; tx_buf[0] = reg_value;
tx_buf[1] = 0xE0; // ramping time - 20 microseconds tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
// For SX1280 boards with no specific PA requirements // For SX1280 boards with no specific PA requirements
#else #else
@ -803,7 +780,7 @@ void sx128x::setTxPower(int level, int outputPin) {
else if (level < -18) { level = -18; } else if (level < -18) { level = -18; }
_txp = level; _txp = level;
tx_buf[0] = level + 18; tx_buf[0] = level + 18;
tx_buf[1] = 0xE0; // ramping time - 20 microseconds tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
#endif #endif
executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2);
@ -821,7 +798,7 @@ void sx128x::setFrequency(uint32_t frequency) {
} }
uint32_t sx128x::getFrequency() { uint32_t sx128x::getFrequency() {
// we can't read the frequency on the sx1280 // We can't read the frequency on the sx1280
uint32_t frequency = _frequency; uint32_t frequency = _frequency;
return frequency; return frequency;
} }
@ -847,12 +824,6 @@ uint32_t sx128x::getSignalBandwidth() {
return 0; return 0;
} }
// TODO: Is this needed for SX1280?
void sx128x::handleLowDataRate() { }
// TODO: Check if there's anything the sx1280 can do here
void sx128x::optimizeModemSensitivity() { }
void sx128x::setSignalBandwidth(uint32_t sbw) { void sx128x::setSignalBandwidth(uint32_t sbw) {
if (sbw <= 203.125E3) { _bw = 0x34; } if (sbw <= 203.125E3) { _bw = 0x34; }
else if (sbw <= 406.25E3) { _bw = 0x26; } else if (sbw <= 406.25E3) { _bw = 0x26; }
@ -872,40 +843,22 @@ void sx128x::setCodingRate4(int denominator) {
setModulationParams(_sf, _bw, _cr); setModulationParams(_sf, _bw, _cr);
} }
void sx128x::handleLowDataRate() { } // TODO: Is this needed for SX1280?
void sx128x::optimizeModemSensitivity() { } // TODO: Check if there's anything the sx1280 can do here
uint8_t sx128x::getCodingRate4() { return _cr + 4; } uint8_t sx128x::getCodingRate4() { return _cr + 4; }
void sx128x::setPreambleLength(long length) { _preambleLength = length; setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx128x::setPreambleLength(long length) { void sx128x::setSyncWord(int sw) { } // TODO: Implement
_preambleLength = length; void sx128x::enableTCXO() { } // TODO: Need to check how to implement on sx1280
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode); void sx128x::disableTCXO() { } // TODO: Need to check how to implement on sx1280
}
// TODO: Implement
void sx128x::setSyncWord(int sw) { }
// TODO: need to check how to implement on sx1280
void sx128x::enableTCXO() { }
// TODO: need to check how to implement on sx1280
void sx128x::disableTCXO() { }
void sx128x::sleep() { uint8_t byte = 0x00; executeOpcode(OP_SLEEP_8X, &byte, 1); } void sx128x::sleep() { uint8_t byte = 0x00; executeOpcode(OP_SLEEP_8X, &byte, 1); }
uint8_t sx128x::getTxPower() { return _txp; } uint8_t sx128x::getTxPower() { return _txp; }
uint8_t sx128x::getSpreadingFactor() { return _sf; } uint8_t sx128x::getSpreadingFactor() { return _sf; }
void sx128x::enableCrc() { _crcMode = 0x20; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } void sx128x::enableCrc() { _crcMode = 0x20; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx128x::disableCrc() { _crcMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } void sx128x::disableCrc() { _crcMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx128x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } void sx128x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
void sx128x::explicitHeaderMode() { _implicitHeaderMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } void sx128x::explicitHeaderMode() { _implicitHeaderMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx128x::implicitHeaderMode() { _implicitHeaderMode = 0x80; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } void sx128x::implicitHeaderMode() { _implicitHeaderMode = 0x80; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
void sx128x::dumpRegisters(Stream& out) { for (int i = 0; i < 128; i++) { out.print("0x"); out.print(i, HEX); out.print(": 0x"); out.println(readRegister(i), HEX); } }
void sx128x::dumpRegisters(Stream& out) {
for (int i = 0; i < 128; i++) { out.print("0x"); out.print(i, HEX); out.print(": 0x"); out.println(readRegister(i), HEX); }
}
sx128x sx128x_modem; sx128x sx128x_modem;
#endif

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved. // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license. // Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX128X_H #ifndef SX128X_H
#define SX128X_H #define SX128X_H
@ -18,10 +15,8 @@
#define LORA_DEFAULT_TXEN_PIN -1 #define LORA_DEFAULT_TXEN_PIN -1
#define LORA_DEFAULT_BUSY_PIN -1 #define LORA_DEFAULT_BUSY_PIN -1
#define LORA_MODEM_TIMEOUT_MS 15E3 #define LORA_MODEM_TIMEOUT_MS 15E3
#define PA_OUTPUT_RFO_PIN 0 #define PA_OUTPUT_RFO_PIN 0
#define PA_OUTPUT_PA_BOOST_PIN 1 #define PA_OUTPUT_PA_BOOST_PIN 1
#define RSSI_OFFSET 157 #define RSSI_OFFSET 157
class sx128x : public Stream { class sx128x : public Stream {