From 73e1535d143e4845a0616e4c3f5ab7cd58cfab84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20H=C3=B6glinger?= Date: Wed, 24 Sep 2025 19:33:50 +0200 Subject: [PATCH] RadioSet: Forgot main(), add first draft of UI I just found out that the STL is not available. Finally, C+. --- .../RadioSet/main/Source/RadioSet.cpp | 149 ++++++++++++++++-- ExternalApps/RadioSet/main/Source/RadioSet.h | 8 +- ExternalApps/RadioSet/main/Source/main.cpp | 29 ++++ 3 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 ExternalApps/RadioSet/main/Source/main.cpp diff --git a/ExternalApps/RadioSet/main/Source/RadioSet.cpp b/ExternalApps/RadioSet/main/Source/RadioSet.cpp index e313dfc4..73da13e0 100644 --- a/ExternalApps/RadioSet/main/Source/RadioSet.cpp +++ b/ExternalApps/RadioSet/main/Source/RadioSet.cpp @@ -1,11 +1,145 @@ #include "RadioSet.h" #include +#include +#include +#include #include #include +#include "tt_app_alertdialog.h" + constexpr const char* TAG = "RadioSet"; +void crash(const char* const message) { + tt_app_alertdialog_start("RadioSet has crashed!", message, nullptr, 0); +} + +class TermView { + +}; + +class SettingsView { +private: + static constexpr size_t MAX_RADIOS = 32; + std::vector radios; + + lv_obj_t *deviceForm = nullptr; + lv_obj_t *radioDropdown = nullptr; + lv_obj_t *radioSwitch = nullptr; + + lv_obj_t *propertiesForm = nullptr; +public: + void queryRadios() { + std::vector devices(MAX_RADIOS); + uint16_t radioCount = 0; + if(!tt_hal_device_find(DEVICE_TYPE_RADIO, devices.data(), &radioCount, devices.capacity())) { + // TT_LOG_W(TAG, "No radios registered with the system?"); + } else { + devices.resize(radioCount); + radios.reserve(devices.size()); + for (auto devId : devices) { + auto radio = tt_hal_radio_alloc(devId); + if (!radio) { + // TT_LOG_E(TAG, "Error allocating radio handle for id=%d", devId); + } else { + radios.push_back(radio); + // TT_LOG_I(TAG, "Discovered radio \"%s\"", tt_hal_radio_get_name(radio)); + } + } + } + } + + bool getRadioNames(std::vector &names) { + int count = 1; + names.clear(); + for (auto radio : radios) { + std::string name(tt_hal_radio_get_name(radio)); + if (name == "") { + std::ostringstream oss("Unknown Radio "); + oss << count; + name = oss.str(); + } + names.push_back(name); + count++; + } + + return !names.empty(); + } + + lv_obj_t* initGridDropdownInput(lv_obj_t *container, int row, const char* const label, const char* const items) { + lv_obj_t* label_obj = lv_label_create(container); + lv_label_set_text(label_obj, label); + lv_obj_set_grid_cell(label_obj, + LV_GRID_ALIGN_STRETCH, 0, 1, + LV_GRID_ALIGN_CENTER, row, 1); + lv_obj_set_size(label_obj, lv_pct(100), LV_SIZE_CONTENT); + + lv_obj_t* input = lv_dropdown_create(container); + lv_obj_set_grid_cell(input, + LV_GRID_ALIGN_STRETCH, 1, 1, + LV_GRID_ALIGN_CENTER, row, 1); + lv_obj_set_size(input, lv_pct(100), LV_SIZE_CONTENT); + lv_dropdown_set_options(input, items); + + return input; + } + + lv_obj_t *initDeviceForm(lv_obj_t *parent) { + lv_obj_t *container = lv_obj_create(parent); + lv_obj_set_size(container, lv_pct(100), lv_pct(100)); + lv_obj_set_style_pad_all(container, 0, 0); + + const int grid_row_size = 40; + const int grid_col_size = 45; + static lv_coord_t lora_col_dsc[] = {LV_GRID_FR(3), LV_GRID_FR(2), grid_col_size, LV_GRID_TEMPLATE_LAST}; + static lv_coord_t lora_row_dsc[] = { + grid_row_size, + grid_row_size, + LV_GRID_TEMPLATE_LAST}; + lv_obj_set_grid_dsc_array(container, lora_col_dsc, lora_row_dsc); + + std::ostringstream item_oss(""); + std::vector radio_names; + if (getRadioNames(radio_names)) { + for (size_t i = 0; i < radio_names.size(); ++i) { + auto name = radio_names[i]; + auto last = (i != (radio_names.size() - 1)); + item_oss << name; + if (!last) { + item_oss << "\n"; + } + } + } + + radioDropdown = initGridDropdownInput(container, 0, "Device", item_oss.str().c_str()); + radioSwitch = lv_switch_create(container); + lv_obj_set_grid_cell(radioSwitch, + LV_GRID_ALIGN_STRETCH, 2, 1, + LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_size(radioSwitch, lv_pct(100), 20); + + return container; + } + + void initUi(lv_obj_t *parent) { + lv_obj_t *container = lv_obj_create(parent); + lv_obj_set_size(container, lv_pct(100), lv_pct(80)); + lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN); + lv_obj_align(container, LV_ALIGN_TOP_MID, 0, 0); + lv_obj_set_style_border_width(container, 0, 0); + lv_obj_set_style_pad_all(container, 0, 0); + // Only needed if container needs to be scrollable through encoder long long press + //lv_obj_add_flag(container, (lv_obj_flag_t)(LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLL_ON_FOCUS)); + deviceForm = initDeviceForm(container); + } + + explicit SettingsView(lv_obj_t *parent) { + queryRadios(); + initUi(parent); + } +}; + void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) { lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); @@ -19,18 +153,10 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) { lv_dropdown_set_options(uiDropDownMenu, LV_SYMBOL_ENVELOPE " Terminal\n" LV_SYMBOL_SETTINGS " Settings"); lv_dropdown_set_text(uiDropDownMenu, "Menu"); lv_dropdown_set_symbol(uiDropDownMenu, LV_SYMBOL_DOWN); - lv_dropdown_set_selected_highlight(uiDropDownMenu, false); + lv_dropdown_set_selected_highlight(uiDropDownMenu, true); lv_obj_set_style_border_color(uiDropDownMenu, lv_color_hex(0xFAFAFA), LV_PART_MAIN); lv_obj_set_style_border_width(uiDropDownMenu, 1, LV_PART_MAIN); lv_obj_align(uiDropDownMenu, LV_ALIGN_RIGHT_MID, 0, 0); - /*lv_obj_add_event_cb(uiDropDownMenu, - [](lv_event_t* e) { - auto *self = static_cast(lv_event_get_user_data(e)); - self->appNotesEventCb(e); - }, - LV_EVENT_VALUE_CHANGED, - this - );*/ lv_obj_t* wrapper = lv_obj_create(parent); lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN); @@ -42,4 +168,9 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) { lv_obj_set_style_pad_row(wrapper, 0, LV_PART_MAIN); lv_obj_set_style_border_width(wrapper, 0, 0); lv_obj_remove_flag(wrapper, LV_OBJ_FLAG_SCROLLABLE); + + settingsView = std::make_shared(wrapper); } + +// ???? +extern "C" void __cxa_pure_virtual() { crash("Entered the Virtual Zone..."); } diff --git a/ExternalApps/RadioSet/main/Source/RadioSet.h b/ExternalApps/RadioSet/main/Source/RadioSet.h index fa1f3a2f..7e249aa5 100644 --- a/ExternalApps/RadioSet/main/Source/RadioSet.h +++ b/ExternalApps/RadioSet/main/Source/RadioSet.h @@ -1,7 +1,9 @@ #pragma once -#include "tt_app.h" +#include +#include "tt_app.h" +#include "tt_hal_radio.h" #include class TermView; @@ -13,8 +15,8 @@ class RadioSet { lv_obj_t* progressBar = nullptr; lv_obj_t* progressText = nullptr; - TermView *termView = nullptr; - SettingsView *settingsView = nullptr; + std::shared_ptr termView = nullptr; + std::shared_ptr settingsView = nullptr; public: diff --git a/ExternalApps/RadioSet/main/Source/main.cpp b/ExternalApps/RadioSet/main/Source/main.cpp new file mode 100644 index 00000000..97fbd692 --- /dev/null +++ b/ExternalApps/RadioSet/main/Source/main.cpp @@ -0,0 +1,29 @@ +#include +#include "RadioSet.h" + +static void onShow(AppHandle appHandle, void* data, lv_obj_t* parent) { + static_cast(data)->onShow(appHandle, parent); +} + +static void* createApp() { + return new RadioSet(); +} + +static void destroyApp(void* app) { + delete static_cast(app); +} + +ExternalAppManifest manifest = { + .createData = createApp, + .destroyData = destroyApp, + .onShow = onShow, +}; + +extern "C" { + +int main(int argc, char* argv[]) { + tt_app_register(&manifest); + return 0; +} + +}