175 lines
4.1 KiB
C++

#pragma once
#include "../Device.h"
#include "Unit.h"
#include <Tactility/Mutex.h>
#include <Tactility/Thread.h>
#include <deque>
#include <utility>
namespace tt::hal::radio {
struct RxPacket {
std::vector<uint8_t> data;
float rssi;
float snr;
};
struct TxPacket {
std::vector<uint8_t> data;
uint32_t address; // FSK only
};
class RadioDevice : public Device {
public:
enum class Modulation {
None,
Fsk,
LoRa,
LrFhss
};
enum class Parameter {
Power,
Frequency,
Bandwidth,
SpreadFactor,
CodingRate,
SyncWord,
PreambleLength,
FrequencyDeviation,
DataRate,
AddressWidth,
NarrowGrid
};
enum class ParameterStatus {
Unavailable,
ValueError,
Success
};
typedef int RxSubscriptionId;
typedef int TxId;
enum class State {
PendingOn,
On,
Error,
PendingOff,
Off
};
enum class TransmissionState {
Queued,
PendingTransmit,
Transmitted,
Timeout,
Error
};
using TxStateCallback = std::function<void(TxId id, TransmissionState state)>;
protected:
struct TxItem {
TxId id;
TxPacket packet;
TxStateCallback callback;
};
private:
struct RxSubscription {
RxSubscriptionId id;
std::shared_ptr<std::function<void(Device::Id id, const RxPacket&)>> onData;
};
State state;
Modulation modulation;
Mutex mutex = Mutex(Mutex::Type::Recursive);
std::vector<RxSubscription> rxSubscriptions;
std::deque<TxItem> txQueue;
TxId lastTxId = 0;
RxSubscriptionId lastRxSubscriptionId = 0;
protected:
const Mutex &getMutex() const { return mutex; }
void setState(State newState);
virtual void txQueuedSignal() = 0;
size_t getTxQueueSize() const {
auto lock = mutex.asScopedLock();
lock.lock();
const auto size = txQueue.size();
return size;
}
TxItem popNextQueuedTx() {
auto lock = mutex.asScopedLock();
lock.lock();
auto tx = std::move(txQueue.front());
txQueue.pop_front();
return tx;
}
void publishRx(const RxPacket& packet);
public:
explicit RadioDevice()
: state(State::Off), modulation(Modulation::None) {}
~RadioDevice() override = default;
Type getType() const override { return Type::Radio; }
bool setModulation(const Modulation newModulation);
Modulation getModulation() const;
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;
virtual bool start() = 0;
virtual bool stop() = 0;
TxId transmit(const TxPacket& packet, TxStateCallback callback) {
auto lock = mutex.asScopedLock();
lock.lock();
const auto txId = lastTxId;
txQueue.push_back(TxItem{.id = txId, .packet = packet, .callback = callback});
callback(txId, TransmissionState::Queued);
lastTxId++;
txQueuedSignal();
return txId;
}
RxSubscriptionId subscribeRx(const std::function<void(Device::Id id, const RxPacket&)>& onData) {
auto lock = mutex.asScopedLock();
lock.lock();
rxSubscriptions.push_back({
.id = ++lastRxSubscriptionId,
.onData = std::make_shared<std::function<void(Device::Id, const RxPacket&)>>(onData)
});
return lastRxSubscriptionId;
}
void unsubscribeRx(RxSubscriptionId subscriptionId) {
auto lock = mutex.asScopedLock();
lock.lock();
std::erase_if(rxSubscriptions, [subscriptionId](auto& subscription) { return subscription.id == subscriptionId; });
}
State getState() const;
};
const char* toString(RadioDevice::Modulation modulation);
const char* toString(RadioDevice::Parameter parameter);
}