Files
MeshCore-Posadmesh/examples/simple_repeater/UITask.h
T
shade 82ec2f4c83 fix(ui): всплывающее окно для ответов устройства в мастере настройки
- ответ CLI показывался строкой поверх экрана и сливался с содержимым, особенно
  в верхней части (например OK - reboot to apply на экране частоты)
- теперь это модальное окно: рамка, свой фон, перенос текста и кнопка OK;
  закрывается коротким нажатием, пока открыто — экран под ним не меняется
- окно показывается сразу (сброс таймера отрисовки), при закрытии экран
  перерисовывается немедленно
- setToast/renderToast заменены на showPopup/renderPopup
- документация: posadmesh-docs/device-setup.md (раздел «Всплывающие сообщения»
  и макет экрана), README — журнал изменений

Проверено сборкой: heltec_v4_repeater_mqtt, Meshadventurer_sx1262_repeater_mqtt,
Generic_E22_sx1262_repeater_mqtt (без дисплея)
2026-10-16 11:16:16 +03:00

113 lines
4.2 KiB
C++

#pragma once
#include <helpers/ui/DisplayDriver.h>
#include <helpers/CommonCLI.h>
class CommonCLI;
// Локальный мастер настройки репитера. Работает на любой плате, у которой есть
// дисплей (DISPLAY_CLASS) и кнопка (PIN_USER_BTN); на остальных целях код
// полностью исключается препроцессором. Все изменения применяются через тот же
// CommonCLI, что и последовательный порт, поэтому проверка значений и запись в
// флеш выполняются одним и тем же кодом.
class UITask {
public:
enum Screen : uint8_t {
SCREEN_STATUS = 0,
SCREEN_MENU,
SCREEN_VALUE, // числа и переключатели: SF, CR, TX, repeat, path hash, advert, flood
SCREEN_DIGITS, // поразрядный ввод значения с точкой (полоса, ADC)
SCREEN_FREQ, // частота: МГц шагом 1, кГц по разрядам
SCREEN_BATTERY, // заряд аккумулятора: напряжение, процент, множитель ADC
SCREEN_COORDS,
SCREEN_COORDS_SAVE
};
private:
mesh::MainBoard* _board;
DisplayDriver* _display;
unsigned long _next_read, _next_refresh, _auto_off;
int _prevBtnState;
NodePrefs* _node_prefs;
CommonCLI* _cli = nullptr;
char _version_info[32];
unsigned long _powering_off_at = 0;
unsigned long _started_at = 0;
// состояние мастера настройки
uint8_t _screen = SCREEN_STATUS;
uint8_t _menu_index = 0;
uint8_t _menu_top = 0;
int _value = 0;
uint8_t _coord_digit = 0; // 0..5 широта, 6..11 долгота
bool _coord_editing = false; // true: цифра правится, false: применена
bool _coord_applied[12];
char _coord_digits[12];
char _toast[64];
bool _popup_active = false; // всплывающее окно с ответом устройства открыто
// радиопараметры: рабочая копия, пока мастер открыт
bool _radio_loaded = false;
bool _radio_dirty = false; // правили ли частоту/полосу/SF/CR в этой сессии
double _radio_freq = 0;
double _radio_bw = 0;
int _radio_sf = 0;
int _radio_cr = 0;
// поразрядный редактор значения с десятичной точкой (полоса)
uint8_t _digit_count = 0;
uint8_t _digit_int = 0; // цифр до точки
uint8_t _digit_index = 0;
bool _digit_editing = false;
bool _digit_applied[8];
char _digit_digits[8];
// редактор частоты: целые МГц меняются шагом 1, кГц — по разрядам
int _freq_mhz = 0;
char _freq_khz[3] = { '0', '0', '0' };
uint8_t _freq_index = 0; // 0 = МГц, 1..3 = разряды кГц
bool _freq_editing = false;
bool _freq_applied[4];
bool wizardActive() const { return _screen != SCREEN_STATUS; }
void openMenu();
void openField(uint8_t index);
void applyField();
void loadRadio();
void applyRadio();
void beginBwEdit();
void beginAdcEdit();
void beginFreqEdit();
void applyDigits();
double digitValue() const;
double freqValue() const;
int batteryPercent() const;
void coordFromPrefs();
void coordSave();
double coordAxisValue(uint8_t axis) const; // axis 0 = lat, 1 = lon
void showPopup(const char* msg);
bool runCommand(const char* command);
void handleButton(int ev);
void renderCurrScreen();
void renderStatus();
void renderMenu();
void renderValue();
void renderDigits();
void renderFreq();
void renderBattery();
void renderCoords();
void renderCoordsSave();
void renderTitleBar(const char* title);
void renderHint(const char* hint);
void renderPopup();
int rowHeight() const;
public:
UITask(mesh::MainBoard& board, DisplayDriver& display) : _board(&board), _display(&display) { _next_read = _next_refresh = 0; }
void begin(NodePrefs* node_prefs, const char* build_date, const char* firmware_version, CommonCLI* cli = nullptr);
void loop();
};