RadioSet: Add presets
The preset dropdown reset any time the value is changed, which includes on parameter loads from the radio. It should only reset on user input, but it's not worth finding out how right now.
This commit is contained in:
parent
b5c27e5cb4
commit
2779b867cc
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;
|
||||
}
|
||||
};
|
||||
@ -3,48 +3,35 @@
|
||||
#include <tt_hal_radio.h>
|
||||
|
||||
#include "Str.h"
|
||||
#include "LinkedList.h"
|
||||
|
||||
class Preset {
|
||||
public:
|
||||
struct PresetItem {
|
||||
RadioParameter parameter;
|
||||
float value;
|
||||
PresetItem* next = nullptr;
|
||||
};
|
||||
|
||||
Str name;
|
||||
Modulation modulation;
|
||||
PresetItem* first = nullptr;
|
||||
PresetItem* last = nullptr;
|
||||
public:
|
||||
LinkedList<PresetItem> items;
|
||||
|
||||
Preset(const char* const name, Modulation modulation)
|
||||
: name(name)
|
||||
, modulation(modulation)
|
||||
{}
|
||||
|
||||
virtual ~Preset() {
|
||||
PresetItem* n = first;
|
||||
while(n) {
|
||||
auto next = n->next;
|
||||
delete n;
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
virtual ~Preset() = default;
|
||||
|
||||
void addParameter(RadioParameter parameter, float value) {
|
||||
auto node = new PresetItem;
|
||||
node->parameter = parameter;
|
||||
node->value = value;
|
||||
|
||||
if (last) {
|
||||
last->next = node;
|
||||
last = node;
|
||||
} else {
|
||||
first = node;
|
||||
last = node;
|
||||
}
|
||||
items.pushBack({parameter, value});
|
||||
}
|
||||
|
||||
PresetItem* first() {
|
||||
return first;
|
||||
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 "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) {
|
||||
@ -548,7 +604,6 @@ class SettingsView {
|
||||
static constexpr Modulation LAST_MODULATION = MODULATION_LRFHSS;
|
||||
static constexpr size_t MAX_MODEMS = LAST_MODULATION + 1;
|
||||
static constexpr size_t MAX_PARAMS = RADIO_NARROWGRID + 1;
|
||||
static constexpr size_t MAX_PRESETS = 32;
|
||||
|
||||
RadioHandle radios[MAX_RADIOS] = {0};
|
||||
size_t radioCount = 0;
|
||||
@ -561,8 +616,8 @@ class SettingsView {
|
||||
ParameterInput* paramInputs[MAX_PARAMS] = {0};
|
||||
size_t paramsAvailableCount = 0;
|
||||
|
||||
Preset* presets[MAX_PRESETS] = {0};
|
||||
size_t presetsCount = 0;
|
||||
LinkedList<Preset*> presets;
|
||||
LinkedList<Preset*> presetsByModulation[MAX_MODEMS];
|
||||
|
||||
lv_obj_t* mainPanel = nullptr;
|
||||
lv_obj_t* deviceForm = nullptr;
|
||||
@ -570,13 +625,14 @@ 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[presetsCount] = preset;
|
||||
presetsCount++;
|
||||
presets.pushBack(preset);
|
||||
presetsByModulation[preset->modulation].pushBack(preset);
|
||||
}
|
||||
|
||||
void queryRadios() {
|
||||
@ -653,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;
|
||||
@ -669,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++;
|
||||
@ -686,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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -696,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;
|
||||
@ -774,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);
|
||||
@ -801,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);
|
||||
@ -810,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);
|
||||
@ -868,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -894,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);
|
||||
@ -950,7 +1069,7 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) {
|
||||
|
||||
settingsView = new SettingsView(wrapper);
|
||||
|
||||
auto presetMtEu868LongFast = new Preset("Meshtastic EU868 LongFast", MODULATION_LORA);
|
||||
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);
|
||||
@ -959,8 +1078,7 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) {
|
||||
presetMtEu868LongFast->addParameter(RADIO_PREAMBLES, 16);
|
||||
|
||||
settingsView->addPreset(presetMtEu868LongFast);
|
||||
|
||||
|
||||
settingsView->updatePresets();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user