205 lines
6.2 KiB
C++

#include "Sx1262.h"
#include <cstring>
#include "hal/gpio_hal.h"
constexpr const char* TAG = "Sx1262";
void IRAM_ATTR dio1handler(void* context) {
((Sx1262*)context)->dio1Event();
}
bool Sx1262::configure(const Parameter parameter, const float value) {
using enum Parameter;
switch (parameter) {
case Power:
power = value;
TT_LOG_I(TAG, "Configure %s=%d", toString(parameter), power);
return true;
case Frequency:
frequency = value;
TT_LOG_I(TAG, "Configure %s=%f", toString(parameter), frequency);
return true;
case Bandwidth:
bandwidth = value;
TT_LOG_I(TAG, "Configure %s=%f", toString(parameter), bandwidth);
return true;
case SpreadFactor:
spreadFactor = value;
TT_LOG_I(TAG, "Configure %s=%d", toString(parameter), spreadFactor);
return true;
case CodingRate:
codingRate = value;
TT_LOG_I(TAG, "Configure %s=%d", toString(parameter), codingRate);
return true;
case SyncWord:
syncWord = value;
TT_LOG_I(TAG, "Configure %s=%X", toString(parameter), syncWord);
return true;
case PreambleLength:
preambleLength = value;
TT_LOG_I(TAG, "Configure %s=%d", toString(parameter), preambleLength);
return true;
case DataRate:
bitRate = value;
return true;
case FrequencyDeviation:
frequencyDeviation = value;
return true;
default:
break;
}
return false;
}
void Sx1262::registerDio1Isr() {
hal.pinMode(GPIO_NUM_9, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_NUM_9, 0);
gpio_hal_context_t gpiohal;
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
gpio_config_t conf = {
.pin_bit_mask = (1ULL<<configuration.irqPin),
.mode = (gpio_mode_t)GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.intr_type = (gpio_int_type_t)gpiohal.dev->pin[configuration.irqPin].int_type,
};
gpio_config(&conf);
// We cannot use the RadioLib API to register this action,
// as it does not have the capability to pass an instance pointer via context.
// A trampoline has been tried, but is not linkable to be in IRAM_ATTR (dangerous relocation).
gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM);
gpio_set_intr_type(configuration.irqPin, GPIO_INTR_POSEDGE);
gpio_isr_handler_add(configuration.irqPin, dio1handler, this);
}
void Sx1262::unregisterDio1Isr() {
gpio_isr_handler_remove(configuration.irqPin);
gpio_wakeup_disable(configuration.irqPin);
gpio_set_intr_type(configuration.irqPin, GPIO_INTR_DISABLE);
}
void IRAM_ATTR Sx1262::dio1Event() {
static const auto DRAM_ATTR bit = SX1262_DIO1_EVENT_BIT;
events.set(bit);
}
void Sx1262::txQueuedSignal() {
events.set(SX1262_QUEUED_TX_BIT);
}
void Sx1262::interruptSignal() {
events.set(SX1262_INTERRUPT_BIT);
}
int Sx1262::doBegin(const Modulation modulation) {
uint16_t rc = RADIOLIB_ERR_NONE;
if (modulation == Modulation::LoRa) {
rc = radio.begin(
frequency,
bandwidth,
spreadFactor,
codingRate,
syncWord,
power,
preambleLength,
configuration.tcxoVoltage,
configuration.useRegulatorLdo
);
} else if (modulation == Modulation::Fsk) {
rc = radio.beginFSK(
frequency,
bitRate,
frequencyDeviation,
bandwidth,
power,
preambleLength,
configuration.tcxoVoltage,
configuration.useRegulatorLdo
);
} else {
TT_LOG_E(TAG, "SX1262 not capable of modulation \"%s\"", toString(modulation));
setState(State::Error);
return -1;
}
if (rc != RADIOLIB_ERR_NONE) {
TT_LOG_E(TAG, "Radiolib init failed with code %hi", rc);
setState(State::Error);
return -1;
}
registerDio1Isr();
return 0;
}
void Sx1262::doEnd() {
unregisterDio1Isr();
}
void Sx1262::doTransmit() {
currentTx = popNextQueuedTx();
radio.standby();
uint16_t rc = radio.startTransmit(currentTx.packet.data.data(), currentTx.packet.data.size());
if (rc == RADIOLIB_ERR_NONE) {
currentTx.callback(currentTx.id, TransmissionState::PendingTransmit);
TT_LOG_I(TAG, "WAIT TX FLAG");
auto txEventFlags = events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT, tt::EventFlag::WaitAny, pdMS_TO_TICKS(2000));
TT_LOG_W(TAG, "Event, flag=%X", txEventFlags);
// Thread might've been interrupted in the meanwhile
if (isThreadInterrupted()) {
return;
}
if (txEventFlags & SX1262_DIO1_EVENT_BIT) {
currentTx.callback(currentTx.id, TransmissionState::Transmitted);
} else {
currentTx.callback(currentTx.id, TransmissionState::Timeout);
}
} else {
TT_LOG_E(TAG, "Error transmitting id=%d, rc=%hi", currentTx.id, rc);
currentTx.callback(currentTx.id, TransmissionState::Error);
}
}
void Sx1262::doListen() {
radio.startReceive();
TT_LOG_I(TAG, "WAIT FLAG");
auto eventFlags = events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT | SX1262_QUEUED_TX_BIT);
TT_LOG_W(TAG, "Event, flag=%X", eventFlags);
}
void Sx1262::doReceive() {
uint16_t rxSize = radio.getPacketLength(true);
std::vector<uint8_t> data(rxSize);
uint16_t rc = radio.readData(data.data(), rxSize);
if (rc != RADIOLIB_ERR_NONE) {
TT_LOG_E(TAG, "Error receiving data, RadioLib returned %hi", rc);
} else if(rxSize == 0) {
//TT_LOG_W(TAG, "Received data length 0");
} else {
float rssi = radio.getRSSI();
float snr = radio.getSNR();
TT_LOG_I(TAG, "LoRa RX size=%d RSSI=%f SNR=%f", rxSize, rssi, snr);
auto rxPacket = tt::hal::radio::RxPacket {
.data = data,
.rssi = rssi,
.snr = snr
};
publishRx(rxPacket);
}
// A delay is needed before a new command
vTaskDelay(pdMS_TO_TICKS(100));
}