Radio: Add parameter validation, add units
This commit is contained in:
parent
4ac4507538
commit
5eb3dbcd9f
@ -33,5 +33,4 @@ public:
|
||||
|
||||
virtual bool start(const Modulation modulation) override;
|
||||
virtual bool stop() override;
|
||||
|
||||
};
|
||||
|
||||
@ -5,94 +5,146 @@
|
||||
|
||||
constexpr const char* TAG = "Sx1262";
|
||||
|
||||
template<typename T>
|
||||
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<int>(value);
|
||||
if ((ivalue % step) != 0) {
|
||||
return Sx1262::ParameterStatus::ValueError;
|
||||
}
|
||||
}
|
||||
|
||||
target = static_cast<T>(value);
|
||||
return Sx1262::ParameterStatus::Success;
|
||||
}
|
||||
return Sx1262::ParameterStatus::ValueError;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr Sx1262::ParameterStatus checkValuesAndApply(T &target, const float value, std::initializer_list<float> valids) {
|
||||
for (float valid : valids) {
|
||||
if (value == valid) {
|
||||
target = static_cast<T>(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() {
|
||||
|
||||
@ -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) ||
|
||||
|
||||
@ -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<RadioDevice::Parameter>((size_t)p + 1)) {
|
||||
float value = 0.0;
|
||||
if (radio.getParameter(p, value) == RadioDevice::ParameterStatus::Success) {
|
||||
set(p, value);
|
||||
}
|
||||
}
|
||||
return successful;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Device.h"
|
||||
#include "Unit.h"
|
||||
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/Thread.h>
|
||||
@ -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;
|
||||
|
||||
|
||||
46
Tactility/Include/Tactility/hal/radio/Unit.h
Normal file
46
Tactility/Include/Tactility/hal/radio/Unit.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
60
Tactility/Source/hal/radio/Unit.cpp
Normal file
60
Tactility/Source/hal/radio/Unit.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "Tactility/hal/radio/Unit.h"
|
||||
#include <cstring>
|
||||
|
||||
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 "?";
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user