#include "Sx1262.h" #include #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<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 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)); }