Compare commits
2 Commits
b3f13767dc
...
659542f094
| Author | SHA1 | Date | |
|---|---|---|---|
| 659542f094 | |||
| 487d75fd73 |
95
ExternalApps/RadioSet/main/Source/Dequeue.h
Normal file
95
ExternalApps/RadioSet/main/Source/Dequeue.h
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
template <typename DataType>
|
||||
class Dequeue {
|
||||
|
||||
struct Node {
|
||||
DataType data;
|
||||
Node* next;
|
||||
Node* previous;
|
||||
|
||||
Node(DataType data, Node* next, Node* previous):
|
||||
data(data),
|
||||
next(next),
|
||||
previous(previous)
|
||||
{}
|
||||
};
|
||||
|
||||
int count = 0;
|
||||
Node* head = nullptr;
|
||||
Node* tail = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
void pushFront(DataType data) {
|
||||
auto* new_node = new Node(data, head, nullptr);
|
||||
|
||||
if (head != nullptr) {
|
||||
head->previous = new_node;
|
||||
}
|
||||
|
||||
if (tail == nullptr) {
|
||||
tail = new_node;
|
||||
}
|
||||
|
||||
head = new_node;
|
||||
count++;
|
||||
}
|
||||
|
||||
void pushBack(DataType data) {
|
||||
auto* new_node = new Node(data, nullptr, tail);
|
||||
|
||||
if (head == nullptr) {
|
||||
head = new_node;
|
||||
}
|
||||
|
||||
if (tail != nullptr) {
|
||||
tail->next = new_node;
|
||||
}
|
||||
|
||||
tail = new_node;
|
||||
count++;
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
if (head != nullptr) {
|
||||
bool is_last_node = (head == tail);
|
||||
Node* node_to_delete = head;
|
||||
head = node_to_delete->next;
|
||||
if (is_last_node) {
|
||||
tail = nullptr;
|
||||
}
|
||||
delete node_to_delete;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
void popBack() {
|
||||
if (tail != nullptr) {
|
||||
bool is_last_node = (head == tail);
|
||||
Node* node_to_delete = tail;
|
||||
tail = node_to_delete->previous;
|
||||
if (is_last_node) {
|
||||
head = nullptr;
|
||||
}
|
||||
delete node_to_delete;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
DataType back() const {
|
||||
assert(tail != nullptr);
|
||||
return tail->data;
|
||||
}
|
||||
|
||||
DataType front() const {
|
||||
assert(head != nullptr);
|
||||
return head->data;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return head == nullptr;
|
||||
}
|
||||
|
||||
int size() const { return count; }
|
||||
};
|
||||
156
ExternalApps/RadioSet/main/Source/LinkedList.h
Normal file
156
ExternalApps/RadioSet/main/Source/LinkedList.h
Normal file
@ -0,0 +1,156 @@
|
||||
#pragma once
|
||||
|
||||
template <typename DataType>
|
||||
class LinkedList {
|
||||
|
||||
struct Node {
|
||||
DataType data;
|
||||
Node* next;
|
||||
Node* previous;
|
||||
|
||||
Node(DataType data, Node* next, Node* previous):
|
||||
data(data),
|
||||
next(next),
|
||||
previous(previous)
|
||||
{}
|
||||
};
|
||||
|
||||
int count = 0;
|
||||
Node* head = nullptr;
|
||||
Node* tail = nullptr;
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
Node *node = nullptr;
|
||||
public:
|
||||
Iterator(Node* node)
|
||||
: node(node) {}
|
||||
|
||||
bool advance(size_t n) {
|
||||
size_t i = 0;
|
||||
if (n == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (; node && (i < n); ++i) {
|
||||
node = node->next;
|
||||
}
|
||||
return (i > 0);
|
||||
}
|
||||
|
||||
DataType& operator* ()
|
||||
{
|
||||
return node->data;
|
||||
}
|
||||
|
||||
DataType* operator-> ()
|
||||
{
|
||||
return &(node->data);
|
||||
}
|
||||
|
||||
Iterator operator++ (int) {
|
||||
assert(advance(1));
|
||||
Iterator i(node);
|
||||
return i;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& right) const {
|
||||
return node == right.node;
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator& right) const {
|
||||
return node != right.node;
|
||||
}
|
||||
};
|
||||
|
||||
void pushFront(DataType data) {
|
||||
auto* new_node = new Node(data, head, nullptr);
|
||||
|
||||
if (head != nullptr) {
|
||||
head->previous = new_node;
|
||||
}
|
||||
|
||||
if (tail == nullptr) {
|
||||
tail = new_node;
|
||||
}
|
||||
|
||||
head = new_node;
|
||||
count++;
|
||||
}
|
||||
|
||||
void pushBack(DataType data) {
|
||||
auto* new_node = new Node(data, nullptr, tail);
|
||||
|
||||
if (head == nullptr) {
|
||||
head = new_node;
|
||||
}
|
||||
|
||||
if (tail != nullptr) {
|
||||
tail->next = new_node;
|
||||
}
|
||||
|
||||
tail = new_node;
|
||||
count++;
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
if (head != nullptr) {
|
||||
bool is_last_node = (head == tail);
|
||||
Node* node_to_delete = head;
|
||||
head = node_to_delete->next;
|
||||
if (is_last_node) {
|
||||
tail = nullptr;
|
||||
}
|
||||
delete node_to_delete;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
void popBack() {
|
||||
if (tail != nullptr) {
|
||||
bool is_last_node = (head == tail);
|
||||
Node* node_to_delete = tail;
|
||||
tail = node_to_delete->previous;
|
||||
if (is_last_node) {
|
||||
head = nullptr;
|
||||
}
|
||||
delete node_to_delete;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
DataType back() const {
|
||||
assert(tail != nullptr);
|
||||
return tail->data;
|
||||
}
|
||||
|
||||
DataType front() const {
|
||||
assert(head != nullptr);
|
||||
return head->data;
|
||||
}
|
||||
|
||||
Iterator begin() const {
|
||||
return Iterator(head);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return head == nullptr;
|
||||
}
|
||||
|
||||
int size() const { return count; }
|
||||
|
||||
DataType operator [] (int i) const {
|
||||
auto iter = begin();
|
||||
assert(iter.advance(i));
|
||||
return *iter;
|
||||
}
|
||||
DataType& operator [] (int i) {
|
||||
auto iter = begin();
|
||||
assert(iter.advance(i));
|
||||
return *iter;
|
||||
}
|
||||
};
|
||||
37
ExternalApps/RadioSet/main/Source/Preset.h
Normal file
37
ExternalApps/RadioSet/main/Source/Preset.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <tt_hal_radio.h>
|
||||
|
||||
#include "Str.h"
|
||||
#include "LinkedList.h"
|
||||
|
||||
class Preset {
|
||||
public:
|
||||
struct PresetItem {
|
||||
RadioParameter parameter;
|
||||
float value;
|
||||
};
|
||||
|
||||
Str name;
|
||||
Modulation modulation;
|
||||
LinkedList<PresetItem> items;
|
||||
|
||||
Preset(const char* const name, Modulation modulation)
|
||||
: name(name)
|
||||
, modulation(modulation)
|
||||
{}
|
||||
|
||||
virtual ~Preset() = default;
|
||||
|
||||
void addParameter(RadioParameter parameter, float value) {
|
||||
items.pushBack({parameter, value});
|
||||
}
|
||||
|
||||
LinkedList<PresetItem>::Iterator begin() {
|
||||
return items.begin();
|
||||
}
|
||||
|
||||
LinkedList<PresetItem>::Iterator end() {
|
||||
return items.end();
|
||||
}
|
||||
};
|
||||
@ -1,21 +1,36 @@
|
||||
#include "RadioSet.h"
|
||||
#include "Str.h"
|
||||
#include "LinkedList.h"
|
||||
#include "Preset.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctype.h>
|
||||
#include <tt_lvgl_toolbar.h>
|
||||
#include <tt_message_queue.h>
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "tt_app_alertdialog.h"
|
||||
#include <tt_app_alertdialog.h>
|
||||
|
||||
constexpr const char* TAG = "RadioSet";
|
||||
|
||||
template <typename Iterator>
|
||||
Iterator next(Iterator i) {
|
||||
return i++;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Container>
|
||||
bool is_last(Iterator i, const Container& c) {
|
||||
return (i != c.end()) && (next(i) == c.end());
|
||||
}
|
||||
|
||||
void crash(const char* const message) {
|
||||
tt_app_alertdialog_start("RadioSet has crashed!", message, nullptr, 0);
|
||||
}
|
||||
|
||||
void crashassert(bool assertion, const char* const message) {
|
||||
if (!assertion) {
|
||||
crash(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Debug function which colors all children randomly
|
||||
// TODO: Remove before flight
|
||||
void clownvomit(lv_obj_t *obj) {
|
||||
@ -117,8 +132,12 @@ static lv_obj_t* createGridDropdownInput(lv_obj_t *container, int row, const cha
|
||||
|
||||
struct ParameterInput {
|
||||
static constexpr auto LV_STATE_INVALID = LV_STATE_USER_1;
|
||||
typedef void (*Callback)(void* ctx);
|
||||
|
||||
const RadioHandle handle;
|
||||
const RadioParameter param;
|
||||
Callback userChangeCallback = nullptr;
|
||||
void* userChangeCtx = nullptr;
|
||||
|
||||
static void apply_error_style(lv_obj_t* obj) {
|
||||
static bool init = false;
|
||||
@ -137,9 +156,23 @@ struct ParameterInput {
|
||||
, param(param) {}
|
||||
|
||||
virtual ~ParameterInput() = default;
|
||||
|
||||
void onUserChange(Callback cb, void* ctx) {
|
||||
userChangeCallback = cb;
|
||||
userChangeCtx = ctx;
|
||||
}
|
||||
|
||||
void emitUserChange() {
|
||||
if (userChangeCallback) {
|
||||
userChangeCallback(userChangeCtx);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void storeToRadio() = 0;
|
||||
virtual void updatePreview() = 0;
|
||||
virtual void activate() = 0;
|
||||
virtual void deactivate() = 0;
|
||||
virtual void setValue(float value) = 0;
|
||||
};
|
||||
|
||||
struct NumericParameterInput : public ParameterInput {
|
||||
@ -199,19 +232,18 @@ struct NumericParameterInput : public ParameterInput {
|
||||
lv_obj_add_event_cb(input, [](lv_event_t * e) {
|
||||
NumericParameterInput* self = (NumericParameterInput*)lv_event_get_user_data(e);
|
||||
self->storeToRadio();
|
||||
self->emitUserChange();
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
}
|
||||
|
||||
void loadFromRadio() {
|
||||
float value;
|
||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||
Str txt;
|
||||
txt.appendf(fmt, value);
|
||||
lv_textarea_set_text(input, txt.c_str());
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void storeToRadio() {
|
||||
virtual void storeToRadio() override {
|
||||
float value;
|
||||
if (sscanf(lv_textarea_get_text(input), "%f", &value) == 1) {
|
||||
if (tt_hal_radio_set_parameter(handle, param, value) != RADIO_PARAM_SUCCESS) {
|
||||
@ -233,6 +265,12 @@ struct NumericParameterInput : public ParameterInput {
|
||||
virtual void deactivate() override {
|
||||
lv_obj_add_state(input, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
virtual void setValue(float value) override {
|
||||
Str txt;
|
||||
txt.appendf(fmt, value);
|
||||
lv_textarea_set_text(input, txt.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
struct SliderParameterInput : public ParameterInput {
|
||||
@ -268,7 +306,6 @@ struct SliderParameterInput : public ParameterInput {
|
||||
lv_obj_set_size(slider, lv_pct(100), 10);
|
||||
lv_slider_set_range(slider, min, max);
|
||||
apply_error_style(slider);
|
||||
loadFromRadio();
|
||||
|
||||
preview = lv_label_create(container);
|
||||
lv_obj_set_grid_cell(preview,
|
||||
@ -276,12 +313,15 @@ struct SliderParameterInput : public ParameterInput {
|
||||
LV_GRID_ALIGN_CENTER, row, 1);
|
||||
lv_obj_set_size(preview, lv_pct(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_text_align(preview , LV_TEXT_ALIGN_LEFT, 0);
|
||||
updatePreview();
|
||||
|
||||
loadFromRadio();
|
||||
|
||||
lv_obj_add_event_cb(slider, [](lv_event_t * e) {
|
||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||
SliderParameterInput* self = (SliderParameterInput*)lv_event_get_user_data(e);
|
||||
self->updatePreview();
|
||||
self->storeToRadio();
|
||||
self->emitUserChange();
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
}
|
||||
@ -289,11 +329,11 @@ struct SliderParameterInput : public ParameterInput {
|
||||
void loadFromRadio() {
|
||||
float value;
|
||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||
lv_slider_set_value(slider, value, LV_ANIM_ON);
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void storeToRadio() {
|
||||
virtual void storeToRadio() override {
|
||||
if (tt_hal_radio_set_parameter(handle, param, lv_slider_get_value(slider)) != RADIO_PARAM_SUCCESS) {
|
||||
lv_obj_add_state(slider, LV_STATE_INVALID);
|
||||
} else {
|
||||
@ -314,6 +354,11 @@ struct SliderParameterInput : public ParameterInput {
|
||||
virtual void deactivate() override {
|
||||
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
virtual void setValue(float value) override {
|
||||
lv_slider_set_value(slider, value, LV_ANIM_ON);
|
||||
updatePreview();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -379,7 +424,6 @@ struct SliderSelectParameterInput : public ParameterInput {
|
||||
lv_obj_set_size(slider, lv_pct(100), 10);
|
||||
lv_slider_set_range(slider, 0, selectionsSize - 1);
|
||||
apply_error_style(slider);
|
||||
loadFromRadio();
|
||||
|
||||
preview = lv_label_create(container);
|
||||
lv_obj_set_grid_cell(preview,
|
||||
@ -389,13 +433,15 @@ struct SliderSelectParameterInput : public ParameterInput {
|
||||
lv_obj_set_style_text_align(preview , LV_TEXT_ALIGN_LEFT, 0);
|
||||
|
||||
tt_hal_radio_get_parameter_unit_str(handle, param, unit, sizeof(unit));
|
||||
updatePreview();
|
||||
|
||||
loadFromRadio();
|
||||
|
||||
lv_obj_add_event_cb(slider, [](lv_event_t * e) {
|
||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||
SliderSelectParameterInput* self = (SliderSelectParameterInput*)lv_event_get_user_data(e);
|
||||
self->updatePreview();
|
||||
self->storeToRadio();
|
||||
self->emitUserChange();
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
}
|
||||
@ -403,11 +449,11 @@ struct SliderSelectParameterInput : public ParameterInput {
|
||||
void loadFromRadio() {
|
||||
float value;
|
||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||
lv_slider_set_value(slider, get_selection_index(value), LV_ANIM_ON);
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void storeToRadio() {
|
||||
virtual void storeToRadio() override {
|
||||
if (tt_hal_radio_set_parameter(handle, param, selections[lv_slider_get_value(slider)]) != RADIO_PARAM_SUCCESS) {
|
||||
lv_obj_add_state(slider, LV_STATE_INVALID);
|
||||
} else {
|
||||
@ -429,6 +475,11 @@ struct SliderSelectParameterInput : public ParameterInput {
|
||||
virtual void deactivate() override {
|
||||
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
virtual void setValue(float value) override {
|
||||
lv_slider_set_value(slider, get_selection_index(value), LV_ANIM_ON);
|
||||
updatePreview();
|
||||
}
|
||||
};
|
||||
|
||||
struct FlagParameterInput : public ParameterInput {
|
||||
@ -464,21 +515,18 @@ struct FlagParameterInput : public ParameterInput {
|
||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||
FlagParameterInput* self = (FlagParameterInput*)lv_event_get_user_data(e);
|
||||
self->storeToRadio();
|
||||
self->emitUserChange();
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
}
|
||||
|
||||
void loadFromRadio() {
|
||||
float value;
|
||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||
if (value != 0.0) {
|
||||
lv_obj_add_state(input, LV_STATE_CHECKED);
|
||||
} else {
|
||||
lv_obj_clear_state(input, LV_STATE_CHECKED);
|
||||
}
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void storeToRadio() {
|
||||
virtual void storeToRadio() override {
|
||||
float value = lv_obj_has_state(input, LV_STATE_CHECKED) ? 1.0 : 0.0;
|
||||
if (tt_hal_radio_set_parameter(handle, param, value) != RADIO_PARAM_SUCCESS) {
|
||||
lv_obj_add_state(input, LV_STATE_INVALID);
|
||||
@ -497,6 +545,14 @@ struct FlagParameterInput : public ParameterInput {
|
||||
virtual void deactivate() override {
|
||||
lv_obj_add_state(input, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
virtual void setValue(float value) override {
|
||||
if (value != 0.0) {
|
||||
lv_obj_add_state(input, LV_STATE_CHECKED);
|
||||
} else {
|
||||
lv_obj_clear_state(input, LV_STATE_CHECKED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ParameterInput* makeLoraInput(RadioHandle handle, const RadioParameter param, lv_obj_t* container, int row) {
|
||||
@ -560,6 +616,8 @@ class SettingsView {
|
||||
ParameterInput* paramInputs[MAX_PARAMS] = {0};
|
||||
size_t paramsAvailableCount = 0;
|
||||
|
||||
LinkedList<Preset*> presets;
|
||||
LinkedList<Preset*> presetsByModulation[MAX_MODEMS];
|
||||
|
||||
lv_obj_t* mainPanel = nullptr;
|
||||
lv_obj_t* deviceForm = nullptr;
|
||||
@ -567,10 +625,16 @@ class SettingsView {
|
||||
lv_obj_t* radioSwitch = nullptr;
|
||||
lv_obj_t* radioStateLabel = nullptr;
|
||||
lv_obj_t* modemDropdown = nullptr;
|
||||
lv_obj_t* modemPresetDropdown = nullptr;
|
||||
|
||||
lv_obj_t *propertiesForm = nullptr;
|
||||
|
||||
public:
|
||||
void addPreset(Preset* preset) {
|
||||
presets.pushBack(preset);
|
||||
presetsByModulation[preset->modulation].pushBack(preset);
|
||||
}
|
||||
|
||||
void queryRadios() {
|
||||
DeviceId devices[MAX_RADIOS];
|
||||
uint16_t device_count = 0;
|
||||
@ -645,8 +709,9 @@ public:
|
||||
|
||||
char unit_buffer[32] = {0};
|
||||
|
||||
// Clean up any input, it's safe and this loop costs nothing'
|
||||
// Clean up any input
|
||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
||||
// As this is a LUT, only some may be set
|
||||
if (paramInputs[i]) {
|
||||
delete paramInputs[i];
|
||||
paramInputs[i] = nullptr;
|
||||
@ -661,7 +726,11 @@ public:
|
||||
auto status = tt_hal_radio_get_parameter(radioSelected, param, &value);
|
||||
if (status == RADIO_PARAM_SUCCESS) {
|
||||
auto input = makeParameterInput(radioSelected, param, modem, container, paramsAvailableCount);
|
||||
paramInputs[paramsAvailableCount] = input;
|
||||
input->onUserChange([](void* ctx) {
|
||||
SettingsView* self = (SettingsView*)ctx;
|
||||
self->onParameterInput();
|
||||
}, this);
|
||||
paramInputs[param] = input;
|
||||
//lv_group_focus_obj(input);
|
||||
paramsAvailable[paramsAvailableCount] = param;
|
||||
paramsAvailableCount++;
|
||||
@ -678,7 +747,60 @@ public:
|
||||
lv_dropdown_set_selected(modemDropdown, modemIndex);
|
||||
if (tt_hal_radio_set_modulation(radioSelected, modemsAvailable[modemIndex])) {
|
||||
propertiesForm = initParameterFormGeneric(mainPanel, modemsAvailable[modemIndex]);
|
||||
//clownvomit(propertiesForm);
|
||||
}
|
||||
|
||||
updatePresets();
|
||||
}
|
||||
|
||||
void selectPreset(int presetIndex) {
|
||||
// The first index is always "No preset" or "None available"
|
||||
// Other indices are the presets for the current modulation + 1
|
||||
|
||||
auto modem = tt_hal_radio_get_modulation(radioSelected);
|
||||
auto& presets = presetsByModulation[modem];
|
||||
if ((presetIndex > 0) && ((presetIndex - 1) < presets.size())) {
|
||||
auto preset = presets[presetIndex - 1];
|
||||
|
||||
for (auto iter = preset->items.begin(); iter != preset->items.end(); iter++) {
|
||||
if (paramInputs[iter->parameter]) {
|
||||
paramInputs[iter->parameter]->setValue(iter->value);
|
||||
paramInputs[iter->parameter]->storeToRadio();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
crash("Selected preset does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
void onParameterInput() {
|
||||
// As the user did an input, this makes any applied
|
||||
// preset inconsistent, revert back to "None".
|
||||
lv_dropdown_set_selected(modemPresetDropdown, 0);
|
||||
}
|
||||
|
||||
void updatePresets() {
|
||||
auto modemIndexConfigured = tt_hal_radio_get_modulation(radioSelected);
|
||||
|
||||
Str preset_list("Select...");
|
||||
auto& presets = presetsByModulation[modemIndexConfigured];
|
||||
if (!presets.empty()) {
|
||||
preset_list.append("\n");
|
||||
}
|
||||
for (auto iter = presets.begin(); iter != presets.end(); iter++) {
|
||||
auto place_sep = !is_last(iter, presets);
|
||||
auto& name = (*iter)->name;
|
||||
preset_list.append(name.c_str());
|
||||
if (place_sep) {
|
||||
preset_list.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (preset_list.empty()) {
|
||||
lv_obj_add_state(modemPresetDropdown, LV_STATE_DISABLED);
|
||||
lv_dropdown_set_options(modemPresetDropdown, "None");
|
||||
} else {
|
||||
lv_obj_clear_state(modemPresetDropdown, LV_STATE_DISABLED);
|
||||
lv_dropdown_set_options(modemPresetDropdown, preset_list.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,7 +810,7 @@ public:
|
||||
}
|
||||
|
||||
radioSelected = radios[index];
|
||||
assert(radioSelected);
|
||||
crashassert(radioSelected, "Radio selected not allocated");
|
||||
|
||||
for (size_t i = 0; i < MAX_MODEMS; ++i) {
|
||||
modemsAvailable[i] = MODULATION_NONE;
|
||||
@ -766,6 +888,7 @@ public:
|
||||
grid_row_size,
|
||||
grid_row_size,
|
||||
grid_row_size,
|
||||
grid_row_size,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
lv_obj_set_layout(container, LV_LAYOUT_GRID);
|
||||
lv_obj_set_grid_dsc_array(container, lora_col_dsc, lora_row_dsc);
|
||||
@ -793,8 +916,8 @@ public:
|
||||
LV_GRID_ALIGN_CENTER, 1, 1);
|
||||
lv_obj_set_size(radioStateLabel, lv_pct(100), LV_SIZE_CONTENT);
|
||||
|
||||
modemDropdown = createGridDropdownInput(container, 2, "Modulation", "none available");
|
||||
|
||||
modemDropdown = createGridDropdownInput(container, 2, "Modulation", "None available");
|
||||
modemPresetDropdown = createGridDropdownInput(container, 3, "Preset", "None");
|
||||
|
||||
lv_obj_add_event_cb(modemDropdown, [](lv_event_t * e) {
|
||||
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
||||
@ -802,6 +925,12 @@ public:
|
||||
self->selectModulation(lv_dropdown_get_selected(input));
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
lv_obj_add_event_cb(modemPresetDropdown, [](lv_event_t * e) {
|
||||
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
||||
lv_obj_t* input = lv_event_get_target_obj(e);
|
||||
self->selectPreset(lv_dropdown_get_selected(input));
|
||||
}, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
lv_obj_add_event_cb(radioSwitch, [](lv_event_t * e) {
|
||||
lv_obj_t* input = lv_event_get_target_obj(e);
|
||||
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
||||
@ -860,18 +989,22 @@ public:
|
||||
void activateConfig() {
|
||||
lv_obj_clear_state(modemDropdown, LV_STATE_DISABLED);
|
||||
lv_obj_clear_state(radioSwitch, LV_STATE_CHECKED);
|
||||
for (size_t i = 0; i < paramsAvailableCount; ++i) {
|
||||
assert(paramInputs[i]);
|
||||
paramInputs[i]->activate();
|
||||
lv_obj_clear_state(modemPresetDropdown, LV_STATE_DISABLED);
|
||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
||||
if (paramInputs[i]) {
|
||||
paramInputs[i]->activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deactivateConfig() {
|
||||
lv_obj_add_state(radioSwitch, LV_STATE_CHECKED);
|
||||
lv_obj_add_state(modemDropdown, LV_STATE_DISABLED);
|
||||
for (size_t i = 0; i < paramsAvailableCount; ++i) {
|
||||
assert(paramInputs[i]);
|
||||
paramInputs[i]->deactivate();
|
||||
lv_obj_add_state(modemPresetDropdown, LV_STATE_DISABLED);
|
||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
||||
if (paramInputs[i]) {
|
||||
paramInputs[i]->deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -886,19 +1019,13 @@ public:
|
||||
lv_obj_add_flag(mainPanel, (lv_obj_flag_t)(LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLL_ON_FOCUS));
|
||||
auto* group = lv_group_get_default();
|
||||
lv_group_add_obj(group, mainPanel);
|
||||
//lv_obj_add_event_cb(btn, scrollbar_highlight, LV_EVENT_FOCUS, NULL);
|
||||
//lv_obj_add_event_cb(btn, scrollbar_restore, LV_EVENT_DEFOCUSED, NULL);
|
||||
|
||||
// Create once (e.g. during init)
|
||||
static lv_style_t style_scroll_focus;
|
||||
lv_style_init(&style_scroll_focus);
|
||||
lv_style_set_bg_color(&style_scroll_focus, lv_color_make(0x40,0xA0,0xFF));
|
||||
lv_style_set_bg_opa(&style_scroll_focus, LV_OPA_COVER);
|
||||
lv_style_set_border_width(&style_scroll_focus, 1);
|
||||
lv_style_set_border_color(&style_scroll_focus, lv_color_black());
|
||||
|
||||
// Apply style targeted to the scrollbar part when the object is FOCUSED
|
||||
// LV_PART_SCROLLBAR | LV_STATE_FOCUSED will ensure the style is used only while focused.
|
||||
lv_style_set_border_color(&style_scroll_focus, lv_theme_get_color_primary(nullptr));
|
||||
lv_obj_add_style(mainPanel, &style_scroll_focus, LV_PART_SCROLLBAR | LV_STATE_FOCUSED);
|
||||
|
||||
deviceForm = initDeviceForm(mainPanel);
|
||||
@ -941,6 +1068,17 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) {
|
||||
lv_obj_remove_flag(wrapper, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
settingsView = new SettingsView(wrapper);
|
||||
|
||||
auto presetMtEu868LongFast = new Preset("MT EU868 LongFast", MODULATION_LORA);
|
||||
presetMtEu868LongFast->addParameter(RADIO_FREQUENCY, 869.525);
|
||||
presetMtEu868LongFast->addParameter(RADIO_BANDWIDTH, 250.0);
|
||||
presetMtEu868LongFast->addParameter(RADIO_SPREADFACTOR, 11);
|
||||
presetMtEu868LongFast->addParameter(RADIO_CODINGRATE, 6);
|
||||
presetMtEu868LongFast->addParameter(RADIO_SYNCWORD, 0x2B);
|
||||
presetMtEu868LongFast->addParameter(RADIO_PREAMBLES, 16);
|
||||
|
||||
settingsView->addPreset(presetMtEu868LongFast);
|
||||
settingsView->updatePresets();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user