diff --git a/Drivers/RadioLibCompat/Source/RadiolibThreadedDevice.h b/Drivers/RadioLibCompat/Source/RadiolibThreadedDevice.h index 6830c6e4..a431b92a 100644 --- a/Drivers/RadioLibCompat/Source/RadiolibThreadedDevice.h +++ b/Drivers/RadioLibCompat/Source/RadiolibThreadedDevice.h @@ -33,5 +33,4 @@ public: virtual bool start(const Modulation modulation) override; virtual bool stop() override; - }; diff --git a/Drivers/SX126x/Source/Sx1262.cpp b/Drivers/SX126x/Source/Sx1262.cpp index 3720f272..41112363 100644 --- a/Drivers/SX126x/Source/Sx1262.cpp +++ b/Drivers/SX126x/Source/Sx1262.cpp @@ -5,94 +5,146 @@ 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 dio1handler(void* context) { ((Sx1262*)context)->dio1Event(); } -bool Sx1262::setParameter(const Parameter parameter, const float value) { +Sx1262::ParameterStatus Sx1262::setParameter(const Parameter parameter, const float value) { using enum Parameter; switch (parameter) { case Power: - power = value; - return true; + return checkLimitsAndApply(power, value, -9.0, 22.0); case Frequency: - frequency = value; - return true; + return checkLimitsAndApply(frequency, value, 150.0, 960.0); case Bandwidth: - bandwidth = value; - return true; + return checkValuesAndApply(bandwidth, value, { + //LoRa + 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0, 500.0, + // FSK + 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, + // LR-FHSS + 39.06, 85.94, 136.72, 183.59, 335.94, 386.72, 722.66, 773.44, 1523.4, 1574.2 + }); case SpreadFactor: - spreadFactor = value; - return true; + return checkLimitsAndApply(spreadFactor, value, 7.0, 12.0, 1); case CodingRate: - codingRate = value; - return true; + return checkLimitsAndApply(codingRate, value, 5.0, 8.0, 1); case SyncWord: - syncWord = value; - return true; + return checkLimitsAndApply(syncWord, value, 0.0, 255.0, 1); case PreambleLength: - preambleLength = value; - return true; + return checkLimitsAndApply(preambleLength, value, 0.0, 65535.0, 1); case DataRate: - bitRate = value; - return true; + return checkLimitsAndApply(bitRate, value, 0.6, 300.0); case FrequencyDeviation: - frequencyDeviation = value; - return true; + return checkLimitsAndApply(frequencyDeviation, value, 0.0, 200.0); case NarrowGrid: - narrowGrid = value; - return true; + return checkLimitsAndApply(narrowGrid, value, 0.0, 1.0, 1); default: break; } TT_LOG_W(TAG, "Tried to set unsupported parameter \"%s\" to %f", toString(parameter), value); - - return false; + return Sx1262::ParameterStatus::NotDefined; } -bool Sx1262::getParameter(const Parameter parameter, float &value) const { +Sx1262::ParameterStatus Sx1262::getParameter(const Parameter parameter, float &value) const { using enum Parameter; switch (parameter) { case Power: value = power; - return true; + return Sx1262::ParameterStatus::Success; case Frequency: value = frequency; - return true; + return Sx1262::ParameterStatus::Success; case Bandwidth: value = bandwidth; - return true; + return Sx1262::ParameterStatus::Success; case SpreadFactor: value = spreadFactor; - return true; + return Sx1262::ParameterStatus::Success; case CodingRate: value = codingRate; - return true; + return Sx1262::ParameterStatus::Success; case SyncWord: value = syncWord; - return true; + return Sx1262::ParameterStatus::Success; case PreambleLength: value = preambleLength; - return true; + return Sx1262::ParameterStatus::Success; case DataRate: value = bitRate; - return true; + return Sx1262::ParameterStatus::Success; case FrequencyDeviation: value = frequencyDeviation; - return true; + return Sx1262::ParameterStatus::Success; case NarrowGrid: value = narrowGrid; - return true; + return Sx1262::ParameterStatus::Success; default: break; } TT_LOG_W(TAG, "Tried to get unsupported parameter \"%s\"", toString(parameter)); + return Sx1262::ParameterStatus::NotDefined; +} - return false; +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::Kilo, 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: + break; + } + + TT_LOG_W(TAG, "Tried to get unit for unsupported parameter \"%s\"", toString(parameter)); + return Unit(Unit::Name::None); } void Sx1262::registerDio1Isr() { diff --git a/Drivers/SX126x/Source/Sx1262.h b/Drivers/SX126x/Source/Sx1262.h index 7ea3b7ff..3d525490 100644 --- a/Drivers/SX126x/Source/Sx1262.h +++ b/Drivers/SX126x/Source/Sx1262.h @@ -82,8 +82,9 @@ public: std::string getDescription() const override { return "Semtech SX1262 LoRa, FSK and LR-FHSS capable radio"; } - bool setParameter(const Parameter parameter, const float value) override; - bool getParameter(const Parameter parameter, float &value) const override; + ParameterStatus setParameter(const Parameter parameter, const float value) override; + ParameterStatus getParameter(const Parameter parameter, float &value) const override; + tt::hal::radio::Unit getParameterUnit(const Parameter parameter) const override; bool canTransmit(const Modulation modulation) override { return (modulation == Modulation::Fsk) || diff --git a/Tactility/Include/Tactility/hal/radio/ParameterSet.h b/Tactility/Include/Tactility/hal/radio/ParameterSet.h index 4016a595..a7f783c3 100644 --- a/Tactility/Include/Tactility/hal/radio/ParameterSet.h +++ b/Tactility/Include/Tactility/hal/radio/ParameterSet.h @@ -34,23 +34,29 @@ public: } return false; } + void clear() { parameters.clear(); } bool apply(RadioDevice &radio) { bool successful = true; for (const auto& [parameter, value] : parameters) { // No break on error chosen to apply all parameters, // a bad one doesn't make the successive tries any more invalid - successful &= radio.setParameter(parameter, value); + successful &= (radio.setParameter(parameter, value) == RadioDevice::ParameterStatus::Success); } return successful; } - bool load(const RadioDevice &radio) { - bool successful = true; - for (const auto& [parameter, value] : parameters) { - successful &= radio.getParameter(parameter, parameters[parameter]); + void load(const RadioDevice &radio) { + // This loop has to be ajusted for each new parameter. + // Could be made more maintainable with a template enum iterator in an utility header. + for (RadioDevice::Parameter p = RadioDevice::Parameter::Power; + p < RadioDevice::Parameter::NarrowGrid; + p = static_cast((size_t)p + 1)) { + float value = 0.0; + if (radio.getParameter(p, value) == RadioDevice::ParameterStatus::Success) { + set(p, value); + } } - return successful; } }; diff --git a/Tactility/Include/Tactility/hal/radio/RadioDevice.h b/Tactility/Include/Tactility/hal/radio/RadioDevice.h index 460b5393..095a95dc 100644 --- a/Tactility/Include/Tactility/hal/radio/RadioDevice.h +++ b/Tactility/Include/Tactility/hal/radio/RadioDevice.h @@ -1,6 +1,7 @@ #pragma once #include "../Device.h" +#include "Unit.h" #include #include @@ -45,6 +46,12 @@ public: NarrowGrid }; + enum class ParameterStatus { + NotDefined, + ValueError, + Success + }; + typedef int RxSubscriptionId; typedef int TxId; @@ -120,8 +127,9 @@ public: Type getType() const override { return Type::Radio; } - virtual bool setParameter(const Parameter parameter, const float value) = 0; - virtual bool getParameter(const Parameter parameter, float &value) const = 0; + virtual ParameterStatus setParameter(const Parameter parameter, const float value) = 0; + virtual ParameterStatus getParameter(const Parameter parameter, float &value) const = 0; + virtual Unit getParameterUnit(const Parameter parameter) const = 0; virtual bool canTransmit(const Modulation modulation) = 0; virtual bool canReceive(const Modulation modulation) = 0; diff --git a/Tactility/Include/Tactility/hal/radio/Unit.h b/Tactility/Include/Tactility/hal/radio/Unit.h new file mode 100644 index 00000000..9efbd88b --- /dev/null +++ b/Tactility/Include/Tactility/hal/radio/Unit.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace tt::hal::radio { + +class Unit { +public: + enum class Prefix { + Femto, + Pico, + Nano, + Milli, + None, + Kilo, + Mega, + Giga, + Terra, + Peta + }; + + enum class Name + { + None, + BitsPerSecond, + BytesPerSecond, + Herz, + Decibel, + DecibelMilliwatts + }; + + const Prefix prefix; + const Name unit; + + explicit Unit(const Prefix si, const Name unit) + : prefix(si), unit(unit) {} + explicit Unit(const Name unit) + : prefix(Prefix::None), unit(unit) {} + + std::string toString() const; +}; + +const char* toString(Unit::Prefix prefix); +const char* toString(Unit::Name unit); + +} diff --git a/Tactility/Source/app/chirpchatter/ChirpChatterApp.cpp b/Tactility/Source/app/chirpchatter/ChirpChatterApp.cpp index f6a2c217..7597608d 100644 --- a/Tactility/Source/app/chirpchatter/ChirpChatterApp.cpp +++ b/Tactility/Source/app/chirpchatter/ChirpChatterApp.cpp @@ -428,17 +428,18 @@ public: void configureFromForm() { using enum tt::hal::radio::RadioDevice::Parameter; + using enum tt::hal::radio::RadioDevice::ParameterStatus; std::string buffer; int value = 0; bool configured = true; buffer = lv_textarea_get_text(frequencyInput); if (!buffer.empty()) { - configured &= loraDevice->setParameter(Frequency, std::stof(buffer)); + configured &= (loraDevice->setParameter(Frequency, std::stof(buffer)) == Success); } buffer = lv_textarea_get_text(bandwidthInput); if (!buffer.empty()) { - configured &= loraDevice->setParameter(Bandwidth, std::stof(buffer)); + configured &= (loraDevice->setParameter(Bandwidth, std::stof(buffer)) == Success); } buffer = lv_textarea_get_text(syncwordInput); if (!buffer.empty()) { @@ -446,20 +447,20 @@ public: std::stringstream ss(buffer); ss >> std::hex >> syncWord; - configured &= loraDevice->setParameter(SyncWord, std::stoi(buffer, nullptr, 16)); + configured &= (loraDevice->setParameter(SyncWord, std::stoi(buffer, nullptr, 16)) == Success); } value = lv_slider_get_value(deBitsInput); - configured &= loraDevice->setParameter(CodingRate, value); + configured &= (loraDevice->setParameter(CodingRate, value) == Success); value = lv_slider_get_value(sfInput); - configured &= loraDevice->setParameter(SpreadFactor, value); + configured &= (loraDevice->setParameter(SpreadFactor, value) == Success); value = lv_slider_get_value(preambleChirpsInput); - configured &= loraDevice->setParameter(PreambleLength, value); + configured &= (loraDevice->setParameter(PreambleLength, value) == Success); buffer = lv_textarea_get_text(txPowInput); if (!buffer.empty()) { - configured &= loraDevice->setParameter(Power, std::stof(buffer)); + configured &= (loraDevice->setParameter(Power, std::stof(buffer)) == Success); } } diff --git a/Tactility/Source/hal/radio/Unit.cpp b/Tactility/Source/hal/radio/Unit.cpp new file mode 100644 index 00000000..b3591631 --- /dev/null +++ b/Tactility/Source/hal/radio/Unit.cpp @@ -0,0 +1,60 @@ +#include "Tactility/hal/radio/Unit.h" +#include + +namespace tt::hal::radio { + +std::string Unit::toString() const { + return std::string(toString(prefix))+std::string(toString(unit)); +} + +const char* toString(Unit::Prefix prefix) { + using enum Unit::Prefix; + + switch (prefix) { + case Femto: + return "f"; + case Pico: + return "p"; + case Nano: + return "n"; + case Milli: + return "m"; + case None: + return ""; + case Kilo: + return "k"; + case Mega: + return "M"; + case Giga: + return "G"; + case Terra: + return "T"; + case Peta: + return "P"; + } + + return "?"; +} + +const char* toString(Unit::Name unit) { + using enum Unit::Name; + + switch (unit) { + case None: + return ""; + case BitsPerSecond: + return "bps"; + case BytesPerSecond: + return "Bps"; + case Herz: + return "Hz"; + case Decibel: + return "dB"; + case DecibelMilliwatts: + return "dBm"; + } + + return "?"; +} + +}