Files
Button/main.cpp
T
GrigoandClaude Opus 5.5 d71fa812da Display/GUI watchdog for the "backlight on, no picture" failure
On PoE sites the MIPI-DSI panel can lose its init on a supply dip while the
RK3566 keeps running; the UI may also hang or exit. Three layers:

- hardware watchdog: systemd RuntimeWatchdogSec=20s (system.conf.d)
- GUI: SdWatchdog pings systemd per swapped frame (WATCHDOG_USEC=30s, enabled
  by the binary so older versions run under the same unit) and writes
  run/qt.frame; buttontask.service gets Restart=always, NotifyAccess=main,
  TimeoutAbortSec=10s
- bt-displaywatch (root, buttontask-displaywatch.service): kernel DRM/DSI
  timeouts, eth link down->up (PoE dip hint), stale UI frames, restart storms
  -> panel re-init (stop UI, fb0 blank 4->0, start UI), repeated -> reboot
  (max 3/day, never during OTA); incident log in /var/log/buttontask/

Manual recovery: hold one finger 10 s in the bottom-left corner (panels are
single-touch). Delivered by OTA via bt-update sync_system; the web service
runs `bt-update sync-system` at start for devices updated by an older
bt-update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:10:10 +00:00

75 lines
2.6 KiB
C++

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include "configmanager.h"
#include "buttonsmodel.h"
#include "buttoncontroller.h"
#include "settingscontainer.h"
#include "systeminfo.h"
#include "sensorsbridge.h"
#include "uiidlewatch.h"
#include "sdwatchdog.h"
#include "recoverygesture.h"
#include <QQuickWindow>
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", "qtvirtualkeyboard");
QGuiApplication app(argc, argv);
QCoreApplication::setApplicationName("ButtonTask");
QCoreApplication::setOrganizationName("ButtonTask");
QCoreApplication::setApplicationVersion("2.5");
QCommandLineParser parser;
parser.setApplicationDescription("ButtonTask v2 - configurable button panel");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption configOpt(QStringList() << "c" << "config",
"Path to config.json",
"path");
parser.addOption(configOpt);
parser.process(app);
QString configPath = parser.value(configOpt);
if (configPath.isEmpty())
configPath = qEnvironmentVariable("BUTTONTASK_CONFIG");
if (configPath.isEmpty())
configPath = QCoreApplication::applicationDirPath() + "/config/config.json";
qInfo() << "Using config:" << configPath;
ConfigManager config(configPath);
ButtonsModel model(&config);
ButtonController controller(&config, &model);
SettingsContainer settings(&config);
SystemInfo systemInfo(&config);
SensorsBridge sensorsBridge;
UiIdleWatch uiIdle;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("config", &config);
engine.rootContext()->setContextProperty("buttonsModel", &model);
engine.rootContext()->setContextProperty("btnController", &controller);
engine.rootContext()->setContextProperty("settingsContainer", &settings);
engine.rootContext()->setContextProperty("systemInfo", &systemInfo);
engine.rootContext()->setContextProperty("sensorsBridge", &sensorsBridge);
engine.rootContext()->setContextProperty("uiIdle", &uiIdle);
engine.load(QUrl(QStringLiteral("qrc:/qml/Main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
// Display/GUI watchdog (see bt-displaywatch): systemd ping per real frame
// + 10 s hold in the bottom-left corner to request a panel re-init.
SdWatchdog sdWatchdog(qobject_cast<QQuickWindow *>(engine.rootObjects().first()));
RecoveryGesture recoveryGesture;
return app.exec();
}