176 lines
4.3 KiB
C++
176 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include "../Device.h"
|
|
|
|
#include <Tactility/EventFlag.h>
|
|
#include <Tactility/Lock.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 {
|
|
Fsk,
|
|
LoRa,
|
|
LrFhss
|
|
};
|
|
|
|
enum class Parameter {
|
|
Power,
|
|
Frequency,
|
|
Bandwidth,
|
|
SpreadFactor,
|
|
CodingRate,
|
|
SyncWord,
|
|
PreambleLength,
|
|
FrequencyDeviation,
|
|
DataRate,
|
|
AddressWidth
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
std::string threadName;
|
|
size_t threadSize;
|
|
State state;
|
|
EventFlag events;
|
|
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
|
std::unique_ptr<Thread> _Nullable thread;
|
|
bool threadInterrupted = false;
|
|
std::vector<RxSubscription> rxSubscriptions;
|
|
std::deque<TxItem> txQueue;
|
|
TxId lastTxId = 0;
|
|
RxSubscriptionId lastRxSubscriptionId = 0;
|
|
|
|
protected:
|
|
|
|
static constexpr auto RADIO_TERMINATE_BIT = BIT0;
|
|
static constexpr auto RADIO_TRANSMIT_QUEUED_BIT = BIT1;
|
|
static constexpr auto RADIO_RECEIVED_BIT = BIT2;
|
|
static constexpr auto RADIO_TRANSMITTED_BIT = BIT3;
|
|
|
|
virtual int32_t threadMain(const Modulation modulation) = 0;
|
|
Mutex &getMutex() { return mutex; }
|
|
EventFlag &getEventFlag() { return events; }
|
|
bool isThreadInterrupted() const;
|
|
void setState(State newState);
|
|
|
|
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(const std::string& threadName, const size_t threadSize)
|
|
: threadName(threadName)
|
|
, threadSize(threadSize)
|
|
, state(State::Off) {}
|
|
|
|
~RadioDevice() override = default;
|
|
|
|
Type getType() const override { return Type::Radio; }
|
|
|
|
virtual bool configure(const Parameter parameter, const float value) = 0;
|
|
virtual bool isCapableOf(const Modulation modulation) = 0;
|
|
|
|
bool start(const Modulation modulation);
|
|
bool stop();
|
|
|
|
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++;
|
|
getEventFlag().set(RADIO_TRANSMIT_QUEUED_BIT);
|
|
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);
|
|
}
|