ui-new: темы сохраняются сразу, POWER: ADC от текущего значения и крупная батарея, рамка частоты по фактическим ширинам
T096Board: множитель АЦП вынесен в поле с set/get вместо захардкоженного 4.9
This commit is contained in:
1 parent
c58782aeeb
commit
440aa8a512
5 files changed
+110
-48
No files matched your search
@@ -42,8 +42,10 @@ git merge upstream/main # правки для upstream отправляю
|
||||
(`amber`, `teal`, `signal`, `neon`, `classic`) лежат в общей таблице
|
||||
[`src/helpers/ui/ColorThemes.h`](./src/helpers/ui/ColorThemes.h) и работают и на ST7735,
|
||||
и на ST7789LCD. В `ui-new` есть страница `THEME`: живой предпросмотр, образцы цветов,
|
||||
сохранение выбора в prefs. По умолчанию — янтарь на Heltec T096 и официальная светлая
|
||||
схема MeshCore на остальных платах (как в upstream).
|
||||
сохранение выбора в prefs. **Тема сохраняется сразу при выборе** — что видно на экране,
|
||||
то и записано, поэтому выход из меню (в том числе по таймауту) ничего не «откатывает»
|
||||
и не подменяет ранее выбранную тему. По умолчанию — янтарь на Heltec T096 и официальная
|
||||
светлая схема MeshCore на остальных платах (как в upstream).
|
||||
- **Индикатор страниц** в `ui-new` строится на `warning_txt` / `secondary_txt`: в upstream
|
||||
цвета брались из `title_bkg`, из-за чего на тёмных темах активная точка сливалась с фоном.
|
||||
|
||||
@@ -79,17 +81,23 @@ git merge upstream/main # правки для upstream отправляю
|
||||
каналов, личных сообщений и уведомлений о новых контактах, но сообщения не теряются.
|
||||
- **Страница POWER** (последняя в списке страниц; длинное нажатие — вход в меню) — питание,
|
||||
батарея и перезагрузка. Раньше этот пункт назывался `Hibernation` и сразу выключал устройство.
|
||||
- `Battery` — что показывать рядом с иконкой батареи: `Volt` (напряжение, `4.05V`),
|
||||
`Perc` (процент) или `Off` (индикатор скрыт). Длинное нажатие переключает значение;
|
||||
применяется и сохраняется сразу. Иконка батареи стала компактнее (18×9).
|
||||
- `ADC corr` — коррекция АЦП батареи. Видно текущее значение (или `auto`, если коррекция
|
||||
не задана); длинное нажатие открывает правку, где короткое нажатие даёт `+0.01`,
|
||||
двойное `-0.01`, а длинное возвращает в меню. Значение применяется к плате и сохраняется
|
||||
сразу, а при следующем включении подхватывается из prefs.
|
||||
На самой странице крупно нарисованы батарея с заливкой по заряду, процент и напряжение.
|
||||
- `Battery` — что показывать рядом с иконкой батареи в статус-баре: `Volt` (напряжение,
|
||||
`4.05V`), `Perc` (процент) или `Off` (индикатор скрыт). Длинное нажатие переключает
|
||||
значение; применяется и сохраняется сразу. Иконка батареи стала компактнее (18×9).
|
||||
- `ADC corr` — коррекция АЦП батареи. Показывается **тот множитель, который действует
|
||||
сейчас**: значение из настроек, иначе — из платы, иначе базовый `ADC_MULTIPLIER` варианта
|
||||
(то есть правка начинается не с нуля, а с реального значения прошивки). Длинное нажатие
|
||||
открывает правку, где короткое нажатие даёт `+0.01`, двойное `-0.01`, а длинное возвращает
|
||||
в меню. Значение применяется к плате и сохраняется сразу, а при следующем включении
|
||||
подхватывается из prefs.
|
||||
- `Reboot/Shut` — подменю из трёх пунктов: `Reboot`, `Shutdown`, `Back`; длинное нажатие
|
||||
выполняет выбранное.
|
||||
- `Back` — выход из меню. Сохранять ничего не нужно: всё сохраняется в момент изменения,
|
||||
через 5 минут простоя меню закрывается само.
|
||||
- Коррекция работает на платах, где борд её поддерживает (`Heltec V4`, `V4 R8`, `Heltec
|
||||
T096`, `promicro`, `Heltec RC32`, `Meshnology W12`); на остальных при попытке правки
|
||||
выводится `ADC not supported`.
|
||||
|
||||
### Сборка и CI
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ class HomeScreen : public UIScreen {
|
||||
void powerStep(int8_t dir);
|
||||
void powerAction();
|
||||
void powerAdcStep(int8_t dir);
|
||||
float adcBaseValue(); // текущий множитель АЦП: prefs → борд → ADC_MULTIPLIER варианта
|
||||
void renderPowerPage(DisplayDriver& display);
|
||||
void renderPowerScreen(DisplayDriver& display);
|
||||
void renderPowerAdc(DisplayDriver& display);
|
||||
@@ -231,12 +232,9 @@ class HomeScreen : public UIScreen {
|
||||
_node_prefs->ui_theme[sizeof(_node_prefs->ui_theme) - 1] = 0;
|
||||
the_mesh.savePrefs();
|
||||
}
|
||||
void themeEditLeave(bool save) {
|
||||
void themeEditLeave(bool confirm) {
|
||||
_theme_edit = false;
|
||||
if (save) {
|
||||
themeStore();
|
||||
_task->showAlert("Saved", 1000);
|
||||
}
|
||||
if (confirm) _task->showAlert("Saved", 800); // тема сохраняется в момент выбора, тут только подтверждение
|
||||
_task->showPendingMessages();
|
||||
}
|
||||
void themeRowStep(int8_t dir) {
|
||||
@@ -244,7 +242,10 @@ class HomeScreen : public UIScreen {
|
||||
if (d == NULL) return;
|
||||
uint8_t rows = d->getThemeCount() + 1; // темы + "Save & exit"
|
||||
_theme_sel = (_theme_sel + rows + dir) % rows;
|
||||
if (_theme_sel < d->getThemeCount()) d->setTheme(_theme_sel); // живой предпросмотр
|
||||
if (_theme_sel < d->getThemeCount()) {
|
||||
d->setTheme(_theme_sel); // применяем сразу
|
||||
themeStore(); // и сразу пишем в prefs: что видно, то и сохранено
|
||||
}
|
||||
}
|
||||
void renderThemePage(DisplayDriver& display);
|
||||
void renderThemeEditor(DisplayDriver& display);
|
||||
@@ -972,29 +973,60 @@ void HomeScreen::powerAction() {
|
||||
}
|
||||
|
||||
void HomeScreen::powerAdcStep(int8_t dir) {
|
||||
float v = _node_prefs->adc_multiplier + (float)dir * 0.01f;
|
||||
// считаем от того значения, которое реально работает сейчас, а не от нуля
|
||||
float base = adcBaseValue();
|
||||
if (base <= 0.0f) base = 1.0f; // плата без множителя — считаем от 1.00
|
||||
float v = base + (float)dir * 0.01f;
|
||||
if (v < 0.0f) v = 0.0f;
|
||||
if (v > 10.0f) v = 10.0f;
|
||||
v = roundf(v * 100.0f) / 100.0f; // без накопления погрешности float
|
||||
_node_prefs->adc_multiplier = v;
|
||||
if (!_task->setAdcMultiplier(v)) {
|
||||
_task->showAlert("ADC not supported", 1200);
|
||||
_task->showAlert("ADC not supported", 1200); // плата не умеет корректировать — не сохраняем
|
||||
return;
|
||||
}
|
||||
_node_prefs->adc_multiplier = v;
|
||||
the_mesh.savePrefs();
|
||||
}
|
||||
|
||||
// Множитель АЦП, который действует сейчас: из prefs, иначе из платы,
|
||||
// иначе — базовый множитель варианта (ADC_MULTIPLIER в variant.h)
|
||||
float HomeScreen::adcBaseValue() {
|
||||
if (_node_prefs->adc_multiplier > 0.0f) return _node_prefs->adc_multiplier;
|
||||
float v = _task->getAdcMultiplier();
|
||||
if (v > 0.0f) return v;
|
||||
#ifdef ADC_MULTIPLIER
|
||||
return (float)ADC_MULTIPLIER;
|
||||
#else
|
||||
return 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
void HomeScreen::renderPowerPage(DisplayDriver& display) {
|
||||
char tmp[32];
|
||||
display.setTextSize(1);
|
||||
char tmp[24];
|
||||
uint16_t mv = _task->getBattMilliVolts();
|
||||
int pct = ((int)mv - BATT_MIN_MILLIVOLTS) * 100 / (BATT_MAX_MILLIVOLTS - BATT_MIN_MILLIVOLTS);
|
||||
if (pct < 0) pct = 0;
|
||||
if (pct > 100) pct = 100;
|
||||
|
||||
// крупная иконка батареи, справа — заряд и напряжение
|
||||
const int iconX = 6, iconY = 8, iconW = 44, iconH = 22;
|
||||
display.setColor(UIColor::primary_txt);
|
||||
display.drawRect(iconX, iconY, iconW, iconH);
|
||||
display.fillRect(iconX + iconW, iconY + 6, 3, iconH - 12); // "пипка"
|
||||
display.setColor(pct <= 15 ? UIColor::warning_txt : UIColor::primary_txt);
|
||||
display.fillRect(iconX + 3, iconY + 3, (pct * (iconW - 6)) / 100, iconH - 6);
|
||||
|
||||
display.setColor(UIColor::warning_txt);
|
||||
display.setTextSize(2);
|
||||
snprintf(tmp, sizeof(tmp), "%d%%", pct);
|
||||
display.drawTextRightAlign(display.width() - 4, iconY + 2, tmp);
|
||||
|
||||
display.setColor(UIColor::secondary_txt);
|
||||
snprintf(tmp, sizeof(tmp), "Battery: %s", battDisplayName(_node_prefs->batt_display));
|
||||
display.drawTextCentered(display.width() / 2, 20, tmp);
|
||||
if (_node_prefs->adc_multiplier > 0.0f) {
|
||||
snprintf(tmp, sizeof(tmp), "ADC corr: %.2f", _node_prefs->adc_multiplier);
|
||||
} else {
|
||||
strcpy(tmp, "ADC corr: auto");
|
||||
}
|
||||
display.drawTextCentered(display.width() / 2, 32, tmp);
|
||||
display.setTextSize(1);
|
||||
if (mv > 0) snprintf(tmp, sizeof(tmp), "%.2f V", mv / 1000.0f);
|
||||
else strcpy(tmp, "-- V");
|
||||
display.drawTextRightAlign(display.width() - 4, iconY + iconH + 4, tmp);
|
||||
|
||||
display.setColor(UIColor::primary_txt);
|
||||
display.drawTextCentered(display.width() / 2, 64 - 11, "power: " PRESS_LABEL);
|
||||
}
|
||||
@@ -1014,7 +1046,8 @@ void HomeScreen::renderPowerScreen(DisplayDriver& display) {
|
||||
return;
|
||||
}
|
||||
char val[16];
|
||||
if (_node_prefs->adc_multiplier > 0.0f) snprintf(val, sizeof(val), "%.2f", _node_prefs->adc_multiplier);
|
||||
float adc = adcBaseValue();
|
||||
if (adc > 0.0f) snprintf(val, sizeof(val), "%.2f", adc);
|
||||
else strcpy(val, "auto");
|
||||
drawMenuRow(display, 2, _power_sel == PWR_BATT, "Battery", battDisplayName(_node_prefs->batt_display));
|
||||
drawMenuRow(display, 12, _power_sel == PWR_ADC_ROW, "ADC corr", val);
|
||||
@@ -1029,7 +1062,8 @@ void HomeScreen::renderPowerAdc(DisplayDriver& display) {
|
||||
display.setColor(UIColor::secondary_txt);
|
||||
display.setTextSize(1);
|
||||
display.drawTextLeftAlign(0, 2, "ADC +0.01/-0.01");
|
||||
if (_node_prefs->adc_multiplier > 0.0f) snprintf(buf, sizeof(buf), "%.2f", _node_prefs->adc_multiplier);
|
||||
float adc = adcBaseValue();
|
||||
if (adc > 0.0f) snprintf(buf, sizeof(buf), "%.2f", adc);
|
||||
else strcpy(buf, "auto");
|
||||
display.setColor(UIColor::warning_txt);
|
||||
display.setTextSize(2);
|
||||
@@ -1056,27 +1090,36 @@ void HomeScreen::renderRadioEditor(DisplayDriver& display) {
|
||||
display.setTextSize(1);
|
||||
display.drawTextLeftAlign(0, 2, head);
|
||||
|
||||
display.setColor(UIColor::warning_txt);
|
||||
display.setTextSize(2);
|
||||
int w = display.getTextWidth(buf);
|
||||
int x = (display.width() - w) / 2;
|
||||
const int y = 20;
|
||||
display.drawTextLeftAlign(x, y, buf);
|
||||
|
||||
// Позиции символов считаем по реальным ширинам: у пропорциональных шрифтов
|
||||
// (TFT_eSPI на T096) точка уже цифры, из-за фиксированного шага рамка уезжала.
|
||||
char mhz_txt[8];
|
||||
snprintf(mhz_txt, sizeof(mhz_txt), "%d", mhz);
|
||||
int sel_len = _radio_fq_pos == 0 ? (int)strlen(mhz_txt) : 1;
|
||||
int sel_start = _radio_fq_pos == 0 ? 0 : (int)strlen(mhz_txt) + _radio_fq_pos; // +1 — точка
|
||||
char sel[10];
|
||||
if (sel_len > (int)sizeof(sel) - 1) sel_len = (int)sizeof(sel) - 1;
|
||||
memcpy(sel, buf + sel_start, sel_len);
|
||||
sel[sel_len] = 0;
|
||||
const int buf_len = (int)strlen(buf);
|
||||
|
||||
const int char_w = 6 * 2; // шрифт моноширинный: 6 px на символ при размере 2
|
||||
display.setColor(UIColor::primary_txt);
|
||||
display.fillRect(x + sel_start * char_w - 1, y - 2, sel_len * char_w + 2, 20);
|
||||
display.setColor(UIColor::window_bkg);
|
||||
display.drawTextLeftAlign(x + sel_start * char_w, y, sel);
|
||||
display.setTextSize(2);
|
||||
int total = 0;
|
||||
for (int i = 0; i < buf_len; i++) {
|
||||
char one[2] = { buf[i], 0 };
|
||||
total += (int)display.getTextWidth(one);
|
||||
}
|
||||
int cx = (display.width() - total) / 2;
|
||||
const int y = 20;
|
||||
for (int i = 0; i < buf_len; i++) {
|
||||
char one[2] = { buf[i], 0 };
|
||||
int cw = (int)display.getTextWidth(one);
|
||||
bool mark = (i >= sel_start && i < sel_start + sel_len);
|
||||
if (mark) {
|
||||
display.setColor(UIColor::primary_txt);
|
||||
display.fillRect(cx - 1, y - 2, cw + 2, 20);
|
||||
display.setColor(UIColor::window_bkg);
|
||||
} else {
|
||||
display.setColor(UIColor::warning_txt);
|
||||
}
|
||||
display.drawTextLeftAlign(cx, y, one);
|
||||
cx += cw;
|
||||
}
|
||||
|
||||
display.setColor(UIColor::secondary_txt);
|
||||
display.setTextSize(1);
|
||||
|
||||
@@ -89,8 +89,9 @@ public:
|
||||
bool isButtonPressed() const;
|
||||
|
||||
// Коррекция АЦП батареи: реализация в board конкретного варианта,
|
||||
// если плата так не умеет — вернёт false
|
||||
// если плата так не умеет — set вернёт false, get вернёт 0
|
||||
bool setAdcMultiplier(float multiplier) { return _board->setAdcMultiplier(multiplier); }
|
||||
float getAdcMultiplier() const { return _board->getAdcMultiplier(); }
|
||||
|
||||
bool isBuzzerQuiet() {
|
||||
#ifdef PIN_BUZZER
|
||||
|
||||
@@ -76,7 +76,14 @@ uint16_t T096Board::getBattMilliVolts() {
|
||||
adcvalue = analogRead(PIN_VBAT_READ);
|
||||
digitalWrite(PIN_BAT_CTL, 0);
|
||||
|
||||
return (uint16_t)((float)adcvalue * MV_LSB * 4.9);
|
||||
return (uint16_t)((float)adcvalue * MV_LSB * adc_mult);
|
||||
}
|
||||
|
||||
// Коррекция АЦП батареи (страница POWER в ui-new): полный множитель делителя
|
||||
bool T096Board::setAdcMultiplier(float multiplier) {
|
||||
if (multiplier <= 0.0f) return false;
|
||||
adc_mult = multiplier;
|
||||
return true;
|
||||
}
|
||||
void T096Board::variant_shutdown() {
|
||||
nrf_gpio_cfg_default(PIN_VEXT_EN);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
class T096Board : public NRF52BoardDCDC {
|
||||
protected:
|
||||
float adc_mult = ADC_MULTIPLIER; // множитель делителя батареи, правится из UI (страница POWER)
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
void initiateShutdown(uint8_t reason) override;
|
||||
#endif
|
||||
@@ -23,6 +24,8 @@ public:
|
||||
void onBeforeTransmit(void) override;
|
||||
void onAfterTransmit(void) override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
bool setAdcMultiplier(float multiplier) override;
|
||||
float getAdcMultiplier() const override { return adc_mult; }
|
||||
const char* getManufacturerName() const override ;
|
||||
void powerOff() override;
|
||||
bool setLoRaFemLnaEnabled(bool enable) override;
|
||||
|
||||
Reference in new issue
Block a user