#include "tt_hal_radio.h" #include "Tactility/Check.h" #include "Tactility/hal/Device.h" #include "Tactility/hal/radio/RadioDevice.h" auto constexpr TAG = "tt_hal_radio"; static RadioState fromCpp(tt::hal::radio::RadioDevice::State state); static tt::hal::radio::RadioDevice::State toCpp(RadioState state); static Modulation fromCpp(tt::hal::radio::RadioDevice::Modulation modulation); static tt::hal::radio::RadioDevice::Modulation toCpp(Modulation modulation); static RadioParameter fromCpp(tt::hal::radio::RadioDevice::Parameter parameter); static tt::hal::radio::RadioDevice::Parameter toCpp(RadioParameter parameter); static RadioParameterStatus fromCpp(tt::hal::radio::RadioDevice::ParameterStatus status); static tt::hal::radio::RadioDevice::ParameterStatus toCpp(RadioParameterStatus status); static RadioTxState fromCpp(tt::hal::radio::RadioDevice::TransmissionState state); static tt::hal::radio::RadioDevice::TransmissionState toCpp(RadioTxState state); struct DeviceWrapper { std::shared_ptr device; std::string name; std::string description; DeviceWrapper(std::shared_ptr device) : device(device) , name(device->getName()) , description(device->getDescription()) {} }; static std::shared_ptr findValidRadioDevice(tt::hal::Device::Id id) { auto device = tt::hal::findDevice(id); if (device == nullptr || device->getType() != tt::hal::Device::Type::Radio) { return nullptr; } return std::reinterpret_pointer_cast(device); } extern "C" { RadioHandle tt_hal_radio_alloc(DeviceId radioId) { auto radio = findValidRadioDevice(radioId); return new DeviceWrapper(radio); } void tt_hal_radio_free(RadioHandle handle) { auto wrapper = static_cast(handle); delete wrapper; } const char* tt_hal_radio_get_name(RadioHandle handle) { auto wrapper = static_cast(handle); return wrapper->name.c_str(); } const char* tt_hal_radio_get_desc(RadioHandle handle) { auto wrapper = static_cast(handle); return wrapper->description.c_str(); } RadioState tt_hal_radio_get_state(RadioHandle handle) { auto wrapper = static_cast(handle); return fromCpp(wrapper->device->getState()); } bool tt_hal_radio_set_modulation(RadioHandle handle, Modulation modulation) { auto wrapper = static_cast(handle); return wrapper->device->setModulation(toCpp(modulation)); } Modulation tt_hal_radio_get_modulation(RadioHandle handle) { auto wrapper = static_cast(handle); return fromCpp(wrapper->device->getModulation()); } RadioParameterStatus tt_hal_radio_set_parameter(RadioHandle handle, RadioParameter parameter, float value) { auto wrapper = static_cast(handle); return fromCpp(wrapper->device->setParameter(toCpp(parameter), value)); } RadioParameterStatus tt_hal_radio_get_parameter(RadioHandle handle, RadioParameter parameter, float *value) { auto wrapper = static_cast(handle); // This is a programming error not an input error, thus assert. // TODO: Does TactC even know assert? Maybe putting a crash is the optimal solution. assert(value); return fromCpp(wrapper->device->getParameter(toCpp(parameter), *value)); } void tt_hal_radio_get_parameter_unit_str(RadioHandle handle, RadioParameter parameter, char str[], unsigned maxSize) { auto wrapper = static_cast(handle); assert(str); std::string unitString = wrapper->device->getParameterUnit(toCpp(parameter)).toString(); size_t i = 0; for (; i < (maxSize - 1); ++i) { str[i] = unitString[i]; } str[i] = '\0'; } bool tt_hal_radio_can_transmit(RadioHandle handle, Modulation modulation) { auto wrapper = static_cast(handle); return wrapper->device->canTransmit(toCpp(modulation)); } bool tt_hal_radio_can_receive(RadioHandle handle, Modulation modulation) { auto wrapper = static_cast(handle); return wrapper->device->canReceive(toCpp(modulation)); } bool tt_hal_radio_start(RadioHandle handle) { auto wrapper = static_cast(handle); return wrapper->device->start(); } bool tt_hal_radio_stop(RadioHandle handle) { auto wrapper = static_cast(handle); return wrapper->device->stop(); } RadioTxId tt_hal_radio_transmit(RadioHandle handle, RadioTxPacket packet, RadioTxStateCallback callback) { auto wrapper = static_cast(handle); auto ttPacket = tt::hal::radio::TxPacket{ .data = std::vector(packet.data, packet.data + packet.size), .address = packet.address }; return wrapper->device->transmit(ttPacket, [callback](tt::hal::radio::RadioDevice::TxId id, tt::hal::radio::RadioDevice::TransmissionState state) { if (callback) { callback(id, fromCpp(state)); } }); } RadioStateSubscriptionId tt_hal_radio_subscribe_state(RadioHandle handle, RadioStateCallback callback) { auto wrapper = static_cast(handle); return wrapper->device->subscribeStateChange([callback](tt::hal::Device::Id id, tt::hal::radio::RadioDevice::State state) { if (callback) { callback(id, fromCpp(state)); } }); } RadioRxSubscriptionId tt_hal_radio_subscribe_receive(RadioHandle handle, RadioOnReceiveCallback callback) { auto wrapper = static_cast(handle); return wrapper->device->subscribeRx([callback](tt::hal::Device::Id id, const tt::hal::radio::RxPacket& ttPacket) { if (callback) { auto ttcPacket = RadioRxPacket{ .data = ttPacket.data.data(), .size = ttPacket.data.size(), .rssi = ttPacket.rssi, .snr = ttPacket.snr }; callback(id, &ttcPacket); } }); } void tt_hal_radio_unsubscribe_receive(RadioHandle handle, RadioRxSubscriptionId id) { auto wrapper = static_cast(handle); wrapper->device->unsubscribeRx(id); } } static RadioState fromCpp(tt::hal::radio::RadioDevice::State state) { switch (state) { case tt::hal::radio::RadioDevice::State::PendingOn: return RADIO_PENDING_ON; case tt::hal::radio::RadioDevice::State::On: return RADIO_ON; case tt::hal::radio::RadioDevice::State::Error: return RADIO_ERROR; case tt::hal::radio::RadioDevice::State::PendingOff: return RADIO_PENDING_OFF; case tt::hal::radio::RadioDevice::State::Off: return RADIO_OFF; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", state); tt_crash("Radio state not supported"); } } static tt::hal::radio::RadioDevice::State toCpp(RadioState state) { switch (state) { case RADIO_PENDING_ON: return tt::hal::radio::RadioDevice::State::PendingOn; case RADIO_ON: return tt::hal::radio::RadioDevice::State::On; case RADIO_ERROR: return tt::hal::radio::RadioDevice::State::Error; case RADIO_PENDING_OFF: return tt::hal::radio::RadioDevice::State::PendingOff; case RADIO_OFF: return tt::hal::radio::RadioDevice::State::Off; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", state); tt_crash("Radio state not supported"); } } static Modulation fromCpp(tt::hal::radio::RadioDevice::Modulation modulation) { switch (modulation) { case tt::hal::radio::RadioDevice::Modulation::None: return MODULATION_NONE; case tt::hal::radio::RadioDevice::Modulation::LoRa: return MODULATION_LORA; case tt::hal::radio::RadioDevice::Modulation::Fsk: return MODULATION_FSK; case tt::hal::radio::RadioDevice::Modulation::LrFhss: return MODULATION_LRFHSS; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", modulation); tt_crash("Modulation not supported"); } } static tt::hal::radio::RadioDevice::Modulation toCpp(Modulation modulation) { switch (modulation) { case MODULATION_NONE: return tt::hal::radio::RadioDevice::Modulation::None; case MODULATION_LORA: return tt::hal::radio::RadioDevice::Modulation::LoRa; case MODULATION_FSK: return tt::hal::radio::RadioDevice::Modulation::Fsk; case MODULATION_LRFHSS: return tt::hal::radio::RadioDevice::Modulation::LrFhss; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", modulation); tt_crash("Modulation not supported"); } } static RadioParameter fromCpp(tt::hal::radio::RadioDevice::Parameter parameter) { switch (parameter) { case tt::hal::radio::RadioDevice::Parameter::Power: return RADIO_POWER; case tt::hal::radio::RadioDevice::Parameter::Frequency: return RADIO_FREQUENCY; case tt::hal::radio::RadioDevice::Parameter::Bandwidth: return RADIO_BANDWIDTH; case tt::hal::radio::RadioDevice::Parameter::SpreadFactor: return RADIO_SPREADFACTOR; case tt::hal::radio::RadioDevice::Parameter::CodingRate: return RADIO_CODINGRATE; case tt::hal::radio::RadioDevice::Parameter::SyncWord: return RADIO_SYNCWORD; case tt::hal::radio::RadioDevice::Parameter::PreambleLength: return RADIO_PREAMBLES; case tt::hal::radio::RadioDevice::Parameter::FrequencyDeviation: return RADIO_FREQDIV; case tt::hal::radio::RadioDevice::Parameter::DataRate: return RADIO_DATARATE; case tt::hal::radio::RadioDevice::Parameter::AddressWidth: return RADIO_ADDRWIDTH; case tt::hal::radio::RadioDevice::Parameter::NarrowGrid: return RADIO_NARROWGRID; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", parameter); tt_crash("Parameter not supported"); } } static tt::hal::radio::RadioDevice::Parameter toCpp(RadioParameter parameter) { switch (parameter) { case RADIO_POWER: return tt::hal::radio::RadioDevice::Parameter::Power; case RADIO_FREQUENCY: return tt::hal::radio::RadioDevice::Parameter::Frequency; case RADIO_BANDWIDTH: return tt::hal::radio::RadioDevice::Parameter::Bandwidth; case RADIO_SPREADFACTOR: return tt::hal::radio::RadioDevice::Parameter::SpreadFactor; case RADIO_CODINGRATE: return tt::hal::radio::RadioDevice::Parameter::CodingRate; case RADIO_SYNCWORD: return tt::hal::radio::RadioDevice::Parameter::SyncWord; case RADIO_PREAMBLES: return tt::hal::radio::RadioDevice::Parameter::PreambleLength; case RADIO_FREQDIV: return tt::hal::radio::RadioDevice::Parameter::FrequencyDeviation; case RADIO_DATARATE: return tt::hal::radio::RadioDevice::Parameter::DataRate; case RADIO_ADDRWIDTH: return tt::hal::radio::RadioDevice::Parameter::AddressWidth; case RADIO_NARROWGRID: return tt::hal::radio::RadioDevice::Parameter::NarrowGrid; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", parameter); tt_crash("Parameter not supported"); } } static RadioParameterStatus fromCpp(tt::hal::radio::RadioDevice::ParameterStatus status) { switch (status) { case tt::hal::radio::RadioDevice::ParameterStatus::Unavailable: return RADIO_PARAM_UNAVAILABLE; case tt::hal::radio::RadioDevice::ParameterStatus::ValueError: return RADIO_PARAM_VALERROR; case tt::hal::radio::RadioDevice::ParameterStatus::Success: return RADIO_PARAM_SUCCESS; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", status); tt_crash("Parameter status not supported"); } } static tt::hal::radio::RadioDevice::ParameterStatus toCpp(RadioParameterStatus status) { switch (status) { case RADIO_PARAM_UNAVAILABLE: return tt::hal::radio::RadioDevice::ParameterStatus::Unavailable; case RADIO_PARAM_VALERROR: return tt::hal::radio::RadioDevice::ParameterStatus::ValueError; case RADIO_PARAM_SUCCESS: return tt::hal::radio::RadioDevice::ParameterStatus::Success; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", status); tt_crash("Parameter status not supported"); } } static RadioTxState fromCpp(tt::hal::radio::RadioDevice::TransmissionState state) { switch (state) { case tt::hal::radio::RadioDevice::TransmissionState::Queued: return RADIO_TX_QUEUED; case tt::hal::radio::RadioDevice::TransmissionState::PendingTransmit: return RADIO_TX_PENDING_TRANSMIT; case tt::hal::radio::RadioDevice::TransmissionState::Transmitted: return RADIO_TX_TRANSMITTED; case tt::hal::radio::RadioDevice::TransmissionState::Timeout: return RADIO_TX_TIMEOUT; case tt::hal::radio::RadioDevice::TransmissionState::Error: return RADIO_TX_ERROR; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", state); tt_crash("Transmission state not supported"); } } static tt::hal::radio::RadioDevice::TransmissionState toCpp(RadioTxState state) { switch (state) { case RADIO_TX_QUEUED: return tt::hal::radio::RadioDevice::TransmissionState::Queued; case RADIO_TX_PENDING_TRANSMIT: return tt::hal::radio::RadioDevice::TransmissionState::PendingTransmit; case RADIO_TX_TRANSMITTED: return tt::hal::radio::RadioDevice::TransmissionState::Transmitted; case RADIO_TX_TIMEOUT: return tt::hal::radio::RadioDevice::TransmissionState::Timeout; case RADIO_TX_ERROR: return tt::hal::radio::RadioDevice::TransmissionState::Error; default: TT_LOG_W(TAG, "Unknown enum \"%d\" passed!", state); tt_crash("Transmission state not supported"); } }