Compare commits

..

No commits in common. "8473c178e648fe1bfc37de56ef3f4a9731f6429a" and "cbfc7305f3b3baea351f3ca744be8a1265ac8f57" have entirely different histories.

13 changed files with 88 additions and 422 deletions

View File

@ -24,7 +24,7 @@ DeviceVector createDevices() {
auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0); auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0);
auto keyboard = std::make_shared<TpagerKeyboard>(tca8418); auto keyboard = std::make_shared<TpagerKeyboard>(tca8418);
auto sx1262 = std::make_shared<Sx1262>(Sx1262::Configuration{ auto sx1262 = std::make_shared<Sx1262>("SX1262", Sx1262::Configuration{
.spiHostDevice = SPI2_HOST, .spiHostDevice = SPI2_HOST,
.spiFrequency = 10'000'000, .spiFrequency = 10'000'000,
.csPin = GPIO_NUM_36, .csPin = GPIO_NUM_36,

View File

@ -54,16 +54,11 @@ void RadiolibTactilityHal::attachInterrupt(uint32_t interruptNum, void (*interru
return; return;
} }
if (!isrServiceInitialized) { gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM);
gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM);
isrServiceInitialized = true;
}
gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7)); gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7));
// this uses function typecasting, which is not defined when the functions have different signatures // this uses function typecasting, which is not defined when the functions have different signatures
// untested and might not work // untested and might not work
// TODO: I think the wisest course of action is forbidding registration via RadioLib entirely,
// as it doesn't suit Tactility with its lack of context passing
gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL); gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL);
} }

View File

@ -21,10 +21,9 @@ private:
spi_device_handle_t spiDeviceHandle; spi_device_handle_t spiDeviceHandle;
std::shared_ptr<tt::Lock> lock; std::shared_ptr<tt::Lock> lock;
bool spiInitialized; bool spiInitialized;
bool isrServiceInitialized;
public: public:
explicit RadiolibTactilityHal(spi_host_device_t spiHostDevice, int spiFrequency, gpio_num_t csPin) explicit RadiolibTactilityHal(spi_host_device_t spiHostDevice, int spiFrequency, gpio_num_t csPin, std::shared_ptr<tt::Lock> spiLock)
: RadioLibHal( : RadioLibHal(
GPIO_MODE_INPUT, GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT, GPIO_MODE_OUTPUT,
@ -35,9 +34,10 @@ public:
, spiHostDevice(spiHostDevice) , spiHostDevice(spiHostDevice)
, spiFrequency(spiFrequency) , spiFrequency(spiFrequency)
, csPin(csPin) , csPin(csPin)
, lock(tt::hal::spi::getLock(spiHostDevice)) , lock(spiLock)
, spiInitialized(false) , spiInitialized(false) {
, isrServiceInitialized(false) {} if (!lock) lock = tt::hal::spi::getLock(spiHostDevice);
}
void init() override; void init() override;
void term() override; void term() override;

View File

@ -3,8 +3,14 @@
constexpr const char* TAG = "RadiolibThreadedDevice"; constexpr const char* TAG = "RadiolibThreadedDevice";
bool RadiolibThreadedDevice::start() { bool RadiolibThreadedDevice::start(const Modulation modulation) {
auto lock = getMutex().asScopedLock(); auto lock = getMutex().asScopedLock();
if (!canTransmit(modulation)) {
TT_LOG_E(TAG, "Can't start device \"%s\", not capable of modulation \"%s\"", getName().c_str(), toString(modulation));
return false;
}
lock.lock(); lock.lock();
if ((thread != nullptr) && (thread->getState() != tt::Thread::State::Stopped)) { if ((thread != nullptr) && (thread->getState() != tt::Thread::State::Stopped)) {
@ -20,8 +26,8 @@ bool RadiolibThreadedDevice::start() {
thread = std::make_unique<tt::Thread>( thread = std::make_unique<tt::Thread>(
threadName, threadName,
threadSize, threadSize,
[this]() { [this, modulation]() {
return this->threadMain(); return this->threadMain(modulation);
} }
); );
thread->setPriority(tt::Thread::Priority::High); thread->setPriority(tt::Thread::Priority::High);
@ -65,9 +71,9 @@ bool RadiolibThreadedDevice::isThreadInterrupted() const {
return threadInterrupted; return threadInterrupted;
} }
int32_t RadiolibThreadedDevice::threadMain() { int32_t RadiolibThreadedDevice::threadMain(const Modulation modulation) {
int rc = doBegin(getModulation()); int rc = doBegin(modulation);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }

View File

@ -12,7 +12,7 @@ private:
bool threadInterrupted = false; bool threadInterrupted = false;
protected: protected:
virtual int32_t threadMain(); virtual int32_t threadMain(const Modulation modulation);
bool isThreadInterrupted() const; bool isThreadInterrupted() const;
virtual void interruptSignal() = 0; virtual void interruptSignal() = 0;
@ -31,6 +31,7 @@ public:
~RadiolibThreadedDevice() override = default; ~RadiolibThreadedDevice() override = default;
virtual bool start() override; virtual bool start(const Modulation modulation) override;
virtual bool stop() override; virtual bool stop() override;
}; };

View File

@ -5,266 +5,94 @@
constexpr const char* TAG = "Sx1262"; 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) { void IRAM_ATTR dio1handler(void* context) {
((Sx1262*)context)->dio1Event(); ((Sx1262*)context)->dio1Event();
} }
Sx1262::ParameterStatus Sx1262::setLoraParameter(const Parameter parameter, const float value) { bool Sx1262::setParameter(const Parameter parameter, const float value) {
using enum Parameter; using enum Parameter;
switch (parameter) { switch (parameter) {
case Power: case Power:
return checkLimitsAndApply(power, value, -9.0, 22.0); power = value;
return true;
case Frequency: case Frequency:
return checkLimitsAndApply(frequency, value, 150.0, 960.0); frequency = value;
return true;
case Bandwidth: case Bandwidth:
return checkValuesAndApply(bandwidth, value, { bandwidth = value;
7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0, 500.0 return true;
});
case SpreadFactor: case SpreadFactor:
return checkLimitsAndApply(spreadFactor, value, 7.0, 12.0, 1); spreadFactor = value;
return true;
case CodingRate: case CodingRate:
return checkLimitsAndApply(codingRate, value, 5.0, 8.0, 1); codingRate = value;
return true;
case SyncWord: case SyncWord:
return checkLimitsAndApply(syncWord, value, 0.0, 255.0, 1); syncWord = value;
return true;
case PreambleLength: case PreambleLength:
return checkLimitsAndApply(preambleLength, value, 0.0, 65535.0, 1); preambleLength = value;
default: return true;
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 Power:
return checkLimitsAndApply(power, value, -9.0, 22.0);
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: case DataRate:
return checkLimitsAndApply(bitRate, value, 0.6, 300.0); bitRate = value;
return true;
case FrequencyDeviation: case FrequencyDeviation:
return checkLimitsAndApply(frequencyDeviation, value, 0.0, 200.0); frequencyDeviation = value;
default: return true;
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 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: case NarrowGrid:
return checkLimitsAndApply(narrowGrid, value, 0.0, 1.0, 1); narrowGrid = value;
return true;
default: default:
break; break;
} }
TT_LOG_W(TAG, "Tried to set unsupported LR-FHSS parameter \"%s\" to %f", toString(parameter), value); TT_LOG_W(TAG, "Tried to set unsupported parameter \"%s\" to %f", toString(parameter), value);
return Sx1262::ParameterStatus::Unavailable;
return false;
} }
bool Sx1262::getParameter(const Parameter parameter, float &value) const {
Sx1262::ParameterStatus Sx1262::setParameter(const Parameter parameter, const float value) {
const auto currentModulation = getModulation();
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::getLoraParameter(const Parameter parameter, float &value) const {
using enum Parameter; using enum Parameter;
switch (parameter) { switch (parameter) {
case Power: case Power:
value = power; value = power;
return Sx1262::ParameterStatus::Success; return true;
case Frequency: case Frequency:
value = frequency; value = frequency;
return Sx1262::ParameterStatus::Success; return true;
case Bandwidth: case Bandwidth:
value = bandwidth; value = bandwidth;
return Sx1262::ParameterStatus::Success; return true;
case SpreadFactor: case SpreadFactor:
value = spreadFactor; value = spreadFactor;
return Sx1262::ParameterStatus::Success; return true;
case CodingRate: case CodingRate:
value = codingRate; value = codingRate;
return Sx1262::ParameterStatus::Success; return true;
case SyncWord: case SyncWord:
value = syncWord; value = syncWord;
return Sx1262::ParameterStatus::Success; return true;
case PreambleLength: case PreambleLength:
value = preambleLength; value = preambleLength;
return Sx1262::ParameterStatus::Success; return true;
default:
break;
}
TT_LOG_W(TAG, "Tried to get unsupported LoRa parameter \"%s\"", toString(parameter));
return Sx1262::ParameterStatus::Unavailable;
}
Sx1262::ParameterStatus Sx1262::getFskParameter(const Parameter parameter, float &value) const {
using enum Parameter;
switch (parameter) {
case Power:
value = power;
return Sx1262::ParameterStatus::Success;
case Frequency:
value = frequency;
return Sx1262::ParameterStatus::Success;
case Bandwidth:
value = bandwidth;
return Sx1262::ParameterStatus::Success;
case DataRate: case DataRate:
value = bitRate; value = bitRate;
return Sx1262::ParameterStatus::Success; return true;
case FrequencyDeviation: case FrequencyDeviation:
value = frequencyDeviation; value = frequencyDeviation;
return Sx1262::ParameterStatus::Success; return true;
default:
break;
}
TT_LOG_W(TAG, "Tried to get unsupported FSK parameter \"%s\"", toString(parameter));
return Sx1262::ParameterStatus::Unavailable;
}
Sx1262::ParameterStatus Sx1262::getLrFhssParameter(const Parameter parameter, float &value) const {
using enum Parameter;
switch (parameter) {
case Power:
value = power;
return Sx1262::ParameterStatus::Success;
case Bandwidth:
value = bandwidth;
return Sx1262::ParameterStatus::Success;
case CodingRate:
value = codingRate;
return Sx1262::ParameterStatus::Success;
case NarrowGrid: case NarrowGrid:
value = narrowGrid; value = narrowGrid;
return Sx1262::ParameterStatus::Success; return true;
default: default:
break; break;
} }
TT_LOG_W(TAG, "Tried to get unsupported LR-FHSS parameter \"%s\"", toString(parameter)); TT_LOG_W(TAG, "Tried to get unsupported parameter \"%s\"", toString(parameter));
return Sx1262::ParameterStatus::Unavailable;
}
return false;
Sx1262::ParameterStatus Sx1262::getParameter(const Parameter parameter, float &value) const {
const auto currentModulation = getModulation();
switch (currentModulation) {
case Modulation::LoRa:
return getLoraParameter(parameter, value);
case Modulation::Fsk:
return getFskParameter(parameter, value);
case Modulation::LrFhss:
return getLrFhssParameter(parameter, value);
default:
break;
}
// 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:
break;
}
TT_LOG_W(TAG, "Tried to get unit for unsupported parameter \"%s\"", toString(parameter));
return Unit(Unit::Name::None);
} }
void Sx1262::registerDio1Isr() { void Sx1262::registerDio1Isr() {
@ -353,6 +181,7 @@ int Sx1262::doBegin(const Modulation modulation) {
return -1; return -1;
} }
currentModem = modulation;
registerDio1Isr(); registerDio1Isr();
return 0; return 0;
} }
@ -369,18 +198,11 @@ void Sx1262::doTransmit() {
TT_LOG_W(TAG, "RadioLib returned %hi on standby", rc); TT_LOG_W(TAG, "RadioLib returned %hi on standby", rc);
} }
if (getModulation() == Modulation::Fsk) { rc = radio.startTransmit(currentTx.packet.data.data(), currentTx.packet.data.size());
rc = radio.startTransmit(currentTx.packet.data.data(), currentTx.packet.data.size(),
currentTx.packet.address);
} else {
rc = radio.startTransmit(currentTx.packet.data.data(), currentTx.packet.data.size());
}
if (rc == RADIOLIB_ERR_NONE) { if (rc == RADIOLIB_ERR_NONE) {
currentTx.callback(currentTx.id, TransmissionState::PendingTransmit); currentTx.callback(currentTx.id, TransmissionState::PendingTransmit);
auto txEventFlags = events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT, tt::EventFlag::WaitAny, auto txEventFlags = events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT, tt::EventFlag::WaitAny, pdMS_TO_TICKS(2000));
pdMS_TO_TICKS(SX1262_TX_TIMEOUT_MILLIS));
// Thread might've been interrupted in the meanwhile // Thread might've been interrupted in the meanwhile
if (isThreadInterrupted()) { if (isThreadInterrupted()) {
@ -401,7 +223,7 @@ void Sx1262::doTransmit() {
} }
void Sx1262::doListen() { void Sx1262::doListen() {
if (getModulation() != Modulation::LrFhss) { if (currentModem != Modulation::LrFhss) {
radio.startReceive(); radio.startReceive();
events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT | SX1262_QUEUED_TX_BIT); events.wait(SX1262_INTERRUPT_BIT | SX1262_DIO1_EVENT_BIT | SX1262_QUEUED_TX_BIT);
} else { } else {
@ -412,7 +234,7 @@ void Sx1262::doListen() {
void Sx1262::doReceive() { void Sx1262::doReceive() {
// LR-FHSS modem only supports TX // LR-FHSS modem only supports TX
if (getModulation() == Modulation::LrFhss) return; if (currentModem == Modulation::LrFhss) return;
uint16_t rxSize = radio.getPacketLength(true); uint16_t rxSize = radio.getPacketLength(true);
std::vector<uint8_t> data(rxSize); std::vector<uint8_t> data(rxSize);

View File

@ -25,9 +25,7 @@ public:
}; };
private: private:
static constexpr auto SX1262_DEFAULT_NAME = "SX1262";
static constexpr auto SX1262_COOLDOWN_MILLIS = 100; static constexpr auto SX1262_COOLDOWN_MILLIS = 100;
static constexpr auto SX1262_TX_TIMEOUT_MILLIS = 2000;
static constexpr auto SX1262_INTERRUPT_BIT = BIT0; static constexpr auto SX1262_INTERRUPT_BIT = BIT0;
static constexpr auto SX1262_DIO1_EVENT_BIT = BIT1; static constexpr auto SX1262_DIO1_EVENT_BIT = BIT1;
static constexpr auto SX1262_QUEUED_TX_BIT = BIT2; static constexpr auto SX1262_QUEUED_TX_BIT = BIT2;
@ -40,6 +38,7 @@ private:
Module radioModule; Module radioModule;
SX1262 radio; SX1262 radio;
TxItem currentTx; TxItem currentTx;
Modulation currentModem;
int8_t power = 0; int8_t power = 0;
float frequency = 0.0; float frequency = 0.0;
@ -55,14 +54,6 @@ private:
void registerDio1Isr(); void registerDio1Isr();
void unregisterDio1Isr(); void unregisterDio1Isr();
ParameterStatus setLoraParameter(const Parameter parameter, const float value);
ParameterStatus setFskParameter(const Parameter parameter, const float value);
ParameterStatus setLrFhssParameter(const Parameter parameter, const float value);
ParameterStatus getLoraParameter(const Parameter parameter, float &value) const;
ParameterStatus getFskParameter(const Parameter parameter, float &value) const;
ParameterStatus getLrFhssParameter(const Parameter parameter, float &value) const;
protected: protected:
virtual void txQueuedSignal() override; virtual void txQueuedSignal() override;
virtual void interruptSignal() override; virtual void interruptSignal() override;
@ -75,23 +66,24 @@ protected:
public: public:
explicit Sx1262(const Configuration& configuration, const std::string& name = SX1262_DEFAULT_NAME) explicit Sx1262(const std::string& name, const Configuration& configuration, std::shared_ptr<tt::Lock> lock = nullptr)
: RadiolibThreadedDevice(name, 4096) : RadiolibThreadedDevice(name, 4096)
, name(name) , name(name)
, configuration(configuration) , configuration(configuration)
, hal(configuration.spiHostDevice, configuration.spiFrequency, configuration.csPin) , hal(configuration.spiHostDevice, configuration.spiFrequency, configuration.csPin, lock)
, radioModule(&hal, configuration.csPin, configuration.irqPin, configuration.resetPin, configuration.busyPin) , radioModule(&hal, configuration.csPin, configuration.irqPin, configuration.resetPin, configuration.busyPin)
, radio(&radioModule) , radio(&radioModule)
, currentModem(Modulation::None)
{} {}
~Sx1262() override = default; ~Sx1262() override = default;
std::string getName() const override { return name; } std::string getName() const override { return name; }
std::string getDescription() const override { return "Semtech SX1262 LoRa, FSK and LR-FHSS capable radio"; } std::string getDescription() const override { return "Semtech SX1262 LoRa, FSK and LR-FHSS capable radio"; }
ParameterStatus setParameter(const Parameter parameter, const float value) override; bool setParameter(const Parameter parameter, const float value) override;
ParameterStatus getParameter(const Parameter parameter, float &value) const override; bool getParameter(const Parameter parameter, float &value) const override;
tt::hal::radio::Unit getParameterUnit(const Parameter parameter) const override;
bool canTransmit(const Modulation modulation) override { bool canTransmit(const Modulation modulation) override {
return (modulation == Modulation::Fsk) || return (modulation == Modulation::Fsk) ||

View File

@ -34,29 +34,23 @@ public:
} }
return false; return false;
} }
void clear() { parameters.clear(); }
bool apply(RadioDevice &radio) { bool apply(RadioDevice &radio) {
bool successful = true; bool successful = true;
for (const auto& [parameter, value] : parameters) { for (const auto& [parameter, value] : parameters) {
// No break on error chosen to apply all parameters, // No break on error chosen to apply all parameters,
// a bad one doesn't make the successive tries any more invalid // a bad one doesn't make the successive tries any more invalid
successful &= (radio.setParameter(parameter, value) == RadioDevice::ParameterStatus::Success); successful &= radio.setParameter(parameter, value);
} }
return successful; return successful;
} }
void load(const RadioDevice &radio) { bool load(const RadioDevice &radio) {
// This loop has to be ajusted for each new parameter. bool successful = true;
// Could be made more maintainable with a template enum iterator in an utility header. for (const auto& [parameter, value] : parameters) {
for (RadioDevice::Parameter p = RadioDevice::Parameter::Power; successful &= radio.getParameter(parameter, parameters[parameter]);
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;
} }
}; };

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../Device.h" #include "../Device.h"
#include "Unit.h"
#include <Tactility/Mutex.h> #include <Tactility/Mutex.h>
#include <Tactility/Thread.h> #include <Tactility/Thread.h>
@ -46,12 +45,6 @@ public:
NarrowGrid NarrowGrid
}; };
enum class ParameterStatus {
Unavailable,
ValueError,
Success
};
typedef int RxSubscriptionId; typedef int RxSubscriptionId;
typedef int TxId; typedef int TxId;
@ -88,7 +81,6 @@ private:
}; };
State state; State state;
Modulation modulation;
Mutex mutex = Mutex(Mutex::Type::Recursive); Mutex mutex = Mutex(Mutex::Type::Recursive);
std::vector<RxSubscription> rxSubscriptions; std::vector<RxSubscription> rxSubscriptions;
std::deque<TxItem> txQueue; std::deque<TxItem> txQueue;
@ -122,21 +114,18 @@ protected:
public: public:
explicit RadioDevice() explicit RadioDevice()
: state(State::Off), modulation(Modulation::None) {} : state(State::Off) {}
~RadioDevice() override = default; ~RadioDevice() override = default;
Type getType() const override { return Type::Radio; } Type getType() const override { return Type::Radio; }
bool setModulation(const Modulation newModulation); virtual bool setParameter(const Parameter parameter, const float value) = 0;
Modulation getModulation() const; 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 canTransmit(const Modulation modulation) = 0;
virtual bool canReceive(const Modulation modulation) = 0; virtual bool canReceive(const Modulation modulation) = 0;
virtual bool start() = 0; virtual bool start(const Modulation modulation) = 0;
virtual bool stop() = 0; virtual bool stop() = 0;
TxId transmit(const TxPacket& packet, TxStateCallback callback) { TxId transmit(const TxPacket& packet, TxStateCallback callback) {

View File

@ -1,46 +0,0 @@
#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);
}

View File

@ -428,18 +428,17 @@ public:
void configureFromForm() { void configureFromForm() {
using enum tt::hal::radio::RadioDevice::Parameter; using enum tt::hal::radio::RadioDevice::Parameter;
using enum tt::hal::radio::RadioDevice::ParameterStatus;
std::string buffer; std::string buffer;
int value = 0; int value = 0;
bool configured = true; bool configured = true;
buffer = lv_textarea_get_text(frequencyInput); buffer = lv_textarea_get_text(frequencyInput);
if (!buffer.empty()) { if (!buffer.empty()) {
configured &= (loraDevice->setParameter(Frequency, std::stof(buffer)) == Success); configured &= loraDevice->setParameter(Frequency, std::stof(buffer));
} }
buffer = lv_textarea_get_text(bandwidthInput); buffer = lv_textarea_get_text(bandwidthInput);
if (!buffer.empty()) { if (!buffer.empty()) {
configured &= (loraDevice->setParameter(Bandwidth, std::stof(buffer)) == Success); configured &= loraDevice->setParameter(Bandwidth, std::stof(buffer));
} }
buffer = lv_textarea_get_text(syncwordInput); buffer = lv_textarea_get_text(syncwordInput);
if (!buffer.empty()) { if (!buffer.empty()) {
@ -447,20 +446,20 @@ public:
std::stringstream ss(buffer); std::stringstream ss(buffer);
ss >> std::hex >> syncWord; ss >> std::hex >> syncWord;
configured &= (loraDevice->setParameter(SyncWord, std::stoi(buffer, nullptr, 16)) == Success); configured &= loraDevice->setParameter(SyncWord, std::stoi(buffer, nullptr, 16));
} }
value = lv_slider_get_value(deBitsInput); value = lv_slider_get_value(deBitsInput);
configured &= (loraDevice->setParameter(CodingRate, value) == Success); configured &= loraDevice->setParameter(CodingRate, value);
value = lv_slider_get_value(sfInput); value = lv_slider_get_value(sfInput);
configured &= (loraDevice->setParameter(SpreadFactor, value) == Success); configured &= loraDevice->setParameter(SpreadFactor, value);
value = lv_slider_get_value(preambleChirpsInput); value = lv_slider_get_value(preambleChirpsInput);
configured &= (loraDevice->setParameter(PreambleLength, value) == Success); configured &= loraDevice->setParameter(PreambleLength, value);
buffer = lv_textarea_get_text(txPowInput); buffer = lv_textarea_get_text(txPowInput);
if (!buffer.empty()) { if (!buffer.empty()) {
configured &= (loraDevice->setParameter(Power, std::stof(buffer)) == Success); configured &= loraDevice->setParameter(Power, std::stof(buffer));
} }
} }
@ -469,9 +468,8 @@ public:
loraDevice = loraDevs[lv_dropdown_get_selected(loraDeviceInput)]; loraDevice = loraDevs[lv_dropdown_get_selected(loraDeviceInput)];
if (loraDevice) { if (loraDevice) {
disableForm(); disableForm();
loraDevice->setModulation(tt::hal::radio::RadioDevice::Modulation::LoRa);
configureFromForm(); configureFromForm();
loraDevice->start(); loraDevice->start(tt::hal::radio::RadioDevice::Modulation::LoRa);
vTaskDelay(pdMS_TO_TICKS(500)); vTaskDelay(pdMS_TO_TICKS(500));
if (loraDevice->getState() != tt::hal::radio::RadioDevice::State::On) { if (loraDevice->getState() != tt::hal::radio::RadioDevice::State::On) {
lv_obj_clear_state(loraDeviceOn, LV_STATE_CHECKED); lv_obj_clear_state(loraDeviceOn, LV_STATE_CHECKED);

View File

@ -5,31 +5,6 @@ namespace tt::hal::radio {
constexpr const char* TAG = "RadioDevice"; constexpr const char* TAG = "RadioDevice";
bool RadioDevice::setModulation(const RadioDevice::Modulation newModulation) {
// A bool is chosen over an enum class because:
// - this is not tied to user input and
// - the programmer can infer why it didn't work using
// other methods such as getState() and canTransmit/Receive()
const auto state = getState();
if ((state == State::PendingOn) || (state == State::On)) {
return false;
} else if (!(canTransmit(newModulation) || canReceive(newModulation))) {
return false;
} else {
auto lock = mutex.asScopedLock();
lock.lock();
modulation = newModulation;
}
return true;
}
RadioDevice::Modulation RadioDevice::getModulation() const {
auto lock = mutex.asScopedLock();
lock.lock();
return modulation;
}
RadioDevice::State RadioDevice::getState() const { RadioDevice::State RadioDevice::getState() const {
auto lock = mutex.asScopedLock(); auto lock = mutex.asScopedLock();
lock.lock(); lock.lock();

View File

@ -1,60 +0,0 @@
#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 "?";
}
}