Compare commits
No commits in common. "659542f094ef1c36f091a0229882846f585632c8" and "b3f13767dcdce5bd6477c2cc91b927e8d26f63bc" have entirely different histories.
659542f094
...
b3f13767dc
@ -1,95 +0,0 @@
|
|||||||
#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; }
|
|
||||||
};
|
|
||||||
@ -1,156 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
#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,36 +1,21 @@
|
|||||||
#include "RadioSet.h"
|
#include "RadioSet.h"
|
||||||
#include "Str.h"
|
#include "Str.h"
|
||||||
#include "LinkedList.h"
|
|
||||||
#include "Preset.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <tt_lvgl_toolbar.h>
|
#include <tt_lvgl_toolbar.h>
|
||||||
#include <tt_message_queue.h>
|
#include <tt_message_queue.h>
|
||||||
#include <tt_app_alertdialog.h>
|
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
#include "tt_app_alertdialog.h"
|
||||||
|
|
||||||
constexpr const char* TAG = "RadioSet";
|
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) {
|
void crash(const char* const message) {
|
||||||
tt_app_alertdialog_start("RadioSet has crashed!", message, nullptr, 0);
|
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
|
// Debug function which colors all children randomly
|
||||||
// TODO: Remove before flight
|
// TODO: Remove before flight
|
||||||
void clownvomit(lv_obj_t *obj) {
|
void clownvomit(lv_obj_t *obj) {
|
||||||
@ -132,12 +117,8 @@ static lv_obj_t* createGridDropdownInput(lv_obj_t *container, int row, const cha
|
|||||||
|
|
||||||
struct ParameterInput {
|
struct ParameterInput {
|
||||||
static constexpr auto LV_STATE_INVALID = LV_STATE_USER_1;
|
static constexpr auto LV_STATE_INVALID = LV_STATE_USER_1;
|
||||||
typedef void (*Callback)(void* ctx);
|
|
||||||
|
|
||||||
const RadioHandle handle;
|
const RadioHandle handle;
|
||||||
const RadioParameter param;
|
const RadioParameter param;
|
||||||
Callback userChangeCallback = nullptr;
|
|
||||||
void* userChangeCtx = nullptr;
|
|
||||||
|
|
||||||
static void apply_error_style(lv_obj_t* obj) {
|
static void apply_error_style(lv_obj_t* obj) {
|
||||||
static bool init = false;
|
static bool init = false;
|
||||||
@ -156,23 +137,9 @@ struct ParameterInput {
|
|||||||
, param(param) {}
|
, param(param) {}
|
||||||
|
|
||||||
virtual ~ParameterInput() = default;
|
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 updatePreview() = 0;
|
||||||
virtual void activate() = 0;
|
virtual void activate() = 0;
|
||||||
virtual void deactivate() = 0;
|
virtual void deactivate() = 0;
|
||||||
virtual void setValue(float value) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NumericParameterInput : public ParameterInput {
|
struct NumericParameterInput : public ParameterInput {
|
||||||
@ -232,18 +199,19 @@ struct NumericParameterInput : public ParameterInput {
|
|||||||
lv_obj_add_event_cb(input, [](lv_event_t * e) {
|
lv_obj_add_event_cb(input, [](lv_event_t * e) {
|
||||||
NumericParameterInput* self = (NumericParameterInput*)lv_event_get_user_data(e);
|
NumericParameterInput* self = (NumericParameterInput*)lv_event_get_user_data(e);
|
||||||
self->storeToRadio();
|
self->storeToRadio();
|
||||||
self->emitUserChange();
|
|
||||||
}, LV_EVENT_VALUE_CHANGED, this);
|
}, LV_EVENT_VALUE_CHANGED, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadFromRadio() {
|
void loadFromRadio() {
|
||||||
float value;
|
float value;
|
||||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||||
setValue(value);
|
Str txt;
|
||||||
|
txt.appendf(fmt, value);
|
||||||
|
lv_textarea_set_text(input, txt.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void storeToRadio() override {
|
void storeToRadio() {
|
||||||
float value;
|
float value;
|
||||||
if (sscanf(lv_textarea_get_text(input), "%f", &value) == 1) {
|
if (sscanf(lv_textarea_get_text(input), "%f", &value) == 1) {
|
||||||
if (tt_hal_radio_set_parameter(handle, param, value) != RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_set_parameter(handle, param, value) != RADIO_PARAM_SUCCESS) {
|
||||||
@ -265,12 +233,6 @@ struct NumericParameterInput : public ParameterInput {
|
|||||||
virtual void deactivate() override {
|
virtual void deactivate() override {
|
||||||
lv_obj_add_state(input, LV_STATE_DISABLED);
|
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 {
|
struct SliderParameterInput : public ParameterInput {
|
||||||
@ -306,6 +268,7 @@ struct SliderParameterInput : public ParameterInput {
|
|||||||
lv_obj_set_size(slider, lv_pct(100), 10);
|
lv_obj_set_size(slider, lv_pct(100), 10);
|
||||||
lv_slider_set_range(slider, min, max);
|
lv_slider_set_range(slider, min, max);
|
||||||
apply_error_style(slider);
|
apply_error_style(slider);
|
||||||
|
loadFromRadio();
|
||||||
|
|
||||||
preview = lv_label_create(container);
|
preview = lv_label_create(container);
|
||||||
lv_obj_set_grid_cell(preview,
|
lv_obj_set_grid_cell(preview,
|
||||||
@ -313,15 +276,12 @@ struct SliderParameterInput : public ParameterInput {
|
|||||||
LV_GRID_ALIGN_CENTER, row, 1);
|
LV_GRID_ALIGN_CENTER, row, 1);
|
||||||
lv_obj_set_size(preview, lv_pct(100), LV_SIZE_CONTENT);
|
lv_obj_set_size(preview, lv_pct(100), LV_SIZE_CONTENT);
|
||||||
lv_obj_set_style_text_align(preview , LV_TEXT_ALIGN_LEFT, 0);
|
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_add_event_cb(slider, [](lv_event_t * e) {
|
||||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||||
SliderParameterInput* self = (SliderParameterInput*)lv_event_get_user_data(e);
|
SliderParameterInput* self = (SliderParameterInput*)lv_event_get_user_data(e);
|
||||||
self->updatePreview();
|
self->updatePreview();
|
||||||
self->storeToRadio();
|
self->storeToRadio();
|
||||||
self->emitUserChange();
|
|
||||||
}, LV_EVENT_VALUE_CHANGED, this);
|
}, LV_EVENT_VALUE_CHANGED, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -329,11 +289,11 @@ struct SliderParameterInput : public ParameterInput {
|
|||||||
void loadFromRadio() {
|
void loadFromRadio() {
|
||||||
float value;
|
float value;
|
||||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||||
setValue(value);
|
lv_slider_set_value(slider, value, LV_ANIM_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void storeToRadio() override {
|
void storeToRadio() {
|
||||||
if (tt_hal_radio_set_parameter(handle, param, lv_slider_get_value(slider)) != RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_set_parameter(handle, param, lv_slider_get_value(slider)) != RADIO_PARAM_SUCCESS) {
|
||||||
lv_obj_add_state(slider, LV_STATE_INVALID);
|
lv_obj_add_state(slider, LV_STATE_INVALID);
|
||||||
} else {
|
} else {
|
||||||
@ -354,11 +314,6 @@ struct SliderParameterInput : public ParameterInput {
|
|||||||
virtual void deactivate() override {
|
virtual void deactivate() override {
|
||||||
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setValue(float value) override {
|
|
||||||
lv_slider_set_value(slider, value, LV_ANIM_ON);
|
|
||||||
updatePreview();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -424,6 +379,7 @@ struct SliderSelectParameterInput : public ParameterInput {
|
|||||||
lv_obj_set_size(slider, lv_pct(100), 10);
|
lv_obj_set_size(slider, lv_pct(100), 10);
|
||||||
lv_slider_set_range(slider, 0, selectionsSize - 1);
|
lv_slider_set_range(slider, 0, selectionsSize - 1);
|
||||||
apply_error_style(slider);
|
apply_error_style(slider);
|
||||||
|
loadFromRadio();
|
||||||
|
|
||||||
preview = lv_label_create(container);
|
preview = lv_label_create(container);
|
||||||
lv_obj_set_grid_cell(preview,
|
lv_obj_set_grid_cell(preview,
|
||||||
@ -433,15 +389,13 @@ struct SliderSelectParameterInput : public ParameterInput {
|
|||||||
lv_obj_set_style_text_align(preview , LV_TEXT_ALIGN_LEFT, 0);
|
lv_obj_set_style_text_align(preview , LV_TEXT_ALIGN_LEFT, 0);
|
||||||
|
|
||||||
tt_hal_radio_get_parameter_unit_str(handle, param, unit, sizeof(unit));
|
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_add_event_cb(slider, [](lv_event_t * e) {
|
||||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||||
SliderSelectParameterInput* self = (SliderSelectParameterInput*)lv_event_get_user_data(e);
|
SliderSelectParameterInput* self = (SliderSelectParameterInput*)lv_event_get_user_data(e);
|
||||||
self->updatePreview();
|
self->updatePreview();
|
||||||
self->storeToRadio();
|
self->storeToRadio();
|
||||||
self->emitUserChange();
|
|
||||||
}, LV_EVENT_VALUE_CHANGED, this);
|
}, LV_EVENT_VALUE_CHANGED, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -449,11 +403,11 @@ struct SliderSelectParameterInput : public ParameterInput {
|
|||||||
void loadFromRadio() {
|
void loadFromRadio() {
|
||||||
float value;
|
float value;
|
||||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||||
setValue(value);
|
lv_slider_set_value(slider, get_selection_index(value), LV_ANIM_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void storeToRadio() override {
|
void storeToRadio() {
|
||||||
if (tt_hal_radio_set_parameter(handle, param, selections[lv_slider_get_value(slider)]) != RADIO_PARAM_SUCCESS) {
|
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);
|
lv_obj_add_state(slider, LV_STATE_INVALID);
|
||||||
} else {
|
} else {
|
||||||
@ -475,11 +429,6 @@ struct SliderSelectParameterInput : public ParameterInput {
|
|||||||
virtual void deactivate() override {
|
virtual void deactivate() override {
|
||||||
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
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 {
|
struct FlagParameterInput : public ParameterInput {
|
||||||
@ -515,18 +464,21 @@ struct FlagParameterInput : public ParameterInput {
|
|||||||
lv_obj_t* slider = lv_event_get_target_obj(e);
|
lv_obj_t* slider = lv_event_get_target_obj(e);
|
||||||
FlagParameterInput* self = (FlagParameterInput*)lv_event_get_user_data(e);
|
FlagParameterInput* self = (FlagParameterInput*)lv_event_get_user_data(e);
|
||||||
self->storeToRadio();
|
self->storeToRadio();
|
||||||
self->emitUserChange();
|
|
||||||
}, LV_EVENT_VALUE_CHANGED, this);
|
}, LV_EVENT_VALUE_CHANGED, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadFromRadio() {
|
void loadFromRadio() {
|
||||||
float value;
|
float value;
|
||||||
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
if (tt_hal_radio_get_parameter(handle, param, &value) == RADIO_PARAM_SUCCESS) {
|
||||||
setValue(value);
|
if (value != 0.0) {
|
||||||
|
lv_obj_add_state(input, LV_STATE_CHECKED);
|
||||||
|
} else {
|
||||||
|
lv_obj_clear_state(input, LV_STATE_CHECKED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void storeToRadio() override {
|
void storeToRadio() {
|
||||||
float value = lv_obj_has_state(input, LV_STATE_CHECKED) ? 1.0 : 0.0;
|
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) {
|
if (tt_hal_radio_set_parameter(handle, param, value) != RADIO_PARAM_SUCCESS) {
|
||||||
lv_obj_add_state(input, LV_STATE_INVALID);
|
lv_obj_add_state(input, LV_STATE_INVALID);
|
||||||
@ -545,14 +497,6 @@ struct FlagParameterInput : public ParameterInput {
|
|||||||
virtual void deactivate() override {
|
virtual void deactivate() override {
|
||||||
lv_obj_add_state(input, LV_STATE_DISABLED);
|
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) {
|
static ParameterInput* makeLoraInput(RadioHandle handle, const RadioParameter param, lv_obj_t* container, int row) {
|
||||||
@ -616,8 +560,6 @@ class SettingsView {
|
|||||||
ParameterInput* paramInputs[MAX_PARAMS] = {0};
|
ParameterInput* paramInputs[MAX_PARAMS] = {0};
|
||||||
size_t paramsAvailableCount = 0;
|
size_t paramsAvailableCount = 0;
|
||||||
|
|
||||||
LinkedList<Preset*> presets;
|
|
||||||
LinkedList<Preset*> presetsByModulation[MAX_MODEMS];
|
|
||||||
|
|
||||||
lv_obj_t* mainPanel = nullptr;
|
lv_obj_t* mainPanel = nullptr;
|
||||||
lv_obj_t* deviceForm = nullptr;
|
lv_obj_t* deviceForm = nullptr;
|
||||||
@ -625,16 +567,10 @@ class SettingsView {
|
|||||||
lv_obj_t* radioSwitch = nullptr;
|
lv_obj_t* radioSwitch = nullptr;
|
||||||
lv_obj_t* radioStateLabel = nullptr;
|
lv_obj_t* radioStateLabel = nullptr;
|
||||||
lv_obj_t* modemDropdown = nullptr;
|
lv_obj_t* modemDropdown = nullptr;
|
||||||
lv_obj_t* modemPresetDropdown = nullptr;
|
|
||||||
|
|
||||||
lv_obj_t *propertiesForm = nullptr;
|
lv_obj_t *propertiesForm = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void addPreset(Preset* preset) {
|
|
||||||
presets.pushBack(preset);
|
|
||||||
presetsByModulation[preset->modulation].pushBack(preset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void queryRadios() {
|
void queryRadios() {
|
||||||
DeviceId devices[MAX_RADIOS];
|
DeviceId devices[MAX_RADIOS];
|
||||||
uint16_t device_count = 0;
|
uint16_t device_count = 0;
|
||||||
@ -709,9 +645,8 @@ public:
|
|||||||
|
|
||||||
char unit_buffer[32] = {0};
|
char unit_buffer[32] = {0};
|
||||||
|
|
||||||
// Clean up any input
|
// Clean up any input, it's safe and this loop costs nothing'
|
||||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
||||||
// As this is a LUT, only some may be set
|
|
||||||
if (paramInputs[i]) {
|
if (paramInputs[i]) {
|
||||||
delete paramInputs[i];
|
delete paramInputs[i];
|
||||||
paramInputs[i] = nullptr;
|
paramInputs[i] = nullptr;
|
||||||
@ -726,11 +661,7 @@ public:
|
|||||||
auto status = tt_hal_radio_get_parameter(radioSelected, param, &value);
|
auto status = tt_hal_radio_get_parameter(radioSelected, param, &value);
|
||||||
if (status == RADIO_PARAM_SUCCESS) {
|
if (status == RADIO_PARAM_SUCCESS) {
|
||||||
auto input = makeParameterInput(radioSelected, param, modem, container, paramsAvailableCount);
|
auto input = makeParameterInput(radioSelected, param, modem, container, paramsAvailableCount);
|
||||||
input->onUserChange([](void* ctx) {
|
paramInputs[paramsAvailableCount] = input;
|
||||||
SettingsView* self = (SettingsView*)ctx;
|
|
||||||
self->onParameterInput();
|
|
||||||
}, this);
|
|
||||||
paramInputs[param] = input;
|
|
||||||
//lv_group_focus_obj(input);
|
//lv_group_focus_obj(input);
|
||||||
paramsAvailable[paramsAvailableCount] = param;
|
paramsAvailable[paramsAvailableCount] = param;
|
||||||
paramsAvailableCount++;
|
paramsAvailableCount++;
|
||||||
@ -747,60 +678,7 @@ public:
|
|||||||
lv_dropdown_set_selected(modemDropdown, modemIndex);
|
lv_dropdown_set_selected(modemDropdown, modemIndex);
|
||||||
if (tt_hal_radio_set_modulation(radioSelected, modemsAvailable[modemIndex])) {
|
if (tt_hal_radio_set_modulation(radioSelected, modemsAvailable[modemIndex])) {
|
||||||
propertiesForm = initParameterFormGeneric(mainPanel, 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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,7 +688,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
radioSelected = radios[index];
|
radioSelected = radios[index];
|
||||||
crashassert(radioSelected, "Radio selected not allocated");
|
assert(radioSelected);
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_MODEMS; ++i) {
|
for (size_t i = 0; i < MAX_MODEMS; ++i) {
|
||||||
modemsAvailable[i] = MODULATION_NONE;
|
modemsAvailable[i] = MODULATION_NONE;
|
||||||
@ -888,7 +766,6 @@ public:
|
|||||||
grid_row_size,
|
grid_row_size,
|
||||||
grid_row_size,
|
grid_row_size,
|
||||||
grid_row_size,
|
grid_row_size,
|
||||||
grid_row_size,
|
|
||||||
LV_GRID_TEMPLATE_LAST};
|
LV_GRID_TEMPLATE_LAST};
|
||||||
lv_obj_set_layout(container, LV_LAYOUT_GRID);
|
lv_obj_set_layout(container, LV_LAYOUT_GRID);
|
||||||
lv_obj_set_grid_dsc_array(container, lora_col_dsc, lora_row_dsc);
|
lv_obj_set_grid_dsc_array(container, lora_col_dsc, lora_row_dsc);
|
||||||
@ -916,8 +793,8 @@ public:
|
|||||||
LV_GRID_ALIGN_CENTER, 1, 1);
|
LV_GRID_ALIGN_CENTER, 1, 1);
|
||||||
lv_obj_set_size(radioStateLabel, lv_pct(100), LV_SIZE_CONTENT);
|
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) {
|
lv_obj_add_event_cb(modemDropdown, [](lv_event_t * e) {
|
||||||
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
||||||
@ -925,12 +802,6 @@ public:
|
|||||||
self->selectModulation(lv_dropdown_get_selected(input));
|
self->selectModulation(lv_dropdown_get_selected(input));
|
||||||
}, LV_EVENT_VALUE_CHANGED, this);
|
}, 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_add_event_cb(radioSwitch, [](lv_event_t * e) {
|
||||||
lv_obj_t* input = lv_event_get_target_obj(e);
|
lv_obj_t* input = lv_event_get_target_obj(e);
|
||||||
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
SettingsView* self = (SettingsView*)lv_event_get_user_data(e);
|
||||||
@ -989,22 +860,18 @@ public:
|
|||||||
void activateConfig() {
|
void activateConfig() {
|
||||||
lv_obj_clear_state(modemDropdown, LV_STATE_DISABLED);
|
lv_obj_clear_state(modemDropdown, LV_STATE_DISABLED);
|
||||||
lv_obj_clear_state(radioSwitch, LV_STATE_CHECKED);
|
lv_obj_clear_state(radioSwitch, LV_STATE_CHECKED);
|
||||||
lv_obj_clear_state(modemPresetDropdown, LV_STATE_DISABLED);
|
for (size_t i = 0; i < paramsAvailableCount; ++i) {
|
||||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
assert(paramInputs[i]);
|
||||||
if (paramInputs[i]) {
|
paramInputs[i]->activate();
|
||||||
paramInputs[i]->activate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivateConfig() {
|
void deactivateConfig() {
|
||||||
lv_obj_add_state(radioSwitch, LV_STATE_CHECKED);
|
lv_obj_add_state(radioSwitch, LV_STATE_CHECKED);
|
||||||
lv_obj_add_state(modemDropdown, LV_STATE_DISABLED);
|
lv_obj_add_state(modemDropdown, LV_STATE_DISABLED);
|
||||||
lv_obj_add_state(modemPresetDropdown, LV_STATE_DISABLED);
|
for (size_t i = 0; i < paramsAvailableCount; ++i) {
|
||||||
for (size_t i = 0; i < MAX_PARAMS; ++i) {
|
assert(paramInputs[i]);
|
||||||
if (paramInputs[i]) {
|
paramInputs[i]->deactivate();
|
||||||
paramInputs[i]->deactivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,13 +886,19 @@ public:
|
|||||||
lv_obj_add_flag(mainPanel, (lv_obj_flag_t)(LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLL_ON_FOCUS));
|
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();
|
auto* group = lv_group_get_default();
|
||||||
lv_group_add_obj(group, mainPanel);
|
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;
|
static lv_style_t style_scroll_focus;
|
||||||
lv_style_init(&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_color(&style_scroll_focus, lv_color_make(0x40,0xA0,0xFF));
|
||||||
lv_style_set_bg_opa(&style_scroll_focus, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_scroll_focus, LV_OPA_COVER);
|
||||||
lv_style_set_border_width(&style_scroll_focus, 1);
|
lv_style_set_border_width(&style_scroll_focus, 1);
|
||||||
lv_style_set_border_color(&style_scroll_focus, lv_theme_get_color_primary(nullptr));
|
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_obj_add_style(mainPanel, &style_scroll_focus, LV_PART_SCROLLBAR | LV_STATE_FOCUSED);
|
lv_obj_add_style(mainPanel, &style_scroll_focus, LV_PART_SCROLLBAR | LV_STATE_FOCUSED);
|
||||||
|
|
||||||
deviceForm = initDeviceForm(mainPanel);
|
deviceForm = initDeviceForm(mainPanel);
|
||||||
@ -1068,17 +941,6 @@ void RadioSet::onShow(AppHandle appHandle, lv_obj_t* parent) {
|
|||||||
lv_obj_remove_flag(wrapper, LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(wrapper, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
|
||||||
settingsView = new SettingsView(wrapper);
|
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