* [Simulator] Create RadioKeyWidget class for UI buttons & refactor ButtonsWidget; Refactor SimulatedUIWidget (and subtypes) to use new RadioKeyWidgets/ButtonsWidget; Centralize help text for key mappings and get creative with some icons; Simplify some radio UI setups with rectangular buttons.
* [Simulator] Convert all simulator data I/O to signals/slots mechanism:
* SimulatorInterface/OpenTxSimulator:
- Now inherits from QObject to allow signal/slot interface;
- Allows data exchange on a per-item basis (eg. each I/O value is treated separately instead of sending whole arrays or structs of data);
- Checks for data changes and only emits signals when change is detected (GUI can now assume only new values are being sent);
- Manages its own 10ms timer (doesn't rely on GUI to do that);
- Sends "heartbeat" signals @ 1Hz for status monitoring;
* Simulator GUI:
- All data is exchanged between GUI elements as well as SimulatorInterface via signals/slots using standardized methods;
- Data is sent immediately, and only, when actually changed (eg. a control is moved) instead of in bulk at specific time intervals;
- Similarly, an asynchronous method is used for reading incoming data, w/out timers or loops;
- Improve VirtualJoystickWidget to be more encapsulated and configurable;
- Pause telemetry simulator if window is hidden;
* [Simulator] Move SimulatorInterface instance to separate thread, ensure safe asynchronous operations & proper timer interactions; Protect/remove some functions, & reorganize the order (cosmetics).
* [Simulator] Traces are now delivered to OpenTxSimulator and one or more QIODevice(s) can be added as recipient(s); Add SimulatorInterface::getCapability() for compile-time settings; Remove reversed POT1/SLIDER1 mixer exception (Taranis) requirement for SIMU; Fix plus/minus key delay on wheel event w/out encoder.
* [Simulator] Add current knob/slider/trim input value in tool-tips (KnobWidget and SliderWidget).
* [Simulator] Fix trims widget internal value not properly updating, and remove trim influence on virtual joystick X/Y value display (closes #4671).
* [SimulatorInterface] Add handling of transmitter input voltage, including a rough conversion of volts to ADC value for different boards, and default battery volts lookup function; Clear analogs array before starting.
* [Simulator] Add SimulatorInterface::init() method to separate pre-startup tasks; Report actual trim range, not just extended on/off; Change how radio widget states are restored; VirtualJoystickWidget: Connect trim changes directly from simulator, connect joystick events directly, report stick mode directly instead of setting values/constraints externally.
* [Simulator] Calculate default Tx V input based on configured range in radio settings (or warning V+2 for radios which don't support a range).
* [Simulator] Add functional aux. trims for Horus (closes #4699).
* [Companion] Remove problematic QMessageLogContext from AppDebugMessageHandler::messageOutput().
* [Simulator] Prevent trim change via slider if disabled for flight mode (closes #4600).
* [OpenTxSimulator] Fixes for Qt < 5.4.
* [OpenTxSimulator] Fix slot name.
135 lines
4.4 KiB
C++
135 lines
4.4 KiB
C++
/*
|
|
* Copyright (C) OpenTX
|
|
*
|
|
* Based on code named
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "appdebugmessagehandler.h"
|
|
|
|
AppDebugMessageHandler::AppDebugMessageHandler(QObject * parent) :
|
|
QObject(parent),
|
|
m_appDebugOutputLevel(APP_DBG_HANDLER_DEFAULT_LEVEL),
|
|
m_showSourcePath(APP_DBG_HANDLER_SHOW_SRC_PATH),
|
|
m_showFunctionDeclarations(APP_DBG_HANDLER_SHOW_FUNCTION_DECL)
|
|
{
|
|
m_srcPathFilter = QRegularExpression("^" APP_DBG_HANDLER_SRC_PATH "[\\\\\\/](.*?)$", QRegularExpression::InvertedGreedinessOption);
|
|
m_functionFilter = QRegularExpression("^.+?(\\w+\\().+$");
|
|
}
|
|
|
|
AppDebugMessageHandler * AppDebugMessageHandler::instance()
|
|
{
|
|
static AppDebugMessageHandler * _instance = NULL;
|
|
#if APP_DBG_HANDLER_ENABLE
|
|
if(_instance == NULL && !qApp->closingDown())
|
|
_instance = new AppDebugMessageHandler(qApp); // Ensure this object is cleaned up when the QApplication exits.
|
|
#endif
|
|
return _instance;
|
|
}
|
|
|
|
void AppDebugMessageHandler::setAppDebugOutputLevel(const quint8 & appDebugOutputLevel)
|
|
{
|
|
m_appDebugOutputLevel = appDebugOutputLevel;
|
|
}
|
|
|
|
void AppDebugMessageHandler::setShowSourcePath(bool showSourcePath)
|
|
{
|
|
m_showSourcePath = showSourcePath;
|
|
}
|
|
|
|
void AppDebugMessageHandler::setShowFunctionDeclarations(bool showFunctionDeclarations)
|
|
{
|
|
m_showFunctionDeclarations = showFunctionDeclarations;
|
|
}
|
|
|
|
void AppDebugMessageHandler::installAppMessageHandler()
|
|
{
|
|
m_defaultHandler = qInstallMessageHandler(g_appDebugMessageHandler);
|
|
}
|
|
|
|
void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
|
|
{
|
|
static const char symbols[] = { 'D', 'W', 'E', 'X', 'I' }; // correspond to QtMsgType enum
|
|
// normalize types, QtDebugMsg stays 0, QtInfoMsg becomes 1, rest are QtMsgType + 1
|
|
quint8 lvl = type;
|
|
if (type == QtInfoMsg)
|
|
lvl = 1;
|
|
else if (type > QtDebugMsg)
|
|
++lvl;
|
|
|
|
if (lvl < m_appDebugOutputLevel && type != QtFatalMsg)
|
|
return;
|
|
|
|
#if defined(Q_OS_LINUX) && (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
|
|
// Filter out lots of QPainter warnings from undocked QDockWidgets... hackish but effective (only workaround found so far)
|
|
if (lvl == 2 && QString(context.function).contains("QPainter::"))
|
|
return;
|
|
#endif
|
|
|
|
QString msgPattern = QString("[%1] ").arg(symbols[type]);
|
|
|
|
if (m_showSourcePath) {
|
|
QString file = QString("%1::").arg(context.file);
|
|
file.replace(m_srcPathFilter, "\\1");
|
|
msgPattern.append(file);
|
|
}
|
|
if (m_showFunctionDeclarations)
|
|
msgPattern.append(context.function);
|
|
else
|
|
msgPattern.append("%{function}()");
|
|
|
|
msgPattern.append(":%{line} -%{if-category} [%{category}]%{endif} %{message}");
|
|
|
|
if (type == QtFatalMsg)
|
|
msgPattern.append("\nBACKTRACE:\n%{backtrace depth=12 separator=\"\n\"}");
|
|
|
|
qSetMessagePattern(msgPattern);
|
|
|
|
if (!m_defaultHandler || receivers(SIGNAL(messageOutput(quint8, const QString &)))) {
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
|
msgPattern = qFormatLogMessage(type, context, msg);
|
|
#else
|
|
msgPattern.replace("%{line}", QString::number(context.line));
|
|
msgPattern.replace("%{if-category} [%{category}]%{endif}", QString(context.category));
|
|
msgPattern.replace("%{message}", msg);
|
|
if (!m_showFunctionDeclarations) {
|
|
QString func = context.function;
|
|
msgPattern.replace("%{function}", func.replace(m_functionFilter, "\\1)"));
|
|
}
|
|
#endif
|
|
|
|
emit messageOutput(lvl, msgPattern);
|
|
}
|
|
|
|
// if (QThread::currentThread() == qApp->thread()) // gui thread
|
|
|
|
if (m_defaultHandler) {
|
|
m_defaultHandler(type, context, msg);
|
|
}
|
|
else {
|
|
fprintf(stderr, "%s", qPrintable(msgPattern));
|
|
if (type == QtFatalMsg)
|
|
abort();
|
|
}
|
|
}
|
|
|
|
// Message handler which is installed using qInstallMessageHandler. This needs to be global.
|
|
void g_appDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
{
|
|
if (AppDebugMessageHandler::instance())
|
|
AppDebugMessageHandler::instance()->messageHandler(type, context, msg);
|
|
}
|