#include "Sx1262.h" #include #include "hal/gpio_hal.h" constexpr const char* TAG = "Sx1262"; template static constexpr Sx1262::ParameterStatus checkLimitsAndApply(T &target, const float value, const float lower, const float upper, const unsigned step = 0) { if ((value >= lower) && (value <= upper)) { if (step != 0) { int ivalue = static_cast(value); if ((ivalue % step) != 0) { return Sx1262::ParameterStatus::ValueError; } } target = static_cast(value); return Sx1262::ParameterStatus::Success; } return Sx1262::ParameterStatus::ValueError; } template static constexpr Sx1262::ParameterStatus checkValuesAndApply(T &target, const float value, std::initializer_list valids) { for (float valid : valids) { if (value == valid) { target = static_cast(value); return Sx1262::ParameterStatus::Success; } } return Sx1262::ParameterStatus::ValueError; } void IRAM_ATTR Sx1262::dio1Isr(void* ctx) { GPIO.out_w1ts = 1 << 9; static_cast(ctx)->dio1Event(); } Sx1262::ParameterStatus Sx1262::setBaseParameter(const Parameter parameter, const float value) { using enum Parameter; switch (parameter) { case Power: return checkLimitsAndApply(power, value, -9.0, 22.0); case BoostedGain: return checkLimitsAndApply(boostedGain, value, 0.0, 1.0, 1); default: return Sx1262::ParameterStatus::Unavailable; } } Sx1262::ParameterStatus Sx1262::setLoraParameter(const Parameter parameter, const float value) { using enum Parameter; switch (parameter) { case Frequency: return checkLimitsAndApply(frequency, value, 150.0, 960.0); case Bandwidth: return checkValuesAndApply(bandwidth, value, { 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0, 500.0 }); case SpreadFactor: return checkLimitsAndApply(spreadFactor, value, 7.0, 12.0, 1); case CodingRate: return checkLimitsAndApply(codingRate, value, 5.0, 8.0, 1); case SyncWord: return checkLimitsAndApply(syncWord, value, 0.0, 255.0, 1); case PreambleLength: return checkLimitsAndApply(preambleLength, value, 0.0, 65535.0, 1); default: break; } TT_LOG_W(TAG, "Tried to set unsupported LoRa parameter \"%s\" to %f", toString(parameter), value); return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::setFskParameter(const Parameter parameter, const float value) { using enum Parameter; switch (parameter) { case Frequency: return checkLimitsAndApply(frequency, value, 150.0, 960.0); case Bandwidth: return checkValuesAndApply(bandwidth, value, { 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2 }); case PreambleLength: return checkLimitsAndApply(preambleLength, value, 0.0, 65535.0, 1); case DataRate: return checkLimitsAndApply(bitRate, value, 0.6, 300.0); case FrequencyDeviation: return checkLimitsAndApply(frequencyDeviation, value, 0.0, 200.0); default: break; } TT_LOG_W(TAG, "Tried to set unsupported FSK parameter \"%s\" to %f", toString(parameter), value); return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::setLrFhssParameter(const Parameter parameter, const float value) { using enum Parameter; switch (parameter) { case Power: return checkLimitsAndApply(power, value, -9.0, 22.0); case Bandwidth: return checkValuesAndApply(bandwidth, value, { 39.06, 85.94, 136.72, 183.59, 335.94, 386.72, 722.66, 773.44, 1523.4, 1574.2 }); case CodingRate: return checkValuesAndApply(codingRate, value, { RADIOLIB_SX126X_LR_FHSS_CR_5_6, RADIOLIB_SX126X_LR_FHSS_CR_2_3, RADIOLIB_SX126X_LR_FHSS_CR_1_2, RADIOLIB_SX126X_LR_FHSS_CR_1_3 }); case NarrowGrid: return checkLimitsAndApply(narrowGrid, value, 0.0, 1.0, 1); default: break; } TT_LOG_W(TAG, "Tried to set unsupported LR-FHSS parameter \"%s\" to %f", toString(parameter), value); return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::setParameter(const Parameter parameter, const float value) { const auto currentModulation = getModulation(); auto base_return = setBaseParameter(parameter, value); if (base_return != Sx1262::ParameterStatus::Unavailable) { return base_return; } switch (currentModulation) { case Modulation::LoRa: return setLoraParameter(parameter, value); case Modulation::Fsk: return setFskParameter(parameter, value); case Modulation::LrFhss: return setLrFhssParameter(parameter, value); default: break; } // Shouldn't be reachable, return failsafe value return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::getBaseParameter(const Parameter parameter, float &value) const { using enum Parameter; switch (parameter) { case Power: value = power; return Sx1262::ParameterStatus::Success; case BoostedGain: value = boostedGain; return Sx1262::ParameterStatus::Success; default: return Sx1262::ParameterStatus::Unavailable; } } Sx1262::ParameterStatus Sx1262::getLoraParameter(const Parameter parameter, float &value) const { using enum Parameter; switch (parameter) { case Frequency: value = frequency; return Sx1262::ParameterStatus::Success; case Bandwidth: value = bandwidth; return Sx1262::ParameterStatus::Success; case SpreadFactor: value = spreadFactor; return Sx1262::ParameterStatus::Success; case CodingRate: value = codingRate; return Sx1262::ParameterStatus::Success; case SyncWord: value = syncWord; return Sx1262::ParameterStatus::Success; case PreambleLength: value = preambleLength; return Sx1262::ParameterStatus::Success; default: break; } return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::getFskParameter(const Parameter parameter, float &value) const { using enum Parameter; switch (parameter) { case Frequency: value = frequency; return Sx1262::ParameterStatus::Success; case Bandwidth: value = bandwidth; return Sx1262::ParameterStatus::Success; case DataRate: value = bitRate; return Sx1262::ParameterStatus::Success; case FrequencyDeviation: value = frequencyDeviation; return Sx1262::ParameterStatus::Success; default: break; } return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::getLrFhssParameter(const Parameter parameter, float &value) const { using enum Parameter; switch (parameter) { case Bandwidth: value = bandwidth; return Sx1262::ParameterStatus::Success; case CodingRate: value = codingRate; return Sx1262::ParameterStatus::Success; case NarrowGrid: value = narrowGrid; return Sx1262::ParameterStatus::Success; default: break; } return Sx1262::ParameterStatus::Unavailable; } Sx1262::ParameterStatus Sx1262::getParameter(const Parameter parameter, float &value) const { const auto currentModulation = getModulation(); // No warnings are emitted to be able to discover parameters by return status auto base_return = getBaseParameter(parameter, value); if (base_return != Sx1262::ParameterStatus::Unavailable) { return base_return; } switch (currentModulation) { case Modulation::LoRa: return getLoraParameter(parameter, value); case Modulation::Fsk: return getFskParameter(parameter, value); case Modulation::LrFhss: return getLrFhssParameter(parameter, value); default: // Shouldn't be reachable, return failsafe value return Sx1262::ParameterStatus::Unavailable; } } tt::hal::radio::Unit Sx1262::getParameterUnit(const Parameter parameter) const { using enum Parameter; using Unit = tt::hal::radio::Unit; switch (parameter) { case Power: return Unit(Unit::Name::DecibelMilliwatts); case Frequency: return Unit(Unit::Prefix::Mega, Unit::Name::Herz); case Bandwidth: return Unit(Unit::Prefix::Kilo, Unit::Name::Herz); case SpreadFactor: case CodingRate: // no break case SyncWord: // no break case PreambleLength: // no break return Unit(Unit::Name::None); case DataRate: return Unit(Unit::Prefix::Kilo, Unit::Name::BitsPerSecond); case FrequencyDeviation: return Unit(Unit::Prefix::Kilo, Unit::Name::Herz); case NarrowGrid: return Unit(Unit::Name::None); default: TT_LOG_W(TAG, "Tried to get unit for unsupported parameter \"%s\"", toString(parameter)); return Unit(Unit::Name::None); } } void Sx1262::registerDio1Isr() { 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_DISABLE, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&conf); // TODO: Debug Code - Remove conf = { .pin_bit_mask = (1ULL< data(rxSize); 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) { // This can cause a flood of messages if there are ones emitted here, // as a warning here doesn't bring that much to the table it is skipped. // The body is kept empty intentionally.' } else { float rssi = radio.getRSSI(); float snr = radio.getSNR(); auto rxPacket = tt::hal::radio::RxPacket { .data = data, .rssi = rssi, .snr = snr }; publishRx(rxPacket); radio.finishReceive(); } // A delay before a new command improves reliability //vTaskDelay(pdMS_TO_TICKS(SX1262_COOLDOWN_MILLIS)); }