mirror of
https://github.com/opentx/opentx.git
synced 2025-07-15 04:15:26 +03:00
[Simulator] Asynchronous SimulatorInterface & a few new features. (#4738)
* [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.
This commit is contained in:
parent
36bb951314
commit
57dc0159d6
46 changed files with 2064 additions and 1327 deletions
|
@ -98,7 +98,7 @@ void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogCon
|
||||||
|
|
||||||
qSetMessagePattern(msgPattern);
|
qSetMessagePattern(msgPattern);
|
||||||
|
|
||||||
if (!m_defaultHandler || receivers(SIGNAL(messageOutput(quint8, const QString &, const QMessageLogContext &)))) {
|
if (!m_defaultHandler || receivers(SIGNAL(messageOutput(quint8, const QString &)))) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
||||||
msgPattern = qFormatLogMessage(type, context, msg);
|
msgPattern = qFormatLogMessage(type, context, msg);
|
||||||
#else
|
#else
|
||||||
|
@ -111,7 +111,7 @@ void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogCon
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
emit messageOutput(lvl, msgPattern, context);
|
emit messageOutput(lvl, msgPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (QThread::currentThread() == qApp->thread()) // gui thread
|
// if (QThread::currentThread() == qApp->thread()) // gui thread
|
||||||
|
|
|
@ -127,7 +127,7 @@ class AppDebugMessageHandler : public QObject
|
||||||
bool m_showFunctionDeclarations;
|
bool m_showFunctionDeclarations;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void messageOutput(quint8 level, const QString & msg, const QMessageLogContext & context);
|
void messageOutput(quint8 level, const QString & msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Message handler which is installed using qInstallMessageHandler. This needs to be global.
|
// Message handler which is installed using qInstallMessageHandler. This needs to be global.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<file>images/track.png</file>
|
<file>images/track.png</file>
|
||||||
<file>images/track0.png</file>
|
<file>images/track0.png</file>
|
||||||
<file>images/taranison.png</file>
|
<file>images/taranison.png</file>
|
||||||
|
<file>images/simulator/icons/svg/arrow_click.svg</file>
|
||||||
<file>images/simulator/icons/svg/camera.svg</file>
|
<file>images/simulator/icons/svg/camera.svg</file>
|
||||||
<file>images/simulator/icons/svg/camera-active.svg</file>
|
<file>images/simulator/icons/svg/camera-active.svg</file>
|
||||||
<file>images/simulator/icons/svg/console.svg</file>
|
<file>images/simulator/icons/svg/console.svg</file>
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
<file>images/simulator/icons/svg/joystick_settings.svg</file>
|
<file>images/simulator/icons/svg/joystick_settings.svg</file>
|
||||||
<file>images/simulator/icons/svg/joystick_settings-active.svg</file>
|
<file>images/simulator/icons/svg/joystick_settings-active.svg</file>
|
||||||
<file>images/simulator/icons/svg/line_horiz.svg</file>
|
<file>images/simulator/icons/svg/line_horiz.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/mouse.svg</file>
|
||||||
<file>images/simulator/icons/svg/toggle_lock.svg</file>
|
<file>images/simulator/icons/svg/toggle_lock.svg</file>
|
||||||
<file>images/simulator/icons/svg/toggle_lock-on.svg</file>
|
<file>images/simulator/icons/svg/toggle_lock-on.svg</file>
|
||||||
<file>images/simulator/icons/svg/radio_outputs.svg</file>
|
<file>images/simulator/icons/svg/radio_outputs.svg</file>
|
||||||
|
|
27
companion/src/images/simulator/icons/svg/arrow_click.svg
Normal file
27
companion/src/images/simulator/icons/svg/arrow_click.svg
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3007">
|
||||||
|
<defs id="defs3009" />
|
||||||
|
<metadata id="metadata3012">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(0.64592419,0,0,0.64592419,3.7118734,3.509355)" id="g4">
|
||||||
|
<g id="g6">
|
||||||
|
<path d="M 49.634152,27.060548 V 2.7303987 c 0,-1.6220105 -1.31026,-2.94910955 -2.911691,-2.94910955 -1.60143,0 -2.911692,1.32709905 -2.911692,2.94910955 V 27.060548 c 0,1.62201 1.310262,2.94911 2.911692,2.94911 1.601431,0 2.911691,-1.3271 2.911691,-2.94911 z" id="path8" />
|
||||||
|
<path d="M 2.3191619,50.211055 H 26.340619 c 1.60143,0 2.911691,-1.3271 2.911691,-2.94911 0,-1.62201 -1.310261,-2.94911 -2.911691,-2.94911 H 2.3191619 c -1.60142995,0 -2.91169115,1.3271 -2.91169115,2.94911 0,1.62201 1.3102612,2.94911 2.91169115,2.94911 z" id="path10" />
|
||||||
|
<path d="m 18.479051,18.803043 c -1.164676,1.179643 -1.164676,2.94911 0,4.128753 l 7.715983,7.815139 c 0.582339,0.589821 1.310262,0.884733 2.038184,0.884733 0.727924,0 1.455846,-0.294912 2.038185,-0.884733 1.164677,-1.179644 1.164677,-2.949109 0,-4.128753 L 22.55542,18.803043 c -1.019093,-1.032188 -2.911692,-1.032188 -4.076369,0 z" id="path12" />
|
||||||
|
<path d="m 70.16158,18.950499 -7.715985,7.815138 c -1.164674,1.179644 -1.164674,2.94911 0,4.128754 0.582339,0.589821 1.310263,0.884732 2.038185,0.884732 0.727924,0 1.455847,-0.294911 2.038185,-0.884732 l 7.715982,-7.81514 c 1.164677,-1.179644 1.164677,-2.949109 0,-4.128752 -1.019092,-1.03219 -2.911691,-1.03219 -4.076367,0 z" id="path14" />
|
||||||
|
<path d="m 26.04945,63.776956 -7.715984,7.81514 c -1.164675,1.179642 -1.164675,2.949108 0,4.128752 0.582339,0.589822 1.310262,0.884733 2.038185,0.884733 0.727924,0 1.455846,-0.294911 2.038184,-0.884733 l 7.715982,-7.815138 c 1.164677,-1.179644 1.164677,-2.94911 0,-4.128754 -1.164675,-1.179644 -2.91169,-1.179644 -4.076367,0 z" id="path16" />
|
||||||
|
<polygon points="85.3,77 64.5,56.2 81.3,50.5 39.5,38.7 51,80.8 56.7,64.1 77.5,84.8 " transform="matrix(0.87815057,0,0,0.88943545,9.8347839,11.453988)" id="polygon18" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
20
companion/src/images/simulator/icons/svg/mouse.svg
Normal file
20
companion/src/images/simulator/icons/svg/mouse.svg
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" width="64" height="64" id="svg3007" inkscape:version="0.48.4 r9939" sodipodi:docname="mouse.svg">
|
||||||
|
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="640" inkscape:window-height="480" id="namedview8" showgrid="false" inkscape:zoom="3.6875" inkscape:cx="32" inkscape:cy="32" inkscape:current-layer="layer1" />
|
||||||
|
<defs id="defs3009" />
|
||||||
|
<metadata id="metadata3012">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<path d="m 32.627622,1.1648443 c -12.462898,0 -22.562142,8.7258932 -22.562142,19.4940177 v 22.27888 c 0,10.768123 10.099244,19.494018 22.562142,19.494018 12.462898,0 22.562144,-8.725895 22.562144,-19.494018 V 20.658862 C 55.189766,9.8907375 45.09052,1.1648443 32.627622,1.1648443 z M 49.817827,42.937742 c 0,8.168921 -7.735593,14.852585 -17.190205,14.852585 -9.454612,0 -17.190204,-6.683664 -17.190204,-14.852585 v -22.27888 c 0,-8.168921 7.735592,-14.8525846 17.190204,-14.8525846 9.454612,0 17.190205,6.6836636 17.190205,14.8525846 v 22.27888 z" id="path4" />
|
||||||
|
<path d="m 32.627622,9.2529782 c -3.116845,0 -5.565794,2.1994928 -5.565794,4.9988458 v 14.596624 c 0,2.799353 2.448949,4.998843 5.565794,4.998843 3.116843,0 5.565795,-2.19949 5.565795,-4.998843 V 14.251824 c 0,-2.599399 -2.448952,-4.9988458 -5.565795,-4.9988458 z" id="path6" inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -40,6 +40,7 @@ set(simulation_HDRS
|
||||||
radiouiaction.h
|
radiouiaction.h
|
||||||
simulateduiwidget.h
|
simulateduiwidget.h
|
||||||
# simulator.h
|
# simulator.h
|
||||||
|
simulatorinterface.h
|
||||||
simulatormainwindow.h
|
simulatormainwindow.h
|
||||||
simulatorstartupdialog.h
|
simulatorstartupdialog.h
|
||||||
simulatorwidget.h
|
simulatorwidget.h
|
||||||
|
@ -49,6 +50,7 @@ set(simulation_HDRS
|
||||||
widgets/lcdwidget.h
|
widgets/lcdwidget.h
|
||||||
widgets/radiowidget.h
|
widgets/radiowidget.h
|
||||||
widgets/radiofaderwidget.h
|
widgets/radiofaderwidget.h
|
||||||
|
widgets/radiokeywidget.h
|
||||||
widgets/radioknobwidget.h
|
widgets/radioknobwidget.h
|
||||||
widgets/radioswitchwidget.h
|
widgets/radioswitchwidget.h
|
||||||
widgets/radiotrimwidget.h
|
widgets/radiotrimwidget.h
|
||||||
|
|
|
@ -36,20 +36,13 @@
|
||||||
|
|
||||||
extern AppData g; // ensure what "g" means
|
extern AppData g; // ensure what "g" means
|
||||||
|
|
||||||
FilteredTextBuffer * DebugOutput::m_dataBufferDevice = Q_NULLPTR;
|
|
||||||
const quint16 DebugOutput::m_savedViewStateVersion = 1;
|
const quint16 DebugOutput::m_savedViewStateVersion = 1;
|
||||||
|
|
||||||
void firmwareTraceCb(const char * text)
|
|
||||||
{
|
|
||||||
if (DebugOutput::m_dataBufferDevice) {
|
|
||||||
DebugOutput::m_dataBufferDevice->write(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator):
|
DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator):
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::DebugOutput),
|
ui(new Ui::DebugOutput),
|
||||||
m_simulator(simulator),
|
m_simulator(simulator),
|
||||||
|
m_dataBufferDevice(NULL),
|
||||||
m_radioProfileId(g.sessionId()),
|
m_radioProfileId(g.sessionId()),
|
||||||
m_filterEnable(false),
|
m_filterEnable(false),
|
||||||
m_filterExclude(false)
|
m_filterExclude(false)
|
||||||
|
@ -101,33 +94,28 @@ DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator):
|
||||||
connect(ui->actionToggleFilter, &QAction::toggled, this, &DebugOutput::onFilterToggled);
|
connect(ui->actionToggleFilter, &QAction::toggled, this, &DebugOutput::onFilterToggled);
|
||||||
connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged);
|
connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged);
|
||||||
|
|
||||||
if (AppDebugMessageHandler::instance()) {
|
if (AppDebugMessageHandler::instance())
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 3, 0)) // https://bugreports.qt.io/browse/QTBUG-36119
|
|
||||||
connect(AppDebugMessageHandler::instance(), SIGNAL(messageOutput(quint8,QString,QMessageLogContext)), this, SLOT(onAppDebugMessage(quint8,QString,QMessageLogContext)));
|
|
||||||
#else
|
|
||||||
connect(AppDebugMessageHandler::instance(), &AppDebugMessageHandler::messageOutput, this, &DebugOutput::onAppDebugMessage);
|
connect(AppDebugMessageHandler::instance(), &AppDebugMessageHandler::messageOutput, this, &DebugOutput::onAppDebugMessage);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// send firmware TRACE events to our data collector
|
// send firmware TRACE events to our data collector
|
||||||
m_simulator->installTraceHook(firmwareTraceCb);
|
m_simulator->addTracebackDevice(m_dataBufferDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugOutput::~DebugOutput()
|
DebugOutput::~DebugOutput()
|
||||||
{
|
{
|
||||||
m_simulator->installTraceHook(NULL);
|
|
||||||
saveState();
|
|
||||||
|
|
||||||
if (AppDebugMessageHandler::instance())
|
if (AppDebugMessageHandler::instance())
|
||||||
disconnect(AppDebugMessageHandler::instance(), 0, this, 0);
|
disconnect(AppDebugMessageHandler::instance(), 0, this, 0);
|
||||||
|
|
||||||
if (m_dataBufferDevice) {
|
if (m_dataBufferDevice) {
|
||||||
|
m_simulator->removeTracebackDevice(m_dataBufferDevice);
|
||||||
disconnect(m_dataBufferDevice, 0, this, 0);
|
disconnect(m_dataBufferDevice, 0, this, 0);
|
||||||
disconnect(this, 0, m_dataBufferDevice, 0);
|
disconnect(this, 0, m_dataBufferDevice, 0);
|
||||||
m_dataBufferDevice->deleteLater();
|
delete m_dataBufferDevice;
|
||||||
m_dataBufferDevice = Q_NULLPTR;
|
m_dataBufferDevice = Q_NULLPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveState();
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,11 +201,10 @@ void DebugOutput::onDataBufferOverflow(const qint64 len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugOutput::onAppDebugMessage(quint8 level, const QString & msg, const QMessageLogContext & context)
|
void DebugOutput::onAppDebugMessage(quint8 level, const QString & msg)
|
||||||
{
|
{
|
||||||
if (level > 0) {
|
if (level > 0 && m_dataBufferDevice) {
|
||||||
firmwareTraceCb(qPrintable(msg));
|
m_dataBufferDevice->write(qPrintable(msg % "\n"));
|
||||||
firmwareTraceCb("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,20 +60,19 @@ class DebugOutput : public QWidget
|
||||||
|
|
||||||
static QRegularExpression makeRegEx(const QString & input, bool * isExlusive = NULL);
|
static QRegularExpression makeRegEx(const QString & input, bool * isExlusive = NULL);
|
||||||
|
|
||||||
static FilteredTextBuffer * m_dataBufferDevice;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filterExprChanged(const QRegularExpression & expr);
|
void filterExprChanged(const QRegularExpression & expr);
|
||||||
void filterEnabledChanged(const bool enabled);
|
void filterEnabledChanged(const bool enabled);
|
||||||
void filterExclusiveChanged(const bool exlusive);
|
void filterExclusiveChanged(const bool exlusive);
|
||||||
void filterChanged(bool enable, bool exclusive, const QRegularExpression & expr);
|
void filterChanged(bool enable, bool exclusive, const QRegularExpression & expr);
|
||||||
|
void tracebackDeviceChange(QIODevice * device);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void saveState();
|
void saveState();
|
||||||
void restoreState();
|
void restoreState();
|
||||||
void processBytesReceived();
|
void processBytesReceived();
|
||||||
void onDataBufferOverflow(const qint64 len);
|
void onDataBufferOverflow(const qint64 len);
|
||||||
void onAppDebugMessage(quint8 level, const QString & msg, const QMessageLogContext & context);
|
void onAppDebugMessage(quint8 level, const QString & msg);
|
||||||
void onFilterStateChanged();
|
void onFilterStateChanged();
|
||||||
void onFilterTextChanged(const QString &);
|
void onFilterTextChanged(const QString &);
|
||||||
void onFilterToggled(bool enable);
|
void onFilterToggled(bool enable);
|
||||||
|
@ -85,6 +84,7 @@ class DebugOutput : public QWidget
|
||||||
protected:
|
protected:
|
||||||
Ui::DebugOutput * ui;
|
Ui::DebugOutput * ui;
|
||||||
SimulatorInterface * m_simulator;
|
SimulatorInterface * m_simulator;
|
||||||
|
FilteredTextBuffer * m_dataBufferDevice;
|
||||||
int m_radioProfileId;
|
int m_radioProfileId;
|
||||||
bool m_filterEnable;
|
bool m_filterEnable;
|
||||||
bool m_filterExclude;
|
bool m_filterExclude;
|
||||||
|
|
|
@ -26,39 +26,32 @@
|
||||||
#include "eeprominterface.h"
|
#include "eeprominterface.h"
|
||||||
#include "radiodata.h"
|
#include "radiodata.h"
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
#include "simulatorinterface.h"
|
|
||||||
|
|
||||||
extern AppData g; // ensure what "g" means
|
extern AppData g; // ensure what "g" means
|
||||||
|
|
||||||
const int RadioOutputsWidget::m_dataUpdateFreqDefault = 10; // ms
|
|
||||||
const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1;
|
const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1;
|
||||||
|
|
||||||
RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
|
RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_simulator(simulator),
|
m_simulator(simulator),
|
||||||
m_firmware(firmware),
|
m_firmware(firmware),
|
||||||
m_tmrUpdateData(new QTimer),
|
|
||||||
m_radioProfileId(g.sessionId()),
|
m_radioProfileId(g.sessionId()),
|
||||||
m_lastFlightPhase(-1),
|
|
||||||
m_started(false),
|
|
||||||
ui(new Ui::RadioOutputsWidget)
|
ui(new Ui::RadioOutputsWidget)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
restoreState();
|
restoreState();
|
||||||
|
|
||||||
m_dataUpdateFreq = m_dataUpdateFreqDefault;
|
connect(m_simulator, &SimulatorInterface::channelOutValueChange, this, &RadioOutputsWidget::onChannelOutValueChange);
|
||||||
m_tmrUpdateData->setInterval(m_dataUpdateFreq);
|
connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange);
|
||||||
|
connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange);
|
||||||
connect(m_tmrUpdateData, &QTimer::timeout, this, &RadioOutputsWidget::setValues);
|
connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioOutputsWidget::~RadioOutputsWidget()
|
RadioOutputsWidget::~RadioOutputsWidget()
|
||||||
{
|
{
|
||||||
stop();
|
//stop();
|
||||||
saveState();
|
saveState();
|
||||||
if (m_tmrUpdateData)
|
|
||||||
delete m_tmrUpdateData;
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,36 +67,20 @@ void RadioOutputsWidget::changeEvent(QEvent *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioOutputsWidget::showEvent(QShowEvent * event)
|
|
||||||
{
|
|
||||||
if (m_started)
|
|
||||||
m_tmrUpdateData->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioOutputsWidget::hideEvent(QHideEvent * event)
|
|
||||||
{
|
|
||||||
m_tmrUpdateData->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioOutputsWidget::start()
|
void RadioOutputsWidget::start()
|
||||||
{
|
{
|
||||||
setupChannelsDisplay();
|
setupChannelsDisplay();
|
||||||
setupGVarsDisplay();
|
setupGVarsDisplay();
|
||||||
setupLsDisplay();
|
setupLsDisplay();
|
||||||
m_lastFlightPhase = -1;
|
|
||||||
m_tmrUpdateData->start();
|
|
||||||
m_started = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioOutputsWidget::stop()
|
//void RadioOutputsWidget::stop()
|
||||||
{
|
//{
|
||||||
m_tmrUpdateData->stop();
|
//}
|
||||||
m_started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioOutputsWidget::restart()
|
void RadioOutputsWidget::restart()
|
||||||
{
|
{
|
||||||
stop();
|
//stop();
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +116,6 @@ void RadioOutputsWidget::restoreState()
|
||||||
ui->splitter->restoreState(splitterState);
|
ui->splitter->restoreState(splitterState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RadioOutputsWidget::setupChannelsDisplay()
|
void RadioOutputsWidget::setupChannelsDisplay()
|
||||||
{
|
{
|
||||||
int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
|
int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
|
||||||
|
@ -297,68 +273,73 @@ QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo
|
||||||
return swtch;
|
return swtch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read various values from firmware simulator and populate values in this UI
|
void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value)
|
||||||
void RadioOutputsWidget::setValues()
|
|
||||||
{
|
{
|
||||||
static TxOutputs prevOutputs = TxOutputs();
|
if (m_channelsMap.contains(index)) {
|
||||||
int currentPhase;
|
QPair<QLabel *, QSlider *> ch = m_channelsMap.value(index);
|
||||||
TxOutputs outputs;
|
ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
|
||||||
QFont font;
|
ch.second->setValue(qMin(1024, qMax(-1024, value)));
|
||||||
|
|
||||||
m_simulator->getValues(outputs);
|
|
||||||
currentPhase = m_simulator->getPhase();
|
|
||||||
|
|
||||||
if (ui->channelsWidget->isVisible()) {
|
|
||||||
QHash<int, QPair<QLabel *, QSlider *> >::const_iterator ch;
|
|
||||||
for (ch = m_channelsMap.constBegin(); ch != m_channelsMap.constEnd(); ++ch) {
|
|
||||||
if (ch.key() >= CPN_MAX_CHNOUT)
|
|
||||||
continue;
|
|
||||||
ch.value().first->setText(QString("%1%").arg(calcRESXto100(outputs.chans[ch.key()])));
|
|
||||||
ch.value().second->setValue(qMin(1024, qMax(-1024, outputs.chans[ch.key()])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//qDebug() << index << value;
|
||||||
if (ui->logicalSwitchesWidget->isVisible()) {
|
}
|
||||||
QHash<int, QLabel* >::const_iterator ls;
|
|
||||||
for (ls = m_logicSwitchMap.constBegin(); ls != m_logicSwitchMap.constEnd(); ++ls) {
|
void RadioOutputsWidget::onVirtSwValueChange(quint8 index, qint32 value)
|
||||||
if (ls.key() >= CPN_MAX_LOGICAL_SWITCHES || (prevOutputs.vsw[ls.key()] == outputs.vsw[ls.key()] && m_lastFlightPhase > -1))
|
{
|
||||||
continue;
|
if (!m_logicSwitchMap.contains(index))
|
||||||
ls.value()->setBackgroundRole(outputs.vsw[ls.key()] ? QPalette::Dark : QPalette::Background);
|
return;
|
||||||
ls.value()->setForegroundRole(outputs.vsw[ls.key()] ? QPalette::BrightText : QPalette::WindowText);
|
|
||||||
ls.value()->setFrameShadow(outputs.vsw[ls.key()] ? QFrame::Sunken : QFrame::Raised);
|
QLabel * ls = m_logicSwitchMap.value(index);
|
||||||
font = ls.value()->font();
|
ls->setBackgroundRole(value ? QPalette::Dark : QPalette::Background);
|
||||||
font.setBold(outputs.vsw[ls.key()]);
|
ls->setForegroundRole(value ? QPalette::BrightText : QPalette::WindowText);
|
||||||
ls.value()->setFont(font);
|
ls->setFrameShadow(value ? QFrame::Sunken : QFrame::Raised);
|
||||||
prevOutputs.vsw[ls.key()] = outputs.vsw[ls.key()];
|
QFont font = ls->font();
|
||||||
}
|
font.setBold((bool)value);
|
||||||
}
|
ls->setFont(font);
|
||||||
|
//qDebug() << index << value;
|
||||||
if (ui->globalVarsWidget->isVisible()) {
|
}
|
||||||
QPalette::ColorRole bgrole;
|
|
||||||
QHash<int, QHash<int, QLabel *> >::const_iterator gv;
|
void RadioOutputsWidget::onGVarValueChange(quint8 index, qint32 value)
|
||||||
QHash<int, QLabel *>::const_iterator fm;
|
{
|
||||||
for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
|
if (!m_globalVarsMap.contains(index))
|
||||||
if (gv.key() >= CPN_MAX_GVARS)
|
return;
|
||||||
continue;
|
|
||||||
for (fm = gv.value().constBegin(); fm != gv.value().constEnd(); ++fm) {
|
QHash<int, QLabel *> fmMap = m_globalVarsMap.value(index);
|
||||||
if (fm.key() >= CPN_MAX_FLIGHT_MODES)
|
SimulatorInterface::gVarMode_t gv(value);
|
||||||
continue;
|
|
||||||
if (currentPhase != m_lastFlightPhase || prevOutputs.gvars[fm.key()][gv.key()] != outputs.gvars[fm.key()][gv.key()]) {
|
if (fmMap.contains(gv.mode)) {
|
||||||
if (fm.key() == currentPhase)
|
QLabel * lbl = fmMap.value(gv.mode);
|
||||||
bgrole = QPalette::Dark;
|
if (lbl)
|
||||||
else
|
lbl->setText(QString::number(gv.value));
|
||||||
bgrole = ((gv.key() % 2) ? QPalette::Background : QPalette::AlternateBase);
|
}
|
||||||
fm.value()->setBackgroundRole(bgrole);
|
//qDebug() << index << value << gv.mode << gv.value;
|
||||||
fm.value()->setForegroundRole(fm.key() == currentPhase ? QPalette::BrightText : QPalette::WindowText);
|
}
|
||||||
font = fm.value()->font();
|
|
||||||
font.setBold(fm.key() == currentPhase);
|
void RadioOutputsWidget::onPhaseChanged(qint32 phase, const QString &)
|
||||||
fm.value()->setFont(font);
|
{
|
||||||
fm.value()->setText(QString::number(outputs.gvars[fm.key()][gv.key()]));
|
QPalette::ColorRole fgrole, bgrole;
|
||||||
prevOutputs.gvars[fm.key()][gv.key()] = outputs.gvars[fm.key()][gv.key()];
|
QLabel * lbl;
|
||||||
}
|
QFont font;
|
||||||
}
|
QHash<int, QHash<int, QLabel *> >::const_iterator gv;
|
||||||
}
|
QHash<int, QLabel *>::const_iterator fm;
|
||||||
}
|
|
||||||
|
for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
|
||||||
m_lastFlightPhase = currentPhase;
|
for (fm = gv.value().constBegin(); fm != gv.value().constEnd(); ++fm) {
|
||||||
|
lbl = fm.value();
|
||||||
|
font = lbl->font();
|
||||||
|
if (fm.key() == phase) {
|
||||||
|
fgrole = QPalette::BrightText;
|
||||||
|
bgrole = QPalette::Dark;
|
||||||
|
font.setBold(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fgrole = QPalette::WindowText;
|
||||||
|
bgrole = ((gv.key() % 2) ? QPalette::Background : QPalette::AlternateBase);
|
||||||
|
font.setBold(false);
|
||||||
|
}
|
||||||
|
lbl->setForegroundRole(fgrole);
|
||||||
|
lbl->setBackgroundRole(bgrole);
|
||||||
|
lbl->setFont(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//qDebug() << phase;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define RADIOOUTPUTSWIDGET_H
|
#define RADIOOUTPUTSWIDGET_H
|
||||||
|
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
@ -31,7 +32,7 @@ class RadioOutputsWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Firmware;
|
class Firmware;
|
||||||
class SimulatorInterface;
|
//class SimulatorInterface;
|
||||||
|
|
||||||
class QFrame;
|
class QFrame;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
@ -47,16 +48,18 @@ class RadioOutputsWidget : public QWidget
|
||||||
explicit RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget * parent = 0);
|
explicit RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget * parent = 0);
|
||||||
~RadioOutputsWidget();
|
~RadioOutputsWidget();
|
||||||
|
|
||||||
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
//void stop();
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void saveState();
|
void saveState();
|
||||||
void restoreState();
|
void restoreState();
|
||||||
void setValues();
|
void onChannelOutValueChange(quint8 index, qint32 value);
|
||||||
void showEvent(QShowEvent *event);
|
void onVirtSwValueChange(quint8 index, qint32 value);
|
||||||
void hideEvent(QHideEvent *event);
|
void onGVarValueChange(quint8 index, qint32 value);
|
||||||
|
void onPhaseChanged(qint32 phase, const QString &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void changeEvent(QEvent *e);
|
void changeEvent(QEvent *e);
|
||||||
|
@ -67,7 +70,6 @@ class RadioOutputsWidget : public QWidget
|
||||||
|
|
||||||
SimulatorInterface * m_simulator;
|
SimulatorInterface * m_simulator;
|
||||||
Firmware * m_firmware;
|
Firmware * m_firmware;
|
||||||
QTimer * m_tmrUpdateData;
|
|
||||||
|
|
||||||
QHash<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
|
QHash<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
|
||||||
QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
|
QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
|
||||||
|
@ -75,10 +77,7 @@ class RadioOutputsWidget : public QWidget
|
||||||
|
|
||||||
int m_radioProfileId;
|
int m_radioProfileId;
|
||||||
int m_dataUpdateFreq;
|
int m_dataUpdateFreq;
|
||||||
int m_lastFlightPhase;
|
|
||||||
bool m_started;
|
|
||||||
|
|
||||||
const static int m_dataUpdateFreqDefault;
|
|
||||||
const static quint16 m_savedViewStateVersion;
|
const static quint16 m_savedViewStateVersion;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -37,12 +37,12 @@ class RadioUiAction : public QObject
|
||||||
/*
|
/*
|
||||||
* @param index Typically this is the hardware array index corresponding to button on current radio model,
|
* @param index Typically this is the hardware array index corresponding to button on current radio model,
|
||||||
* but it could be anything. Use -1 or any other negative value for non-hardware indices.
|
* but it could be anything. Use -1 or any other negative value for non-hardware indices.
|
||||||
* @param key An optional Qt:Key code for shortcut.
|
* @param key An optional Qt:Key code for shortcut (zero for none).
|
||||||
* @param parent Parent widget, required for handling keyboard events.
|
* @param parent Parent widget, required for handling keyboard events.
|
||||||
* @param text Optional title for this action. The text and description are currently used in generated help text.
|
* @param text Optional title for this action. The text and description are currently used in generated help text.
|
||||||
* @param descript Optional longer description text for this action.
|
* @param descript Optional longer description text for this action.
|
||||||
*/
|
*/
|
||||||
RadioUiAction(int index = -1, int key = 0, QWidget * parent = NULL, const QString &text = "", const QString &descript = ""):
|
RadioUiAction(int index = -1, int key = 0, const QString &text = "", const QString &descript = "", QWidget * parent = NULL):
|
||||||
m_hwIndex(index),
|
m_hwIndex(index),
|
||||||
m_active(false),
|
m_active(false),
|
||||||
m_keys(QList<int>()),
|
m_keys(QList<int>()),
|
||||||
|
@ -50,36 +50,50 @@ class RadioUiAction : public QObject
|
||||||
m_description(descript),
|
m_description(descript),
|
||||||
m_parent(parent)
|
m_parent(parent)
|
||||||
{
|
{
|
||||||
if (key)
|
addKey(key);
|
||||||
m_keys.append(key);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* @param keys QList of Qt:Key codes to use as shortcuts.
|
* @param keys QList of Qt:Key codes to use as shortcuts.
|
||||||
* [See above for other params.]
|
* [See above for other params.]
|
||||||
*/
|
*/
|
||||||
RadioUiAction(int index, QList<int> keys, QWidget * parent = NULL, const QString &text = "", const QString &descript = ""):
|
RadioUiAction(int index, QList<int> keys, const QString &text = "", const QString &descript = "", QWidget * parent = NULL):
|
||||||
m_hwIndex(index),
|
RadioUiAction(index, 0, text, descript, parent)
|
||||||
m_active(false),
|
|
||||||
m_keys(keys),
|
|
||||||
m_text(text),
|
|
||||||
m_description(descript),
|
|
||||||
m_parent(parent)
|
|
||||||
{
|
{
|
||||||
init();
|
addKeys(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
void addKey(const int & key)
|
||||||
{
|
{
|
||||||
if (m_keys.size())
|
if (key > 0 && !m_keys.contains(key)) {
|
||||||
|
m_keys.append(key);
|
||||||
addShortcut();
|
addShortcut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addKeys(const QList<int> & keys)
|
||||||
|
{
|
||||||
|
foreach (int key, keys)
|
||||||
|
addKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addShortcut()
|
void addShortcut()
|
||||||
{
|
{
|
||||||
if (m_parent)
|
if (m_parent) {
|
||||||
m_parent->installEventFilter(this);
|
m_parent->removeEventFilter(this);
|
||||||
|
if (m_keys.size())
|
||||||
|
m_parent->installEventFilter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// override
|
||||||
|
void setParent(QObject * parent)
|
||||||
|
{
|
||||||
|
QObject::setParent(parent);
|
||||||
|
QWidget * w = qobject_cast<QWidget *>(parent);
|
||||||
|
if (w && w != m_parent) {
|
||||||
|
m_parent = w;
|
||||||
|
addShortcut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDescription(const QString & description) { m_description = description; }
|
void setDescription(const QString & description) { m_description = description; }
|
||||||
|
|
|
@ -22,8 +22,13 @@
|
||||||
#include "eeprominterface.h"
|
#include "eeprominterface.h"
|
||||||
#include "lcdwidget.h"
|
#include "lcdwidget.h"
|
||||||
#include "radiouiaction.h"
|
#include "radiouiaction.h"
|
||||||
|
#include "radiokeywidget.h"
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
|
//#define FLASH_DURATION 10
|
||||||
|
//#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
||||||
|
//#define CBEEP_OFF "QLabel { }"
|
||||||
|
|
||||||
SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, QWidget * parent) :
|
SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, QWidget * parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_simulator(simulator),
|
m_simulator(simulator),
|
||||||
|
@ -31,16 +36,18 @@ SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, QWidget * p
|
||||||
m_lcd(NULL),
|
m_lcd(NULL),
|
||||||
m_scrollUpAction(NULL),
|
m_scrollUpAction(NULL),
|
||||||
m_scrollDnAction(NULL),
|
m_scrollDnAction(NULL),
|
||||||
m_rotEncClickAction(NULL),
|
m_mouseMidClickAction(NULL),
|
||||||
|
m_screenshotAction(NULL),
|
||||||
m_board(getCurrentBoard()),
|
m_board(getCurrentBoard()),
|
||||||
m_backLight(0),
|
m_backLight(0),
|
||||||
m_lightOn(false),
|
|
||||||
m_beepShow(0),
|
m_beepShow(0),
|
||||||
m_beepVal(0)
|
m_beepVal(0)
|
||||||
{
|
{
|
||||||
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
|
m_screenshotAction = new RadioUiAction(-1, Qt::Key_Print);
|
||||||
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
|
|
||||||
connect(m_screenshotAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), this, &SimulatedUIWidget::captureScreenshot);
|
connect(m_screenshotAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), this, &SimulatedUIWidget::captureScreenshot);
|
||||||
|
|
||||||
|
connect(m_simulator, &SimulatorInterface::lcdChange, this, &SimulatedUIWidget::onLcdChange);
|
||||||
|
connect(this, &SimulatedUIWidget::simulatorWheelEvent, m_simulator, &SimulatorInterface::rotaryEncoderEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedUIWidget::~SimulatedUIWidget()
|
SimulatedUIWidget::~SimulatedUIWidget()
|
||||||
|
@ -49,28 +56,44 @@ SimulatedUIWidget::~SimulatedUIWidget()
|
||||||
if (act)
|
if (act)
|
||||||
delete act;
|
delete act;
|
||||||
}
|
}
|
||||||
|
foreach (RadioWidget * w, m_widgets) {
|
||||||
|
if (w)
|
||||||
|
delete w;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioUiAction * SimulatedUIWidget::addRadioUiAction(RadioUiAction * act)
|
RadioWidget * SimulatedUIWidget::addRadioWidget(RadioWidget * widget)
|
||||||
{
|
{
|
||||||
if (act) {
|
if (widget && !m_widgets.contains(widget)) {
|
||||||
|
m_widgets.append(widget);
|
||||||
|
// TODO : connect to actions instead
|
||||||
|
connect(widget, &RadioWidget::valueChange, this, &SimulatedUIWidget::controlValueChange);
|
||||||
|
if (widget->getAction())
|
||||||
|
addRadioAction(widget->getAction());
|
||||||
|
}
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioUiAction * SimulatedUIWidget::addRadioAction(RadioUiAction * act)
|
||||||
|
{
|
||||||
|
if (act && !m_actions.contains(act)) {
|
||||||
|
act->setParent(m_parent);
|
||||||
m_actions.append(act);
|
m_actions.append(act);
|
||||||
if (!act->getText().isEmpty() && !act->getDescription().isEmpty())
|
|
||||||
m_keymapHelp.append(keymapHelp_t(act->getText(), act->getDescription()));
|
|
||||||
}
|
}
|
||||||
return act;
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioUiAction * SimulatedUIWidget::addRadioUiAction(int index, int key, const QString & text, const QString & descript)
|
QVector<Simulator::keymapHelp_t> SimulatedUIWidget::getKeymapHelp() const
|
||||||
{
|
{
|
||||||
return addRadioUiAction(new RadioUiAction(index, key, m_parent, text, descript));
|
QVector<Simulator::keymapHelp_t> keymapHelp;
|
||||||
}
|
foreach (RadioUiAction * act, m_actions) {
|
||||||
|
if (act && !act->getText().isEmpty())
|
||||||
RadioUiAction * SimulatedUIWidget::addRadioUiAction(int index, QList<int> keys, const QString & text, const QString & descript)
|
keymapHelp.append(Simulator::keymapHelp_t(act->getText(), act->getDescription()));
|
||||||
{
|
}
|
||||||
return addRadioUiAction(new RadioUiAction(index, keys, m_parent, text, descript));
|
return keymapHelp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAngle, int endAngle, int step)
|
QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAngle, int endAngle, int step)
|
||||||
{
|
{
|
||||||
QPolygon polygon;
|
QPolygon polygon;
|
||||||
|
@ -83,20 +106,10 @@ QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAng
|
||||||
return polygon;
|
return polygon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO : beep indicator
|
||||||
void SimulatedUIWidget::updateUi()
|
void SimulatedUIWidget::updateUi()
|
||||||
{
|
{
|
||||||
//static quint32 loop = 0;
|
//static quint32 loop = 0;
|
||||||
if (m_lcd->isVisible()) {
|
|
||||||
bool lightEnable;
|
|
||||||
if (m_simulator->lcdChanged(lightEnable)) {
|
|
||||||
m_lcd->onLcdChanged(lightEnable);
|
|
||||||
if (m_lightOn != lightEnable) {
|
|
||||||
setLightOn(lightEnable);
|
|
||||||
m_lightOn = lightEnable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* TODO : beep indicator
|
|
||||||
if (!(loop % 5)) {
|
if (!(loop % 5)) {
|
||||||
TxOutputs outputs;
|
TxOutputs outputs;
|
||||||
simulator->getValues(outputs);
|
simulator->getValues(outputs);
|
||||||
|
@ -111,7 +124,16 @@ void SimulatedUIWidget::updateUi()
|
||||||
beepShow--;
|
beepShow--;
|
||||||
}
|
}
|
||||||
ui->label_beep->setStyleSheet(beepShow ? CBEEP_ON : CBEEP_OFF);
|
ui->label_beep->setStyleSheet(beepShow ? CBEEP_ON : CBEEP_OFF);
|
||||||
} */
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
void SimulatedUIWidget::onLcdChange(bool backlightEnable)
|
||||||
|
{
|
||||||
|
if (!m_lcd || !m_lcd->isVisible())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_lcd->onLcdChanged(backlightEnable);
|
||||||
|
setLightOn(backlightEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedUIWidget::captureScreenshot()
|
void SimulatedUIWidget::captureScreenshot()
|
||||||
|
@ -136,32 +158,27 @@ void SimulatedUIWidget::captureScreenshot()
|
||||||
m_lcd->makeScreenshot(fileName);
|
m_lcd->makeScreenshot(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// steps can be negative or positive to determine direction (negative is UP/RIGHT scroll)
|
|
||||||
void SimulatedUIWidget::simulatorWheelEvent(qint8 steps)
|
|
||||||
{
|
|
||||||
m_simulator->wheelEvent(steps);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedUIWidget::wheelEvent(QWheelEvent * event)
|
void SimulatedUIWidget::wheelEvent(QWheelEvent * event)
|
||||||
{
|
{
|
||||||
if (event->angleDelta().isNull())
|
if (event->angleDelta().isNull())
|
||||||
return;
|
return;
|
||||||
|
// steps can be negative or positive to determine direction (negative is UP/LEFT scroll)
|
||||||
QPoint numSteps = event->angleDelta() / 8 / 15 * -1; // one step per 15deg
|
QPoint numSteps = event->angleDelta() / 8 / 15 * -1; // one step per 15deg
|
||||||
simulatorWheelEvent(numSteps.y());
|
emit simulatorWheelEvent(numSteps.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedUIWidget::mousePressEvent(QMouseEvent * event)
|
void SimulatedUIWidget::mousePressEvent(QMouseEvent * event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::MidButton && m_rotEncClickAction)
|
if (event->button() == Qt::MidButton && m_mouseMidClickAction)
|
||||||
m_rotEncClickAction->trigger(true);
|
m_mouseMidClickAction->trigger(true);
|
||||||
else
|
else
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedUIWidget::mouseReleaseEvent(QMouseEvent * event)
|
void SimulatedUIWidget::mouseReleaseEvent(QMouseEvent * event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::MidButton && m_rotEncClickAction)
|
if (event->button() == Qt::MidButton && m_mouseMidClickAction)
|
||||||
m_rotEncClickAction->trigger(false);
|
m_mouseMidClickAction->trigger(false);
|
||||||
else
|
else
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
@ -184,13 +201,19 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
|
||||||
|
|
||||||
void SimulatedUIWidget::connectScrollActions()
|
void SimulatedUIWidget::connectScrollActions()
|
||||||
{
|
{
|
||||||
connect(m_scrollUpAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
if (m_scrollUpAction) {
|
||||||
this->simulatorWheelEvent(-1);
|
addRadioAction(m_scrollUpAction);
|
||||||
m_scrollUpAction->toggle(false);
|
connect(m_scrollUpAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||||
});
|
emit simulatorWheelEvent(-1);
|
||||||
|
m_scrollUpAction->toggle(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
connect(m_scrollDnAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
if (m_scrollDnAction) {
|
||||||
simulatorWheelEvent(1);
|
addRadioAction(m_scrollDnAction);
|
||||||
m_scrollDnAction->toggle(false);
|
connect(m_scrollDnAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||||
});
|
emit simulatorWheelEvent(1);
|
||||||
|
m_scrollDnAction->toggle(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,18 @@
|
||||||
|
|
||||||
#include "boards.h"
|
#include "boards.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "radiowidget.h"
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
|
#include "simulator_strings.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
|
||||||
class SimulatorInterface;
|
class SimulatorInterface;
|
||||||
class LcdWidget;
|
class LcdWidget;
|
||||||
|
class RadioKeyWidget;
|
||||||
class RadioUiAction;
|
class RadioUiAction;
|
||||||
|
|
||||||
using namespace Simulator;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a base class for the main hardware-specific radio user interface, including LCD screen and navigation buttons/widgets.
|
* This is a base class for the main hardware-specific radio user interface, including LCD screen and navigation buttons/widgets.
|
||||||
* It is responsible for hanlding all interactions with this part of the simulation (vs. common radio widgets like sticks/switches/knobs).
|
* It is responsible for hanlding all interactions with this part of the simulation (vs. common radio widgets like sticks/switches/knobs).
|
||||||
|
@ -52,51 +53,51 @@ class SimulatedUIWidget : public QWidget
|
||||||
|
|
||||||
~SimulatedUIWidget();
|
~SimulatedUIWidget();
|
||||||
|
|
||||||
RadioUiAction * addRadioUiAction(RadioUiAction * act);
|
RadioWidget * addRadioWidget(RadioWidget * keyWidget);
|
||||||
RadioUiAction * addRadioUiAction(int index = -1, int key = 0, const QString &text = "", const QString &descript = "");
|
RadioUiAction * addRadioAction(RadioUiAction * act);
|
||||||
RadioUiAction * addRadioUiAction(int index, QList<int> keys, const QString &text = "", const QString &descript = "");
|
|
||||||
|
|
||||||
QVector<keymapHelp_t> * getKeymapHelp() { return &m_keymapHelp; }
|
QVector<Simulator::keymapHelp_t> getKeymapHelp() const;
|
||||||
QList<RadioUiAction *> getActions() const { return m_actions; }
|
|
||||||
RadioUiAction * getRotEncAction() const { return m_rotEncClickAction; }
|
|
||||||
|
|
||||||
QPolygon polyArc(int ctrX, int ctrY, int radius, int startAngle = 0, int endAngle = 360, int step = 10);
|
static QPolygon polyArc(int ctrX, int ctrY, int radius, int startAngle = 0, int endAngle = 360, int step = 10);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void updateUi();
|
|
||||||
void captureScreenshot();
|
void captureScreenshot();
|
||||||
void simulatorWheelEvent(qint8 steps);
|
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent *event);
|
void wheelEvent(QWheelEvent *event);
|
||||||
void mousePressEvent(QMouseEvent *event);
|
void mousePressEvent(QMouseEvent *event);
|
||||||
void mouseReleaseEvent(QMouseEvent *event);
|
void mouseReleaseEvent(QMouseEvent *event);
|
||||||
|
|
||||||
protected:
|
signals:
|
||||||
|
|
||||||
|
void controlValueChange(RadioWidget::RadioWidgetType type, int index, int value);
|
||||||
|
void customStyleRequest(const QString & style);
|
||||||
|
void simulatorWheelEvent(qint8 steps);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
void setLcd(LcdWidget * lcd);
|
void setLcd(LcdWidget * lcd);
|
||||||
void connectScrollActions();
|
void connectScrollActions();
|
||||||
|
void onLcdChange(bool backlightEnable);
|
||||||
virtual void setLightOn(bool enable) { }
|
virtual void setLightOn(bool enable) { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
SimulatorInterface * m_simulator;
|
SimulatorInterface * m_simulator;
|
||||||
QWidget * m_parent;
|
QWidget * m_parent;
|
||||||
LcdWidget * m_lcd;
|
LcdWidget * m_lcd;
|
||||||
QVector<QColor> m_backlightColors;
|
QVector<QColor> m_backlightColors;
|
||||||
QVector<keymapHelp_t> m_keymapHelp;
|
|
||||||
QList<RadioUiAction *> m_actions;
|
QList<RadioUiAction *> m_actions;
|
||||||
|
QList<RadioWidget *> m_widgets;
|
||||||
RadioUiAction * m_scrollUpAction;
|
RadioUiAction * m_scrollUpAction;
|
||||||
RadioUiAction * m_scrollDnAction;
|
RadioUiAction * m_scrollDnAction;
|
||||||
RadioUiAction * m_rotEncClickAction;
|
RadioUiAction * m_mouseMidClickAction;
|
||||||
RadioUiAction * m_screenshotAction;
|
RadioUiAction * m_screenshotAction;
|
||||||
Board::Type m_board;
|
Board::Type m_board;
|
||||||
unsigned int m_backLight;
|
unsigned int m_backLight;
|
||||||
bool m_lightOn;
|
|
||||||
int m_beepShow;
|
int m_beepShow;
|
||||||
int m_beepVal;
|
int m_beepVal;
|
||||||
|
|
||||||
signals:
|
|
||||||
void customStyleRequest(const QString & style);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "simulateduiwidget.h"
|
#include "simulateduiwidget.h"
|
||||||
#include "ui_simulateduiwidget9X.h"
|
#include "ui_simulateduiwidget9X.h"
|
||||||
|
#include "eeprominterface.h"
|
||||||
|
|
||||||
SimulatedUIWidget9X::SimulatedUIWidget9X(SimulatorInterface * simulator, QWidget * parent):
|
SimulatedUIWidget9X::SimulatedUIWidget9X(SimulatorInterface * simulator, QWidget * parent):
|
||||||
SimulatedUIWidget(simulator, parent),
|
SimulatedUIWidget(simulator, parent),
|
||||||
|
@ -30,39 +31,49 @@ SimulatedUIWidget9X::SimulatedUIWidget9X(SimulatorInterface * simulator, QWidget
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
bool hasRotEnc = getCurrentFirmware()->getCapability(Capability::RotaryEncoders);
|
||||||
|
|
||||||
// add actions in order of appearance on the help menu
|
// add actions in order of appearance on the help menu
|
||||||
|
|
||||||
int x = 68, y = 91, oR = 63;
|
int x = 68, y = 91, oR = 63;
|
||||||
|
|
||||||
polygon << QPoint(x, y) << polyArc(x, y, oR, -45, 45);
|
polygon << QPoint(x, y) << polyArc(x, y, oR, -45, 45);
|
||||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_Up << Qt::Key_PageUp, tr("UP/PG-UP"), tr("[ UP ]"));
|
act = new RadioUiAction(3, QList<int>() << Qt::Key_Up << Qt::Key_PageUp, tr(SIMU_STR_HLP_KEYS_GO_UP) % (hasRotEnc ? "" : tr("|" SIMU_STR_HLP_MOUSE_UP)), tr(SIMU_STR_HLP_ACT_UP));
|
||||||
ui->leftbuttons->addArea(polygon, "9X/9xcursup.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursup.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << QPoint(x, y) << polyArc(x, y, oR, 135, 225);
|
polygon << QPoint(x, y) << polyArc(x, y, oR, 135, 225);
|
||||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Down << Qt::Key_PageDown, tr("DN/PG-DN"), tr("[ DN ]"));
|
act = new RadioUiAction(2, QList<int>() << Qt::Key_Down << Qt::Key_PageDown, tr(SIMU_STR_HLP_KEYS_GO_DN) % (hasRotEnc ? "" : tr("|" SIMU_STR_HLP_MOUSE_DN)), tr(SIMU_STR_HLP_ACT_DN));
|
||||||
ui->leftbuttons->addArea(polygon, "9X/9xcursdown.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursdown.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << QPoint(x, y) << polyArc(x, y, oR, 45, 135);
|
polygon << QPoint(x, y) << polyArc(x, y, oR, 45, 135);
|
||||||
act = addRadioUiAction(4, QList<int>() << Qt::Key_Right << Qt::Key_Plus << Qt::Key_Equal, tr("RIGHT/+"), tr("[ + ]"));
|
act = new RadioUiAction(4, QList<int>() << Qt::Key_Right << Qt::Key_Minus, tr(SIMU_STR_HLP_KEY_RGT "|" SIMU_STR_HLP_KEY_MIN), tr(SIMU_STR_HLP_ACT_MIN));
|
||||||
ui->leftbuttons->addArea(polygon, "9X/9xcursmin.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursmin.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << QPoint(x, y) << polyArc(x, y, oR, 225, 315);
|
polygon << QPoint(x, y) << polyArc(x, y, oR, 225, 315);
|
||||||
act = addRadioUiAction(5, QList<int>() << Qt::Key_Left << Qt::Key_Minus, tr("LEFT/-"), tr("[ - ]"));
|
act = new RadioUiAction(5, QList<int>() << Qt::Key_Left << Qt::Key_Plus << Qt::Key_Equal, tr(SIMU_STR_HLP_KEY_LFT "|" SIMU_STR_HLP_KEY_PLS), tr(SIMU_STR_HLP_ACT_PLS));
|
||||||
ui->leftbuttons->addArea(polygon, "9X/9xcursplus.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursplus.png", act));
|
||||||
|
|
||||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("[ MENU ]"));
|
act = new RadioUiAction(0, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEY_ENTER), tr(SIMU_STR_HLP_ACT_MENU));
|
||||||
m_rotEncClickAction = act;
|
addRadioWidget(ui->rightbuttons->addArea(QRect(16, 54, 60, 34), "9X/9xmenumenu.png", act));
|
||||||
ui->rightbuttons->addArea(25, 60, 71, 81, "9X/9xmenumenu.png", act);
|
|
||||||
|
|
||||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
if (!hasRotEnc) {
|
||||||
ui->rightbuttons->addArea(25, 117, 71, 139, "9X/9xmenuexit.png", act);
|
m_mouseMidClickAction = act;
|
||||||
|
m_mouseMidClickAction->setText(act->getText() % "|" SIMU_STR_HLP_MOUSE_MID);
|
||||||
|
}
|
||||||
|
|
||||||
ui->leftbuttons->addArea(-1, 148, 39, 182, "9X/9xcursphoto.png", m_screenshotAction);
|
act = new RadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr(SIMU_STR_HLP_KEYS_EXIT), tr(SIMU_STR_HLP_ACT_EXIT));
|
||||||
|
addRadioWidget(ui->rightbuttons->addArea(QRect(16, 114, 60, 34), "9X/9xmenuexit.png", act));
|
||||||
|
|
||||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("[ UP ]/[ DN ] or Rotary Sel.")));
|
addRadioWidget(ui->leftbuttons->addArea(QRect(6, 149, 30, 30), "9X/9xcursphoto.png", m_screenshotAction));
|
||||||
|
|
||||||
|
if (hasRotEnc) {
|
||||||
|
addRadioAction(new RadioUiAction(-1, 0, tr(SIMU_STR_HLP_MOUSE_SCRL), tr(SIMU_STR_HLP_ROTENC " " SIMU_STR_HLP_ROTENC_LR)));
|
||||||
|
m_mouseMidClickAction = new RadioUiAction(14, Qt::Key_Insert, tr(SIMU_STR_HLP_KEY_INS "|" SIMU_STR_HLP_MOUSE_MID), tr(SIMU_STR_HLP_ACT_ROT_DN));
|
||||||
|
addRadioWidget(ui->leftbuttons->addArea(QRect(0, 0, 0, 0), "9X/9xcurs.png", m_mouseMidClickAction));
|
||||||
|
}
|
||||||
|
|
||||||
m_backlightColors << QColor(159,165,247);
|
m_backlightColors << QColor(159,165,247);
|
||||||
m_backlightColors << QColor(166,247,159);
|
m_backlightColors << QColor(166,247,159);
|
||||||
|
|
|
@ -35,48 +35,47 @@ SimulatedUIWidgetX12::SimulatedUIWidgetX12(SimulatorInterface *simulator, QWidge
|
||||||
int x = 74, y = 190, oR = 63, iR = 40;
|
int x = 74, y = 190, oR = 63, iR = 40;
|
||||||
|
|
||||||
polygon << polyArc(x, y, oR, 225, 315) << polyArc(x, y, iR, 225, 315);
|
polygon << polyArc(x, y, oR, 225, 315) << polyArc(x, y, iR, 225, 315);
|
||||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ PgUp ]"));
|
act = new RadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr(SIMU_STR_HLP_KEY_PGUP), tr(SIMU_STR_HLP_ACT_PGUP));
|
||||||
ui->leftbuttons->addArea(polygon, "Horus/left_btn1.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "Horus/left_btn1.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(x, y, oR, 135, 225) << polyArc(x, y, iR, 135, 225);
|
polygon << polyArc(x, y, oR, 135, 225) << polyArc(x, y, iR, 135, 225);
|
||||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PgDn ]"));
|
act = new RadioUiAction(1, QList<int>() << Qt::Key_PageDown, tr(SIMU_STR_HLP_KEY_PGDN), tr(SIMU_STR_HLP_ACT_PGDN));
|
||||||
ui->leftbuttons->addArea(polygon, "Horus/left_btn2.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "Horus/left_btn2.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(x, y, oR, -45, 45) << polyArc(x, y, iR, -45, 45);
|
polygon << polyArc(x, y, oR, -45, 45) << polyArc(x, y, iR, -45, 45);
|
||||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_Up, tr("UP"), tr("[ MDL ]"));
|
act = new RadioUiAction(3, QList<int>() << Qt::Key_Up, tr(SIMU_STR_HLP_KEY_UP), tr(SIMU_STR_HLP_ACT_MDL));
|
||||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnU.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnU.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
|
||||||
polygon << polyArc(x, y, oR, 135, 225) << polyArc(x, y, iR, 135, 225);
|
|
||||||
act = addRadioUiAction(4, QList<int>() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DN/DEL/BKSP"), tr("[ RTN ]"));
|
|
||||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnD.png", act);
|
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(x, y, oR, 225, 315) << polyArc(x, y, iR, 225, 315);
|
polygon << polyArc(x, y, oR, 225, 315) << polyArc(x, y, iR, 225, 315);
|
||||||
act = addRadioUiAction(6, QList<int>() << Qt::Key_Left, tr("LEFT"), tr("[ SYS ]"));
|
act = new RadioUiAction(6, QList<int>() << Qt::Key_Left, tr(SIMU_STR_HLP_KEY_LFT), tr(SIMU_STR_HLP_ACT_SYS));
|
||||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnL.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnL.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(x, y, oR, 45, 135) << polyArc(x, y, iR, 45, 135);
|
polygon << polyArc(x, y, oR, 45, 135) << polyArc(x, y, iR, 45, 135);
|
||||||
act = addRadioUiAction(5, QList<int>() << Qt::Key_Right, tr("RIGHT"), tr("[ TELE ]"));
|
act = new RadioUiAction(5, QList<int>() << Qt::Key_Right, tr(SIMU_STR_HLP_KEY_RGT), tr(SIMU_STR_HLP_ACT_TELE));
|
||||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnR.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnR.png", act));
|
||||||
|
|
||||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("Rotary Selector")));
|
polygon.clear();
|
||||||
|
polygon << polyArc(x, y, oR, 135, 225) << polyArc(x, y, iR, 135, 225);
|
||||||
|
act = new RadioUiAction(4, QList<int>() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace,
|
||||||
|
tr(SIMU_STR_HLP_KEY_DN "<br>" SIMU_STR_HLP_KEYS_EXIT), tr(SIMU_STR_HLP_ACT_RTN));
|
||||||
|
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnD.png", act));
|
||||||
|
|
||||||
m_scrollUpAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_X, tr("-/X"), tr("Rotary UP"));
|
m_scrollUpAction = new RadioUiAction(-1, QList<int>() << Qt::Key_Minus, tr(SIMU_STR_HLP_KEY_MIN "|" SIMU_STR_HLP_MOUSE_UP), tr(SIMU_STR_HLP_ACT_ROT_LFT));
|
||||||
m_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_C, tr("+/C"), tr("Rotary DOWN"));
|
m_scrollDnAction = new RadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Equal, tr(SIMU_STR_HLP_KEY_PLS "|" SIMU_STR_HLP_MOUSE_DN), tr(SIMU_STR_HLP_ACT_ROT_RGT));
|
||||||
|
connectScrollActions();
|
||||||
|
|
||||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("Selector Press"));
|
m_mouseMidClickAction = new RadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEYS_ACTIVATE), tr(SIMU_STR_HLP_ACT_ROT_DN));
|
||||||
ui->rightbuttons->addArea(polyArc(x, y, iR), "Horus/right_ent.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polyArc(x, y, iR), "Horus/right_ent.png", m_mouseMidClickAction));
|
||||||
|
|
||||||
ui->leftbuttons->addArea(9, 259, 34, 282, "Horus/left_scrnsht.png", m_screenshotAction);
|
addRadioWidget(ui->leftbuttons->addArea(QRect(9, 259, 30, 30), "Horus/left_scrnsht.png", m_screenshotAction));
|
||||||
|
|
||||||
m_backlightColors << QColor(47, 123, 227);
|
m_backlightColors << QColor(47, 123, 227);
|
||||||
|
|
||||||
setLcd(ui->lcd);
|
setLcd(ui->lcd);
|
||||||
connectScrollActions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedUIWidgetX12::~SimulatedUIWidgetX12()
|
SimulatedUIWidgetX12::~SimulatedUIWidgetX12()
|
||||||
|
|
|
@ -14,26 +14,25 @@ SimulatedUIWidgetX7::SimulatedUIWidgetX7(SimulatorInterface *simulator, QWidget
|
||||||
|
|
||||||
QPoint ctr(70, 91);
|
QPoint ctr(70, 91);
|
||||||
polygon << polyArc(ctr.x(), ctr.y(), 50, -90, 90) << polyArc(ctr.x(), ctr.y(), 22, -90, 90);
|
polygon << polyArc(ctr.x(), ctr.y(), 50, -90, 90) << polyArc(ctr.x(), ctr.y(), 22, -90, 90);
|
||||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ PAGE ]"));
|
act = new RadioUiAction(3, QList<int>() << Qt::Key_PageUp << Qt::Key_Up, tr(SIMU_STR_HLP_KEYS_GO_UP), tr(SIMU_STR_HLP_ACT_PAGE));
|
||||||
ui->leftbuttons->addArea(polygon, "X7/left_page.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "X7/left_page.png", act));
|
||||||
|
|
||||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ MENU ]"));
|
act = new RadioUiAction(0, QList<int>() << Qt::Key_PageDown << Qt::Key_Down, tr(SIMU_STR_HLP_KEYS_GO_DN), tr(SIMU_STR_HLP_ACT_MENU_ICN));
|
||||||
ui->leftbuttons->addArea(polyArc(ctr.x(), ctr.y(), 20), "X7/left_menu.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polyArc(ctr.x(), ctr.y(), 20), "X7/left_menu.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(ctr.x(), ctr.y(), 50, 90, 270) << polyArc(ctr.x(), ctr.y(), 22, 90, 270);
|
polygon << polyArc(ctr.x(), ctr.y(), 50, 90, 270) << polyArc(ctr.x(), ctr.y(), 22, 90, 270);
|
||||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
act = new RadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr(SIMU_STR_HLP_KEYS_EXIT), tr(SIMU_STR_HLP_ACT_EXIT));
|
||||||
ui->leftbuttons->addArea(polygon, "X7/left_exit.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "X7/left_exit.png", act));
|
||||||
|
|
||||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("Rotary Selector")));
|
m_scrollUpAction = new RadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Left, tr(SIMU_STR_HLP_KEYS_GO_LFT), tr(SIMU_STR_HLP_ACT_ROT_LFT));
|
||||||
m_scrollUpAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
|
m_scrollDnAction = new RadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Right, tr(SIMU_STR_HLP_KEYS_GO_RGT), tr(SIMU_STR_HLP_ACT_ROT_RGT));
|
||||||
m_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
|
|
||||||
connectScrollActions();
|
connectScrollActions();
|
||||||
|
|
||||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("Selector Press"));
|
m_mouseMidClickAction = new RadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEYS_ACTIVATE), tr(SIMU_STR_HLP_ACT_ROT_DN));
|
||||||
ui->rightbuttons->addArea(polyArc(88, 92, 33), "X7/right_ent.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polyArc(88, 92, 33), "X7/right_ent.png", m_mouseMidClickAction));
|
||||||
|
|
||||||
ui->leftbuttons->addArea(9, 154, 34, 177, "X7/left_scrnshot.png", m_screenshotAction);
|
addRadioWidget(ui->leftbuttons->addArea(QRect(9, 154, 30, 30), "X7/left_scrnshot.png", m_screenshotAction));
|
||||||
|
|
||||||
m_backlightColors << QColor(215, 243, 255); // X7 Blue
|
m_backlightColors << QColor(215, 243, 255); // X7 Blue
|
||||||
m_backlightColors << QColor(166,247,159);
|
m_backlightColors << QColor(166,247,159);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Taranis X7 Simulator</string>
|
<string notr="true">Taranis X7 Simulator</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));</string>
|
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255));</string>
|
||||||
|
|
|
@ -26,40 +26,46 @@ SimulatedUIWidgetX9::SimulatedUIWidgetX9(SimulatorInterface *simulator, QWidget
|
||||||
ui(new Ui::SimulatedUIWidgetX9)
|
ui(new Ui::SimulatedUIWidgetX9)
|
||||||
{
|
{
|
||||||
RadioUiAction * act;
|
RadioUiAction * act;
|
||||||
QPolygon polygon;
|
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
// add actions in order of appearance on the help menu
|
// add actions in order of appearance on the help menu
|
||||||
|
|
||||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ MENU ]"));
|
// button placement, size, spacing
|
||||||
polygon.setPoints(6, 20, 59, 27, 50, 45, 52, 56, 59, 50, 71, 26, 72);
|
const int btop = 45, vsp = 17;
|
||||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l1.png", act);
|
QRect btn(16, btop, 46, 31);
|
||||||
|
|
||||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PAGE ]"));
|
// left side
|
||||||
polygon.setPoints(6, 23, 107, 30, 99, 46, 100, 55, 106, 47, 117, 28, 117);
|
|
||||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l2.png", act);
|
|
||||||
|
|
||||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
act = new RadioUiAction(0, QList<int>() << Qt::Key_Up << Qt::Key_PageUp, tr(SIMU_STR_HLP_KEYS_GO_UP), tr(SIMU_STR_HLP_ACT_MENU));
|
||||||
polygon.setPoints(6, 24, 154, 32, 144, 46, 146, 57, 156, 46, 167, 29, 166);
|
addRadioWidget(ui->leftbuttons->addArea(btn, "Taranis/x9l1.png", act));
|
||||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l3.png", act);
|
btn.moveTop(btn.top() + btn.height() + vsp);
|
||||||
|
|
||||||
m_scrollUpAction = addRadioUiAction(4, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_Up, tr("+/UP"), tr("[ + ]"));
|
act = new RadioUiAction(3, QList<int>() << Qt::Key_Down << Qt::Key_PageDown, tr(SIMU_STR_HLP_KEYS_GO_DN), tr(SIMU_STR_HLP_ACT_PAGE));
|
||||||
m_scrollDnAction = addRadioUiAction(5, QList<int>() << Qt::Key_Minus << Qt::Key_Down, tr("-/DN"), tr("[ - ]"));
|
addRadioWidget(ui->leftbuttons->addArea(btn, "Taranis/x9l2.png", act));
|
||||||
|
btn.moveTop(btn.top() + btn.height() + vsp);
|
||||||
|
|
||||||
polygon.setPoints(6, 64, 60, 71, 50, 90, 50, 100, 60, 90, 73, 72, 73);
|
act = new RadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr(SIMU_STR_HLP_KEYS_EXIT), tr(SIMU_STR_HLP_ACT_EXIT));
|
||||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r1.png", m_scrollUpAction);
|
addRadioWidget(ui->leftbuttons->addArea(btn, "Taranis/x9l3.png", act));
|
||||||
|
|
||||||
polygon.setPoints(6, 63, 109, 73, 100, 88, 100, 98, 109, 88, 119, 72, 119);
|
m_scrollUpAction = new RadioUiAction(4, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_Left,
|
||||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r2.png", m_scrollDnAction);
|
tr(SIMU_STR_HLP_KEY_LFT "|" SIMU_STR_HLP_KEY_PLS "|" SIMU_STR_HLP_MOUSE_UP), tr(SIMU_STR_HLP_ACT_PLS));
|
||||||
|
m_scrollDnAction = new RadioUiAction(5, QList<int>() << Qt::Key_Minus << Qt::Key_Right,
|
||||||
|
tr(SIMU_STR_HLP_KEY_RGT "|" SIMU_STR_HLP_KEY_MIN "|" SIMU_STR_HLP_MOUSE_DN), tr(SIMU_STR_HLP_ACT_MIN));
|
||||||
|
|
||||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("[ ENT ]"));
|
// right side
|
||||||
polygon.setPoints(6, 63, 155, 72, 146, 90, 146, 98, 155, 88, 166, 72, 166);
|
btn.moveTopLeft(QPoint(58, btop));
|
||||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r3.png", act);
|
|
||||||
|
|
||||||
ui->leftbuttons->addArea(90, 177, 118, 197, "Taranis/x9l4.png", m_screenshotAction);
|
addRadioWidget(ui->rightbuttons->addArea(btn, "Taranis/x9r1.png", m_scrollUpAction));
|
||||||
|
btn.moveTop(btn.top() + btn.height() + vsp);
|
||||||
|
|
||||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("[ + ]/[ - ]")));
|
addRadioWidget(ui->rightbuttons->addArea(btn, "Taranis/x9r2.png", m_scrollDnAction));
|
||||||
|
btn.moveTop(btn.top() + btn.height() + vsp);
|
||||||
|
|
||||||
|
m_mouseMidClickAction = new RadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEYS_ACTIVATE), tr(SIMU_STR_HLP_ACT_ENT));
|
||||||
|
addRadioWidget(ui->rightbuttons->addArea(btn, "Taranis/x9r3.png", m_mouseMidClickAction));
|
||||||
|
|
||||||
|
addRadioWidget(ui->leftbuttons->addArea(QRect(89, 177, 30, 20), "Taranis/x9l4.png", m_screenshotAction));
|
||||||
|
|
||||||
m_backlightColors << QColor(47, 123, 227); // Taranis Blue
|
m_backlightColors << QColor(47, 123, 227); // Taranis Blue
|
||||||
m_backlightColors << QColor(166,247,159);
|
m_backlightColors << QColor(166,247,159);
|
||||||
|
|
|
@ -35,28 +35,27 @@ SimulatedUIWidgetX9E::SimulatedUIWidgetX9E(SimulatorInterface *simulator, QWidge
|
||||||
QPoint ctr(70, 100);
|
QPoint ctr(70, 100);
|
||||||
|
|
||||||
polygon << polyArc(ctr.x(), ctr.y(), 60, -90, 0) << ctr;
|
polygon << polyArc(ctr.x(), ctr.y(), 60, -90, 0) << ctr;
|
||||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ MENU ]"));
|
act = new RadioUiAction(0, QList<int>() << Qt::Key_Up << Qt::Key_PageUp, tr(SIMU_STR_HLP_KEYS_GO_UP), tr(SIMU_STR_HLP_ACT_MENU));
|
||||||
ui->leftbuttons->addArea(polygon, "X9E/left_menu.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "X9E/left_menu.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(ctr.x(), ctr.y(), 45, 0, 180);
|
polygon << polyArc(ctr.x(), ctr.y(), 45, 0, 180);
|
||||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PAGE ]"));
|
act = new RadioUiAction(3, QList<int>() << Qt::Key_Down << Qt::Key_PageDown, tr(SIMU_STR_HLP_KEYS_GO_DN), tr(SIMU_STR_HLP_ACT_PAGE));
|
||||||
ui->leftbuttons->addArea(polygon, "X9E/left_page.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "X9E/left_page.png", act));
|
||||||
|
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
polygon << polyArc(ctr.x(), ctr.y(), 60, 180, 270) << ctr;
|
polygon << polyArc(ctr.x(), ctr.y(), 60, 180, 270) << ctr;
|
||||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
act = new RadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr(SIMU_STR_HLP_KEYS_EXIT), tr(SIMU_STR_HLP_ACT_EXIT));
|
||||||
ui->leftbuttons->addArea(polygon, "X9E/left_exit.png", act);
|
addRadioWidget(ui->leftbuttons->addArea(polygon, "X9E/left_exit.png", act));
|
||||||
|
|
||||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("Rotary Selector")));
|
m_scrollUpAction = addRadioAction(new RadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Left, tr(SIMU_STR_HLP_KEYS_GO_LFT), tr(SIMU_STR_HLP_ACT_ROT_LFT)));
|
||||||
m_scrollUpAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
|
m_scrollDnAction = addRadioAction(new RadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_Right, tr(SIMU_STR_HLP_KEYS_GO_RGT), tr(SIMU_STR_HLP_ACT_ROT_RGT)));
|
||||||
m_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
|
|
||||||
connectScrollActions();
|
connectScrollActions();
|
||||||
|
|
||||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("Selector Press"));
|
m_mouseMidClickAction = new RadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEYS_ACTIVATE), tr(SIMU_STR_HLP_ACT_ROT_DN));
|
||||||
ui->rightbuttons->addArea(polyArc(90, 100, 50), "X9E/right_enter.png", act);
|
addRadioWidget(ui->rightbuttons->addArea(polyArc(90, 100, 50), "X9E/right_enter.png", m_mouseMidClickAction));
|
||||||
|
|
||||||
ui->leftbuttons->addArea(10, 170, 40, 200, "X9E/left_scrnshot.png", m_screenshotAction);
|
addRadioWidget(ui->leftbuttons->addArea(QRect(10, 170, 30, 30), "X9E/left_scrnshot.png", m_screenshotAction));
|
||||||
|
|
||||||
m_backlightColors << QColor(47, 123, 227); // Taranis Blue
|
m_backlightColors << QColor(47, 123, 227); // Taranis Blue
|
||||||
m_backlightColors << QColor(166,247,159);
|
m_backlightColors << QColor(166,247,159);
|
||||||
|
|
66
companion/src/simulation/simulator_strings.h
Normal file
66
companion/src/simulation/simulator_strings.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef SIMULATOR_STRINGS_H
|
||||||
|
#define SIMULATOR_STRINGS_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_KEY_ENTER QT_TRANSLATE_NOOP("SimulatedUIWidget", "ENTER")
|
||||||
|
#define SIMU_STR_HLP_KEY_PGUP QT_TRANSLATE_NOOP("SimulatedUIWidget", "PG-UP")
|
||||||
|
#define SIMU_STR_HLP_KEY_PGDN QT_TRANSLATE_NOOP("SimulatedUIWidget", "PG-DN")
|
||||||
|
#define SIMU_STR_HLP_KEY_DEL QT_TRANSLATE_NOOP("SimulatedUIWidget", "DEL")
|
||||||
|
#define SIMU_STR_HLP_KEY_BKSP QT_TRANSLATE_NOOP("SimulatedUIWidget", "BKSP")
|
||||||
|
#define SIMU_STR_HLP_KEY_ESC QT_TRANSLATE_NOOP("SimulatedUIWidget", "ESC")
|
||||||
|
#define SIMU_STR_HLP_KEY_INS QT_TRANSLATE_NOOP("SimulatedUIWidget", "INS")
|
||||||
|
#define SIMU_STR_HLP_KEY_PLS QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>+</font>")
|
||||||
|
#define SIMU_STR_HLP_KEY_MIN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>-</font>")
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_KEY_LFT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>←</font>") // ←
|
||||||
|
#define SIMU_STR_HLP_KEY_RGT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>→</font>") // →
|
||||||
|
#define SIMU_STR_HLP_KEY_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>↑</font>") // ↑
|
||||||
|
#define SIMU_STR_HLP_KEY_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>↓</font>") // ↓
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_ROTENC QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⚆</font>") // ⚆
|
||||||
|
#define SIMU_STR_HLP_ROTENC_LFT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>↶</font>") // ↶
|
||||||
|
#define SIMU_STR_HLP_ROTENC_RGT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>↷</font>") // ↷
|
||||||
|
#define SIMU_STR_HLP_ROTENC_LR QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⇆</font>") // ⇆
|
||||||
|
#define SIMU_STR_HLP_ROTENC_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⇓</font>") // ⇓
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_SCRL_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⇑</font>") // ⇑
|
||||||
|
#define SIMU_STR_HLP_SCRL_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⇓</font>") // ⇓
|
||||||
|
#define SIMU_STR_HLP_SCRL_UD QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>⇕</font>") // ⇕
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_MOUSE QT_TRANSLATE_NOOP("SimulatedUIWidget", "<img src='qrc:/images/simulator/icons/svg/mouse.svg' width=20 height=18 />")
|
||||||
|
#define SIMU_STR_HLP_CLICK QT_TRANSLATE_NOOP("SimulatedUIWidget", "<img src='qrc:/images/simulator/icons/svg/arrow_click.svg' width=18 height=18 />")
|
||||||
|
#define SIMU_STR_HLP_MOUSE_MID SIMU_STR_HLP_MOUSE SIMU_STR_HLP_CLICK
|
||||||
|
#define SIMU_STR_HLP_MOUSE_UP SIMU_STR_HLP_MOUSE SIMU_STR_HLP_SCRL_UP
|
||||||
|
#define SIMU_STR_HLP_MOUSE_DN SIMU_STR_HLP_MOUSE SIMU_STR_HLP_SCRL_DN
|
||||||
|
#define SIMU_STR_HLP_MOUSE_SCRL SIMU_STR_HLP_MOUSE SIMU_STR_HLP_SCRL_UD
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_ACT_MENU QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ MENU ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_PAGE QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ PAGE ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_EXIT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ EXIT ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_ENT QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ ENT ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ UP ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ DN ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_PLS QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ <font size=+2>+</font> ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_MIN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ <font size=+2>-</font> ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_PGUP QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ PgUp ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_PGDN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ PgDn ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_MDL QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ MDL ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_RTN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ RTN ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_SYS QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ SYS ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_TELE QT_TRANSLATE_NOOP("SimulatedUIWidget", "<pre>[ TELE ]</pre>")
|
||||||
|
#define SIMU_STR_HLP_ACT_MENU_ICN QT_TRANSLATE_NOOP("SimulatedUIWidget", "<font size=+3>≡</font>") // ≡
|
||||||
|
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_KEYS_EXIT SIMU_STR_HLP_KEY_DEL "|" SIMU_STR_HLP_KEY_BKSP "|" SIMU_STR_HLP_KEY_ESC
|
||||||
|
#define SIMU_STR_HLP_KEYS_ACTIVATE SIMU_STR_HLP_KEY_ENTER "|" SIMU_STR_HLP_MOUSE_MID
|
||||||
|
#define SIMU_STR_HLP_KEYS_GO_UP SIMU_STR_HLP_KEY_UP "|" SIMU_STR_HLP_KEY_PGUP
|
||||||
|
#define SIMU_STR_HLP_KEYS_GO_DN SIMU_STR_HLP_KEY_DN "|" SIMU_STR_HLP_KEY_PGDN
|
||||||
|
#define SIMU_STR_HLP_KEYS_GO_LFT SIMU_STR_HLP_KEY_LFT "|" SIMU_STR_HLP_KEY_MIN "|" SIMU_STR_HLP_MOUSE_UP
|
||||||
|
#define SIMU_STR_HLP_KEYS_GO_RGT SIMU_STR_HLP_KEY_RGT "|" SIMU_STR_HLP_KEY_PLS "|" SIMU_STR_HLP_MOUSE_DN
|
||||||
|
|
||||||
|
#define SIMU_STR_HLP_ACT_ROT_LFT SIMU_STR_HLP_ROTENC " " SIMU_STR_HLP_ROTENC_LFT
|
||||||
|
#define SIMU_STR_HLP_ACT_ROT_RGT SIMU_STR_HLP_ROTENC " " SIMU_STR_HLP_ROTENC_RGT
|
||||||
|
#define SIMU_STR_HLP_ACT_ROT_DN SIMU_STR_HLP_ROTENC " " SIMU_STR_HLP_ROTENC_DN
|
||||||
|
|
||||||
|
#endif // SIMULATOR_STRINGS_H
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdint.h>
|
|
||||||
|
|
||||||
#if !defined(MAX_LOGICAL_SWITCHES) && defined(NUM_CSW)
|
|
||||||
#define MAX_LOGICAL_SWITCHES NUM_CSW
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef INIT_IMPORT
|
|
||||||
#undef INIT_IMPORT
|
|
||||||
#ifdef TELEMETRY_FRSKY
|
|
||||||
telemetryStreaming = 20;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SETVALUES_IMPORT
|
|
||||||
#undef SETVALUES_IMPORT
|
|
||||||
for (int i=0; i<NUM_STICKS; i++)
|
|
||||||
g_anas[i] = inputs.sticks[i];
|
|
||||||
for (int i=0; i<NUM_POTS+NUM_SLIDERS; i++)
|
|
||||||
g_anas[NUM_STICKS+i] = inputs.pots[i];
|
|
||||||
for (int i=0; i<CPN_MAX_SWITCHES; i++)
|
|
||||||
simuSetSwitch(i, inputs.switches[i]);
|
|
||||||
for (int i=0; i<CPN_MAX_KEYS; i++)
|
|
||||||
simuSetKey(i, inputs.keys[i]);
|
|
||||||
for (int i=0; i<(NUM_STICKS+NUM_AUX_TRIMS)*2; i++)
|
|
||||||
simuSetTrim(i, inputs.trims[i]);
|
|
||||||
|
|
||||||
// rotary encoders
|
|
||||||
#if defined(PCBGRUVIN9X)
|
|
||||||
pind = 0;
|
|
||||||
if (inputs.rotenc)
|
|
||||||
pind |= 0x20;
|
|
||||||
#elif defined(PCBSKY9X)
|
|
||||||
if (inputs.rotenc)
|
|
||||||
PIOB->PIO_PDSR &= ~0x40;
|
|
||||||
else
|
|
||||||
PIOB->PIO_PDSR |= 0x40;
|
|
||||||
#else
|
|
||||||
if (inputs.rotenc)
|
|
||||||
simuSetKey(KEY_ENTER, true);
|
|
||||||
#endif
|
|
||||||
#endif // SETVALUES_IMPORT
|
|
||||||
|
|
||||||
#ifdef GETVALUES_IMPORT
|
|
||||||
#undef GETVALUES_IMPORT
|
|
||||||
memset(outputs.chans, 0, sizeof(outputs.chans));
|
|
||||||
for (unsigned int i=0; i<DIM(g_chans512); i++)
|
|
||||||
outputs.chans[i] = g_chans512[i];
|
|
||||||
for (int i=0; i<MAX_LOGICAL_SWITCHES; i++)
|
|
||||||
#if defined(BOLD_FONT)
|
|
||||||
outputs.vsw[i] = getSwitch(SWSRC_SW1+i);
|
|
||||||
#else
|
|
||||||
outputs.vsw[i] = getSwitch(SWSRC_SW1+i, 0);
|
|
||||||
#endif
|
|
||||||
#ifdef GVAR_VALUE // defined(GVARS)
|
|
||||||
/* TODO it could be a good idea instead of getPhase() / getPhaseName() outputs.phase = getFlightMode(); */
|
|
||||||
#if defined(GVARS)
|
|
||||||
for (int fm=0; fm<MAX_FLIGHT_MODES; fm++) {
|
|
||||||
for (int gv=0; gv<MAX_GVARS; gv++) {
|
|
||||||
outputs.gvars[fm][gv] = GVAR_VALUE(gv, getGVarFlightMode(fm, gv));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LCDCHANGED_IMPORT
|
|
||||||
#undef LCDCHANGED_IMPORT
|
|
||||||
if (simuLcdRefresh) {
|
|
||||||
lightEnable = isBacklightEnabled();
|
|
||||||
simuLcdRefresh = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TIMER10MS_IMPORT
|
|
||||||
#undef TIMER10MS_IMPORT
|
|
||||||
if (!main_thread_running)
|
|
||||||
return false;
|
|
||||||
per10ms();
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GETERROR_IMPORT
|
|
||||||
#undef GETERROR_IMPORT
|
|
||||||
return main_thread_error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SETTRAINER_IMPORT
|
|
||||||
#undef SETTRAINER_IMPORT
|
|
||||||
ppmInputValidityTimer = 100;
|
|
||||||
ppmInput[inputNumber] = qMin(qMax((int16_t)-512, value), (int16_t)512);
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -34,96 +34,141 @@
|
||||||
#include <QLibrary>
|
#include <QLibrary>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
||||||
struct TxInputs
|
#define SIMULATOR_INTERFACE_HEARTBEAT_PERIOD 1000 // ms
|
||||||
{
|
|
||||||
int sticks[CPN_MAX_STICKS]; /* lh lv rv rh */
|
|
||||||
int pots[CPN_MAX_POTS];
|
|
||||||
int switches[CPN_MAX_SWITCHES];
|
|
||||||
bool keys[CPN_MAX_KEYS];
|
|
||||||
bool rotenc;
|
|
||||||
bool trims[CPN_MAX_TRIM_SW];
|
|
||||||
};
|
|
||||||
|
|
||||||
class TxOutputs
|
class SimulatorInterface : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TxOutputs() { memset(this, 0, sizeof(TxOutputs)); }
|
|
||||||
int chans[CPN_MAX_CHNOUT];
|
|
||||||
bool vsw[CPN_MAX_LOGICAL_SWITCHES];
|
|
||||||
int gvars[CPN_MAX_FLIGHT_MODES][CPN_MAX_GVARS];
|
|
||||||
unsigned int beep;
|
|
||||||
// uint8_t phase;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Trims
|
enum InputSourceType {
|
||||||
{
|
INPUT_SRC_NONE = 0,
|
||||||
int values[CPN_MAX_TRIMS]; /* lh lv rv rh t5 t6 */
|
INPUT_SRC_ANALOG, // any analog source, index into g_anas[]
|
||||||
bool extended;
|
INPUT_SRC_STICK, // Board::StickAxes, g_anas[index]
|
||||||
};
|
INPUT_SRC_KNOB, // g_anas[index + StickAxes]
|
||||||
|
INPUT_SRC_SLIDER, // g_anas[index + StickAxes + num_pots]
|
||||||
|
INPUT_SRC_TXVIN, // g_anas[Analogs::TX_VOLTAGE]
|
||||||
|
INPUT_SRC_SWITCH, // Named 2/3-pos switches
|
||||||
|
INPUT_SRC_TRIM_SW, // Board::TrimSwitches
|
||||||
|
INPUT_SRC_TRIM, // Board::TrimAxes
|
||||||
|
INPUT_SRC_KEY, // UI key/pushbutton
|
||||||
|
INPUT_SRC_ROTENC, // Rotary encoder (TODO)
|
||||||
|
INPUT_SRC_TRAINER, // Virtual trainer input
|
||||||
|
INPUT_SRC_ENUM_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
class SimulatorInterface
|
enum OutputSourceType {
|
||||||
{
|
OUTPUT_SRC_NONE = 0,
|
||||||
public:
|
OUTPUT_SRC_CHAN_OUT,
|
||||||
|
OUTPUT_SRC_CHAN_MIX,
|
||||||
|
OUTPUT_SRC_TRIM_VALUE,
|
||||||
|
OUTPUT_SRC_TRIM_RANGE,
|
||||||
|
OUTPUT_SRC_VIRTUAL_SW,
|
||||||
|
OUTPUT_SRC_PHASE,
|
||||||
|
OUTPUT_SRC_GVAR,
|
||||||
|
OUTPUT_SRC_ENUM_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
// only for data not available from Boards or Firmware, eg. compile-time options
|
||||||
|
enum Capability {
|
||||||
|
CAP_LUA, // LUA
|
||||||
|
CAP_ROTARY_ENC, // ROTARY_ENCODERS
|
||||||
|
CAP_ROTARY_ENC_NAV, // ROTARY_ENCODER_NAVIGATION
|
||||||
|
CAP_TELEM_FRSKY_SPORT, // TELEMETRY_FRSKY_SPORT
|
||||||
|
CAP_ENUM_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
// This allows automatic en/decoding of flight mode + gvar value to/from any int32
|
||||||
|
struct gVarMode_t {
|
||||||
|
int16_t value;
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
gVarMode_t(int i = 0) {
|
||||||
|
set(i);
|
||||||
|
}
|
||||||
|
void set(int i) {
|
||||||
|
mode = (i >> 16) & 0xFF;
|
||||||
|
value = (i & 0xFFFF);
|
||||||
|
}
|
||||||
|
operator int() {
|
||||||
|
return ((mode << 16) | (value & 0xFFFF));
|
||||||
|
}
|
||||||
|
gVarMode_t & operator =(const int i) {
|
||||||
|
set(i);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxOutputs {
|
||||||
|
TxOutputs() { clear(); }
|
||||||
|
void clear() { memset(this, 0, sizeof(TxOutputs)); }
|
||||||
|
|
||||||
|
int16_t chans[CPN_MAX_CHNOUT]; // final channel outputs
|
||||||
|
int16_t ex_chans[CPN_MAX_CHNOUT]; // raw mix outputs
|
||||||
|
int16_t gvars[CPN_MAX_FLIGHT_MODES][CPN_MAX_GVARS];
|
||||||
|
int trims[CPN_MAX_TRIMS]; // Board::TrimAxes enum
|
||||||
|
bool vsw[CPN_MAX_LOGICAL_SWITCHES]; // virtual/logic switches
|
||||||
|
int8_t phase;
|
||||||
|
qint16 trimRange; // TRIM_MAX or TRIM_EXTENDED_MAX
|
||||||
|
// bool beep;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~SimulatorInterface() {}
|
virtual ~SimulatorInterface() {}
|
||||||
|
|
||||||
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "") { }
|
virtual QString name() = 0;
|
||||||
|
virtual bool isRunning() = 0;
|
||||||
virtual void setVolumeGain(int value) { }
|
virtual void readRadioData(QByteArray & dest) = 0;
|
||||||
|
|
||||||
virtual void start(QByteArray & eeprom, bool tests=true) = 0;
|
|
||||||
|
|
||||||
virtual void start(const char * filename, bool tests=true) = 0;
|
|
||||||
|
|
||||||
virtual void stop() = 0;
|
|
||||||
|
|
||||||
virtual void readEepromData(QByteArray & dest) = 0;
|
|
||||||
|
|
||||||
virtual bool timer10ms() = 0;
|
|
||||||
|
|
||||||
virtual uint8_t * getLcd() = 0;
|
virtual uint8_t * getLcd() = 0;
|
||||||
|
|
||||||
virtual bool lcdChanged(bool &lightEnable) = 0;
|
|
||||||
|
|
||||||
virtual void setValues(TxInputs &inputs) = 0;
|
|
||||||
|
|
||||||
virtual void getValues(TxOutputs &outputs) = 0;
|
|
||||||
|
|
||||||
virtual void setTrim(unsigned int idx, int value) = 0;
|
|
||||||
|
|
||||||
virtual void getTrims(Trims &trims) = 0;
|
|
||||||
|
|
||||||
virtual unsigned int getPhase() = 0;
|
|
||||||
|
|
||||||
virtual const char * getPhaseName(unsigned int phase) = 0;
|
|
||||||
|
|
||||||
virtual void wheelEvent(int steps) { }
|
|
||||||
|
|
||||||
virtual const char * getError() = 0;
|
|
||||||
|
|
||||||
virtual void sendTelemetry(uint8_t * data, unsigned int len) = 0;
|
|
||||||
|
|
||||||
virtual uint8_t getSensorInstance(uint16_t id, uint8_t defaultValue = 0) = 0;
|
virtual uint8_t getSensorInstance(uint16_t id, uint8_t defaultValue = 0) = 0;
|
||||||
|
|
||||||
virtual uint16_t getSensorRatio(uint16_t id) = 0;
|
virtual uint16_t getSensorRatio(uint16_t id) = 0;
|
||||||
|
virtual const int getCapability(Capability cap) = 0;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void start(const char * filename = NULL, bool tests = true) = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "") = 0;
|
||||||
|
virtual void setVolumeGain(const int value) = 0;
|
||||||
|
virtual void setRadioData(const QByteArray & data) = 0;
|
||||||
|
virtual void setAnalogValue(uint8_t index, int16_t value) = 0;
|
||||||
|
virtual void setKey(uint8_t key, bool state) = 0;
|
||||||
|
virtual void setSwitch(uint8_t swtch, int8_t state) = 0;
|
||||||
|
virtual void setTrim(unsigned int idx, int value) = 0;
|
||||||
|
virtual void setTrimSwitch(uint8_t trim, bool state) = 0;
|
||||||
virtual void setTrainerInput(unsigned int inputNumber, int16_t value) = 0;
|
virtual void setTrainerInput(unsigned int inputNumber, int16_t value) = 0;
|
||||||
|
virtual void setInputValue(int type, uint8_t index, int16_t value) = 0;
|
||||||
virtual void installTraceHook(void (*callback)(const char *)) = 0;
|
virtual void rotaryEncoderEvent(int steps) = 0;
|
||||||
|
virtual void setTrainerTimeout(uint16_t ms) = 0;
|
||||||
|
virtual void sendTelemetry(uint8_t * data, unsigned int len) = 0;
|
||||||
virtual void setLuaStateReloadPermanentScripts() = 0;
|
virtual void setLuaStateReloadPermanentScripts() = 0;
|
||||||
|
virtual void addTracebackDevice(QIODevice * device) = 0;
|
||||||
|
virtual void removeTracebackDevice(QIODevice * device) = 0;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void started();
|
||||||
|
void stopped();
|
||||||
|
void heartbeat(qint32 loops, qint64 timestamp);
|
||||||
|
void runtimeError(const QString & error);
|
||||||
|
void lcdChange(bool backlightEnable);
|
||||||
|
void phaseChanged(qint8 phase, const QString & name);
|
||||||
|
void channelOutValueChange(quint8 index, qint32 value);
|
||||||
|
void channelMixValueChange(quint8 index, qint32 value);
|
||||||
|
void virtualSwValueChange(quint8 index, qint32 value);
|
||||||
|
void trimValueChange(quint8 index, qint32 value);
|
||||||
|
void trimRangeChange(quint8 index, qint32 min, qint16 max);
|
||||||
|
void gVarValueChange(quint8 index, qint32 value);
|
||||||
|
void outputValueChange(int type, quint8 index, qint32 value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimulatorFactory {
|
class SimulatorFactory {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~SimulatorFactory() { }
|
virtual ~SimulatorFactory() { }
|
||||||
|
|
||||||
virtual QString name() = 0;
|
virtual QString name() = 0;
|
||||||
|
|
||||||
virtual Board::Type type() = 0;
|
virtual Board::Type type() = 0;
|
||||||
|
|
||||||
virtual SimulatorInterface *create() = 0;
|
virtual SimulatorInterface *create() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,9 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_simulator->moveToThread(&simuThread);
|
||||||
|
simuThread.start();
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
||||||
|
@ -103,38 +106,42 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa
|
||||||
ui->menuView->insertSeparator(ui->actionToggleMenuBar);
|
ui->menuView->insertSeparator(ui->actionToggleMenuBar);
|
||||||
ui->menuView->insertAction(ui->actionToggleMenuBar, ui->toolBar->toggleViewAction());
|
ui->menuView->insertAction(ui->actionToggleMenuBar, ui->toolBar->toggleViewAction());
|
||||||
|
|
||||||
// Hide some actions based on board capabilities.
|
// Hide some actions based on simulator capabilities.
|
||||||
Firmware * firmware = getCurrentFirmware();
|
if(!m_simulator->getCapability(SimulatorInterface::CAP_LUA))
|
||||||
if(!firmware->getCapability(Capability(LuaInputsPerScript)))
|
|
||||||
ui->actionReloadLua->setDisabled(true);
|
ui->actionReloadLua->setDisabled(true);
|
||||||
if (!firmware->getCapability(Capability(SportTelemetry)))
|
if(!m_simulator->getCapability(SimulatorInterface::CAP_TELEM_FRSKY_SPORT))
|
||||||
m_telemetryDockWidget->toggleViewAction()->setDisabled(true);
|
m_telemetryDockWidget->toggleViewAction()->setDisabled(true);
|
||||||
#ifndef JOYSTICKS
|
#ifndef JOYSTICKS
|
||||||
ui->actionJoystickSettings->setDisabled(true);
|
ui->actionJoystickSettings->setDisabled(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Add radio-specific help text from simulator widget
|
|
||||||
foreach (keymapHelp_t item, *m_simulatorWidget->getKeymapHelp())
|
|
||||||
m_keymapHelp.append(item);
|
|
||||||
|
|
||||||
restoreUiState();
|
restoreUiState();
|
||||||
|
|
||||||
setStyleSheet(SimulatorStyle::styleSheet());
|
setStyleSheet(SimulatorStyle::styleSheet());
|
||||||
|
|
||||||
connect(ui->actionShowKeymap, &QAction::triggered, this, &SimulatorMainWindow::showHelp);
|
connect(ui->actionShowKeymap, &QAction::triggered, this, &SimulatorMainWindow::showHelp);
|
||||||
connect(ui->actionJoystickSettings, &QAction::triggered, this, &SimulatorMainWindow::openJoystickDialog);
|
connect(ui->actionJoystickSettings, &QAction::triggered, this, &SimulatorMainWindow::openJoystickDialog);
|
||||||
connect(ui->actionReloadLua, &QAction::triggered, this, &SimulatorMainWindow::luaReload);
|
|
||||||
connect(ui->actionToggleMenuBar, &QAction::toggled, this, &SimulatorMainWindow::showMenuBar);
|
connect(ui->actionToggleMenuBar, &QAction::toggled, this, &SimulatorMainWindow::showMenuBar);
|
||||||
connect(ui->actionFixedRadioWidth, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedWidth);
|
connect(ui->actionFixedRadioWidth, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedWidth);
|
||||||
connect(ui->actionFixedRadioHeight, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedHeight);
|
connect(ui->actionFixedRadioHeight, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedHeight);
|
||||||
connect(ui->actionDockRadio, &QAction::toggled, this, &SimulatorMainWindow::showRadioDocked);
|
connect(ui->actionDockRadio, &QAction::toggled, this, &SimulatorMainWindow::showRadioDocked);
|
||||||
|
connect(ui->actionReloadRadioData, &QAction::triggered, this, &SimulatorMainWindow::simulatorRestart);
|
||||||
|
|
||||||
|
connect(ui->actionReloadLua, &QAction::triggered, m_simulator, &SimulatorInterface::setLuaStateReloadPermanentScripts);
|
||||||
|
|
||||||
|
if (m_outputsWidget) {
|
||||||
|
connect(this, &SimulatorMainWindow::simulatorStart, m_outputsWidget, &RadioOutputsWidget::start);
|
||||||
|
connect(this, &SimulatorMainWindow::simulatorRestart, m_outputsWidget, &RadioOutputsWidget::restart);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_simulatorWidget) {
|
if (m_simulatorWidget) {
|
||||||
|
connect(this, &SimulatorMainWindow::simulatorStart, m_simulatorWidget, &SimulatorWidget::start);
|
||||||
|
connect(this, &SimulatorMainWindow::simulatorRestart, m_simulatorWidget, &SimulatorWidget::restart);
|
||||||
connect(ui->actionScreenshot, &QAction::triggered, m_simulatorWidget, &SimulatorWidget::captureScreenshot);
|
connect(ui->actionScreenshot, &QAction::triggered, m_simulatorWidget, &SimulatorWidget::captureScreenshot);
|
||||||
connect(ui->actionReloadRadioData, &QAction::triggered, m_simulatorWidget, &SimulatorWidget::restart);
|
|
||||||
connect(m_simulatorWidget, &SimulatorWidget::windowTitleChanged, this, &SimulatorMainWindow::setWindowTitle);
|
connect(m_simulatorWidget, &SimulatorWidget::windowTitleChanged, this, &SimulatorMainWindow::setWindowTitle);
|
||||||
}
|
}
|
||||||
if (m_outputsWidget)
|
|
||||||
connect(ui->actionReloadRadioData, &QAction::triggered, m_outputsWidget, &RadioOutputsWidget::restart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorMainWindow::~SimulatorMainWindow()
|
SimulatorMainWindow::~SimulatorMainWindow()
|
||||||
|
@ -154,9 +161,11 @@ SimulatorMainWindow::~SimulatorMainWindow()
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
|
|
||||||
if (m_simulator)
|
if (m_simulator) {
|
||||||
|
simuThread.quit();
|
||||||
|
simuThread.wait();
|
||||||
delete m_simulator;
|
delete m_simulator;
|
||||||
|
}
|
||||||
SimulatorLoader::unloadSimulator(m_simulatorId);
|
SimulatorLoader::unloadSimulator(m_simulatorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,11 +265,6 @@ bool SimulatorMainWindow::setOptions(SimulatorOptions & options, bool withSave)
|
||||||
|
|
||||||
void SimulatorMainWindow::start()
|
void SimulatorMainWindow::start()
|
||||||
{
|
{
|
||||||
if (m_simulatorWidget)
|
|
||||||
m_simulatorWidget->start();
|
|
||||||
if (m_outputsWidget)
|
|
||||||
m_outputsWidget->start();
|
|
||||||
|
|
||||||
emit simulatorStart();
|
emit simulatorStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,8 +286,6 @@ void SimulatorMainWindow::createDockWidgets()
|
||||||
m_telemetryDockWidget->setWidget(telem);
|
m_telemetryDockWidget->setWidget(telem);
|
||||||
m_telemetryDockWidget->setObjectName("TELEMETRY_SIMULATOR");
|
m_telemetryDockWidget->setObjectName("TELEMETRY_SIMULATOR");
|
||||||
addTool(m_telemetryDockWidget, Qt::LeftDockWidgetArea, icon, QKeySequence(tr("F4")));
|
addTool(m_telemetryDockWidget, Qt::LeftDockWidgetArea, icon, QKeySequence(tr("F4")));
|
||||||
connect(this, &SimulatorMainWindow::simulatorStart, telem, &TelemetrySimulator::onSimulatorStarted);
|
|
||||||
connect(ui->actionReloadRadioData, &QAction::triggered, telem, &TelemetrySimulator::onSimulatorStarted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_trainerDockWidget) {
|
if (!m_trainerDockWidget) {
|
||||||
|
@ -453,13 +455,6 @@ void SimulatorMainWindow::toggleRadioDocked(bool dock)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorMainWindow::luaReload(bool)
|
|
||||||
{
|
|
||||||
// force a reload of the lua environment
|
|
||||||
if (m_simulator)
|
|
||||||
m_simulator->setLuaStateReloadPermanentScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorMainWindow::openJoystickDialog(bool)
|
void SimulatorMainWindow::openJoystickDialog(bool)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
|
@ -472,19 +467,34 @@ void SimulatorMainWindow::openJoystickDialog(bool)
|
||||||
|
|
||||||
void SimulatorMainWindow::showHelp(bool show)
|
void SimulatorMainWindow::showHelp(bool show)
|
||||||
{
|
{
|
||||||
QString helpText = tr("Simulator Controls:");
|
QString helpText = ""
|
||||||
|
"<style>"
|
||||||
|
" td { text-align: center; vertical-align: middle; font-size: large; padding: 0 1em; white-space: nowrap; }"
|
||||||
|
" th { background-color: palette(alternate-base); }"
|
||||||
|
" img { vertical-align: text-top; }"
|
||||||
|
"</style>";
|
||||||
|
helpText += tr("<b>Simulator Controls:</b>");
|
||||||
helpText += "<table cellspacing=4 cellpadding=0>";
|
helpText += "<table cellspacing=4 cellpadding=0>";
|
||||||
helpText += tr("<tr><th>Key/Mouse</td><th>Action</td></tr>");
|
helpText += tr("<tr><th>Key/Mouse</th><th>Action</th></tr>", "note: must match html layout of each table row (keyTemplate).");
|
||||||
QString keyTemplate = "<tr><td align='center'><pre>%1</pre></td><td align='center'>%2</td></tr>";
|
|
||||||
foreach (keymapHelp_t pair, m_keymapHelp)
|
QString keyTemplate = tr("<tr><td><kbd>%1</kbd></td><td>%2</td></tr>", "note: must match html layout of help text table header.");
|
||||||
|
keymapHelp_t pair;
|
||||||
|
// Add our own help text (if any)
|
||||||
|
foreach (pair, m_keymapHelp)
|
||||||
helpText += keyTemplate.arg(pair.first, pair.second);
|
helpText += keyTemplate.arg(pair.first, pair.second);
|
||||||
|
// Add any radio-specific help text from simulator widget
|
||||||
|
foreach (pair, m_simulatorWidget->getKeymapHelp())
|
||||||
|
helpText += keyTemplate.arg(pair.first, pair.second);
|
||||||
|
|
||||||
helpText += "</table>";
|
helpText += "</table>";
|
||||||
|
|
||||||
QMessageBox * msgBox = new QMessageBox(this);
|
QMessageBox * msgBox = new QMessageBox(this);
|
||||||
|
msgBox->setObjectName("SimulatorHelpText");
|
||||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
msgBox->setStandardButtons( QMessageBox::Ok );
|
msgBox->setStandardButtons( QMessageBox::Ok );
|
||||||
msgBox->setWindowTitle(tr("Simulator Help"));
|
msgBox->setWindowTitle(tr("Simulator Help"));
|
||||||
|
msgBox->setTextFormat(Qt::RichText);
|
||||||
msgBox->setText(helpText);
|
msgBox->setText(helpText);
|
||||||
msgBox->setModal(false);
|
msgBox->setModal(false);
|
||||||
msgBox->show();
|
msgBox->show();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
class DebugOutput;
|
class DebugOutput;
|
||||||
class RadioData;
|
class RadioData;
|
||||||
|
@ -67,6 +68,7 @@ class SimulatorMainWindow : public QMainWindow
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void simulatorStart();
|
void simulatorStart();
|
||||||
|
void simulatorRestart();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
virtual void closeEvent(QCloseEvent *);
|
virtual void closeEvent(QCloseEvent *);
|
||||||
|
@ -76,7 +78,6 @@ class SimulatorMainWindow : public QMainWindow
|
||||||
void toggleMenuBar(bool show);
|
void toggleMenuBar(bool show);
|
||||||
void setRadioSizePolicy(int fixType);
|
void setRadioSizePolicy(int fixType);
|
||||||
void toggleRadioDocked(bool dock);
|
void toggleRadioDocked(bool dock);
|
||||||
void luaReload(bool);
|
|
||||||
void openJoystickDialog(bool);
|
void openJoystickDialog(bool);
|
||||||
void showHelp(bool show);
|
void showHelp(bool show);
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ class SimulatorMainWindow : public QMainWindow
|
||||||
QDockWidget * m_trainerDockWidget;
|
QDockWidget * m_trainerDockWidget;
|
||||||
QDockWidget * m_outputsDockWidget;
|
QDockWidget * m_outputsDockWidget;
|
||||||
|
|
||||||
|
QThread simuThread;
|
||||||
QVector<keymapHelp_t> m_keymapHelp;
|
QVector<keymapHelp_t> m_keymapHelp;
|
||||||
QString m_simulatorId;
|
QString m_simulatorId;
|
||||||
QString m_exitStatusMsg;
|
QString m_exitStatusMsg;
|
||||||
|
|
|
@ -24,12 +24,13 @@
|
||||||
#include "appdata.h"
|
#include "appdata.h"
|
||||||
#include "appdebugmessagehandler.h"
|
#include "appdebugmessagehandler.h"
|
||||||
#include "radiofaderwidget.h"
|
#include "radiofaderwidget.h"
|
||||||
|
#include "radiokeywidget.h"
|
||||||
#include "radioknobwidget.h"
|
#include "radioknobwidget.h"
|
||||||
#include "radioswitchwidget.h"
|
#include "radioswitchwidget.h"
|
||||||
|
#include "radiotrimwidget.h"
|
||||||
#include "radiouiaction.h"
|
#include "radiouiaction.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "simulateduiwidget.h"
|
#include "simulateduiwidget.h"
|
||||||
#include "simulatorinterface.h"
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "virtualjoystickwidget.h"
|
#include "virtualjoystickwidget.h"
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
|
@ -41,36 +42,27 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator, quint8 flags):
|
using namespace Simulator;
|
||||||
|
|
||||||
|
SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulator, quint8 flags):
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::SimulatorWidget),
|
ui(new Ui::SimulatorWidget),
|
||||||
simulator(simulator),
|
simulator(simulator),
|
||||||
firmware(getCurrentFirmware()),
|
firmware(getCurrentFirmware()),
|
||||||
radioSettings(GeneralSettings()),
|
radioSettings(GeneralSettings()),
|
||||||
timer(new QTimer(this)),
|
|
||||||
radioUiWidget(NULL),
|
radioUiWidget(NULL),
|
||||||
vJoyLeft(NULL),
|
vJoyLeft(NULL),
|
||||||
vJoyRight(NULL),
|
vJoyRight(NULL),
|
||||||
m_board(getCurrentBoard()),
|
m_board(getCurrentBoard()),
|
||||||
flags(flags),
|
flags(flags),
|
||||||
lastPhase(-1),
|
|
||||||
buttonPressed(0),
|
|
||||||
trimPressed(255),
|
|
||||||
startupFromFile(false),
|
startupFromFile(false),
|
||||||
deleteTempRadioData(false),
|
deleteTempRadioData(false),
|
||||||
saveTempRadioData(false),
|
saveTempRadioData(false)
|
||||||
middleButtonPressed(false),
|
|
||||||
firstShow(true)
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
joystick = NULL;
|
, joystick(NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// defaults
|
{
|
||||||
setRadioProfileId(g.sessionId());
|
|
||||||
setSdPath(g.profile[radioProfileId].sdPath());
|
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
windowName = tr("Radio Simulator (%1)").arg(firmware->getName());
|
windowName = tr("Radio Simulator (%1)").arg(firmware->getName());
|
||||||
|
@ -96,7 +88,7 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp())
|
foreach (keymapHelp_t item, radioUiWidget->getKeymapHelp())
|
||||||
keymapHelp.append(item);
|
keymapHelp.append(item);
|
||||||
|
|
||||||
ui->radioUiWidget->layout()->removeItem(ui->radioUiTempSpacer);
|
ui->radioUiWidget->layout()->removeItem(ui->radioUiTempSpacer);
|
||||||
|
@ -105,6 +97,7 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
||||||
radioUiWidget->setFocusPolicy(Qt::WheelFocus);
|
radioUiWidget->setFocusPolicy(Qt::WheelFocus);
|
||||||
radioUiWidget->setFocus();
|
radioUiWidget->setFocus();
|
||||||
|
|
||||||
|
connect(radioUiWidget, &SimulatedUIWidget::controlValueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||||
connect(radioUiWidget, &SimulatedUIWidget::customStyleRequest, this, &SimulatorWidget::setUiAreaStyle);
|
connect(radioUiWidget, &SimulatedUIWidget::customStyleRequest, this, &SimulatorWidget::setUiAreaStyle);
|
||||||
|
|
||||||
vJoyLeft = new VirtualJoystickWidget(this, 'L');
|
vJoyLeft = new VirtualJoystickWidget(this, 'L');
|
||||||
|
@ -113,25 +106,43 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
||||||
vJoyRight = new VirtualJoystickWidget(this, 'R');
|
vJoyRight = new VirtualJoystickWidget(this, 'R');
|
||||||
ui->rightStickLayout->addWidget(vJoyRight);
|
ui->rightStickLayout->addWidget(vJoyRight);
|
||||||
|
|
||||||
connect(vJoyLeft, &VirtualJoystickWidget::trimButtonPressed, this, &SimulatorWidget::onTrimPressed);
|
connect(vJoyLeft, &VirtualJoystickWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||||
connect(vJoyLeft, &VirtualJoystickWidget::trimButtonReleased, this, &SimulatorWidget::onTrimReleased);
|
connect(vJoyRight, &VirtualJoystickWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||||
connect(vJoyLeft, &VirtualJoystickWidget::trimSliderMoved, this, &SimulatorWidget::onTrimSliderMoved);
|
connect(this, &SimulatorWidget::stickModeChange, vJoyLeft, &VirtualJoystickWidget::loadDefaultsForMode);
|
||||||
|
connect(this, &SimulatorWidget::stickModeChange, vJoyRight, &VirtualJoystickWidget::loadDefaultsForMode);
|
||||||
|
connect(simulator, &SimulatorInterface::trimValueChange, vJoyLeft, &VirtualJoystickWidget::setTrimValue);
|
||||||
|
connect(simulator, &SimulatorInterface::trimValueChange, vJoyRight, &VirtualJoystickWidget::setTrimValue);
|
||||||
|
connect(simulator, &SimulatorInterface::trimRangeChange, vJoyLeft, &VirtualJoystickWidget::setTrimRange);
|
||||||
|
connect(simulator, &SimulatorInterface::trimRangeChange, vJoyRight, &VirtualJoystickWidget::setTrimRange);
|
||||||
|
|
||||||
connect(vJoyRight, &VirtualJoystickWidget::trimButtonPressed, this, &SimulatorWidget::onTrimPressed);
|
connect(this, &SimulatorWidget::simulatorInit, simulator, &SimulatorInterface::init);
|
||||||
connect(vJoyRight, &VirtualJoystickWidget::trimButtonReleased, this, &SimulatorWidget::onTrimReleased);
|
connect(this, &SimulatorWidget::simulatorStart, simulator, &SimulatorInterface::start);
|
||||||
connect(vJoyRight, &VirtualJoystickWidget::trimSliderMoved, this, &SimulatorWidget::onTrimSliderMoved);
|
connect(this, &SimulatorWidget::simulatorStop, simulator, &SimulatorInterface::stop);
|
||||||
|
//connect(this, &SimulatorWidget::simulatorSetData, simulator, &SimulatorInterface::setRadioData);
|
||||||
|
connect(this, &SimulatorWidget::inputValueChange, simulator, &SimulatorInterface::setInputValue);
|
||||||
|
connect(this, &SimulatorWidget::simulatorSdPathChange, simulator, &SimulatorInterface::setSdPath);
|
||||||
|
connect(this, &SimulatorWidget::simulatorVolumeGainChange, simulator, &SimulatorInterface::setVolumeGain);
|
||||||
|
|
||||||
timer->setInterval(10);
|
connect(simulator, &SimulatorInterface::started, this, &SimulatorWidget::onSimulatorStarted);
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
connect(simulator, &SimulatorInterface::stopped, this, &SimulatorWidget::onSimulatorStopped);
|
||||||
connect(timer, SIGNAL(timeout()), radioUiWidget, SLOT(updateUi()));
|
connect(simulator, &SimulatorInterface::heartbeat, this, &SimulatorWidget::onSimulatorHeartbeat);
|
||||||
|
connect(simulator, &SimulatorInterface::runtimeError, this, &SimulatorWidget::onSimulatorError);
|
||||||
|
connect(simulator, &SimulatorInterface::phaseChanged, this, &SimulatorWidget::onPhaseChanged);
|
||||||
|
|
||||||
|
m_timer.setInterval(SIMULATOR_INTERFACE_HEARTBEAT_PERIOD * 6);
|
||||||
|
connect(&m_timer, &QTimer::timeout, this, &SimulatorWidget::onTimerEvent);
|
||||||
|
|
||||||
|
setupJoysticks();
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
setRadioProfileId(g.sessionId());
|
||||||
|
setSdPath(g.profile[radioProfileId].sdPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorWidget::~SimulatorWidget()
|
SimulatorWidget::~SimulatorWidget()
|
||||||
{
|
{
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
||||||
if (timer)
|
|
||||||
timer->deleteLater();
|
|
||||||
if (radioUiWidget)
|
if (radioUiWidget)
|
||||||
delete radioUiWidget;
|
delete radioUiWidget;
|
||||||
if (vJoyLeft)
|
if (vJoyLeft)
|
||||||
|
@ -142,10 +153,7 @@ SimulatorWidget::~SimulatorWidget()
|
||||||
if (joystick)
|
if (joystick)
|
||||||
delete joystick;
|
delete joystick;
|
||||||
#endif
|
#endif
|
||||||
|
firmware = NULL;
|
||||||
firmware = NULL; // Not sure we should delete this but at least release our pointer.
|
|
||||||
// NOTE : <simulator> should be deleted (or not) in the parent process which gave it to us in the first place.
|
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,8 +176,7 @@ void SimulatorWidget::setPaths(const QString & sdPath, const QString & dataPath)
|
||||||
{
|
{
|
||||||
sdCardPath = sdPath;
|
sdCardPath = sdPath;
|
||||||
radioDataPath = dataPath;
|
radioDataPath = dataPath;
|
||||||
if (simulator)
|
emit simulatorSdPathChange(sdPath, dataPath);
|
||||||
simulator->setSdPath(sdPath, dataPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::setRadioSettings(const GeneralSettings settings)
|
void SimulatorWidget::setRadioSettings(const GeneralSettings settings)
|
||||||
|
@ -264,7 +271,7 @@ bool SimulatorWidget::setRadioData(RadioData * radioData)
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (radioDataPath.isEmpty()) {
|
if (radioDataPath.isEmpty()) {
|
||||||
startupData.fill(0, getEEpromSize(m_board));
|
startupData.fill(0, Boards::getEEpromSize(m_board));
|
||||||
if (firmware->getEEpromInterface()->save((uint8_t *)startupData.data(), *radioData, 0, firmware->getCapability(SimulatorVariant)) <= 0) {
|
if (firmware->getEEpromInterface()->save((uint8_t *)startupData.data(), *radioData, 0, firmware->getCapability(SimulatorVariant)) <= 0) {
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
@ -410,8 +417,7 @@ void SimulatorWidget::deleteTempData()
|
||||||
void SimulatorWidget::saveState()
|
void SimulatorWidget::saveState()
|
||||||
{
|
{
|
||||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||||
//opts.windowGeometry = saveGeometry();
|
saveRadioWidgetsState(opts.controlsState);
|
||||||
opts.controlsState = saveRadioWidgetsState();
|
|
||||||
g.profile[radioProfileId].simulatorOptions(opts);
|
g.profile[radioProfileId].simulatorOptions(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,35 +438,58 @@ void SimulatorWidget::captureScreenshot(bool)
|
||||||
|
|
||||||
void SimulatorWidget::start()
|
void SimulatorWidget::start()
|
||||||
{
|
{
|
||||||
|
emit simulatorInit(); // init simulator default I/O values
|
||||||
|
|
||||||
setupRadioWidgets();
|
setupRadioWidgets();
|
||||||
setupJoysticks();
|
|
||||||
restoreRadioWidgetsState();
|
restoreRadioWidgetsState();
|
||||||
|
|
||||||
if (startupData.isEmpty())
|
bool tests = !(flags & SIMULATOR_FLAGS_NOTX);
|
||||||
simulator->start((const char *)0);
|
if (!startupData.isEmpty()) {
|
||||||
else if (startupFromFile)
|
if (startupFromFile) {
|
||||||
simulator->start(startupData.constData());
|
emit simulatorStart(startupData.constData(), tests);
|
||||||
else
|
}
|
||||||
simulator->start(startupData, (flags & SIMULATOR_FLAGS_NOTX) ? false : true);
|
else {
|
||||||
|
simulator->setRadioData(startupData);
|
||||||
setTrims();
|
emit simulatorStart((const char *)0, tests);
|
||||||
getValues();
|
}
|
||||||
setupTimer();
|
}
|
||||||
|
else {
|
||||||
|
emit simulatorStart((const char *)0, tests);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::stop()
|
void SimulatorWidget::stop()
|
||||||
{
|
{
|
||||||
if (timer)
|
emit simulatorStop();
|
||||||
timer->stop();
|
QElapsedTimer tmout;
|
||||||
if (simulator) {
|
tmout.start();
|
||||||
simulator->stop();
|
// block until simulator stops or times out
|
||||||
if (saveTempRadioData) {
|
while (simulator->isRunning()) {
|
||||||
startupData.fill(0, getEEpromSize(m_board));
|
if (tmout.hasExpired(2000)) {
|
||||||
simulator->readEepromData(startupData);
|
onSimulatorError("Timeout while trying to stop simulation!");
|
||||||
|
onSimulatorStopped();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimulatorWidget::onSimulatorStarted()
|
||||||
|
{
|
||||||
|
m_heartbeatTimer.start();
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatorWidget::onSimulatorStopped()
|
||||||
|
{
|
||||||
|
m_timer.stop();
|
||||||
|
m_heartbeatTimer.invalidate();
|
||||||
|
|
||||||
|
if (simulator && !simulator->isRunning() && saveTempRadioData) {
|
||||||
|
startupData.fill(0, getEEpromSize(m_board));
|
||||||
|
simulator->readRadioData(startupData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SimulatorWidget::restart()
|
void SimulatorWidget::restart()
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
|
@ -486,100 +515,112 @@ void SimulatorWidget::shutdown()
|
||||||
void SimulatorWidget::setRadioProfileId(int value)
|
void SimulatorWidget::setRadioProfileId(int value)
|
||||||
{
|
{
|
||||||
radioProfileId = value;
|
radioProfileId = value;
|
||||||
if (simulator)
|
emit simulatorVolumeGainChange(g.profile[radioProfileId].volumeGain());
|
||||||
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::setupRadioWidgets()
|
void SimulatorWidget::setupRadioWidgets()
|
||||||
{
|
{
|
||||||
int i, midpos, aIdx;
|
|
||||||
QString wname;
|
QString wname;
|
||||||
Board::Type board = firmware->getBoard();
|
int i, midpos;
|
||||||
|
const int ttlSticks = Boards::getCapability(m_board, Board::Sticks);
|
||||||
|
const int ttlSwitches = Boards::getCapability(m_board, Board::Switches);
|
||||||
|
const int ttlKnobs = Boards::getCapability(m_board, Board::Pots);
|
||||||
|
const int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
|
||||||
|
const int extraTrims = Boards::getCapability(m_board, Board::NumTrims) - ttlSticks;
|
||||||
|
|
||||||
// First clear out any existing widgets.
|
// First clear out any existing widgets.
|
||||||
if (switches.size()) {
|
foreach (RadioWidget * rw, m_radioWidgets) {
|
||||||
foreach (RadioWidget * w, switches) {
|
switch(rw->getType()) {
|
||||||
ui->radioWidgetsHTLayout->removeWidget(w);
|
case RadioWidget::RADIO_WIDGET_SWITCH :
|
||||||
w->deleteLater();
|
case RadioWidget::RADIO_WIDGET_KNOB :
|
||||||
|
ui->radioWidgetsHTLayout->removeWidget(rw);
|
||||||
|
break;
|
||||||
|
case RadioWidget::RADIO_WIDGET_FADER :
|
||||||
|
case RadioWidget::RADIO_WIDGET_TRIM :
|
||||||
|
ui->VCGridLayout->removeWidget(rw);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
switches.clear();
|
disconnect(rw, 0, this, 0);
|
||||||
}
|
disconnect(this, 0, rw, 0);
|
||||||
if (analogs.size()) {
|
rw->deleteLater();
|
||||||
foreach (RadioWidget * w, analogs) {
|
|
||||||
if (w->getType() == RadioWidget::RADIO_WIDGET_KNOB)
|
|
||||||
ui->radioWidgetsHTLayout->removeWidget(w);
|
|
||||||
else
|
|
||||||
ui->VCGridLayout->removeWidget(w);
|
|
||||||
w->deleteLater();
|
|
||||||
}
|
|
||||||
analogs.clear();
|
|
||||||
}
|
}
|
||||||
|
m_radioWidgets.clear();
|
||||||
|
|
||||||
// Now set up new widgets.
|
// Now set up new widgets.
|
||||||
|
|
||||||
// switches
|
// switches
|
||||||
Board::SwitchInfo switchInfo;
|
|
||||||
Board::SwitchType swcfg;
|
Board::SwitchType swcfg;
|
||||||
for (i = 0; i < getBoardCapability(board, Board::Switches) && i < CPN_MAX_SWITCHES; ++i) {
|
for (i = 0; i < ttlSwitches; ++i) {
|
||||||
if (radioSettings.switchConfig[i] == Board::SWITCH_NOT_AVAILABLE)
|
if (radioSettings.switchConfig[i] == Board::SWITCH_NOT_AVAILABLE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
||||||
|
wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(NULL, &radioSettings);
|
||||||
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
|
|
||||||
switchInfo = getSwitchInfo(board, i);
|
|
||||||
wname = QString(switchInfo.name);
|
|
||||||
}
|
|
||||||
RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT);
|
RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT);
|
||||||
sw->setIndex(i);
|
sw->setIndex(i);
|
||||||
ui->radioWidgetsHTLayout->addWidget(sw);
|
ui->radioWidgetsHTLayout->addWidget(sw);
|
||||||
switches.append(sw);
|
|
||||||
|
m_radioWidgets.append(sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
midpos = (int)floorf(switches.size() / 2.0f);
|
midpos = (int)floorf(m_radioWidgets.size() / 2.0f);
|
||||||
aIdx = 0;
|
|
||||||
|
|
||||||
// pots in middle of switches
|
// pots in middle of switches
|
||||||
for (i = 0; i < getBoardCapability(board, Board::Pots) && i < CPN_MAX_POTS; ++i) {
|
for (i = 0; i < ttlKnobs; ++i) {
|
||||||
if (!radioSettings.isPotAvailable(i))
|
if (!radioSettings.isPotAvailable(i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((wname = QString(radioSettings.potName[i])).isEmpty())
|
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + i).toString(NULL, &radioSettings);
|
||||||
wname = firmware->getAnalogInputName(4 + aIdx + i);
|
|
||||||
|
|
||||||
RadioKnobWidget * pot = new RadioKnobWidget(Board::PotType(radioSettings.potConfig[i]), wname, 0, ui->radioWidgetsHT);
|
RadioKnobWidget * pot = new RadioKnobWidget(Board::PotType(radioSettings.potConfig[i]), wname, 0, ui->radioWidgetsHT);
|
||||||
pot->setIndex(aIdx + i);
|
pot->setIndex(i);
|
||||||
// FIXME : total hack here -- this needs to follow the exception in radio/src/mixer.cpp:evalInputs()
|
|
||||||
if (i == 0 && IS_TARANIS(board) && !IS_TARANIS_X7(board))
|
|
||||||
pot->setInvertValue(true);
|
|
||||||
ui->radioWidgetsHTLayout->insertWidget(midpos++, pot);
|
ui->radioWidgetsHTLayout->insertWidget(midpos++, pot);
|
||||||
analogs.append(pot);
|
|
||||||
|
m_radioWidgets.append(pot);
|
||||||
}
|
}
|
||||||
|
|
||||||
aIdx += i;
|
|
||||||
|
|
||||||
// faders between sticks
|
// faders between sticks
|
||||||
int r = 0, c = 0;
|
int c = extraTrims / 2; // leave space for any extra trims
|
||||||
for (i = 0; i < getBoardCapability(board, Board::Sliders) && i + aIdx < CPN_MAX_POTS; ++i) {
|
for (i = 0; i < ttlFaders; ++i) {
|
||||||
if (!radioSettings.isSliderAvailable(i))
|
if (!radioSettings.isSliderAvailable(i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((wname = QString(radioSettings.sliderName[i])).isEmpty())
|
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + ttlKnobs + i).toString(NULL, &radioSettings);
|
||||||
wname = firmware->getAnalogInputName(4 + aIdx + i);
|
|
||||||
|
|
||||||
RadioFaderWidget * sl = new RadioFaderWidget(wname, 0, ui->radioWidgetsVC);
|
RadioFaderWidget * sl = new RadioFaderWidget(wname, 0, ui->radioWidgetsVC);
|
||||||
sl->setIndex(aIdx + i);
|
sl->setIndex(i);
|
||||||
// FIXME : total hack here -- this needs to follow the exception in radio/src/mixer.cpp:evalInputs()
|
ui->VCGridLayout->addWidget(sl, 0, c++, 1, 1);
|
||||||
if (i == 0 && IS_TARANIS(board) && !IS_TARANIS_X7(board))
|
|
||||||
sl->setInvertValue(true);
|
m_radioWidgets.append(sl);
|
||||||
/* 2-row option
|
|
||||||
if (!(i % 2)) {
|
|
||||||
++r;
|
|
||||||
c = 0;
|
|
||||||
} */
|
|
||||||
ui->VCGridLayout->addWidget(sl, r, c++, 1, 1);
|
|
||||||
analogs.append(sl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extra trims around faders
|
||||||
|
int tridx = Board::TRIM_AXIS_COUNT;
|
||||||
|
int trswidx = Board::TRIM_SW_COUNT;
|
||||||
|
for (i = extraTrims; i > 0; --i) {
|
||||||
|
trswidx -= 2;
|
||||||
|
--tridx;
|
||||||
|
wname = RawSource(RawSourceType::SOURCE_TYPE_TRIM, tridx).toString(NULL, &radioSettings);
|
||||||
|
wname = wname.left(1) % wname.right(1);
|
||||||
|
RadioTrimWidget * tw = new RadioTrimWidget(Qt::Vertical, ui->radioWidgetsVC);
|
||||||
|
tw->setIndices(tridx, trswidx, trswidx + 1);
|
||||||
|
tw->setLabelText(wname);
|
||||||
|
if (i <= extraTrims / 2)
|
||||||
|
c = 0;
|
||||||
|
ui->VCGridLayout->addWidget(tw, 0, c++, 1, 1);
|
||||||
|
|
||||||
|
connect(simulator, &SimulatorInterface::trimValueChange, tw, &RadioTrimWidget::setTrimValue);
|
||||||
|
connect(simulator, &SimulatorInterface::trimRangeChange, tw, &RadioTrimWidget::setTrimRangeQual);
|
||||||
|
m_radioWidgets.append(tw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect all the widgets
|
||||||
|
foreach (RadioWidget * rw, m_radioWidgets) {
|
||||||
|
connect(rw, &RadioWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||||
|
connect(this, &SimulatorWidget::widgetValueChange, rw, &RadioWidget::setValueQual);
|
||||||
|
connect(this, &SimulatorWidget::widgetStateChange, rw, &RadioWidget::setStateData);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::setupJoysticks()
|
void SimulatorWidget::setupJoysticks()
|
||||||
|
@ -600,6 +641,10 @@ void SimulatorWidget::setupJoysticks()
|
||||||
joystick->deadzones[j] = 0;
|
joystick->deadzones[j] = 0;
|
||||||
}
|
}
|
||||||
connect(joystick, &Joystick::axisValueChanged, this, &SimulatorWidget::onjoystickAxisValueChanged);
|
connect(joystick, &Joystick::axisValueChanged, this, &SimulatorWidget::onjoystickAxisValueChanged);
|
||||||
|
if (vJoyLeft)
|
||||||
|
connect(this, &SimulatorWidget::stickValueChange, vJoyLeft, &VirtualJoystickWidget::setStickAxisValue);
|
||||||
|
if (vJoyRight)
|
||||||
|
connect(this, &SimulatorWidget::stickValueChange, vJoyRight, &VirtualJoystickWidget::setStickAxisValue);
|
||||||
joysticksEnabled = true;
|
joysticksEnabled = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -609,164 +654,50 @@ void SimulatorWidget::setupJoysticks()
|
||||||
else if (joystick) {
|
else if (joystick) {
|
||||||
joystick->close();
|
joystick->close();
|
||||||
disconnect(joystick, 0, this, 0);
|
disconnect(joystick, 0, this, 0);
|
||||||
|
if (vJoyLeft)
|
||||||
|
disconnect(this, 0, vJoyLeft, 0);
|
||||||
|
if (vJoyRight)
|
||||||
|
disconnect(this, 0, vJoyRight, 0);
|
||||||
joystick->deleteLater();
|
joystick->deleteLater();
|
||||||
joystick = NULL;
|
joystick = NULL;
|
||||||
}
|
}
|
||||||
if (vJoyRight) {
|
if (vJoyRight)
|
||||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_X, joysticksEnabled);
|
vJoyRight->setStickConstraint((VirtualJoystickWidget::HOLD_X | VirtualJoystickWidget::HOLD_Y), joysticksEnabled);
|
||||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, joysticksEnabled);
|
if (vJoyLeft)
|
||||||
}
|
vJoyLeft->setStickConstraint((VirtualJoystickWidget::HOLD_X | VirtualJoystickWidget::HOLD_Y), joysticksEnabled);
|
||||||
if (vJoyLeft) {
|
|
||||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_X, joysticksEnabled);
|
|
||||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, joysticksEnabled);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::setupTimer()
|
|
||||||
{
|
|
||||||
if (!timer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (timer->isActive())
|
|
||||||
timer->stop();
|
|
||||||
|
|
||||||
timer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorWidget::restoreRadioWidgetsState()
|
void SimulatorWidget::restoreRadioWidgetsState()
|
||||||
{
|
{
|
||||||
|
// All RadioWidgets
|
||||||
RadioWidget::RadioWidgetState state;
|
RadioWidget::RadioWidgetState state;
|
||||||
QMap<int, QByteArray> switchesMap;
|
|
||||||
QMap<int, QByteArray> analogsMap;
|
|
||||||
QList<QByteArray> states = g.profile[radioProfileId].simulatorOptions().controlsState;
|
QList<QByteArray> states = g.profile[radioProfileId].simulatorOptions().controlsState;
|
||||||
|
|
||||||
foreach (QByteArray ba, states) {
|
foreach (QByteArray ba, states) {
|
||||||
QDataStream stream(ba);
|
QDataStream stream(ba);
|
||||||
stream >> state;
|
stream >> state;
|
||||||
if (state.type == RadioWidget::RADIO_WIDGET_SWITCH)
|
emit widgetStateChange(state);
|
||||||
switchesMap.insert(state.index, ba);
|
|
||||||
else
|
|
||||||
analogsMap.insert(state.index, ba);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < analogs.size(); ++i) {
|
|
||||||
if (analogsMap.contains(analogs[i]->getIndex()))
|
|
||||||
analogs[i]->setStateData(analogsMap.value(analogs[i]->getIndex()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < switches.size(); ++i) {
|
|
||||||
if (switchesMap.contains(switches[i]->getIndex()))
|
|
||||||
switches[i]->setStateData(switchesMap.value(switches[i]->getIndex()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set throttle stick down and locked, side depends on mode
|
// Set throttle stick down and locked, side depends on mode
|
||||||
if (radioSettings.stickMode & 1) {
|
emit stickModeChange(radioSettings.stickMode);
|
||||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
|
||||||
vJoyLeft->setStickY(1);
|
// TODO : custom voltages
|
||||||
}
|
qint16 volts = radioSettings.vBatWarn + 2;
|
||||||
else {
|
if (firmware->getCapability(Capability::HasBatMeterRange))
|
||||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
volts = (radioSettings.vBatMin + 90) + ((radioSettings.vBatMax + 30) - radioSettings.vBatMin) / 2;
|
||||||
vJoyRight->setStickY(1);
|
emit inputValueChange(SimulatorInterface::INPUT_SRC_TXVIN, 0, volts);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QByteArray> SimulatorWidget::saveRadioWidgetsState()
|
void SimulatorWidget::saveRadioWidgetsState(QList<QByteArray> & state)
|
||||||
{
|
{
|
||||||
QList<QByteArray> states;
|
if (m_radioWidgets.size()) {
|
||||||
|
state.clear();
|
||||||
for (int i = 0; i < analogs.size(); ++i)
|
foreach (RadioWidget * rw, m_radioWidgets)
|
||||||
states.append(analogs[i]->getStateData());
|
state.append(rw->getStateData());
|
||||||
|
|
||||||
for (int i = 0; i < switches.size(); ++i)
|
|
||||||
states.append(switches[i]->getStateData());
|
|
||||||
|
|
||||||
return states;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Input/Output handlers for SimulatorInterface
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Read various values from firmware simulator and populate values in this UI
|
|
||||||
void SimulatorWidget::setValues()
|
|
||||||
{
|
|
||||||
int currentPhase = simulator->getPhase();
|
|
||||||
|
|
||||||
// display current flight mode in window title
|
|
||||||
if (currentPhase != lastPhase) {
|
|
||||||
lastPhase = currentPhase;
|
|
||||||
QString phase_name = QString(simulator->getPhaseName(currentPhase));
|
|
||||||
if (phase_name.isEmpty())
|
|
||||||
phase_name = QString::number(currentPhase);
|
|
||||||
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "get" values from this UI and send them to the firmware simulator.
|
|
||||||
void SimulatorWidget::getValues()
|
|
||||||
{
|
|
||||||
static const int numTrims = getBoardCapability(m_board, Board::NumTrimSwitches);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
TxInputs inp;
|
|
||||||
memset(&inp, 0, sizeof(TxInputs));
|
|
||||||
|
|
||||||
inp.sticks[0] = int(1024 * vJoyLeft->getStickX()); // LEFT HORZ
|
|
||||||
inp.sticks[1] = int(-1024 * vJoyLeft->getStickY()); // LEFT VERT
|
|
||||||
inp.sticks[2] = int(-1024 * vJoyRight->getStickY()); // RGHT VERT
|
|
||||||
inp.sticks[3] = int(1024 * vJoyRight->getStickX()); // RGHT HORZ
|
|
||||||
|
|
||||||
for (i = 0; i < analogs.size() && i < CPN_MAX_POTS; ++i)
|
|
||||||
inp.pots[analogs[i]->getIndex()] = analogs[i]->getValue();
|
|
||||||
|
|
||||||
for (i = 0; i < switches.size() && i < CPN_MAX_SWITCHES; ++i)
|
|
||||||
inp.switches[switches[i]->getIndex()] = switches[i]->getValue();
|
|
||||||
|
|
||||||
for (i = 0; i < numTrims; ++i)
|
|
||||||
inp.trims[i] = (trimPressed == i);
|
|
||||||
|
|
||||||
foreach (RadioUiAction * act, radioUiWidget->getActions()) {
|
|
||||||
if (act->getIndex() > -1 && act->getIndex() < CPN_MAX_KEYS)
|
|
||||||
inp.keys[act->getIndex()] = act->isActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radioUiWidget->getRotEncAction())
|
|
||||||
inp.rotenc = radioUiWidget->getRotEncAction()->isActive();
|
|
||||||
|
|
||||||
simulator->setValues(inp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read stick trim values from firmware simulator and set joystick widgets as needed.
|
|
||||||
void SimulatorWidget::setTrims()
|
|
||||||
{
|
|
||||||
using namespace Board;
|
|
||||||
static Trims lastTrims;
|
|
||||||
Trims trims;
|
|
||||||
simulator->getTrims(trims);
|
|
||||||
|
|
||||||
if (trims.values[TRIM_AXIS_LH] != lastTrims.values[TRIM_AXIS_LH])
|
|
||||||
vJoyLeft->setTrimValue(TRIM_AXIS_LH, trims.values[TRIM_AXIS_LH]);
|
|
||||||
if (trims.values[TRIM_AXIS_LV] != lastTrims.values[TRIM_AXIS_LV])
|
|
||||||
vJoyLeft->setTrimValue(TRIM_AXIS_LV, trims.values[TRIM_AXIS_LV]);
|
|
||||||
if (trims.values[TRIM_AXIS_RV] != lastTrims.values[TRIM_AXIS_RV])
|
|
||||||
vJoyRight->setTrimValue(TRIM_AXIS_RV, trims.values[TRIM_AXIS_RV]);
|
|
||||||
if (trims.values[TRIM_AXIS_RH] != lastTrims.values[TRIM_AXIS_RH])
|
|
||||||
vJoyRight->setTrimValue(TRIM_AXIS_RH, trims.values[TRIM_AXIS_RH]);
|
|
||||||
|
|
||||||
if (trims.extended != lastTrims.extended) {
|
|
||||||
int trimMin = -125, trimMax = +125;
|
|
||||||
if (trims.extended) {
|
|
||||||
trimMin = -500;
|
|
||||||
trimMax = +500;
|
|
||||||
}
|
|
||||||
vJoyLeft->setTrimRange(TRIM_AXIS_LH, trimMin, trimMax);
|
|
||||||
vJoyLeft->setTrimRange(TRIM_AXIS_LV, trimMin, trimMax);
|
|
||||||
vJoyRight->setTrimRange(TRIM_AXIS_RV, trimMin, trimMax);
|
|
||||||
vJoyRight->setTrimRange(TRIM_AXIS_RH, trimMin, trimMax);
|
|
||||||
}
|
|
||||||
lastTrims = trims;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Event handlers/private slots
|
* Event handlers/private slots
|
||||||
|
@ -792,51 +723,95 @@ void SimulatorWidget::wheelEvent(QWheelEvent *event)
|
||||||
|
|
||||||
void SimulatorWidget::onTimerEvent()
|
void SimulatorWidget::onTimerEvent()
|
||||||
{
|
{
|
||||||
static unsigned int lcd_counter = 0;
|
if (m_heartbeatTimer.isValid() && m_heartbeatTimer.hasExpired(m_timer.interval())) {
|
||||||
|
onSimulatorError("Heartbeat timeout!");
|
||||||
|
onSimulatorStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!simulator->timer10ms()) {
|
void SimulatorWidget::onSimulatorHeartbeat(qint32 loops, qint64 timestamp)
|
||||||
QMessageBox::critical(this, "Companion", tr("Firmware %1 error: %2").arg(firmware->getName()).arg(simulator->getError()));
|
{
|
||||||
timer->stop();
|
Q_UNUSED(loops)
|
||||||
|
Q_UNUSED(timestamp)
|
||||||
|
m_heartbeatTimer.start();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static qint64 lastTs = 0;
|
||||||
|
if (!(loops % 1000)) {
|
||||||
|
qDebug() << "loops:" << loops << "ts:" << timestamp << "ts-delta:" << timestamp - lastTs << "This:" << QThread::currentThread() << "Simu:" << simulator->thread();
|
||||||
|
lastTs = timestamp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatorWidget::onSimulatorError(const QString & error)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, windowName, tr("Radio firmware error: %1").arg(error.isEmpty() ? "Unknown reason" : error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatorWidget::onPhaseChanged(qint32 phase, const QString & name)
|
||||||
|
{
|
||||||
|
setWindowTitle(windowName + tr(" - Flight Mode %1 (#%2)").arg(name).arg(phase));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatorWidget::onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, const int index, int value)
|
||||||
|
{
|
||||||
|
//qDebug() << type << index << value;
|
||||||
|
if (!simulator || index < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SimulatorInterface::InputSourceType inpType = SimulatorInterface::INPUT_SRC_NONE;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RadioWidget::RADIO_WIDGET_SWITCH :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_SWITCH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RadioWidget::RADIO_WIDGET_KNOB :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_KNOB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RadioWidget::RADIO_WIDGET_FADER :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_SLIDER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RadioWidget::RADIO_WIDGET_TRIM :
|
||||||
|
switch (value) {
|
||||||
|
case RadioWidget::RADIO_TRIM_BTN_ON :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_TRIM_SW;
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case RadioWidget::RADIO_TRIM_BTN_OFF :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_TRIM_SW;
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_TRIM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RadioWidget::RADIO_WIDGET_STICK :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_STICK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RadioWidget::RADIO_WIDGET_KEY :
|
||||||
|
inpType = SimulatorInterface::INPUT_SRC_KEY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getValues();
|
emit inputValueChange(inpType, index, value);
|
||||||
|
|
||||||
if (!(lcd_counter++ % 5)) {
|
|
||||||
setValues();
|
|
||||||
setTrims();
|
|
||||||
centerSticks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorWidget::onTrimPressed(int index)
|
|
||||||
{
|
|
||||||
trimPressed = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorWidget::onTrimReleased(int)
|
|
||||||
{
|
|
||||||
trimPressed = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorWidget::onTrimSliderMoved(int index, int value)
|
|
||||||
{
|
|
||||||
simulator->setTrim(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorWidget::centerSticks()
|
|
||||||
{
|
|
||||||
if (vJoyLeft)
|
|
||||||
vJoyLeft->centerStick();
|
|
||||||
|
|
||||||
if (vJoyRight)
|
|
||||||
vJoyRight->centerStick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
static const int ttlSticks = CPN_MAX_STICKS;
|
static const int ttlSticks = 4;
|
||||||
|
static const int ttlKnobs = Boards::getCapability(m_board, Board::Pots);
|
||||||
|
static const int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
|
||||||
static const int valueRange = 1024;
|
static const int valueRange = 1024;
|
||||||
|
|
||||||
if (!joystick || axis >= MAX_JOYSTICKS)
|
if (!joystick || axis >= MAX_JOYSTICKS)
|
||||||
|
@ -845,7 +820,7 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
||||||
int dlta;
|
int dlta;
|
||||||
int stick = g.joystick[axis].stick_axe();
|
int stick = g.joystick[axis].stick_axe();
|
||||||
|
|
||||||
if (stick < 0 || stick >= ttlSticks + analogs.count())
|
if (stick < 0 || stick >= ttlSticks + ttlKnobs + ttlFaders)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int stickval = valueRange * (value - g.joystick[axis].stick_med());
|
int stickval = valueRange * (value - g.joystick[axis].stick_med());
|
||||||
|
@ -861,20 +836,15 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
||||||
if (g.joystick[axis].stick_inv())
|
if (g.joystick[axis].stick_inv())
|
||||||
stickval *= -1;
|
stickval *= -1;
|
||||||
|
|
||||||
if (stick==1 ) {
|
if (stick < ttlSticks) {
|
||||||
vJoyRight->setStickY(-stickval/1024.0);
|
emit stickValueChange(stick, stickval);
|
||||||
}
|
}
|
||||||
else if (stick==2) {
|
else {
|
||||||
vJoyRight->setStickX(stickval/1024.0);
|
stick -= ttlSticks;
|
||||||
}
|
if (stick < ttlKnobs)
|
||||||
else if (stick==3) {
|
emit widgetValueChange(RadioWidget::RADIO_WIDGET_KNOB, stick, stickval);
|
||||||
vJoyLeft->setStickY(-stickval/1024.0);
|
else
|
||||||
}
|
emit widgetValueChange(RadioWidget::RADIO_WIDGET_FADER, stick, stickval);
|
||||||
else if (stick==4) {
|
|
||||||
vJoyLeft->setStickX(stickval/1024.0);
|
|
||||||
}
|
|
||||||
else if (stick > ttlSticks) {
|
|
||||||
analogs[stick-ttlSticks-1]->setValue(stickval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,24 +24,20 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "radiodata.h"
|
#include "radiodata.h"
|
||||||
|
#include "radiowidget.h"
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#define FLASH_DURATION 10
|
|
||||||
|
|
||||||
#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
|
||||||
#define CBEEP_OFF "QLabel { }"
|
|
||||||
|
|
||||||
void traceCb(const char * text);
|
void traceCb(const char * text);
|
||||||
|
|
||||||
class Firmware;
|
class Firmware;
|
||||||
class SimulatorInterface;
|
class SimulatorInterface;
|
||||||
class SimulatedUIWidget;
|
class SimulatedUIWidget;
|
||||||
class RadioWidget;
|
|
||||||
class RadioSwitchWidget;
|
|
||||||
class VirtualJoystickWidget;
|
class VirtualJoystickWidget;
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
class Joystick;
|
class Joystick;
|
||||||
|
@ -56,8 +52,6 @@ namespace Ui {
|
||||||
class SimulatorWidget;
|
class SimulatorWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace Simulator;
|
|
||||||
|
|
||||||
class SimulatorWidget : public QWidget
|
class SimulatorWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -84,7 +78,7 @@ class SimulatorWidget : public QWidget
|
||||||
|
|
||||||
QString getSdPath() const { return sdCardPath; }
|
QString getSdPath() const { return sdCardPath; }
|
||||||
QString getDataPath() const { return radioDataPath; }
|
QString getDataPath() const { return radioDataPath; }
|
||||||
QVector<keymapHelp_t> * getKeymapHelp() { return &keymapHelp; }
|
QVector<Simulator::keymapHelp_t> getKeymapHelp() const { return keymapHelp; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
|
@ -92,52 +86,18 @@ class SimulatorWidget : public QWidget
|
||||||
void restart();
|
void restart();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
private:
|
signals:
|
||||||
void setRadioProfileId(int value);
|
void stickValueChange(int axis, int value);
|
||||||
void setupRadioWidgets();
|
void stickModeChange(const unsigned mode);
|
||||||
void setupTimer();
|
void widgetValueChange(const RadioWidget::RadioWidgetType type, const int index, const int value);
|
||||||
void restoreRadioWidgetsState();
|
void widgetStateChange(const RadioWidget::RadioWidgetState & state);
|
||||||
QList<QByteArray> saveRadioWidgetsState();
|
void inputValueChange(int type, quint8 index, qint16 value);
|
||||||
|
void simulatorSetData(const QByteArray & data);
|
||||||
void setValues();
|
void simulatorInit();
|
||||||
void getValues();
|
void simulatorStart(const char * filename, bool tests);
|
||||||
void setTrims();
|
void simulatorStop();
|
||||||
|
void simulatorSdPathChange(const QString & sdPath, const QString & dataPath);
|
||||||
|
void simulatorVolumeGainChange(const int gain);
|
||||||
Ui::SimulatorWidget * ui;
|
|
||||||
SimulatorInterface * simulator;
|
|
||||||
Firmware * firmware;
|
|
||||||
GeneralSettings radioSettings;
|
|
||||||
|
|
||||||
QTimer * timer;
|
|
||||||
QString windowName;
|
|
||||||
QVector<keymapHelp_t> keymapHelp;
|
|
||||||
|
|
||||||
SimulatedUIWidget * radioUiWidget;
|
|
||||||
VirtualJoystickWidget * vJoyLeft;
|
|
||||||
VirtualJoystickWidget * vJoyRight;
|
|
||||||
|
|
||||||
QVector<RadioSwitchWidget *> switches;
|
|
||||||
QVector<RadioWidget *> analogs;
|
|
||||||
|
|
||||||
QString sdCardPath;
|
|
||||||
QString radioDataPath;
|
|
||||||
QByteArray startupData;
|
|
||||||
Board::Type m_board;
|
|
||||||
quint8 flags;
|
|
||||||
int radioProfileId;
|
|
||||||
int lastPhase;
|
|
||||||
int buttonPressed;
|
|
||||||
int trimPressed;
|
|
||||||
bool startupFromFile;
|
|
||||||
bool deleteTempRadioData;
|
|
||||||
bool saveTempRadioData;
|
|
||||||
bool middleButtonPressed;
|
|
||||||
bool firstShow;
|
|
||||||
|
|
||||||
#ifdef JOYSTICKS
|
|
||||||
Joystick *joystick;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
virtual void mousePressEvent(QMouseEvent *event);
|
virtual void mousePressEvent(QMouseEvent *event);
|
||||||
|
@ -145,12 +105,50 @@ class SimulatorWidget : public QWidget
|
||||||
virtual void wheelEvent(QWheelEvent *event);
|
virtual void wheelEvent(QWheelEvent *event);
|
||||||
|
|
||||||
void onTimerEvent();
|
void onTimerEvent();
|
||||||
void onTrimPressed(int index);
|
void onSimulatorStarted();
|
||||||
void onTrimReleased(int);
|
void onSimulatorStopped();
|
||||||
void onTrimSliderMoved(int index, int value);
|
void onSimulatorHeartbeat(qint32 loops, qint64 timestamp);
|
||||||
void centerSticks();
|
void onPhaseChanged(qint32 phase, const QString & name);
|
||||||
|
void onSimulatorError(const QString & error);
|
||||||
|
void onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, const int index, int value);
|
||||||
void onjoystickAxisValueChanged(int axis, int value);
|
void onjoystickAxisValueChanged(int axis, int value);
|
||||||
|
|
||||||
|
void setRadioProfileId(int value);
|
||||||
|
void setupRadioWidgets();
|
||||||
|
void restoreRadioWidgetsState();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void saveRadioWidgetsState(QList<QByteArray> & state);
|
||||||
|
|
||||||
|
Ui::SimulatorWidget * ui;
|
||||||
|
SimulatorInterface * simulator;
|
||||||
|
Firmware * firmware;
|
||||||
|
GeneralSettings radioSettings;
|
||||||
|
|
||||||
|
QTimer m_timer;
|
||||||
|
QString windowName;
|
||||||
|
QVector<Simulator::keymapHelp_t> keymapHelp;
|
||||||
|
QElapsedTimer m_heartbeatTimer;
|
||||||
|
|
||||||
|
SimulatedUIWidget * radioUiWidget;
|
||||||
|
VirtualJoystickWidget * vJoyLeft;
|
||||||
|
VirtualJoystickWidget * vJoyRight;
|
||||||
|
QVector<RadioWidget *> m_radioWidgets;
|
||||||
|
|
||||||
|
QString sdCardPath;
|
||||||
|
QString radioDataPath;
|
||||||
|
QByteArray startupData;
|
||||||
|
Board::Type m_board;
|
||||||
|
quint8 flags;
|
||||||
|
int radioProfileId;
|
||||||
|
bool startupFromFile;
|
||||||
|
bool deleteTempRadioData;
|
||||||
|
bool saveTempRadioData;
|
||||||
|
|
||||||
|
#ifdef JOYSTICKS
|
||||||
|
Joystick *joystick;
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _SIMULATORWIDGET_H_
|
#endif // _SIMULATORWIDGET_H_
|
||||||
|
|
|
@ -27,25 +27,13 @@
|
||||||
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::TelemetrySimulator),
|
ui(new Ui::TelemetrySimulator),
|
||||||
simulator(simulator)
|
simulator(simulator),
|
||||||
|
m_simuStarted(false),
|
||||||
|
m_telemEnable(false),
|
||||||
|
m_logReplayEnable(false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
timer.setInterval(10);
|
|
||||||
connect(&timer, &QTimer::timeout, this, &TelemetrySimulator::generateTelemetryFrame);
|
|
||||||
|
|
||||||
connect(&logTimer, &QTimer::timeout, this, &TelemetrySimulator::onLogTimerEvent);
|
|
||||||
|
|
||||||
connect(ui->Simulate, SIGNAL(toggled(bool)), this, SLOT(onSimulateToggled(bool)));
|
|
||||||
connect(ui->loadLogFile, SIGNAL(released()), this, SLOT(onLoadLogFile()));
|
|
||||||
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
|
|
||||||
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
|
|
||||||
connect(ui->stepForward, SIGNAL(clicked()), this, SLOT(onStepForward()));
|
|
||||||
connect(ui->stepBack, SIGNAL(clicked()), this, SLOT(onStepBack()));
|
|
||||||
connect(ui->stop, SIGNAL(clicked()), this, SLOT(onStop()));
|
|
||||||
connect(ui->positionIndicator, SIGNAL(valueChanged(int)), this, SLOT(onPositionIndicatorChanged(int)));
|
|
||||||
connect(ui->replayRate, SIGNAL(valueChanged(int)), this, SLOT(onReplayRateChanged(int)));
|
|
||||||
|
|
||||||
ui->A1->setSpecialValueText(" ");
|
ui->A1->setSpecialValueText(" ");
|
||||||
ui->A2->setSpecialValueText(" ");
|
ui->A2->setSpecialValueText(" ");
|
||||||
ui->A3->setSpecialValueText(" ");
|
ui->A3->setSpecialValueText(" ");
|
||||||
|
@ -57,7 +45,27 @@ TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * si
|
||||||
ui->A1_ratio->setEnabled(false);
|
ui->A1_ratio->setEnabled(false);
|
||||||
ui->A2_ratio->setEnabled(false);
|
ui->A2_ratio->setEnabled(false);
|
||||||
|
|
||||||
|
|
||||||
|
timer.setInterval(10);
|
||||||
|
connect(&timer, &QTimer::timeout, this, &TelemetrySimulator::generateTelemetryFrame);
|
||||||
|
|
||||||
|
connect(&logTimer, &QTimer::timeout, this, &TelemetrySimulator::onLogTimerEvent);
|
||||||
|
|
||||||
logPlayback = new LogPlaybackController(ui);
|
logPlayback = new LogPlaybackController(ui);
|
||||||
|
|
||||||
|
connect(ui->Simulate, SIGNAL(toggled(bool)), this, SLOT(onSimulateToggled(bool)));
|
||||||
|
connect(ui->loadLogFile, SIGNAL(released()), this, SLOT(onLoadLogFile()));
|
||||||
|
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
|
||||||
|
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
|
||||||
|
connect(ui->stepForward, SIGNAL(clicked()), this, SLOT(onStepForward()));
|
||||||
|
connect(ui->stepBack, SIGNAL(clicked()), this, SLOT(onStepBack()));
|
||||||
|
connect(ui->stop, SIGNAL(clicked()), this, SLOT(onStop()));
|
||||||
|
connect(ui->positionIndicator, SIGNAL(valueChanged(int)), this, SLOT(onPositionIndicatorChanged(int)));
|
||||||
|
connect(ui->replayRate, SIGNAL(valueChanged(int)), this, SLOT(onReplayRateChanged(int)));
|
||||||
|
|
||||||
|
connect(this, &TelemetrySimulator::telemetryDataChanged, simulator, &SimulatorInterface::sendTelemetry);
|
||||||
|
connect(simulator, &SimulatorInterface::started, this, &TelemetrySimulator::onSimulatorStarted);
|
||||||
|
connect(simulator, &SimulatorInterface::stopped, this, &TelemetrySimulator::onSimulatorStopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
TelemetrySimulator::~TelemetrySimulator()
|
TelemetrySimulator::~TelemetrySimulator()
|
||||||
|
@ -70,9 +78,15 @@ TelemetrySimulator::~TelemetrySimulator()
|
||||||
|
|
||||||
void TelemetrySimulator::onSimulatorStarted()
|
void TelemetrySimulator::onSimulatorStarted()
|
||||||
{
|
{
|
||||||
|
m_simuStarted = true;
|
||||||
setupDataFields();
|
setupDataFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TelemetrySimulator::onSimulatorStopped()
|
||||||
|
{
|
||||||
|
m_simuStarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
||||||
{
|
{
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
|
@ -149,13 +163,23 @@ void TelemetrySimulator::onReplayRateChanged(int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TelemetrySimulator::closeEvent(QCloseEvent *event)
|
void TelemetrySimulator::hideEvent(QHideEvent *event)
|
||||||
{
|
{
|
||||||
timer.stop();
|
m_telemEnable = ui->Simulate->isChecked();
|
||||||
logTimer.stop();
|
m_logReplayEnable = logTimer.isActive();
|
||||||
|
|
||||||
|
ui->Simulate->setChecked(false);
|
||||||
|
ui->stop->click();
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TelemetrySimulator::showEvent(QShowEvent * event)
|
||||||
|
{
|
||||||
|
ui->Simulate->setChecked(m_telemEnable);
|
||||||
|
if (m_logReplayEnable)
|
||||||
|
ui->play->click();
|
||||||
|
}
|
||||||
|
|
||||||
#define SET_INSTANCE(control, id, def) ui->control->setText(QString::number(simulator->getSensorInstance(id, ((def) & 0x1F) + 1)))
|
#define SET_INSTANCE(control, id, def) ui->control->setText(QString::number(simulator->getSensorInstance(id, ((def) & 0x1F) + 1)))
|
||||||
|
|
||||||
void TelemetrySimulator::setupDataFields()
|
void TelemetrySimulator::setupDataFields()
|
||||||
|
@ -237,6 +261,9 @@ void TelemetrySimulator::generateTelemetryFrame()
|
||||||
static FlvssEmulator *flvss = new FlvssEmulator();
|
static FlvssEmulator *flvss = new FlvssEmulator();
|
||||||
static GPSEmulator *gps = new GPSEmulator();
|
static GPSEmulator *gps = new GPSEmulator();
|
||||||
|
|
||||||
|
if (!m_simuStarted)
|
||||||
|
return;
|
||||||
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
switch (item++) {
|
switch (item++) {
|
||||||
|
@ -405,7 +432,7 @@ void TelemetrySimulator::generateTelemetryFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok && (buffer[2] || buffer[3]))
|
if (ok && (buffer[2] || buffer[3]))
|
||||||
simulator->sendTelemetry(buffer, FRSKY_SPORT_PACKET_SIZE);
|
emit telemetryDataChanged(buffer, FRSKY_SPORT_PACKET_SIZE);
|
||||||
else
|
else
|
||||||
generateTelemetryFrame();
|
generateTelemetryFrame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,14 +45,19 @@ class TelemetrySimulator : public QWidget
|
||||||
|
|
||||||
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||||
virtual ~TelemetrySimulator();
|
virtual ~TelemetrySimulator();
|
||||||
void onSimulatorStarted();
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void telemetryDataChanged(uint8_t * data, unsigned int len);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void hideEvent(QHideEvent *event);
|
||||||
|
virtual void showEvent(QShowEvent *event);
|
||||||
|
void onSimulatorStarted();
|
||||||
|
void onSimulatorStopped();
|
||||||
void setupDataFields();
|
void setupDataFields();
|
||||||
void onSimulateToggled(bool isChecked);
|
void onSimulateToggled(bool isChecked);
|
||||||
void generateTelemetryFrame();
|
|
||||||
void onLogTimerEvent();
|
void onLogTimerEvent();
|
||||||
void onLoadLogFile();
|
void onLoadLogFile();
|
||||||
void onPlay();
|
void onPlay();
|
||||||
|
@ -62,6 +67,7 @@ class TelemetrySimulator : public QWidget
|
||||||
void onStop();
|
void onStop();
|
||||||
void onPositionIndicatorChanged(int value);
|
void onPositionIndicatorChanged(int value);
|
||||||
void onReplayRateChanged(int value);
|
void onReplayRateChanged(int value);
|
||||||
|
void generateTelemetryFrame();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -69,6 +75,9 @@ class TelemetrySimulator : public QWidget
|
||||||
QTimer timer;
|
QTimer timer;
|
||||||
QTimer logTimer;
|
QTimer logTimer;
|
||||||
SimulatorInterface *simulator;
|
SimulatorInterface *simulator;
|
||||||
|
bool m_simuStarted;
|
||||||
|
bool m_telemEnable;
|
||||||
|
bool m_logReplayEnable;
|
||||||
|
|
||||||
// protected classes follow
|
// protected classes follow
|
||||||
|
|
||||||
|
@ -81,7 +90,7 @@ class TelemetrySimulator : public QWidget
|
||||||
void play();
|
void play();
|
||||||
void stop();
|
void stop();
|
||||||
void rewind();
|
void rewind();
|
||||||
void stepForward(bool focusOnStop);
|
void stepForward(bool focusOnStop = false);
|
||||||
void stepBack();
|
void stepBack();
|
||||||
void updatePositionLabel(int32_t percentage);
|
void updatePositionLabel(int32_t percentage);
|
||||||
void setUiDataValues();
|
void setUiDataValues();
|
||||||
|
|
|
@ -24,32 +24,40 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "virtualjoystickwidget.h"
|
#include "virtualjoystickwidget.h"
|
||||||
|
|
||||||
|
#define TRAINERSIMU_HEARTBEAT_PERIOD 500 // [ms]
|
||||||
|
|
||||||
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::TrainerSimulator),
|
ui(new Ui::TrainerSimulator),
|
||||||
simulator(simulator)
|
simulator(simulator),
|
||||||
|
m_simuStarted(false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
vJoyLeft = new VirtualJoystickWidget(this, 'L', false);
|
vJoyLeft = new VirtualJoystickWidget(this, 'L', false);
|
||||||
vJoyLeft->setStickColor(Qt::cyan);
|
vJoyLeft->setStickColor(Qt::cyan);
|
||||||
|
vJoyLeft->setStickScale(512);
|
||||||
ui->leftStickLayout->addWidget(vJoyLeft);
|
ui->leftStickLayout->addWidget(vJoyLeft);
|
||||||
|
|
||||||
vJoyRight = new VirtualJoystickWidget(this, 'R', false);
|
vJoyRight = new VirtualJoystickWidget(this, 'R', false);
|
||||||
vJoyRight->setStickColor(Qt::cyan);
|
vJoyRight->setStickColor(Qt::cyan);
|
||||||
|
vJoyRight->setStickScale(512);
|
||||||
ui->rightStickLayout->addWidget(vJoyRight);
|
ui->rightStickLayout->addWidget(vJoyRight);
|
||||||
|
|
||||||
timer = new QTimer(this);
|
connect(vJoyLeft, &VirtualJoystickWidget::valueChange, this, &TrainerSimulator::onRadioWidgetValueChange);
|
||||||
timer->setInterval(10);
|
connect(vJoyRight, &VirtualJoystickWidget::valueChange, this, &TrainerSimulator::onRadioWidgetValueChange);
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
|
||||||
|
connect(this, &TrainerSimulator::trainerHeartbeat, simulator, &SimulatorInterface::setTrainerTimeout);
|
||||||
|
connect(this, &TrainerSimulator::trainerChannelChange, simulator, &SimulatorInterface::setTrainerInput);
|
||||||
|
connect(simulator, &SimulatorInterface::started, this, &TrainerSimulator::onSimulatorStarted);
|
||||||
|
connect(simulator, &SimulatorInterface::stopped, this, &TrainerSimulator::onSimulatorStopped);
|
||||||
|
|
||||||
|
timer.setInterval(TRAINERSIMU_HEARTBEAT_PERIOD - 10);
|
||||||
|
connect(&timer, &QTimer::timeout, this, &TrainerSimulator::emitHeartbeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrainerSimulator::~TrainerSimulator()
|
TrainerSimulator::~TrainerSimulator()
|
||||||
{
|
{
|
||||||
if (timer) {
|
|
||||||
timer->stop();
|
|
||||||
delete timer;
|
|
||||||
}
|
|
||||||
if (vJoyLeft)
|
if (vJoyLeft)
|
||||||
delete vJoyLeft;
|
delete vJoyLeft;
|
||||||
if (vJoyRight)
|
if (vJoyRight)
|
||||||
|
@ -60,42 +68,44 @@ TrainerSimulator::~TrainerSimulator()
|
||||||
|
|
||||||
void TrainerSimulator::showEvent(QShowEvent *event)
|
void TrainerSimulator::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
timer->start();
|
start();
|
||||||
event->accept();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerSimulator::closeEvent(QCloseEvent *event)
|
void TrainerSimulator::hideEvent(QHideEvent *event)
|
||||||
{
|
{
|
||||||
timer->stop();
|
stop();
|
||||||
event->accept();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerSimulator::centerSticks()
|
void TrainerSimulator::start()
|
||||||
{
|
{
|
||||||
if (vJoyLeft)
|
timer.start();
|
||||||
vJoyLeft->centerStick();
|
|
||||||
|
|
||||||
if (vJoyRight)
|
|
||||||
vJoyRight->centerStick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerSimulator::onTimerEvent()
|
void TrainerSimulator::stop()
|
||||||
{
|
{
|
||||||
centerSticks();
|
timer.stop();
|
||||||
setTrainerInputs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerSimulator::setTrainerInputs()
|
void TrainerSimulator::onSimulatorStarted()
|
||||||
{
|
{
|
||||||
if (!simulator)
|
m_simuStarted = true;
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (vJoyLeft) {
|
void TrainerSimulator::onSimulatorStopped()
|
||||||
simulator->setTrainerInput(0, int( 512 * vJoyLeft->getStickX())); // LEFT HORZ
|
{
|
||||||
simulator->setTrainerInput(1, int(-512 * vJoyLeft->getStickY())); // LEFT VERT
|
m_simuStarted = false;
|
||||||
}
|
stop();
|
||||||
if (vJoyRight) {
|
}
|
||||||
simulator->setTrainerInput(2, int(-512 * vJoyRight->getStickY())); // RGHT VERT
|
|
||||||
simulator->setTrainerInput(3, int( 512 * vJoyRight->getStickX())); // RGHT HORZ
|
void TrainerSimulator::emitHeartbeat()
|
||||||
|
{
|
||||||
|
emit trainerHeartbeat(TRAINERSIMU_HEARTBEAT_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrainerSimulator::onRadioWidgetValueChange(RadioWidget::RadioWidgetType type, int index, int value)
|
||||||
|
{
|
||||||
|
if (type == RadioWidget::RADIO_WIDGET_STICK && m_simuStarted && timer.isActive()) {
|
||||||
|
emit trainerChannelChange(index, value);
|
||||||
|
emitHeartbeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include "radiowidget.h"
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -42,21 +43,27 @@ class TrainerSimulator : public QWidget
|
||||||
explicit TrainerSimulator(QWidget * parent, SimulatorInterface * simulator);
|
explicit TrainerSimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||||
virtual ~TrainerSimulator();
|
virtual ~TrainerSimulator();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void trainerHeartbeat(quint16 ms);
|
||||||
|
void trainerChannelChange(quint8 index, qint16 value);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
virtual void showEvent(QShowEvent *event);
|
virtual void showEvent(QShowEvent *event);
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void hideEvent(QHideEvent *event);
|
||||||
void centerSticks();
|
void onSimulatorStarted();
|
||||||
void setTrainerInputs();
|
void onSimulatorStopped();
|
||||||
void onTimerEvent();
|
void onRadioWidgetValueChange(RadioWidget::RadioWidgetType type, int index, int value);
|
||||||
|
void emitHeartbeat();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Ui::TrainerSimulator * ui;
|
Ui::TrainerSimulator * ui;
|
||||||
QTimer * timer;
|
|
||||||
SimulatorInterface *simulator;
|
SimulatorInterface *simulator;
|
||||||
|
|
||||||
VirtualJoystickWidget * vJoyLeft;
|
VirtualJoystickWidget * vJoyLeft;
|
||||||
VirtualJoystickWidget * vJoyRight;
|
VirtualJoystickWidget * vJoyRight;
|
||||||
|
QTimer timer;
|
||||||
|
bool m_simuStarted;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,47 +22,12 @@
|
||||||
#define _BUTTONSWIDGET_H_
|
#define _BUTTONSWIDGET_H_
|
||||||
|
|
||||||
#include "radiouiaction.h"
|
#include "radiouiaction.h"
|
||||||
|
#include "radiokeywidget.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
class Area : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Area(const QPolygon & polygon, const QString &image, RadioUiAction * action = NULL, QObject * parent = NULL):
|
|
||||||
QObject(parent),
|
|
||||||
polygon(polygon),
|
|
||||||
imgFile(image),
|
|
||||||
action(action)
|
|
||||||
{
|
|
||||||
if (action)
|
|
||||||
connect(action, &RadioUiAction::toggled, this, &Area::onActionToggled);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(int x, int y)
|
|
||||||
{
|
|
||||||
return polygon.containsPoint(QPoint(x, y), Qt::OddEvenFill);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onActionToggled(int, bool active)
|
|
||||||
{
|
|
||||||
if (active)
|
|
||||||
emit imageChanged(imgFile);
|
|
||||||
else
|
|
||||||
emit imageChanged("");
|
|
||||||
}
|
|
||||||
|
|
||||||
QPolygon polygon;
|
|
||||||
QString imgFile;
|
|
||||||
RadioUiAction * action;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void imageChanged(const QString image);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ButtonsWidget : public QWidget
|
class ButtonsWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -80,18 +45,17 @@ class ButtonsWidget : public QWidget
|
||||||
QWidget::setStyleSheet(sheet);
|
QWidget::setStyleSheet(sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addArea(int x1, int y1, int x2, int y2, const char * image, RadioUiAction * action = NULL)
|
RadioKeyWidget * addArea(const QRect & rect, const char * image, RadioUiAction * action = NULL)
|
||||||
{
|
{
|
||||||
QPolygon polygon;
|
return addArea(QPolygon(rect), image, action);
|
||||||
polygon.setPoints(4, x1, y1, x1, y2, x2, y2, x2, y1);
|
|
||||||
addArea(polygon, image, action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addArea(const QPolygon & polygon, const char * image, RadioUiAction * action = NULL)
|
RadioKeyWidget * addArea(const QPolygon & polygon, const char * image, RadioUiAction * action = NULL)
|
||||||
{
|
{
|
||||||
Area * area = new Area(polygon, image, action, this);
|
RadioKeyWidget * btn = new RadioKeyWidget(polygon, image, action, this);
|
||||||
areas.push_back(area);
|
m_buttons.append(btn);
|
||||||
connect(area, &Area::imageChanged, this, &ButtonsWidget::setBitmap);
|
connect(btn, &RadioKeyWidget::imageChanged, this, &ButtonsWidget::setBitmap);
|
||||||
|
return btn;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -113,16 +77,14 @@ class ButtonsWidget : public QWidget
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(Area * area, areas) {
|
foreach(RadioKeyWidget * key, m_buttons) {
|
||||||
if (!area->action)
|
if (key->contains(event->pos())) {
|
||||||
continue;
|
key->toggle(press);
|
||||||
if (area->contains(event->x(), event->y())) {
|
|
||||||
area->action->trigger(press);
|
|
||||||
event->accept();
|
event->accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (area->action->isActive()) {
|
else if (key->getValue()) {
|
||||||
area->action->trigger(false);
|
key->toggle(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event->ignore();
|
event->ignore();
|
||||||
|
@ -145,7 +107,7 @@ class ButtonsWidget : public QWidget
|
||||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Area *> areas;
|
QList<RadioKeyWidget *> m_buttons;
|
||||||
QString defaultStyleSheet;
|
QString defaultStyleSheet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
100
companion/src/simulation/widgets/radiokeywidget.h
Normal file
100
companion/src/simulation/widgets/radiokeywidget.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RADIOKEYWIDGET_H
|
||||||
|
#define RADIOKEYWIDGET_H
|
||||||
|
|
||||||
|
#include "radiouiaction.h"
|
||||||
|
#include "radiowidget.h"
|
||||||
|
|
||||||
|
class RadioKeyWidget : public RadioWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit RadioKeyWidget(const QPolygon & polygon, const QString &image, RadioUiAction * action = NULL, QWidget * parent = NULL, Qt::WindowFlags f = Qt::WindowFlags()):
|
||||||
|
RadioWidget(action, parent, f),
|
||||||
|
polygon(polygon),
|
||||||
|
imgFile(image)
|
||||||
|
{
|
||||||
|
m_type = RADIO_WIDGET_KEY;
|
||||||
|
setValue(0);
|
||||||
|
hide(); // we're a "virtual" button for now
|
||||||
|
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setAction(RadioUiAction * action)
|
||||||
|
{
|
||||||
|
if (m_action)
|
||||||
|
disconnect(m_action, 0, this, 0);
|
||||||
|
RadioWidget::setAction(action);
|
||||||
|
if (m_action)
|
||||||
|
connect(m_action, &RadioUiAction::toggled, this, &RadioKeyWidget::onActionToggled);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getValue() const
|
||||||
|
{
|
||||||
|
return (m_action && m_action->isActive()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void press() {
|
||||||
|
if (m_action)
|
||||||
|
m_action->trigger(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release() {
|
||||||
|
if (m_action)
|
||||||
|
m_action->trigger(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggle(bool down)
|
||||||
|
{
|
||||||
|
if (down)
|
||||||
|
press();
|
||||||
|
else
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const QPoint & point)
|
||||||
|
{
|
||||||
|
return polygon.containsPoint(point, Qt::OddEvenFill);
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void imageChanged(const QString image);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void onActionToggled(int index, bool active)
|
||||||
|
{
|
||||||
|
RadioWidget::onActionToggled(index, active);
|
||||||
|
emit imageChanged(active ? imgFile : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygon polygon;
|
||||||
|
QString imgFile;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RADIOKEYWIDGET_H
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include <QDial>
|
#include <QDial>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QDebug>
|
#include <QToolTip>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
class RadioKnobWidget : public RadioWidget
|
class RadioKnobWidget : public RadioWidget
|
||||||
|
@ -65,7 +65,6 @@ class RadioKnobWidget : public RadioWidget
|
||||||
|
|
||||||
Board::PotType m_potType;
|
Board::PotType m_potType;
|
||||||
|
|
||||||
|
|
||||||
class KnobWidget : public QDial
|
class KnobWidget : public QDial
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -73,6 +72,8 @@ class RadioKnobWidget : public RadioWidget
|
||||||
explicit KnobWidget(Board::PotType type, QWidget * parent = 0):
|
explicit KnobWidget(Board::PotType type, QWidget * parent = 0):
|
||||||
QDial(parent)
|
QDial(parent)
|
||||||
{
|
{
|
||||||
|
m_toolTip = tr("<p>Value (input): <b>%1</b></p>");
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
setFixedSize(QSize(42, 42));
|
setFixedSize(QSize(42, 42));
|
||||||
setNotchesVisible(true);
|
setNotchesVisible(true);
|
||||||
|
@ -88,7 +89,7 @@ class RadioKnobWidget : public RadioWidget
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_stepSize = 1;
|
m_stepSize = 1;
|
||||||
setToolTip(tr("Right-double-click to reset to center."));
|
m_toolTip.append(tr("Right-double-click to reset to center."));
|
||||||
setMinimum(-1024);
|
setMinimum(-1024);
|
||||||
setMaximum(1024);
|
setMaximum(1024);
|
||||||
setPageStep(128);
|
setPageStep(128);
|
||||||
|
@ -104,6 +105,19 @@ class RadioKnobWidget : public RadioWidget
|
||||||
QDial::setValue(value);
|
QDial::setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool event(QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::ToolTip) {
|
||||||
|
QHelpEvent * helpEvent = static_cast<QHelpEvent *>(event);
|
||||||
|
if (helpEvent) {
|
||||||
|
QToolTip::showText(helpEvent->globalPos(), m_toolTip.arg(this->value()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent * event)
|
void mousePressEvent(QMouseEvent * event)
|
||||||
{
|
{
|
||||||
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||||
|
@ -129,6 +143,7 @@ class RadioKnobWidget : public RadioWidget
|
||||||
}
|
}
|
||||||
|
|
||||||
quint16 m_stepSize;
|
quint16 m_stepSize;
|
||||||
|
QString m_toolTip;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -110,9 +110,8 @@ class RadioSwitchWidget : public RadioWidget
|
||||||
void setToggleLocked(bool lock)
|
void setToggleLocked(bool lock)
|
||||||
{
|
{
|
||||||
if (m_flags != (quint16)lock) {
|
if (m_flags != (quint16)lock) {
|
||||||
m_flags = lock;
|
setFlags((quint16)lock);
|
||||||
setValue((int)lock);
|
setValue((int)lock);
|
||||||
emit flagsChanged(m_flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define _RADIOTRIMWIDGET_H_
|
#define _RADIOTRIMWIDGET_H_
|
||||||
|
|
||||||
#include "radiowidget.h"
|
#include "radiowidget.h"
|
||||||
|
#include "boards.h"
|
||||||
#include "sliderwidget.h"
|
#include "sliderwidget.h"
|
||||||
|
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
|
@ -38,12 +39,6 @@ class RadioTrimWidget : public RadioWidget
|
||||||
{
|
{
|
||||||
init(orientation);
|
init(orientation);
|
||||||
}
|
}
|
||||||
explicit RadioTrimWidget(const QString & labelText, Qt::Orientation orientation = Qt::Vertical, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
|
|
||||||
RadioWidget(labelText, value, parent, f),
|
|
||||||
m_slider(NULL)
|
|
||||||
{
|
|
||||||
init(orientation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIndices(int sliderIdx = -1, int decrBtnIdx = -1, int incrBtnIdx = -1)
|
void setIndices(int sliderIdx = -1, int decrBtnIdx = -1, int incrBtnIdx = -1)
|
||||||
{
|
{
|
||||||
|
@ -58,11 +53,27 @@ class RadioTrimWidget : public RadioWidget
|
||||||
m_slider->setRange(min, max);
|
m_slider->setRange(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
void setTrimRangeQual(const int index, const int min, const int max)
|
||||||
|
{
|
||||||
|
if (index == m_index || index == Board::TRIM_AXIS_COUNT)
|
||||||
|
setTrimRange(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
void trimButtonPressed(int index);
|
void setTrimValue(const int index, const int value)
|
||||||
void trimButtonReleased(int index);
|
{
|
||||||
void trimSliderMoved(int index, int value);
|
if (index == m_index || index == Board::TRIM_AXIS_COUNT)
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(const int & value)
|
||||||
|
{
|
||||||
|
if (sender() && qobject_cast<SliderWidget *>(sender())) {
|
||||||
|
RadioWidget::setValue(value);
|
||||||
|
}
|
||||||
|
else if (m_slider) {
|
||||||
|
m_slider->setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
|
@ -75,20 +86,20 @@ class RadioTrimWidget : public RadioWidget
|
||||||
setTrimRange(-125, 125);
|
setTrimRange(-125, 125);
|
||||||
setIndices();
|
setIndices();
|
||||||
|
|
||||||
QSize btnIcnSz(12, 12);
|
const QSize btnSz(18, 18);
|
||||||
QWidget * trimWidget = new QWidget(this);
|
QWidget * trimWidget = new QWidget(this);
|
||||||
QBoxLayout * trimLayout = new QVBoxLayout(trimWidget);
|
QBoxLayout * trimLayout = new QVBoxLayout(trimWidget);
|
||||||
trimLayout->setSpacing(5);
|
trimLayout->setSpacing(4);
|
||||||
trimLayout->setContentsMargins(8, 8, 8, 8);
|
|
||||||
QToolButton * trimBtnInc = new QToolButton(trimWidget);
|
QToolButton * trimBtnInc = new QToolButton(trimWidget);
|
||||||
trimBtnInc->setIconSize(btnIcnSz);
|
trimBtnInc->setMaximumSize(btnSz);
|
||||||
QToolButton * trimBtnDec = new QToolButton(trimWidget);
|
QToolButton * trimBtnDec = new QToolButton(trimWidget);
|
||||||
trimBtnDec->setIconSize(btnIcnSz);
|
trimBtnDec->setMaximumSize(btnSz);
|
||||||
|
|
||||||
Qt::Alignment algn;
|
Qt::Alignment algn;
|
||||||
if (orientation == Qt::Horizontal) {
|
if (orientation == Qt::Horizontal) {
|
||||||
trimWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
trimWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
trimLayout->setDirection(QBoxLayout::RightToLeft);
|
trimLayout->setDirection(QBoxLayout::RightToLeft);
|
||||||
|
trimLayout->setContentsMargins(0, 8, 0, 8);
|
||||||
trimBtnInc->setArrowType(Qt::RightArrow);
|
trimBtnInc->setArrowType(Qt::RightArrow);
|
||||||
trimBtnDec->setArrowType(Qt::LeftArrow);
|
trimBtnDec->setArrowType(Qt::LeftArrow);
|
||||||
algn = Qt::AlignVCenter;
|
algn = Qt::AlignVCenter;
|
||||||
|
@ -96,6 +107,7 @@ class RadioTrimWidget : public RadioWidget
|
||||||
else {
|
else {
|
||||||
trimWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
trimWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
trimLayout->setDirection(QBoxLayout::TopToBottom);
|
trimLayout->setDirection(QBoxLayout::TopToBottom);
|
||||||
|
trimLayout->setContentsMargins(8, 0, 8, 0);
|
||||||
trimBtnInc->setArrowType(Qt::UpArrow);
|
trimBtnInc->setArrowType(Qt::UpArrow);
|
||||||
trimBtnDec->setArrowType(Qt::DownArrow);
|
trimBtnDec->setArrowType(Qt::DownArrow);
|
||||||
algn = Qt::AlignHCenter;
|
algn = Qt::AlignHCenter;
|
||||||
|
@ -107,21 +119,11 @@ class RadioTrimWidget : public RadioWidget
|
||||||
|
|
||||||
setWidget(trimWidget, algn);
|
setWidget(trimWidget, algn);
|
||||||
|
|
||||||
connect(m_slider, &SliderWidget::valueChanged, this, &RadioWidget::setValue);
|
connect(m_slider, &SliderWidget::valueChanged, this, &RadioTrimWidget::setValue);
|
||||||
connect(this, &RadioWidget::valueChanged, this, &RadioTrimWidget::onValueChanged);
|
connect(trimBtnInc, &QToolButton::pressed, [this]() { emit valueChange(m_type, m_btnIncIndex, RADIO_TRIM_BTN_ON); });
|
||||||
|
connect(trimBtnInc, &QToolButton::released, [this]() { emit valueChange(m_type, m_btnIncIndex, RADIO_TRIM_BTN_OFF); });
|
||||||
connect(trimBtnInc, &QToolButton::pressed, [this]() { emit trimButtonPressed(m_btnIncIndex); });
|
connect(trimBtnDec, &QToolButton::pressed, [this]() { emit valueChange(m_type, m_btnDecIndex, RADIO_TRIM_BTN_ON); });
|
||||||
connect(trimBtnInc, &QToolButton::released, [this]() { emit trimButtonReleased(m_btnIncIndex); });
|
connect(trimBtnDec, &QToolButton::released, [this]() { emit valueChange(m_type, m_btnDecIndex, RADIO_TRIM_BTN_OFF); });
|
||||||
connect(trimBtnDec, &QToolButton::pressed, [this]() { emit trimButtonPressed(m_btnDecIndex); });
|
|
||||||
connect(trimBtnDec, &QToolButton::released, [this]() { emit trimButtonReleased(m_btnDecIndex); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValueChanged(int value)
|
|
||||||
{
|
|
||||||
m_slider->blockSignals(true);
|
|
||||||
m_slider->setValue(value);
|
|
||||||
m_slider->blockSignals(false);
|
|
||||||
emit trimSliderMoved(m_index, m_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -130,5 +132,4 @@ class RadioTrimWidget : public RadioWidget
|
||||||
int m_btnIncIndex;
|
int m_btnIncIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _RADIOTRIMWIDGET_H_
|
#endif // _RADIOTRIMWIDGET_H_
|
||||||
|
|
|
@ -18,51 +18,66 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "radiouiaction.h"
|
||||||
#include "radiowidget.h"
|
#include "radiowidget.h"
|
||||||
|
|
||||||
RadioWidget::RadioWidget(QWidget * parent, Qt::WindowFlags f) :
|
RadioWidget::RadioWidget(QWidget * parent, Qt::WindowFlags f) :
|
||||||
QWidget(parent, f),
|
QWidget(parent, f),
|
||||||
|
m_gridLayout(NULL),
|
||||||
|
m_controlWidget(NULL),
|
||||||
|
m_nameLabel(NULL),
|
||||||
|
m_action(NULL),
|
||||||
m_value(0),
|
m_value(0),
|
||||||
m_flags(0),
|
m_flags(0),
|
||||||
m_invertValue(false),
|
m_valueReset(false),
|
||||||
m_showLabel(false),
|
m_showLabel(false),
|
||||||
m_labelText(""),
|
m_labelText("")
|
||||||
m_type(RADIO_WIDGET_NONE)
|
|
||||||
{
|
{
|
||||||
init();
|
qRegisterMetaType<RadioWidgetState>();
|
||||||
|
setIndex(-1);
|
||||||
|
setType(RADIO_WIDGET_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioWidget::RadioWidget(RadioUiAction * action, QWidget * parent, Qt::WindowFlags f) :
|
||||||
|
RadioWidget(parent, f)
|
||||||
|
{
|
||||||
|
setAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioWidget::RadioWidget(const QString & labelText, int value, QWidget * parent, Qt::WindowFlags f) :
|
RadioWidget::RadioWidget(const QString & labelText, int value, QWidget * parent, Qt::WindowFlags f) :
|
||||||
QWidget(parent, f),
|
RadioWidget(parent, f)
|
||||||
m_value(value),
|
|
||||||
m_flags(0),
|
|
||||||
m_invertValue(false),
|
|
||||||
m_showLabel(true),
|
|
||||||
m_labelText(labelText),
|
|
||||||
m_type(RADIO_WIDGET_NONE)
|
|
||||||
{
|
{
|
||||||
init();
|
setValue(value);
|
||||||
|
setLabelText(labelText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setIndex(int index)
|
void RadioWidget::setIndex(const int & index)
|
||||||
{
|
{
|
||||||
m_index = index;
|
m_index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setInvertValue(bool invertValue)
|
void RadioWidget::setType(const RadioWidgetType & type)
|
||||||
{
|
{
|
||||||
m_invertValue = invertValue;
|
m_type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setValue(int value)
|
void RadioWidget::setValue(const int & value)
|
||||||
{
|
{
|
||||||
if (value != m_value) {
|
if (value != m_value || m_valueReset) {
|
||||||
m_value = value;
|
m_value = value;
|
||||||
|
m_valueReset = false;
|
||||||
emit valueChanged(value);
|
emit valueChanged(value);
|
||||||
|
emit valueChange(m_type, m_index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setFlags(quint16 flags)
|
void RadioWidget::setValueQual(const RadioWidget::RadioWidgetType & type, const int & index, const int & value)
|
||||||
|
{
|
||||||
|
if (type == m_type && index == m_index)
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioWidget::setFlags(const quint16 & flags)
|
||||||
{
|
{
|
||||||
if (flags != m_flags) {
|
if (flags != m_flags) {
|
||||||
m_flags = flags;
|
m_flags = flags;
|
||||||
|
@ -70,7 +85,7 @@ void RadioWidget::setFlags(quint16 flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setShowLabel(bool show)
|
void RadioWidget::setShowLabel(const bool show)
|
||||||
{
|
{
|
||||||
if (show != m_showLabel) {
|
if (show != m_showLabel) {
|
||||||
m_showLabel = show;
|
m_showLabel = show;
|
||||||
|
@ -85,13 +100,12 @@ void RadioWidget::setLabelText(const QString & labelText, bool showLabel)
|
||||||
addLabel();
|
addLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::setStateData(const QByteArray & data)
|
void RadioWidget::setStateData(const RadioWidgetState & state)
|
||||||
{
|
{
|
||||||
RadioWidgetState state;
|
if (state.type != m_type || state.index != m_index)
|
||||||
QDataStream stream(data);
|
return;
|
||||||
stream >> state;
|
|
||||||
|
|
||||||
//setIndex(state.index);
|
m_valueReset = true;
|
||||||
setValue(state.value);
|
setValue(state.value);
|
||||||
setFlags(state.flags);
|
setFlags(state.flags);
|
||||||
}
|
}
|
||||||
|
@ -109,9 +123,26 @@ void RadioWidget::changeVisibility(bool visible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RadioWidget::setAction(RadioUiAction * action)
|
||||||
|
{
|
||||||
|
if (m_action) {
|
||||||
|
disconnect(m_action, 0, this, 0);
|
||||||
|
delete m_action;
|
||||||
|
m_action = NULL;
|
||||||
|
}
|
||||||
|
m_action = action;
|
||||||
|
|
||||||
|
if (m_action) {
|
||||||
|
if (m_action->getIndex() > -1)
|
||||||
|
setIndex(m_action->getIndex());
|
||||||
|
connect(m_action, &RadioUiAction::toggled, this, &RadioWidget::onActionToggled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RadioWidget::getValue() const
|
int RadioWidget::getValue() const
|
||||||
{
|
{
|
||||||
return m_value * (m_invertValue ? -1 : 1);
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RadioWidget::getIndex() const
|
int RadioWidget::getIndex() const
|
||||||
|
@ -134,25 +165,34 @@ QByteArray RadioWidget::getStateData() const
|
||||||
|
|
||||||
RadioWidget::RadioWidgetState RadioWidget::getState() const
|
RadioWidget::RadioWidgetState RadioWidget::getState() const
|
||||||
{
|
{
|
||||||
return RadioWidgetState(quint8(m_type), qint8(m_index), qint16(m_value), quint16(m_flags));;
|
return RadioWidgetState(quint8(m_type), qint8(m_index), qint16(m_value), quint16(m_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::init()
|
RadioUiAction * RadioWidget::getAction() const
|
||||||
{
|
{
|
||||||
setIndex(0);
|
return m_action;
|
||||||
m_controlWidget = NULL;
|
}
|
||||||
m_nameLabel = NULL;
|
|
||||||
|
|
||||||
m_gridLayout= new QGridLayout(this);
|
void RadioWidget::onActionToggled(int index, bool active)
|
||||||
|
{
|
||||||
|
emit valueChange(m_type, index, getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RadioWidget::addLayout()
|
||||||
|
{
|
||||||
|
if (m_gridLayout)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_gridLayout = new QGridLayout(this);
|
||||||
m_gridLayout->setContentsMargins(0, 0, 0, 0);
|
m_gridLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
m_gridLayout->setVerticalSpacing(4);
|
m_gridLayout->setVerticalSpacing(4);
|
||||||
m_gridLayout->setHorizontalSpacing(0);
|
m_gridLayout->setHorizontalSpacing(0);
|
||||||
|
|
||||||
addLabel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioWidget::addLabel()
|
void RadioWidget::addLabel()
|
||||||
{
|
{
|
||||||
|
addLayout();
|
||||||
if (m_nameLabel) {
|
if (m_nameLabel) {
|
||||||
m_gridLayout->removeWidget(m_nameLabel);
|
m_gridLayout->removeWidget(m_nameLabel);
|
||||||
m_nameLabel->deleteLater();
|
m_nameLabel->deleteLater();
|
||||||
|
@ -168,6 +208,7 @@ void RadioWidget::addLabel()
|
||||||
|
|
||||||
void RadioWidget::setWidget(QWidget * widget, Qt::Alignment align)
|
void RadioWidget::setWidget(QWidget * widget, Qt::Alignment align)
|
||||||
{
|
{
|
||||||
|
addLayout();
|
||||||
if (m_controlWidget) {
|
if (m_controlWidget) {
|
||||||
m_gridLayout->removeWidget(m_controlWidget);
|
m_gridLayout->removeWidget(m_controlWidget);
|
||||||
m_controlWidget->deleteLater();
|
m_controlWidget->deleteLater();
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#define RADIO_WIDGET_STATE_VERSION 1
|
#define RADIO_WIDGET_STATE_VERSION 1
|
||||||
|
|
||||||
|
class RadioUiAction;
|
||||||
|
|
||||||
class RadioWidget : public QWidget
|
class RadioWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -41,10 +43,14 @@ class RadioWidget : public QWidget
|
||||||
RADIO_WIDGET_SWITCH,
|
RADIO_WIDGET_SWITCH,
|
||||||
RADIO_WIDGET_KNOB,
|
RADIO_WIDGET_KNOB,
|
||||||
RADIO_WIDGET_FADER,
|
RADIO_WIDGET_FADER,
|
||||||
RADIO_WIDGET_TRIM,
|
RADIO_WIDGET_TRIM, // trim axis, usually 2 buttons & slider
|
||||||
RADIO_WIDGET_STICK // actually one axis of a stick
|
RADIO_WIDGET_STICK, // actually one axis of a stick
|
||||||
|
RADIO_WIDGET_KEY, // UI key/pushbutton
|
||||||
|
RADIO_WIDGET_ENUM_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RadioTrimWidgetButtonStates { RADIO_TRIM_BTN_ON = 1024, RADIO_TRIM_BTN_OFF = -1024 };
|
||||||
|
|
||||||
struct RadioWidgetState {
|
struct RadioWidgetState {
|
||||||
public:
|
public:
|
||||||
RadioWidgetState(quint8 type = 0, qint8 index = 0, qint16 value = 0, quint16 flags = 0) :
|
RadioWidgetState(quint8 type = 0, qint8 index = 0, qint16 value = 0, quint16 flags = 0) :
|
||||||
|
@ -65,49 +71,58 @@ class RadioWidget : public QWidget
|
||||||
quint8 _version = RADIO_WIDGET_STATE_VERSION; // structure definition version
|
quint8 _version = RADIO_WIDGET_STATE_VERSION; // structure definition version
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit RadioWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
explicit RadioWidget(QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||||
explicit RadioWidget(const QString &labelText, int value = 0, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
explicit RadioWidget(RadioUiAction * action = NULL, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||||
|
explicit RadioWidget(const QString & labelText, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||||
void setIndex(int index);
|
|
||||||
void setInvertValue(bool invertValue);
|
|
||||||
void setValue(int value);
|
|
||||||
void setFlags(quint16 flags);
|
|
||||||
void setShowLabel(bool show);
|
|
||||||
void setLabelText(const QString &labelText, bool showLabel = true);
|
|
||||||
void setStateData(const QByteArray & data);
|
|
||||||
void changeVisibility(bool visible);
|
|
||||||
|
|
||||||
virtual int getValue() const;
|
virtual int getValue() const;
|
||||||
int getIndex() const;
|
virtual int getIndex() const;
|
||||||
int getType() const;
|
virtual int getType() const;
|
||||||
QByteArray getStateData() const;
|
virtual QByteArray getStateData() const;
|
||||||
RadioWidgetState getState() const;
|
virtual RadioWidgetState getState() const;
|
||||||
|
virtual RadioUiAction * getAction() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
virtual void setIndex(const int & index);
|
||||||
|
virtual void setType(const RadioWidgetType & type);
|
||||||
|
virtual void setValue(const int & value);
|
||||||
|
virtual void setValueQual(const RadioWidgetType & type, const int & index, const int & value);
|
||||||
|
virtual void setFlags(const quint16 & flags);
|
||||||
|
virtual void setShowLabel(const bool show);
|
||||||
|
virtual void setLabelText(const QString & labelText, bool showLabel = true);
|
||||||
|
virtual void setStateData(const RadioWidgetState & state);
|
||||||
|
virtual void changeVisibility(bool visible);
|
||||||
|
virtual void setAction(RadioUiAction * action);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void valueChange(const RadioWidgetType type, const int index, int value);
|
||||||
|
void valueChanged(const int value);
|
||||||
|
void flagsChanged(const quint16 flags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void init();
|
void addLayout();
|
||||||
void addLabel();
|
void addLabel();
|
||||||
void setWidget(QWidget * widget = NULL, Qt::Alignment align = Qt::AlignHCenter);
|
void setWidget(QWidget * widget = NULL, Qt::Alignment align = Qt::AlignHCenter);
|
||||||
|
virtual void onActionToggled(int index, bool active);
|
||||||
int m_value;
|
|
||||||
int m_index;
|
|
||||||
quint16 m_flags;
|
|
||||||
bool m_invertValue;
|
|
||||||
bool m_showLabel;
|
|
||||||
QString m_labelText;
|
|
||||||
RadioWidgetType m_type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
QGridLayout * m_gridLayout;
|
QGridLayout * m_gridLayout;
|
||||||
QWidget * m_controlWidget;
|
QWidget * m_controlWidget;
|
||||||
QLabel * m_nameLabel;
|
QLabel * m_nameLabel;
|
||||||
|
RadioUiAction * m_action;
|
||||||
|
|
||||||
signals:
|
int m_value;
|
||||||
|
int m_index;
|
||||||
void valueChanged(int value);
|
quint16 m_flags;
|
||||||
void flagsChanged(quint16 flags);
|
bool m_valueReset;
|
||||||
|
bool m_showLabel;
|
||||||
|
QString m_labelText;
|
||||||
|
RadioWidgetType m_type;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(RadioWidget::RadioWidgetState)
|
||||||
|
|
||||||
#endif // _RADIOWIDGET_H_
|
#endif // _RADIOWIDGET_H_
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
class SliderWidget : public QSlider
|
class SliderWidget : public QSlider
|
||||||
{
|
{
|
||||||
|
@ -33,20 +34,34 @@ class SliderWidget : public QSlider
|
||||||
explicit SliderWidget(QWidget * parent = 0):
|
explicit SliderWidget(QWidget * parent = 0):
|
||||||
QSlider(parent)
|
QSlider(parent)
|
||||||
{
|
{
|
||||||
setToolTip(tr("Right-double-click to reset to center."));
|
m_toolTip = tr("<p>Value (input): <b>%1</b></p>") % tr("Right-double-click to reset to center.");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent * event)
|
bool event(QEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
if (event->type() == QEvent::ToolTip) {
|
||||||
setValue(0);
|
QHelpEvent * helpEvent = static_cast<QHelpEvent *>(event);
|
||||||
emit sliderMoved(0);
|
if (helpEvent) {
|
||||||
event->accept();
|
QToolTip::showText(helpEvent->globalPos(), m_toolTip.arg(this->value()));
|
||||||
}
|
return true;
|
||||||
QSlider::mousePressEvent(event);
|
}
|
||||||
}
|
}
|
||||||
|
return QWidget::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent * event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||||
|
setValue(0);
|
||||||
|
emit sliderMoved(0);
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
QSlider::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString m_toolTip;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _SLIDERWIDGET_H_
|
#endif // _SLIDERWIDGET_H_
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
#define GBALL_SIZE 25
|
#define GBALL_SIZE 25
|
||||||
#define GBALL_SIZE_MN 20
|
#define GBALL_SIZE_MN 20
|
||||||
#define GBALL_SIZE_MX 35
|
#define GBALL_SIZE_MX 35
|
||||||
|
#define CENTER_INTERVAL 50 // ms
|
||||||
|
|
||||||
#include "virtualjoystickwidget.h"
|
#include "virtualjoystickwidget.h"
|
||||||
|
|
||||||
#include "boards.h"
|
#include "boards.h"
|
||||||
#include "constants.h"
|
|
||||||
#include "modeledit/node.h"
|
#include "modeledit/node.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "radiotrimwidget.h"
|
#include "radiotrimwidget.h"
|
||||||
|
@ -43,6 +43,7 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
||||||
btnFixY(NULL),
|
btnFixY(NULL),
|
||||||
nodeLabelX(NULL),
|
nodeLabelX(NULL),
|
||||||
nodeLabelY(NULL),
|
nodeLabelY(NULL),
|
||||||
|
m_stickScale(1024),
|
||||||
m_stickPressed(false)
|
m_stickPressed(false)
|
||||||
{
|
{
|
||||||
ar = (float)size.width() / size.height();
|
ar = (float)size.width() / size.height();
|
||||||
|
@ -135,12 +136,18 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
||||||
layout->addItem(new QSpacerItem(0, 0), 1, 4, 2, 1); // r1-2 c4: right h spacer
|
layout->addItem(new QSpacerItem(0, 0), 1, 4, 2, 1); // r1-2 c4: right h spacer
|
||||||
layout->addItem(new QSpacerItem(0, 0), 3, 0, 1, 5); // r4 c0-4: bot v spacer
|
layout->addItem(new QSpacerItem(0, 0), 3, 0, 1, 5); // r4 c0-4: bot v spacer
|
||||||
|
|
||||||
connect(node, &Node::xChanged, this, &VirtualJoystickWidget::updateNodeValueLabels);
|
setStickIndices(getStickIndex('H'), getStickIndex('V'));
|
||||||
connect(node, &Node::yChanged, this, &VirtualJoystickWidget::updateNodeValueLabels);
|
|
||||||
|
connect(node, &Node::xChanged, this, &VirtualJoystickWidget::onNodeXChanged);
|
||||||
|
connect(node, &Node::yChanged, this, &VirtualJoystickWidget::onNodeYChanged);
|
||||||
|
|
||||||
connect(scene, &CustomGraphicsScene::mouseEvent, this, &VirtualJoystickWidget::onGsMouseEvent);
|
connect(scene, &CustomGraphicsScene::mouseEvent, this, &VirtualJoystickWidget::onGsMouseEvent);
|
||||||
|
|
||||||
setSize(prefSize, frameSize());
|
setSize(prefSize, frameSize());
|
||||||
|
|
||||||
|
centerStickTimer.setInterval(CENTER_INTERVAL);
|
||||||
|
connect(¢erStickTimer, &QTimer::timeout, this, &VirtualJoystickWidget::centerStick);
|
||||||
|
centerStickTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setStickX(qreal x)
|
void VirtualJoystickWidget::setStickX(qreal x)
|
||||||
|
@ -158,6 +165,31 @@ void VirtualJoystickWidget::setStickPos(QPointF xy)
|
||||||
node->setPos(xy);
|
node->setPos(xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setStickAxisValue(int index, int value)
|
||||||
|
{
|
||||||
|
using namespace Board;
|
||||||
|
qreal rvalue = value / 1024.0f;
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case STICK_AXIS_LH :
|
||||||
|
if (stickSide == 'L')
|
||||||
|
setStickX(rvalue);
|
||||||
|
break;
|
||||||
|
case STICK_AXIS_RH :
|
||||||
|
if (stickSide == 'R')
|
||||||
|
setStickX(rvalue);
|
||||||
|
break;
|
||||||
|
case STICK_AXIS_LV :
|
||||||
|
if (stickSide == 'L')
|
||||||
|
setStickY(rvalue);
|
||||||
|
break;
|
||||||
|
case STICK_AXIS_RV :
|
||||||
|
if (stickSide == 'R')
|
||||||
|
setStickY(rvalue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::centerStick()
|
void VirtualJoystickWidget::centerStick()
|
||||||
{
|
{
|
||||||
node->stepToCenter();
|
node->stepToCenter();
|
||||||
|
@ -178,20 +210,55 @@ QPointF VirtualJoystickWidget::getStickPos()
|
||||||
return QPointF(node->getX(), node->getY());
|
return QPointF(node->getX(), node->getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setTrimValue(int which, int value)
|
void VirtualJoystickWidget::setTrimsRange(int min, int max)
|
||||||
{
|
{
|
||||||
RadioTrimWidget * trim = getTrimWidget(which);
|
if (hTrimWidget)
|
||||||
|
hTrimWidget->setTrimRange(min, max);
|
||||||
|
if (vTrimWidget)
|
||||||
|
vTrimWidget->setTrimRange(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setTrimsRange(int rng)
|
||||||
|
{
|
||||||
|
setTrimsRange(-rng, rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setTrimRange(int index, int min, int max)
|
||||||
|
{
|
||||||
|
if (index == Board::TRIM_AXIS_COUNT) {
|
||||||
|
setTrimsRange(min, max);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RadioTrimWidget * trim = getTrimWidget(index);
|
||||||
|
if (trim) {
|
||||||
|
trim->setTrimRange(min, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setTrimValue(int index, int value)
|
||||||
|
{
|
||||||
|
RadioTrimWidget * trim = getTrimWidget(index);
|
||||||
if (trim) {
|
if (trim) {
|
||||||
trim->setValue(value);
|
trim->setValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setTrimRange(int which, int min, int max)
|
int VirtualJoystickWidget::getStickScale() const
|
||||||
{
|
{
|
||||||
RadioTrimWidget * trim = getTrimWidget(which);
|
return m_stickScale;
|
||||||
if (trim) {
|
}
|
||||||
trim->setTrimRange(min, max);
|
|
||||||
}
|
void VirtualJoystickWidget::setStickScale(int stickScale)
|
||||||
|
{
|
||||||
|
m_stickScale = stickScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setWidgetValue(const RadioWidget::RadioWidgetType type, const int index, const int value)
|
||||||
|
{
|
||||||
|
if (type == RadioWidget::RADIO_WIDGET_TRIM)
|
||||||
|
setTrimValue(index, value);
|
||||||
|
else if (type == RadioWidget::RADIO_WIDGET_STICK)
|
||||||
|
setStickAxisValue(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int VirtualJoystickWidget::getTrimValue(int which)
|
int VirtualJoystickWidget::getTrimValue(int which)
|
||||||
|
@ -203,27 +270,25 @@ int VirtualJoystickWidget::getTrimValue(int which)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setStickConstraint(int which, bool active)
|
void VirtualJoystickWidget::setStickIndices(int xIdx, int yIdx)
|
||||||
{
|
{
|
||||||
if (btnHoldX == NULL)
|
m_xIndex = xIdx;
|
||||||
|
m_yIndex = yIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::setStickConstraint(quint8 index, bool active)
|
||||||
|
{
|
||||||
|
if (btnHoldX == NULL || !index)
|
||||||
return; // no buttons
|
return; // no buttons
|
||||||
|
|
||||||
switch (which) {
|
if (index & HOLD_X)
|
||||||
case HOLD_X:
|
btnHoldX->setChecked(active);
|
||||||
btnHoldX->setChecked(active);
|
if (index & HOLD_Y)
|
||||||
break;
|
btnHoldY->setChecked(active);
|
||||||
case HOLD_Y:
|
if (index & FIX_X)
|
||||||
btnHoldY->setChecked(active);
|
btnFixX->setChecked(active);
|
||||||
break;
|
if (index & FIX_Y)
|
||||||
case FIX_X:
|
btnFixY->setChecked(active);
|
||||||
btnFixX->setChecked(active);
|
|
||||||
break;
|
|
||||||
case FIX_Y:
|
|
||||||
btnFixY->setChecked(active);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setStickColor(const QColor & color)
|
void VirtualJoystickWidget::setStickColor(const QColor & color)
|
||||||
|
@ -231,6 +296,15 @@ void VirtualJoystickWidget::setStickColor(const QColor & color)
|
||||||
node->setColor(color);
|
node->setColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::loadDefaultsForMode(const unsigned mode)
|
||||||
|
{
|
||||||
|
if (((mode & 1) && stickSide == 'L') || (!(mode & 1) && stickSide == 'R')) {
|
||||||
|
setStickConstraint(HOLD_Y, true);
|
||||||
|
setStickY(1.0);
|
||||||
|
onNodeYChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QSize VirtualJoystickWidget::sizeHint() const {
|
QSize VirtualJoystickWidget::sizeHint() const {
|
||||||
return prefSize;
|
return prefSize;
|
||||||
}
|
}
|
||||||
|
@ -241,6 +315,18 @@ void VirtualJoystickWidget::resizeEvent(QResizeEvent * event)
|
||||||
setSize(event->size(), event->oldSize());
|
setSize(event->size(), event->oldSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::onNodeXChanged()
|
||||||
|
{
|
||||||
|
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_xIndex, int(m_stickScale * getStickX()));
|
||||||
|
updateNodeValueLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualJoystickWidget::onNodeYChanged()
|
||||||
|
{
|
||||||
|
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_yIndex, int(-m_stickScale * getStickY()));
|
||||||
|
updateNodeValueLabels();
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setSize(const QSize & size, const QSize &)
|
void VirtualJoystickWidget::setSize(const QSize & size, const QSize &)
|
||||||
{
|
{
|
||||||
float thisAspectRatio = (float)size.width() / size.height();
|
float thisAspectRatio = (float)size.width() / size.height();
|
||||||
|
@ -301,9 +387,7 @@ RadioTrimWidget * VirtualJoystickWidget::createTrimWidget(QChar type)
|
||||||
RadioTrimWidget * trimWidget = new RadioTrimWidget(type == 'H' ? Qt::Horizontal : Qt::Vertical);
|
RadioTrimWidget * trimWidget = new RadioTrimWidget(type == 'H' ? Qt::Horizontal : Qt::Vertical);
|
||||||
trimWidget->setIndices(getTrimSliderType(type), getTrimButtonType(type, 0), getTrimButtonType(type, 1));
|
trimWidget->setIndices(getTrimSliderType(type), getTrimButtonType(type, 0), getTrimButtonType(type, 1));
|
||||||
|
|
||||||
connect(trimWidget, &RadioTrimWidget::trimButtonPressed, this, &VirtualJoystickWidget::trimButtonPressed);
|
connect(trimWidget, &RadioTrimWidget::valueChange, this, &VirtualJoystickWidget::valueChange);
|
||||||
connect(trimWidget, &RadioTrimWidget::trimButtonReleased, this, &VirtualJoystickWidget::trimButtonReleased);
|
|
||||||
connect(trimWidget, &RadioTrimWidget::trimSliderMoved, this, &VirtualJoystickWidget::trimSliderMoved);
|
|
||||||
|
|
||||||
return trimWidget;
|
return trimWidget;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +455,24 @@ QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valL
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VirtualJoystickWidget::getStickIndex(QChar type)
|
||||||
|
{
|
||||||
|
using namespace Board;
|
||||||
|
|
||||||
|
if (stickSide == 'L') {
|
||||||
|
if (type == 'H')
|
||||||
|
return STICK_AXIS_LH;
|
||||||
|
else
|
||||||
|
return STICK_AXIS_LV;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (type == 'H')
|
||||||
|
return STICK_AXIS_RH;
|
||||||
|
else
|
||||||
|
return STICK_AXIS_RV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int VirtualJoystickWidget::getTrimSliderType(QChar type)
|
int VirtualJoystickWidget::getTrimSliderType(QChar type)
|
||||||
{
|
{
|
||||||
using namespace Board;
|
using namespace Board;
|
||||||
|
@ -426,10 +528,12 @@ int VirtualJoystickWidget::getTrimButtonType(QChar type, int pos)
|
||||||
|
|
||||||
RadioTrimWidget * VirtualJoystickWidget::getTrimWidget(int which)
|
RadioTrimWidget * VirtualJoystickWidget::getTrimWidget(int which)
|
||||||
{
|
{
|
||||||
if (which == Board::TRIM_AXIS_LH || which == Board::TRIM_AXIS_RH)
|
if ((stickSide == 'L' && which == Board::TRIM_AXIS_LH) || (stickSide == 'R' && which == Board::TRIM_AXIS_RH))
|
||||||
return hTrimWidget;
|
return hTrimWidget;
|
||||||
else
|
else if ((stickSide == 'L' && which == Board::TRIM_AXIS_LV) || (stickSide == 'R' && which == Board::TRIM_AXIS_RV))
|
||||||
return vTrimWidget;
|
return vTrimWidget;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::onButtonChange(bool checked)
|
void VirtualJoystickWidget::onButtonChange(bool checked)
|
||||||
|
@ -456,9 +560,9 @@ void VirtualJoystickWidget::onButtonChange(bool checked)
|
||||||
void VirtualJoystickWidget::updateNodeValueLabels()
|
void VirtualJoystickWidget::updateNodeValueLabels()
|
||||||
{
|
{
|
||||||
if (nodeLabelX)
|
if (nodeLabelX)
|
||||||
nodeLabelX->setText(QString("%1").arg((qreal)node->getX() * 100 + getTrimValue(0) / 5, 2, 'f', 0));
|
nodeLabelX->setText(QString("%1").arg(node->getX() * 100.0f, 2, 'f', 0));
|
||||||
if (nodeLabelY)
|
if (nodeLabelY)
|
||||||
nodeLabelY->setText(QString("%1").arg((qreal)node->getY() * -100 + getTrimValue(1) / 5, 2, 'f', 0));
|
nodeLabelY->setText(QString("%1").arg(node->getY() * -100.0f, 2, 'f', 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::onGsMouseEvent(QGraphicsSceneMouseEvent * event)
|
void VirtualJoystickWidget::onGsMouseEvent(QGraphicsSceneMouseEvent * event)
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#ifndef VIRTUALJOYSTICKWIDGET_H
|
#ifndef VIRTUALJOYSTICKWIDGET_H
|
||||||
#define VIRTUALJOYSTICKWIDGET_H
|
#define VIRTUALJOYSTICKWIDGET_H
|
||||||
|
|
||||||
|
#include "radiowidget.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
|
@ -28,6 +30,7 @@
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
|
#include <QTimer>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
class CustomGraphicsScene;
|
class CustomGraphicsScene;
|
||||||
|
@ -40,38 +43,47 @@ class VirtualJoystickWidget : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ConstraintTypes {
|
enum ConstraintTypes {
|
||||||
HOLD_X = 0,
|
HOLD_X = 0x01,
|
||||||
HOLD_Y,
|
HOLD_Y = 0x02,
|
||||||
FIX_X,
|
FIX_X = 0x04,
|
||||||
FIX_Y
|
FIX_Y = 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(125, 125));
|
explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(125, 125));
|
||||||
|
|
||||||
void setStickX(qreal x);
|
|
||||||
void setStickY(qreal y);
|
|
||||||
void setStickPos(QPointF xy);
|
|
||||||
void centerStick();
|
|
||||||
qreal getStickX();
|
qreal getStickX();
|
||||||
qreal getStickY();
|
qreal getStickY();
|
||||||
QPointF getStickPos();
|
QPointF getStickPos();
|
||||||
|
|
||||||
void setTrimValue(int which, int value);
|
|
||||||
void setTrimRange(int which, int min, int max);
|
|
||||||
int getTrimValue(int which);
|
int getTrimValue(int which);
|
||||||
|
|
||||||
void setStickConstraint(int which, bool active);
|
|
||||||
void setStickColor(const QColor & color);
|
|
||||||
|
|
||||||
virtual QSize sizeHint() const;
|
virtual QSize sizeHint() const;
|
||||||
virtual void resizeEvent(QResizeEvent *event);
|
virtual void resizeEvent(QResizeEvent *event);
|
||||||
|
|
||||||
|
int getStickScale() const;
|
||||||
|
void setStickScale(int stickScale);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setStickX(qreal x);
|
||||||
|
void setStickY(qreal y);
|
||||||
|
void setStickPos(QPointF xy);
|
||||||
|
void setStickAxisValue(int index, int value);
|
||||||
|
void centerStick();
|
||||||
|
void setTrimsRange(int min, int max);
|
||||||
|
void setTrimsRange(int rng);
|
||||||
|
void setTrimRange(int index, int min, int max);
|
||||||
|
void setTrimValue(int index, int value);
|
||||||
|
void setWidgetValue(const RadioWidget::RadioWidgetType type, const int index, const int value);
|
||||||
|
|
||||||
|
void setStickIndices(int xIdx = -1, int yIdx = -1);
|
||||||
|
void setStickConstraint(quint8 index, bool active);
|
||||||
|
void setStickColor(const QColor & color);
|
||||||
|
void loadDefaultsForMode(const unsigned mode);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void trimButtonPressed(int index);
|
void valueChange(const RadioWidget::RadioWidgetType type, const int index, int value);
|
||||||
void trimButtonReleased(int index);
|
|
||||||
void trimSliderMoved(int index, int value);
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
void onNodeXChanged();
|
||||||
|
void onNodeYChanged();
|
||||||
void onButtonChange(bool checked);
|
void onButtonChange(bool checked);
|
||||||
void updateNodeValueLabels();
|
void updateNodeValueLabels();
|
||||||
void onGsMouseEvent(QGraphicsSceneMouseEvent * event);
|
void onGsMouseEvent(QGraphicsSceneMouseEvent * event);
|
||||||
|
@ -81,6 +93,7 @@ class VirtualJoystickWidget : public QWidget
|
||||||
RadioTrimWidget * createTrimWidget(QChar type);
|
RadioTrimWidget * createTrimWidget(QChar type);
|
||||||
QToolButton * createButtonWidget(int type);
|
QToolButton * createButtonWidget(int type);
|
||||||
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
||||||
|
int getStickIndex(QChar type);
|
||||||
int getTrimSliderType(QChar type);
|
int getTrimSliderType(QChar type);
|
||||||
int getTrimButtonType(QChar type, int pos);
|
int getTrimButtonType(QChar type, int pos);
|
||||||
RadioTrimWidget * getTrimWidget(int which);
|
RadioTrimWidget * getTrimWidget(int which);
|
||||||
|
@ -97,7 +110,11 @@ class VirtualJoystickWidget : public QWidget
|
||||||
QToolButton * btnFixX, * btnFixY;
|
QToolButton * btnFixX, * btnFixY;
|
||||||
QLabel * nodeLabelX, * nodeLabelY;
|
QLabel * nodeLabelX, * nodeLabelY;
|
||||||
QSize extraSize;
|
QSize extraSize;
|
||||||
|
QTimer centerStickTimer;
|
||||||
float ar; // aspect ratio
|
float ar; // aspect ratio
|
||||||
|
int m_xIndex;
|
||||||
|
int m_yIndex;
|
||||||
|
int m_stickScale;
|
||||||
bool m_stickPressed;
|
bool m_stickPressed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,7 @@ void evalInputs(uint8_t mode)
|
||||||
if (v < -RESX) v = -RESX;
|
if (v < -RESX) v = -RESX;
|
||||||
if (v > RESX) v = RESX;
|
if (v > RESX) v = RESX;
|
||||||
|
|
||||||
#if defined(PCBTARANIS) && !defined(PCBX7)
|
#if defined(PCBTARANIS) && !defined(PCBX7) && !defined(SIMU)
|
||||||
// TODO why not in the driver?
|
// TODO why not in the driver?
|
||||||
if (i==POT1 || i==SLIDER1) {
|
if (i==POT1 || i==SLIDER1) {
|
||||||
v = -v;
|
v = -v;
|
||||||
|
|
|
@ -68,7 +68,6 @@ uint32_t readTrims()
|
||||||
result |= 0x40;
|
result |= 0x40;
|
||||||
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
|
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
|
||||||
result |= 0x80;
|
result |= 0x80;
|
||||||
#if !defined(SIMU)
|
|
||||||
if (~TRIMS_GPIO_REG_LSD & TRIMS_GPIO_PIN_LSD)
|
if (~TRIMS_GPIO_REG_LSD & TRIMS_GPIO_PIN_LSD)
|
||||||
result |= 0x100;
|
result |= 0x100;
|
||||||
if (~TRIMS_GPIO_REG_LSU & TRIMS_GPIO_PIN_LSU)
|
if (~TRIMS_GPIO_REG_LSU & TRIMS_GPIO_PIN_LSU)
|
||||||
|
@ -77,7 +76,6 @@ uint32_t readTrims()
|
||||||
result |= 0x400;
|
result |= 0x400;
|
||||||
if (~TRIMS_GPIO_REG_RSU & TRIMS_GPIO_PIN_RSU)
|
if (~TRIMS_GPIO_REG_RSU & TRIMS_GPIO_PIN_RSU)
|
||||||
result |= 0x800;
|
result |= 0x800;
|
||||||
#endif
|
|
||||||
// TRACE("readTrims(): result=0x%04x", result);
|
// TRACE("readTrims(): result=0x%04x", result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -164,7 +162,7 @@ uint8_t keyState(uint8_t index)
|
||||||
uint32_t switchState(uint8_t index)
|
uint32_t switchState(uint8_t index)
|
||||||
{
|
{
|
||||||
uint32_t xxx = 0;
|
uint32_t xxx = 0;
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
ADD_3POS_CASE(A, 0);
|
ADD_3POS_CASE(A, 0);
|
||||||
ADD_3POS_CASE(B, 1);
|
ADD_3POS_CASE(B, 1);
|
||||||
|
|
|
@ -26,7 +26,9 @@ if(Qt5Widgets_FOUND)
|
||||||
set(SIMULATOR_TARGET ${SIMULATOR_FLAVOUR}-simulator)
|
set(SIMULATOR_TARGET ${SIMULATOR_FLAVOUR}-simulator)
|
||||||
add_definitions(-DSIMULATOR_FLAVOUR="${SIMULATOR_FLAVOUR}")
|
add_definitions(-DSIMULATOR_FLAVOUR="${SIMULATOR_FLAVOUR}")
|
||||||
include_directories(${COMPANION_SRC_DIRECTORY} ${COMPANION_SRC_DIRECTORY}/simulation)
|
include_directories(${COMPANION_SRC_DIRECTORY} ${COMPANION_SRC_DIRECTORY}/simulation)
|
||||||
add_library(${SIMULATOR_TARGET} SHARED ${SIMU_SRC} opentxsimulator.cpp)
|
qt5_wrap_cpp(SIMULATOR_SRC ${COMPANION_SRC_DIRECTORY}/simulation/simulatorinterface.h opentxsimulator.h)
|
||||||
|
list(APPEND SIMULATOR_SRC ${SIMU_SRC} opentxsimulator.cpp)
|
||||||
|
add_library(${SIMULATOR_TARGET} SHARED ${SIMULATOR_SRC})
|
||||||
add_dependencies(${SIMULATOR_TARGET} ${FIRMWARE_DEPENDENCIES})
|
add_dependencies(${SIMULATOR_TARGET} ${FIRMWARE_DEPENDENCIES})
|
||||||
target_compile_definitions(${SIMULATOR_TARGET} PUBLIC ${APP_COMMON_DEFINES}) # set in top-level CMakeLists
|
target_compile_definitions(${SIMULATOR_TARGET} PUBLIC ${APP_COMMON_DEFINES}) # set in top-level CMakeLists
|
||||||
target_link_libraries(${SIMULATOR_TARGET} ${SDL_LIBRARY})
|
target_link_libraries(${SIMULATOR_TARGET} ${SDL_LIBRARY})
|
||||||
|
|
|
@ -18,7 +18,23 @@
|
||||||
#include "opentx.h"
|
#include "opentx.h"
|
||||||
#include "simulcd.h"
|
#include "simulcd.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
|
#if !defined(MAX_LOGICAL_SWITCHES) && defined(NUM_CSW)
|
||||||
|
#define MAX_LOGICAL_SWITCHES NUM_CSW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPUARM)
|
||||||
|
#define GET_SWITCH_BOOL(sw__) getSwitch((sw__), 0);
|
||||||
|
#else
|
||||||
|
#define GET_SWITCH_BOOL(sw__) getSwitch(sw__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OTXS_DBG qDebug() << "(" << simuTimerMicros() << "us)"
|
||||||
|
|
||||||
int16_t g_anas[Analogs::NUM_ANALOGS];
|
int16_t g_anas[Analogs::NUM_ANALOGS];
|
||||||
|
QVector<QIODevice *> OpenTxSimulator::tracebackDevices;
|
||||||
|
|
||||||
uint16_t anaIn(uint8_t chan)
|
uint16_t anaIn(uint8_t chan)
|
||||||
{
|
{
|
||||||
|
@ -30,36 +46,135 @@ uint16_t getAnalogValue(uint8_t index)
|
||||||
return anaIn(index);
|
return anaIn(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasExtendedTrims()
|
void firmwareTraceCb(const char * text)
|
||||||
{
|
{
|
||||||
return g_model.extendedTrims;
|
foreach (QIODevice * dev, OpenTxSimulator::tracebackDevices) {
|
||||||
|
if (dev)
|
||||||
|
dev->write(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getStickMode()
|
OpenTxSimulator::OpenTxSimulator() :
|
||||||
|
SimulatorInterface(),
|
||||||
|
m_timer10ms(NULL),
|
||||||
|
m_resetOutputsData(true),
|
||||||
|
m_stopRequested(false)
|
||||||
{
|
{
|
||||||
return limit<uint8_t>(0, g_eeGeneral.stickMode, 3);
|
tracebackDevices.clear();
|
||||||
|
traceCallback = firmwareTraceCb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenTxSimulator::~OpenTxSimulator()
|
||||||
OpenTxSimulator::OpenTxSimulator()
|
|
||||||
{
|
{
|
||||||
|
traceCallback = NULL;
|
||||||
|
tracebackDevices.clear();
|
||||||
|
|
||||||
|
if (m_timer10ms)
|
||||||
|
delete m_timer10ms;
|
||||||
|
|
||||||
|
if (isRunning()) {
|
||||||
|
stop();
|
||||||
|
QElapsedTimer tmout;
|
||||||
|
tmout.start();
|
||||||
|
while (isRunning() && !tmout.hasExpired(1000))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
//qDebug() << "Deleting OpenTxSimulator";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenTxSimulator::name()
|
||||||
|
{
|
||||||
|
return QString(SIMULATOR_FLAVOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTxSimulator::isRunning()
|
||||||
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxSimuMain);
|
||||||
|
return (bool)main_thread_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::init()
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
return;
|
||||||
|
OTXS_DBG;
|
||||||
|
|
||||||
|
if (!m_timer10ms) {
|
||||||
|
// make sure we create & control the timer from current thread
|
||||||
|
m_timer10ms = new QTimer();
|
||||||
|
m_timer10ms->setInterval(10);
|
||||||
|
connect(m_timer10ms, &QTimer::timeout, this, &OpenTxSimulator::run);
|
||||||
|
connect(this, SIGNAL(started()), m_timer10ms, SLOT(start()));
|
||||||
|
connect(this, SIGNAL(stopped()), m_timer10ms, SLOT(stop()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_resetOutputsData = true;
|
||||||
|
setStopRequested(false);
|
||||||
|
|
||||||
|
QMutexLocker lckr(&m_mtxSimuMain);
|
||||||
|
memset(g_anas, 0, sizeof(g_anas));
|
||||||
|
simuInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::start(const char * filename, bool tests)
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
return;
|
||||||
|
OTXS_DBG << "file:" << filename << "tests:" << tests;
|
||||||
|
|
||||||
|
QMutexLocker lckr(&m_mtxSimuMain);
|
||||||
|
QMutexLocker slckr(&m_mtxSettings);
|
||||||
|
StartEepromThread(filename);
|
||||||
|
StartAudioThread(volumeGain);
|
||||||
|
StartSimu(tests, simuSdDirectory.toLatin1().constData(), simuSettingsDirectory.toLatin1().constData());
|
||||||
|
|
||||||
|
emit started();
|
||||||
|
QTimer::singleShot(0, this, SLOT(run())); // old style for Qt < 5.4
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::stop()
|
||||||
|
{
|
||||||
|
if (!isRunning())
|
||||||
|
return;
|
||||||
|
OTXS_DBG;
|
||||||
|
|
||||||
|
setStopRequested(true);
|
||||||
|
|
||||||
|
QMutexLocker lckr(&m_mtxSimuMain);
|
||||||
|
StopSimu();
|
||||||
|
StopAudioThread();
|
||||||
|
StopEepromThread();
|
||||||
|
|
||||||
|
emit stopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::setSdPath(const QString & sdPath, const QString & settingsPath)
|
void OpenTxSimulator::setSdPath(const QString & sdPath, const QString & settingsPath)
|
||||||
{
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxSettings);
|
||||||
simuSdDirectory = sdPath;
|
simuSdDirectory = sdPath;
|
||||||
simuSettingsDirectory = settingsPath;
|
simuSettingsDirectory = settingsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::setVolumeGain(int value)
|
void OpenTxSimulator::setVolumeGain(const int value)
|
||||||
{
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxSettings);
|
||||||
volumeGain = value;
|
volumeGain = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenTxSimulator::timer10ms()
|
void OpenTxSimulator::setRadioData(const QByteArray & data)
|
||||||
{
|
{
|
||||||
#define TIMER10MS_IMPORT
|
#if defined(EEPROM_SIZE)
|
||||||
#include "simulatorimport.h"
|
QMutexLocker lckr(&m_mtxRadioData);
|
||||||
|
memcpy(eeprom, data.data(), qMin<int>(EEPROM_SIZE, data.size()));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::readRadioData(QByteArray & dest)
|
||||||
|
{
|
||||||
|
#if defined(EEPROM_SIZE)
|
||||||
|
QMutexLocker lckr(&m_mtxRadioData);
|
||||||
|
memcpy(dest.data(), eeprom, std::min<int>(EEPROM_SIZE, dest.size()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * OpenTxSimulator::getLcd()
|
uint8_t * OpenTxSimulator::getLcd()
|
||||||
|
@ -67,100 +182,364 @@ uint8_t * OpenTxSimulator::getLcd()
|
||||||
return (uint8_t *)simuLcdBuf;
|
return (uint8_t *)simuLcdBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenTxSimulator::lcdChanged(bool & lightEnable)
|
void OpenTxSimulator::setAnalogValue(uint8_t index, int16_t value)
|
||||||
{
|
{
|
||||||
#define LCDCHANGED_IMPORT
|
static int dim = DIM(g_anas);
|
||||||
#include "simulatorimport.h"
|
if (index < dim)
|
||||||
|
g_anas[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::start(QByteArray & ee, bool tests)
|
void OpenTxSimulator::setSwitch(uint8_t swtch, int8_t state)
|
||||||
{
|
{
|
||||||
#if defined(EEPROM_SIZE)
|
simuSetSwitch(swtch, state);
|
||||||
memcpy(eeprom, ee.data(), std::min<int>(EEPROM_SIZE, ee.size()));
|
|
||||||
#endif
|
|
||||||
start((const char *)0, tests);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::start(const char * filename, bool tests)
|
void OpenTxSimulator::setKey(uint8_t key, bool state)
|
||||||
{
|
{
|
||||||
if (main_thread_running)
|
simuSetKey(key, state);
|
||||||
return;
|
|
||||||
|
|
||||||
StartEepromThread(filename);
|
|
||||||
StartAudioThread(volumeGain);
|
|
||||||
StartSimu(tests, simuSdDirectory.toLatin1().constData(), simuSettingsDirectory.toLatin1().constData());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::stop()
|
void OpenTxSimulator::setTrimSwitch(uint8_t trim, bool state)
|
||||||
{
|
{
|
||||||
if (!main_thread_running)
|
simuSetTrim(trim, state);
|
||||||
return;
|
|
||||||
|
|
||||||
StopSimu();
|
|
||||||
#if defined(CPUARM)
|
|
||||||
StopAudioThread();
|
|
||||||
#endif
|
|
||||||
StopEepromThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::readEepromData(QByteArray & dest)
|
|
||||||
{
|
|
||||||
#if defined(EEPROM_SIZE)
|
|
||||||
memcpy(dest.data(), eeprom, std::min<int>(EEPROM_SIZE, dest.size()));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::getValues(TxOutputs &outputs)
|
|
||||||
{
|
|
||||||
#define GETVALUES_IMPORT
|
|
||||||
#define g_chans512 channelOutputs
|
|
||||||
#include "simulatorimport.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::setValues(TxInputs &inputs)
|
|
||||||
{
|
|
||||||
#define SETVALUES_IMPORT
|
|
||||||
#include "simulatorimport.h"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::setTrim(unsigned int idx, int value)
|
void OpenTxSimulator::setTrim(unsigned int idx, int value)
|
||||||
{
|
{
|
||||||
idx = modn12x3[4*getStickMode() + idx];
|
unsigned i = idx;
|
||||||
uint8_t phase = getTrimFlightMode(getFlightMode(), idx);
|
if (i < 4) // swap axes
|
||||||
setTrimValue(phase, idx, value);
|
i = modn12x3[4 * getStickMode() + idx];
|
||||||
|
uint8_t phase = getTrimFlightMode(getFlightMode(), i);
|
||||||
|
|
||||||
|
if (!setTrimValue(phase, i, value)) {
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, [=]() {
|
||||||
|
emit trimValueChange(idx, 0);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_TRIM_VALUE, idx, 0);
|
||||||
|
timer->deleteLater();
|
||||||
|
});
|
||||||
|
timer->start(350);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::getTrims(Trims & trims)
|
void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value)
|
||||||
{
|
{
|
||||||
uint8_t phase = getFlightMode();
|
static unsigned dim = DIM(ppmInput);
|
||||||
trims.extended = hasExtendedTrims();
|
//setTrainerTimeout(100);
|
||||||
for (uint8_t idx=0; idx < CPN_MAX_TRIMS; idx++) {
|
if (inputNumber < dim)
|
||||||
trims.values[idx] = getTrimValue(getTrimFlightMode(phase, idx), idx);
|
ppmInput[inputNumber] = qMin(qMax((int16_t)-512, value), (int16_t)512);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<2; i++) {
|
void OpenTxSimulator::setInputValue(int type, uint8_t index, int16_t value)
|
||||||
uint8_t idx = modn12x3[4*getStickMode() + i];
|
{
|
||||||
int16_t tmp = trims.values[i];
|
//qDebug() << type << index << value << this->thread();
|
||||||
trims.values[i] = trims.values[idx];
|
switch (type) {
|
||||||
trims.values[idx] = tmp;
|
case INPUT_SRC_ANALOG :
|
||||||
|
case INPUT_SRC_STICK :
|
||||||
|
setAnalogValue(index, value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_KNOB :
|
||||||
|
setAnalogValue(index + NUM_STICKS, value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_SLIDER :
|
||||||
|
setAnalogValue(index + NUM_STICKS + NUM_POTS, value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_TXVIN :
|
||||||
|
setAnalogValue(Analogs::TX_VOLTAGE, voltageToAdc(value));
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_SWITCH :
|
||||||
|
setSwitch(index, (int8_t)value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_TRIM_SW :
|
||||||
|
setTrimSwitch(index, (bool)value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_TRIM :
|
||||||
|
setTrim(index, value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_KEY :
|
||||||
|
setKey(index, (bool)value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_TRAINER :
|
||||||
|
setTrainerInput(index, value);
|
||||||
|
break;
|
||||||
|
case INPUT_SRC_ROTENC : // TODO
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::wheelEvent(int steps)
|
void OpenTxSimulator::rotaryEncoderEvent(int steps)
|
||||||
{
|
{
|
||||||
#if defined(ROTARY_ENCODER_NAVIGATION)
|
#if defined(ROTARY_ENCODER_NAVIGATION)
|
||||||
ROTARY_ENCODER_NAVIGATION_VALUE += steps * ROTARY_ENCODER_GRANULARITY;
|
ROTARY_ENCODER_NAVIGATION_VALUE += steps * ROTARY_ENCODER_GRANULARITY;
|
||||||
#else
|
#else
|
||||||
|
// TODO : this should probably be handled in the GUI
|
||||||
|
int key;
|
||||||
if (steps > 0)
|
if (steps > 0)
|
||||||
simuSetKey(KEY_MINUS, 1);
|
key = KEY_MINUS;
|
||||||
else if (steps < 0)
|
else if (steps < 0)
|
||||||
simuSetKey(KEY_PLUS, 1);
|
key = KEY_PLUS;
|
||||||
|
|
||||||
|
setKey(key, 1);
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
||||||
|
QTimer::singleShot(10, [this, key]() { setKey(key, 0); });
|
||||||
|
#else
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, [=]() {
|
||||||
|
setKey(key, 0);
|
||||||
|
timer->deleteLater();
|
||||||
|
} );
|
||||||
|
timer->start(10);
|
||||||
|
#endif
|
||||||
|
#endif // defined(ROTARY_ENCODER_NAVIGATION)
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::setTrainerTimeout(uint16_t ms)
|
||||||
|
{
|
||||||
|
ppmInputValidityTimer = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::sendTelemetry(uint8_t * data, unsigned int len)
|
||||||
|
{
|
||||||
|
Q_UNUSED(len)
|
||||||
|
#if defined(TELEMETRY_FRSKY_SPORT)
|
||||||
|
sportProcessTelemetryPacket(data);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(data)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int OpenTxSimulator::getPhase()
|
uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
|
||||||
{
|
{
|
||||||
return getFlightMode();
|
#if defined(TELEMETRY_FRSKY_SPORT)
|
||||||
|
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
|
||||||
|
if (isTelemetryFieldAvailable(i)) {
|
||||||
|
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
||||||
|
if (sensor->id == id) {
|
||||||
|
return sensor->instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(id)
|
||||||
|
#endif
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
|
||||||
|
{
|
||||||
|
#if defined(TELEMETRY_FRSKY_SPORT)
|
||||||
|
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
|
||||||
|
if (isTelemetryFieldAvailable(i)) {
|
||||||
|
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
||||||
|
if (sensor->id == id) {
|
||||||
|
return sensor->custom.ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(id)
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int OpenTxSimulator::getCapability(Capability cap)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
switch(cap) {
|
||||||
|
case CAP_LUA :
|
||||||
|
#ifdef LUA
|
||||||
|
ret = 1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAP_ROTARY_ENC :
|
||||||
|
#ifdef ROTARY_ENCODERS
|
||||||
|
ret = ROTARY_ENCODERS;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAP_ROTARY_ENC_NAV :
|
||||||
|
#ifdef ROTARY_ENCODER_NAVIGATION
|
||||||
|
ret = 1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAP_TELEM_FRSKY_SPORT :
|
||||||
|
#ifdef TELEMETRY_FRSKY_SPORT
|
||||||
|
ret = 1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::setLuaStateReloadPermanentScripts()
|
||||||
|
{
|
||||||
|
#if defined(LUA)
|
||||||
|
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::addTracebackDevice(QIODevice * device)
|
||||||
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxTbDevices);
|
||||||
|
if (device && !tracebackDevices.contains(device))
|
||||||
|
tracebackDevices.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::removeTracebackDevice(QIODevice * device)
|
||||||
|
{
|
||||||
|
if (device) {
|
||||||
|
QMutexLocker lckr(&m_mtxTbDevices);
|
||||||
|
// no QVector::removeAll() in Qt < 5.4
|
||||||
|
int i = 0;
|
||||||
|
foreach (QIODevice * d, tracebackDevices) {
|
||||||
|
if (d == device)
|
||||||
|
tracebackDevices.remove(i);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** Protected classes ***/
|
||||||
|
|
||||||
|
void OpenTxSimulator::run()
|
||||||
|
{
|
||||||
|
static uint32_t loops = 0;
|
||||||
|
static QElapsedTimer ts;
|
||||||
|
|
||||||
|
if (!loops)
|
||||||
|
ts.start();
|
||||||
|
|
||||||
|
if (isStopRequested()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isRunning()) {
|
||||||
|
QString err(getError());
|
||||||
|
emit runtimeError(err);
|
||||||
|
emit stopped();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++loops;
|
||||||
|
|
||||||
|
per10ms();
|
||||||
|
|
||||||
|
checkLcdChanged();
|
||||||
|
|
||||||
|
if (!(loops % 5)) {
|
||||||
|
checkOutputsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(loops % (SIMULATOR_INTERFACE_HEARTBEAT_PERIOD / 10))) {
|
||||||
|
emit heartbeat(loops, simuTimerMicros() / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTxSimulator::isStopRequested()
|
||||||
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxStopReq);
|
||||||
|
return m_stopRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::setStopRequested(bool stop)
|
||||||
|
{
|
||||||
|
QMutexLocker lckr(&m_mtxStopReq);
|
||||||
|
m_stopRequested = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTxSimulator::checkLcdChanged()
|
||||||
|
{
|
||||||
|
if (simuLcdRefresh) {
|
||||||
|
simuLcdRefresh = false;
|
||||||
|
emit lcdChange(isBacklightEnabled());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTxSimulator::checkOutputsChanged()
|
||||||
|
{
|
||||||
|
static TxOutputs lastOutputs;
|
||||||
|
static size_t chansDim = DIM(channelOutputs);
|
||||||
|
qint32 tmpVal;
|
||||||
|
uint8_t i, idx;
|
||||||
|
uint8_t phase = getFlightMode(); // opentx.cpp
|
||||||
|
uint8_t mode = getStickMode();
|
||||||
|
|
||||||
|
for (i=0; i < chansDim; i++) {
|
||||||
|
if (lastOutputs.chans[i] != channelOutputs[i] || m_resetOutputsData) {
|
||||||
|
emit channelOutValueChange(i, channelOutputs[i]);
|
||||||
|
emit channelMixValueChange(i, ex_chans[i]);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_CHAN_OUT, i, channelOutputs[i]);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_CHAN_MIX, i, ex_chans[i]);
|
||||||
|
lastOutputs.chans[i] = channelOutputs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < MAX_LOGICAL_SWITCHES; i++) {
|
||||||
|
tmpVal = (qint32)GET_SWITCH_BOOL(SWSRC_SW1+i);
|
||||||
|
if (lastOutputs.vsw[i] != (bool)tmpVal || m_resetOutputsData) {
|
||||||
|
emit virtualSwValueChange(i, tmpVal);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_VIRTUAL_SW, i, tmpVal);
|
||||||
|
lastOutputs.vsw[i] = tmpVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < Board::TRIM_AXIS_COUNT; i++) {
|
||||||
|
if (i < 4) // swap axes
|
||||||
|
idx = modn12x3[4 * mode + i];
|
||||||
|
else
|
||||||
|
idx = i;
|
||||||
|
|
||||||
|
tmpVal = getTrimValue(getTrimFlightMode(phase, idx), idx);
|
||||||
|
if (lastOutputs.trims[i] != tmpVal || m_resetOutputsData) {
|
||||||
|
emit trimValueChange(i, tmpVal);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_TRIM_VALUE, i, tmpVal);
|
||||||
|
lastOutputs.trims[i] = tmpVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpVal = g_model.extendedTrims ? TRIM_EXTENDED_MAX : TRIM_MAX;
|
||||||
|
if (lastOutputs.trimRange != tmpVal || m_resetOutputsData) {
|
||||||
|
emit trimRangeChange(Board::TRIM_AXIS_COUNT, -tmpVal, tmpVal);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_TRIM_RANGE, Board::TRIM_AXIS_COUNT, tmpVal);
|
||||||
|
lastOutputs.trimRange = tmpVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastOutputs.phase != phase || m_resetOutputsData) {
|
||||||
|
emit phaseChanged(phase, getCurrentPhaseName());
|
||||||
|
emit outputValueChange(OUTPUT_SRC_PHASE, 0, qint16(phase));
|
||||||
|
lastOutputs.phase = phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GVAR_VALUE) && defined(GVARS)
|
||||||
|
gVarMode_t gvar;
|
||||||
|
for (uint8_t fm=0; fm < MAX_FLIGHT_MODES; fm++) {
|
||||||
|
gvar.mode = fm;
|
||||||
|
for (uint8_t gv=0; gv < MAX_GVARS; gv++) {
|
||||||
|
tmpVal = GVAR_VALUE(gv, getGVarFlightMode(fm, gv));
|
||||||
|
if (lastOutputs.gvars[fm][gv] != tmpVal || m_resetOutputsData) {
|
||||||
|
lastOutputs.gvars[fm][gv] = tmpVal;
|
||||||
|
gvar.value = (int16_t)tmpVal;
|
||||||
|
tmpVal = gvar;
|
||||||
|
emit gVarValueChange(gv, tmpVal);
|
||||||
|
emit outputValueChange(OUTPUT_SRC_GVAR, gv, tmpVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_resetOutputsData = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t OpenTxSimulator::getStickMode()
|
||||||
|
{
|
||||||
|
return limit<uint8_t>(0, g_eeGeneral.stickMode, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * OpenTxSimulator::getPhaseName(unsigned int phase)
|
const char * OpenTxSimulator::getPhaseName(unsigned int phase)
|
||||||
|
@ -170,66 +549,39 @@ const char * OpenTxSimulator::getPhaseName(unsigned int phase)
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString OpenTxSimulator::getCurrentPhaseName()
|
||||||
|
{
|
||||||
|
unsigned phase = getFlightMode();
|
||||||
|
QString name(getPhaseName(phase));
|
||||||
|
if (name.isEmpty())
|
||||||
|
name = QString::number(phase);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
const char * OpenTxSimulator::getError()
|
const char * OpenTxSimulator::getError()
|
||||||
{
|
{
|
||||||
#define GETERROR_IMPORT
|
return main_thread_error;
|
||||||
#include "simulatorimport.h"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::sendTelemetry(uint8_t * data, unsigned int len)
|
const int OpenTxSimulator::voltageToAdc(const int volts)
|
||||||
{
|
{
|
||||||
#if defined(TELEMETRY_FRSKY_SPORT)
|
int ret = 0;
|
||||||
sportProcessTelemetryPacket(data);
|
#if defined(PCBHORUS) || defined(PCBX7)
|
||||||
|
ret = (float)volts * 16.2f;
|
||||||
|
#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBSKY9X)
|
||||||
|
ret = (float)volts * 13.3f;
|
||||||
|
#elif defined(PCBGRUVIN9X)
|
||||||
|
ret = (float)volts * 1.63f;
|
||||||
|
#else
|
||||||
|
ret = (float)volts * 14.15f;
|
||||||
#endif
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
|
|
||||||
{
|
|
||||||
#if defined(TELEMETRY_FRSKY_SPORT)
|
|
||||||
for (int i = 0; i<MAX_TELEMETRY_SENSORS; i++) {
|
|
||||||
if (isTelemetryFieldAvailable(i)) {
|
|
||||||
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
|
||||||
if (sensor->id == id) {
|
|
||||||
return sensor->instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
|
/*
|
||||||
{
|
* OpenTxSimulatorFactory
|
||||||
#if defined(TELEMETRY_FRSKY_SPORT)
|
*/
|
||||||
for (int i = 0; i<MAX_TELEMETRY_SENSORS; i++) {
|
|
||||||
if (isTelemetryFieldAvailable(i)) {
|
|
||||||
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
|
||||||
if (sensor->id == id) {
|
|
||||||
return sensor->custom.ratio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value)
|
|
||||||
{
|
|
||||||
#define SETTRAINER_IMPORT
|
|
||||||
#include "simulatorimport.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::setLuaStateReloadPermanentScripts()
|
|
||||||
{
|
|
||||||
#if defined(LUA)
|
|
||||||
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTxSimulator::installTraceHook(void (*callback)(const char *))
|
|
||||||
{
|
|
||||||
traceCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OpenTxSimulatorFactory: public SimulatorFactory
|
class OpenTxSimulatorFactory: public SimulatorFactory
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,68 +19,84 @@
|
||||||
|
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#if defined __GNUC__
|
#if defined __GNUC__
|
||||||
#define DLLEXPORT
|
#define DLLEXPORT
|
||||||
#else
|
#else
|
||||||
#define DLLEXPORT __declspec(dllexport)
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class DLLEXPORT OpenTxSimulator : public SimulatorInterface {
|
class DLLEXPORT OpenTxSimulator : public SimulatorInterface
|
||||||
|
{
|
||||||
private:
|
Q_OBJECT
|
||||||
int volumeGain;
|
|
||||||
QString simuSdDirectory;
|
|
||||||
QString simuSettingsDirectory;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OpenTxSimulator();
|
OpenTxSimulator();
|
||||||
|
virtual ~OpenTxSimulator();
|
||||||
|
|
||||||
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "");
|
virtual QString name();
|
||||||
|
virtual bool isRunning();
|
||||||
virtual void setVolumeGain(int value);
|
virtual void readRadioData(QByteArray & dest);
|
||||||
|
|
||||||
virtual void start(QByteArray & eeprom, bool tests=true);
|
|
||||||
|
|
||||||
virtual void start(const char * filename, bool tests=true);
|
|
||||||
|
|
||||||
virtual void stop();
|
|
||||||
|
|
||||||
virtual void readEepromData(QByteArray & dest);
|
|
||||||
|
|
||||||
virtual bool timer10ms();
|
|
||||||
|
|
||||||
virtual uint8_t * getLcd();
|
virtual uint8_t * getLcd();
|
||||||
|
|
||||||
virtual bool lcdChanged(bool & lightEnable);
|
|
||||||
|
|
||||||
virtual void setValues(TxInputs &inputs);
|
|
||||||
|
|
||||||
virtual void getValues(TxOutputs &outputs);
|
|
||||||
|
|
||||||
virtual void setTrim(unsigned int idx, int value);
|
|
||||||
|
|
||||||
virtual void getTrims(Trims & trims);
|
|
||||||
|
|
||||||
virtual unsigned int getPhase();
|
|
||||||
|
|
||||||
virtual const char * getPhaseName(unsigned int phase);
|
|
||||||
|
|
||||||
virtual void wheelEvent(int steps);
|
|
||||||
|
|
||||||
virtual const char * getError();
|
|
||||||
|
|
||||||
virtual void sendTelemetry(uint8_t * data, unsigned int len);
|
|
||||||
|
|
||||||
virtual uint8_t getSensorInstance(uint16_t id, uint8_t defaultValue = 0);
|
virtual uint8_t getSensorInstance(uint16_t id, uint8_t defaultValue = 0);
|
||||||
|
|
||||||
virtual uint16_t getSensorRatio(uint16_t id);
|
virtual uint16_t getSensorRatio(uint16_t id);
|
||||||
|
virtual const int getCapability(Capability cap);
|
||||||
|
|
||||||
|
static QVector<QIODevice *> tracebackDevices;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
virtual void init();
|
||||||
|
virtual void start(const char * filename = NULL, bool tests = true);
|
||||||
|
virtual void stop();
|
||||||
|
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "");
|
||||||
|
virtual void setVolumeGain(const int value);
|
||||||
|
virtual void setRadioData(const QByteArray & data);
|
||||||
|
virtual void setAnalogValue(uint8_t index, int16_t value);
|
||||||
|
virtual void setKey(uint8_t key, bool state);
|
||||||
|
virtual void setSwitch(uint8_t swtch, int8_t state);
|
||||||
|
virtual void setTrim(unsigned int idx, int value);
|
||||||
|
virtual void setTrimSwitch(uint8_t trim, bool state);
|
||||||
virtual void setTrainerInput(unsigned int inputNumber, int16_t value);
|
virtual void setTrainerInput(unsigned int inputNumber, int16_t value);
|
||||||
|
virtual void setInputValue(int type, uint8_t index, int16_t value);
|
||||||
virtual void installTraceHook(void (*callback)(const char *));
|
virtual void rotaryEncoderEvent(int steps);
|
||||||
|
virtual void setTrainerTimeout(uint16_t ms);
|
||||||
|
virtual void sendTelemetry(uint8_t * data, unsigned int len);
|
||||||
virtual void setLuaStateReloadPermanentScripts();
|
virtual void setLuaStateReloadPermanentScripts();
|
||||||
|
virtual void addTracebackDevice(QIODevice * device);
|
||||||
|
virtual void removeTracebackDevice(QIODevice * device);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool isStopRequested();
|
||||||
|
void setStopRequested(bool stop);
|
||||||
|
bool checkLcdChanged();
|
||||||
|
void checkOutputsChanged();
|
||||||
|
uint8_t getStickMode();
|
||||||
|
const char * getPhaseName(unsigned int phase);
|
||||||
|
const QString getCurrentPhaseName();
|
||||||
|
const char * getError();
|
||||||
|
const int voltageToAdc(const int volts);
|
||||||
|
|
||||||
|
QString simuSdDirectory;
|
||||||
|
QString simuSettingsDirectory;
|
||||||
|
QTimer * m_timer10ms;
|
||||||
|
QMutex m_mtxStopReq;
|
||||||
|
QMutex m_mtxSimuMain;
|
||||||
|
QMutex m_mtxRadioData;
|
||||||
|
QMutex m_mtxSettings;
|
||||||
|
QMutex m_mtxTbDevices;
|
||||||
|
int volumeGain;
|
||||||
|
bool m_resetOutputsData;
|
||||||
|
bool m_stopRequested;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _OPENTX_SIMULATOR_H_
|
#endif // _OPENTX_SIMULATOR_H_
|
||||||
|
|
|
@ -257,10 +257,10 @@ void simuSetTrim(uint8_t trim, bool state)
|
||||||
TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL)
|
TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL)
|
||||||
TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR)
|
TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR)
|
||||||
#if defined(PCBHORUS)
|
#if defined(PCBHORUS)
|
||||||
TRIM_CASE(8, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU)
|
TRIM_CASE(8, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_LSD)
|
||||||
TRIM_CASE(9, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_RVU)
|
TRIM_CASE(9, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU)
|
||||||
TRIM_CASE(10, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RHL)
|
TRIM_CASE(10, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RSD)
|
||||||
TRIM_CASE(11, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RHR)
|
TRIM_CASE(11, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RSU)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue