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);
|
||||
|
||||
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))
|
||||
msgPattern = qFormatLogMessage(type, context, msg);
|
||||
#else
|
||||
|
@ -111,7 +111,7 @@ void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogCon
|
|||
}
|
||||
#endif
|
||||
|
||||
emit messageOutput(lvl, msgPattern, context);
|
||||
emit messageOutput(lvl, msgPattern);
|
||||
}
|
||||
|
||||
// if (QThread::currentThread() == qApp->thread()) // gui thread
|
||||
|
|
|
@ -127,7 +127,7 @@ class AppDebugMessageHandler : public QObject
|
|||
bool m_showFunctionDeclarations;
|
||||
|
||||
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.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<file>images/track.png</file>
|
||||
<file>images/track0.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-active.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-active.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-on.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
|
||||
simulateduiwidget.h
|
||||
# simulator.h
|
||||
simulatorinterface.h
|
||||
simulatormainwindow.h
|
||||
simulatorstartupdialog.h
|
||||
simulatorwidget.h
|
||||
|
@ -49,6 +50,7 @@ set(simulation_HDRS
|
|||
widgets/lcdwidget.h
|
||||
widgets/radiowidget.h
|
||||
widgets/radiofaderwidget.h
|
||||
widgets/radiokeywidget.h
|
||||
widgets/radioknobwidget.h
|
||||
widgets/radioswitchwidget.h
|
||||
widgets/radiotrimwidget.h
|
||||
|
|
|
@ -36,20 +36,13 @@
|
|||
|
||||
extern AppData g; // ensure what "g" means
|
||||
|
||||
FilteredTextBuffer * DebugOutput::m_dataBufferDevice = Q_NULLPTR;
|
||||
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):
|
||||
QWidget(parent),
|
||||
ui(new Ui::DebugOutput),
|
||||
m_simulator(simulator),
|
||||
m_dataBufferDevice(NULL),
|
||||
m_radioProfileId(g.sessionId()),
|
||||
m_filterEnable(false),
|
||||
m_filterExclude(false)
|
||||
|
@ -101,33 +94,28 @@ DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator):
|
|||
connect(ui->actionToggleFilter, &QAction::toggled, this, &DebugOutput::onFilterToggled);
|
||||
connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged);
|
||||
|
||||
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
|
||||
if (AppDebugMessageHandler::instance())
|
||||
connect(AppDebugMessageHandler::instance(), &AppDebugMessageHandler::messageOutput, this, &DebugOutput::onAppDebugMessage);
|
||||
#endif
|
||||
}
|
||||
|
||||
// send firmware TRACE events to our data collector
|
||||
m_simulator->installTraceHook(firmwareTraceCb);
|
||||
m_simulator->addTracebackDevice(m_dataBufferDevice);
|
||||
}
|
||||
|
||||
DebugOutput::~DebugOutput()
|
||||
{
|
||||
m_simulator->installTraceHook(NULL);
|
||||
saveState();
|
||||
|
||||
if (AppDebugMessageHandler::instance())
|
||||
disconnect(AppDebugMessageHandler::instance(), 0, this, 0);
|
||||
|
||||
if (m_dataBufferDevice) {
|
||||
m_simulator->removeTracebackDevice(m_dataBufferDevice);
|
||||
disconnect(m_dataBufferDevice, 0, this, 0);
|
||||
disconnect(this, 0, m_dataBufferDevice, 0);
|
||||
m_dataBufferDevice->deleteLater();
|
||||
delete m_dataBufferDevice;
|
||||
m_dataBufferDevice = Q_NULLPTR;
|
||||
}
|
||||
|
||||
saveState();
|
||||
|
||||
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) {
|
||||
firmwareTraceCb(qPrintable(msg));
|
||||
firmwareTraceCb("\n");
|
||||
if (level > 0 && m_dataBufferDevice) {
|
||||
m_dataBufferDevice->write(qPrintable(msg % "\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,20 +60,19 @@ class DebugOutput : public QWidget
|
|||
|
||||
static QRegularExpression makeRegEx(const QString & input, bool * isExlusive = NULL);
|
||||
|
||||
static FilteredTextBuffer * m_dataBufferDevice;
|
||||
|
||||
signals:
|
||||
void filterExprChanged(const QRegularExpression & expr);
|
||||
void filterEnabledChanged(const bool enabled);
|
||||
void filterExclusiveChanged(const bool exlusive);
|
||||
void filterChanged(bool enable, bool exclusive, const QRegularExpression & expr);
|
||||
void tracebackDeviceChange(QIODevice * device);
|
||||
|
||||
protected slots:
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void processBytesReceived();
|
||||
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 onFilterTextChanged(const QString &);
|
||||
void onFilterToggled(bool enable);
|
||||
|
@ -85,6 +84,7 @@ class DebugOutput : public QWidget
|
|||
protected:
|
||||
Ui::DebugOutput * ui;
|
||||
SimulatorInterface * m_simulator;
|
||||
FilteredTextBuffer * m_dataBufferDevice;
|
||||
int m_radioProfileId;
|
||||
bool m_filterEnable;
|
||||
bool m_filterExclude;
|
||||
|
|
|
@ -26,39 +26,32 @@
|
|||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "simulator.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
extern AppData g; // ensure what "g" means
|
||||
|
||||
const int RadioOutputsWidget::m_dataUpdateFreqDefault = 10; // ms
|
||||
const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1;
|
||||
|
||||
RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_simulator(simulator),
|
||||
m_firmware(firmware),
|
||||
m_tmrUpdateData(new QTimer),
|
||||
m_radioProfileId(g.sessionId()),
|
||||
m_lastFlightPhase(-1),
|
||||
m_started(false),
|
||||
ui(new Ui::RadioOutputsWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
restoreState();
|
||||
|
||||
m_dataUpdateFreq = m_dataUpdateFreqDefault;
|
||||
m_tmrUpdateData->setInterval(m_dataUpdateFreq);
|
||||
|
||||
connect(m_tmrUpdateData, &QTimer::timeout, this, &RadioOutputsWidget::setValues);
|
||||
connect(m_simulator, &SimulatorInterface::channelOutValueChange, this, &RadioOutputsWidget::onChannelOutValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged);
|
||||
}
|
||||
|
||||
RadioOutputsWidget::~RadioOutputsWidget()
|
||||
{
|
||||
stop();
|
||||
//stop();
|
||||
saveState();
|
||||
if (m_tmrUpdateData)
|
||||
delete m_tmrUpdateData;
|
||||
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()
|
||||
{
|
||||
setupChannelsDisplay();
|
||||
setupGVarsDisplay();
|
||||
setupLsDisplay();
|
||||
m_lastFlightPhase = -1;
|
||||
m_tmrUpdateData->start();
|
||||
m_started = true;
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::stop()
|
||||
{
|
||||
m_tmrUpdateData->stop();
|
||||
m_started = false;
|
||||
}
|
||||
//void RadioOutputsWidget::stop()
|
||||
//{
|
||||
//}
|
||||
|
||||
void RadioOutputsWidget::restart()
|
||||
{
|
||||
stop();
|
||||
//stop();
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -139,7 +116,6 @@ void RadioOutputsWidget::restoreState()
|
|||
ui->splitter->restoreState(splitterState);
|
||||
}
|
||||
|
||||
|
||||
void RadioOutputsWidget::setupChannelsDisplay()
|
||||
{
|
||||
int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
|
||||
|
@ -297,68 +273,73 @@ QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo
|
|||
return swtch;
|
||||
}
|
||||
|
||||
// Read various values from firmware simulator and populate values in this UI
|
||||
void RadioOutputsWidget::setValues()
|
||||
void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value)
|
||||
{
|
||||
static TxOutputs prevOutputs = TxOutputs();
|
||||
int currentPhase;
|
||||
TxOutputs outputs;
|
||||
if (m_channelsMap.contains(index)) {
|
||||
QPair<QLabel *, QSlider *> ch = m_channelsMap.value(index);
|
||||
ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
|
||||
ch.second->setValue(qMin(1024, qMax(-1024, value)));
|
||||
}
|
||||
//qDebug() << index << value;
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::onVirtSwValueChange(quint8 index, qint32 value)
|
||||
{
|
||||
if (!m_logicSwitchMap.contains(index))
|
||||
return;
|
||||
|
||||
QLabel * ls = m_logicSwitchMap.value(index);
|
||||
ls->setBackgroundRole(value ? QPalette::Dark : QPalette::Background);
|
||||
ls->setForegroundRole(value ? QPalette::BrightText : QPalette::WindowText);
|
||||
ls->setFrameShadow(value ? QFrame::Sunken : QFrame::Raised);
|
||||
QFont font = ls->font();
|
||||
font.setBold((bool)value);
|
||||
ls->setFont(font);
|
||||
//qDebug() << index << value;
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::onGVarValueChange(quint8 index, qint32 value)
|
||||
{
|
||||
if (!m_globalVarsMap.contains(index))
|
||||
return;
|
||||
|
||||
QHash<int, QLabel *> fmMap = m_globalVarsMap.value(index);
|
||||
SimulatorInterface::gVarMode_t gv(value);
|
||||
|
||||
if (fmMap.contains(gv.mode)) {
|
||||
QLabel * lbl = fmMap.value(gv.mode);
|
||||
if (lbl)
|
||||
lbl->setText(QString::number(gv.value));
|
||||
}
|
||||
//qDebug() << index << value << gv.mode << gv.value;
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::onPhaseChanged(qint32 phase, const QString &)
|
||||
{
|
||||
QPalette::ColorRole fgrole, bgrole;
|
||||
QLabel * lbl;
|
||||
QFont font;
|
||||
|
||||
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()])));
|
||||
}
|
||||
}
|
||||
|
||||
if (ui->logicalSwitchesWidget->isVisible()) {
|
||||
QHash<int, QLabel* >::const_iterator ls;
|
||||
for (ls = m_logicSwitchMap.constBegin(); ls != m_logicSwitchMap.constEnd(); ++ls) {
|
||||
if (ls.key() >= CPN_MAX_LOGICAL_SWITCHES || (prevOutputs.vsw[ls.key()] == outputs.vsw[ls.key()] && m_lastFlightPhase > -1))
|
||||
continue;
|
||||
ls.value()->setBackgroundRole(outputs.vsw[ls.key()] ? QPalette::Dark : QPalette::Background);
|
||||
ls.value()->setForegroundRole(outputs.vsw[ls.key()] ? QPalette::BrightText : QPalette::WindowText);
|
||||
ls.value()->setFrameShadow(outputs.vsw[ls.key()] ? QFrame::Sunken : QFrame::Raised);
|
||||
font = ls.value()->font();
|
||||
font.setBold(outputs.vsw[ls.key()]);
|
||||
ls.value()->setFont(font);
|
||||
prevOutputs.vsw[ls.key()] = outputs.vsw[ls.key()];
|
||||
}
|
||||
}
|
||||
|
||||
if (ui->globalVarsWidget->isVisible()) {
|
||||
QPalette::ColorRole bgrole;
|
||||
QHash<int, QHash<int, QLabel *> >::const_iterator gv;
|
||||
QHash<int, QLabel *>::const_iterator fm;
|
||||
for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
|
||||
if (gv.key() >= CPN_MAX_GVARS)
|
||||
continue;
|
||||
for (fm = gv.value().constBegin(); fm != gv.value().constEnd(); ++fm) {
|
||||
if (fm.key() >= CPN_MAX_FLIGHT_MODES)
|
||||
continue;
|
||||
if (currentPhase != m_lastFlightPhase || prevOutputs.gvars[fm.key()][gv.key()] != outputs.gvars[fm.key()][gv.key()]) {
|
||||
if (fm.key() == currentPhase)
|
||||
bgrole = QPalette::Dark;
|
||||
else
|
||||
bgrole = ((gv.key() % 2) ? QPalette::Background : QPalette::AlternateBase);
|
||||
fm.value()->setBackgroundRole(bgrole);
|
||||
fm.value()->setForegroundRole(fm.key() == currentPhase ? QPalette::BrightText : QPalette::WindowText);
|
||||
font = fm.value()->font();
|
||||
font.setBold(fm.key() == currentPhase);
|
||||
fm.value()->setFont(font);
|
||||
fm.value()->setText(QString::number(outputs.gvars[fm.key()][gv.key()]));
|
||||
prevOutputs.gvars[fm.key()][gv.key()] = outputs.gvars[fm.key()][gv.key()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lastFlightPhase = currentPhase;
|
||||
for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
|
||||
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
|
||||
|
||||
#include "simulator.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
@ -31,7 +32,7 @@ class RadioOutputsWidget;
|
|||
}
|
||||
|
||||
class Firmware;
|
||||
class SimulatorInterface;
|
||||
//class SimulatorInterface;
|
||||
|
||||
class QFrame;
|
||||
class QLabel;
|
||||
|
@ -47,16 +48,18 @@ class RadioOutputsWidget : public QWidget
|
|||
explicit RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget * parent = 0);
|
||||
~RadioOutputsWidget();
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
//void stop();
|
||||
void restart();
|
||||
|
||||
protected slots:
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void setValues();
|
||||
void showEvent(QShowEvent *event);
|
||||
void hideEvent(QHideEvent *event);
|
||||
void onChannelOutValueChange(quint8 index, qint32 value);
|
||||
void onVirtSwValueChange(quint8 index, qint32 value);
|
||||
void onGVarValueChange(quint8 index, qint32 value);
|
||||
void onPhaseChanged(qint32 phase, const QString &);
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e);
|
||||
|
@ -67,7 +70,6 @@ class RadioOutputsWidget : public QWidget
|
|||
|
||||
SimulatorInterface * m_simulator;
|
||||
Firmware * m_firmware;
|
||||
QTimer * m_tmrUpdateData;
|
||||
|
||||
QHash<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
|
||||
QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
|
||||
|
@ -75,10 +77,7 @@ class RadioOutputsWidget : public QWidget
|
|||
|
||||
int m_radioProfileId;
|
||||
int m_dataUpdateFreq;
|
||||
int m_lastFlightPhase;
|
||||
bool m_started;
|
||||
|
||||
const static int m_dataUpdateFreqDefault;
|
||||
const static quint16 m_savedViewStateVersion;
|
||||
|
||||
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,
|
||||
* 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 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.
|
||||
*/
|
||||
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_active(false),
|
||||
m_keys(QList<int>()),
|
||||
|
@ -50,37 +50,51 @@ class RadioUiAction : public QObject
|
|||
m_description(descript),
|
||||
m_parent(parent)
|
||||
{
|
||||
if (key)
|
||||
m_keys.append(key);
|
||||
|
||||
init();
|
||||
addKey(key);
|
||||
}
|
||||
/*
|
||||
* @param keys QList of Qt:Key codes to use as shortcuts.
|
||||
* [See above for other params.]
|
||||
*/
|
||||
RadioUiAction(int index, QList<int> keys, QWidget * parent = NULL, const QString &text = "", const QString &descript = ""):
|
||||
m_hwIndex(index),
|
||||
m_active(false),
|
||||
m_keys(keys),
|
||||
m_text(text),
|
||||
m_description(descript),
|
||||
m_parent(parent)
|
||||
RadioUiAction(int index, QList<int> keys, const QString &text = "", const QString &descript = "", QWidget * parent = NULL):
|
||||
RadioUiAction(index, 0, text, descript, 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();
|
||||
}
|
||||
}
|
||||
|
||||
void addKeys(const QList<int> & keys)
|
||||
{
|
||||
foreach (int key, keys)
|
||||
addKey(key);
|
||||
}
|
||||
|
||||
void addShortcut()
|
||||
{
|
||||
if (m_parent)
|
||||
if (m_parent) {
|
||||
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 setText(QPair<QString, QString> name_descript) { setText(name_descript.first, name_descript.second); }
|
||||
|
|
|
@ -22,8 +22,13 @@
|
|||
#include "eeprominterface.h"
|
||||
#include "lcdwidget.h"
|
||||
#include "radiouiaction.h"
|
||||
#include "radiokeywidget.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) :
|
||||
QWidget(parent),
|
||||
m_simulator(simulator),
|
||||
|
@ -31,16 +36,18 @@ SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, QWidget * p
|
|||
m_lcd(NULL),
|
||||
m_scrollUpAction(NULL),
|
||||
m_scrollDnAction(NULL),
|
||||
m_rotEncClickAction(NULL),
|
||||
m_mouseMidClickAction(NULL),
|
||||
m_screenshotAction(NULL),
|
||||
m_board(getCurrentBoard()),
|
||||
m_backLight(0),
|
||||
m_lightOn(false),
|
||||
m_beepShow(0),
|
||||
m_beepVal(0)
|
||||
{
|
||||
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
|
||||
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
|
||||
m_screenshotAction = new RadioUiAction(-1, Qt::Key_Print);
|
||||
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()
|
||||
|
@ -49,28 +56,44 @@ SimulatedUIWidget::~SimulatedUIWidget()
|
|||
if (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);
|
||||
if (!act->getText().isEmpty() && !act->getDescription().isEmpty())
|
||||
m_keymapHelp.append(keymapHelp_t(act->getText(), act->getDescription()));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
RadioUiAction * SimulatedUIWidget::addRadioUiAction(int index, QList<int> keys, const QString & text, const QString & descript)
|
||||
{
|
||||
return addRadioUiAction(new RadioUiAction(index, keys, m_parent, text, descript));
|
||||
QVector<Simulator::keymapHelp_t> keymapHelp;
|
||||
foreach (RadioUiAction * act, m_actions) {
|
||||
if (act && !act->getText().isEmpty())
|
||||
keymapHelp.append(Simulator::keymapHelp_t(act->getText(), act->getDescription()));
|
||||
}
|
||||
return keymapHelp;
|
||||
}
|
||||
|
||||
// static
|
||||
QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAngle, int endAngle, int step)
|
||||
{
|
||||
QPolygon polygon;
|
||||
|
@ -83,20 +106,10 @@ QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAng
|
|||
return polygon;
|
||||
}
|
||||
|
||||
/* TODO : beep indicator
|
||||
void SimulatedUIWidget::updateUi()
|
||||
{
|
||||
//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)) {
|
||||
TxOutputs outputs;
|
||||
simulator->getValues(outputs);
|
||||
|
@ -111,7 +124,16 @@ void SimulatedUIWidget::updateUi()
|
|||
beepShow--;
|
||||
}
|
||||
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()
|
||||
|
@ -136,32 +158,27 @@ void SimulatedUIWidget::captureScreenshot()
|
|||
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)
|
||||
{
|
||||
if (event->angleDelta().isNull())
|
||||
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
|
||||
simulatorWheelEvent(numSteps.y());
|
||||
emit simulatorWheelEvent(numSteps.y());
|
||||
}
|
||||
|
||||
void SimulatedUIWidget::mousePressEvent(QMouseEvent * event)
|
||||
{
|
||||
if (event->button() == Qt::MidButton && m_rotEncClickAction)
|
||||
m_rotEncClickAction->trigger(true);
|
||||
if (event->button() == Qt::MidButton && m_mouseMidClickAction)
|
||||
m_mouseMidClickAction->trigger(true);
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void SimulatedUIWidget::mouseReleaseEvent(QMouseEvent * event)
|
||||
{
|
||||
if (event->button() == Qt::MidButton && m_rotEncClickAction)
|
||||
m_rotEncClickAction->trigger(false);
|
||||
if (event->button() == Qt::MidButton && m_mouseMidClickAction)
|
||||
m_mouseMidClickAction->trigger(false);
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
@ -184,13 +201,19 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
|
|||
|
||||
void SimulatedUIWidget::connectScrollActions()
|
||||
{
|
||||
if (m_scrollUpAction) {
|
||||
addRadioAction(m_scrollUpAction);
|
||||
connect(m_scrollUpAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||
this->simulatorWheelEvent(-1);
|
||||
emit simulatorWheelEvent(-1);
|
||||
m_scrollUpAction->toggle(false);
|
||||
});
|
||||
}
|
||||
|
||||
if (m_scrollDnAction) {
|
||||
addRadioAction(m_scrollDnAction);
|
||||
connect(m_scrollDnAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||
simulatorWheelEvent(1);
|
||||
emit simulatorWheelEvent(1);
|
||||
m_scrollDnAction->toggle(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,17 +23,18 @@
|
|||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "radiowidget.h"
|
||||
#include "simulator.h"
|
||||
#include "simulator_strings.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class SimulatorInterface;
|
||||
class LcdWidget;
|
||||
class RadioKeyWidget;
|
||||
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.
|
||||
* 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();
|
||||
|
||||
RadioUiAction * addRadioUiAction(RadioUiAction * act);
|
||||
RadioUiAction * addRadioUiAction(int index = -1, int key = 0, const QString &text = "", const QString &descript = "");
|
||||
RadioUiAction * addRadioUiAction(int index, QList<int> keys, const QString &text = "", const QString &descript = "");
|
||||
RadioWidget * addRadioWidget(RadioWidget * keyWidget);
|
||||
RadioUiAction * addRadioAction(RadioUiAction * act);
|
||||
|
||||
QVector<keymapHelp_t> * getKeymapHelp() { return &m_keymapHelp; }
|
||||
QList<RadioUiAction *> getActions() const { return m_actions; }
|
||||
RadioUiAction * getRotEncAction() const { return m_rotEncClickAction; }
|
||||
QVector<Simulator::keymapHelp_t> getKeymapHelp() const;
|
||||
|
||||
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:
|
||||
|
||||
void updateUi();
|
||||
void captureScreenshot();
|
||||
void simulatorWheelEvent(qint8 steps);
|
||||
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void mousePressEvent(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 connectScrollActions();
|
||||
void onLcdChange(bool backlightEnable);
|
||||
virtual void setLightOn(bool enable) { }
|
||||
|
||||
protected:
|
||||
|
||||
SimulatorInterface * m_simulator;
|
||||
QWidget * m_parent;
|
||||
LcdWidget * m_lcd;
|
||||
QVector<QColor> m_backlightColors;
|
||||
QVector<keymapHelp_t> m_keymapHelp;
|
||||
QList<RadioUiAction *> m_actions;
|
||||
QList<RadioWidget *> m_widgets;
|
||||
RadioUiAction * m_scrollUpAction;
|
||||
RadioUiAction * m_scrollDnAction;
|
||||
RadioUiAction * m_rotEncClickAction;
|
||||
RadioUiAction * m_mouseMidClickAction;
|
||||
RadioUiAction * m_screenshotAction;
|
||||
Board::Type m_board;
|
||||
unsigned int m_backLight;
|
||||
bool m_lightOn;
|
||||
int m_beepShow;
|
||||
int m_beepVal;
|
||||
|
||||
signals:
|
||||
void customStyleRequest(const QString & style);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "simulateduiwidget.h"
|
||||
#include "ui_simulateduiwidget9X.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
SimulatedUIWidget9X::SimulatedUIWidget9X(SimulatorInterface * simulator, QWidget * parent):
|
||||
SimulatedUIWidget(simulator, parent),
|
||||
|
@ -30,39 +31,49 @@ SimulatedUIWidget9X::SimulatedUIWidget9X(SimulatorInterface * simulator, QWidget
|
|||
|
||||
ui->setupUi(this);
|
||||
|
||||
bool hasRotEnc = getCurrentFirmware()->getCapability(Capability::RotaryEncoders);
|
||||
|
||||
// add actions in order of appearance on the help menu
|
||||
|
||||
int x = 68, y = 91, oR = 63;
|
||||
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "9X/9xcursup.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursup.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "9X/9xcursdown.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursdown.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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("[ + ]"));
|
||||
ui->leftbuttons->addArea(polygon, "9X/9xcursmin.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "9X/9xcursmin.png", act));
|
||||
|
||||
polygon.clear();
|
||||
polygon << QPoint(x, y) << polyArc(x, y, oR, 225, 315);
|
||||
act = addRadioUiAction(5, QList<int>() << Qt::Key_Left << Qt::Key_Minus, tr("LEFT/-"), tr("[ - ]"));
|
||||
ui->leftbuttons->addArea(polygon, "9X/9xcursplus.png", act);
|
||||
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));
|
||||
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 ]"));
|
||||
m_rotEncClickAction = act;
|
||||
ui->rightbuttons->addArea(25, 60, 71, 81, "9X/9xmenumenu.png", act);
|
||||
act = new RadioUiAction(0, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr(SIMU_STR_HLP_KEY_ENTER), tr(SIMU_STR_HLP_ACT_MENU));
|
||||
addRadioWidget(ui->rightbuttons->addArea(QRect(16, 54, 60, 34), "9X/9xmenumenu.png", act));
|
||||
|
||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
||||
ui->rightbuttons->addArea(25, 117, 71, 139, "9X/9xmenuexit.png", act);
|
||||
if (!hasRotEnc) {
|
||||
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(166,247,159);
|
||||
|
|
|
@ -35,48 +35,47 @@ SimulatedUIWidgetX12::SimulatedUIWidgetX12(SimulatorInterface *simulator, QWidge
|
|||
int x = 74, y = 190, oR = 63, iR = 40;
|
||||
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "Horus/left_btn1.png", act);
|
||||
act = new RadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr(SIMU_STR_HLP_KEY_PGUP), tr(SIMU_STR_HLP_ACT_PGUP));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "Horus/left_btn1.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "Horus/left_btn2.png", act);
|
||||
act = new RadioUiAction(1, QList<int>() << Qt::Key_PageDown, tr(SIMU_STR_HLP_KEY_PGDN), tr(SIMU_STR_HLP_ACT_PGDN));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "Horus/left_btn2.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
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);
|
||||
act = new RadioUiAction(3, QList<int>() << Qt::Key_Up, tr(SIMU_STR_HLP_KEY_UP), tr(SIMU_STR_HLP_ACT_MDL));
|
||||
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnU.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnL.png", act);
|
||||
act = new RadioUiAction(6, QList<int>() << Qt::Key_Left, tr(SIMU_STR_HLP_KEY_LFT), tr(SIMU_STR_HLP_ACT_SYS));
|
||||
addRadioWidget(ui->rightbuttons->addArea(polygon, "Horus/right_btnL.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->rightbuttons->addArea(polygon, "Horus/right_btnR.png", act);
|
||||
act = new RadioUiAction(5, QList<int>() << Qt::Key_Right, tr(SIMU_STR_HLP_KEY_RGT), tr(SIMU_STR_HLP_ACT_TELE));
|
||||
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_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_C, tr("+/C"), tr("Rotary DOWN"));
|
||||
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 = 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"));
|
||||
ui->rightbuttons->addArea(polyArc(x, y, iR), "Horus/right_ent.png", act);
|
||||
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));
|
||||
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);
|
||||
|
||||
setLcd(ui->lcd);
|
||||
connectScrollActions();
|
||||
}
|
||||
|
||||
SimulatedUIWidgetX12::~SimulatedUIWidgetX12()
|
||||
|
|
|
@ -14,26 +14,25 @@ SimulatedUIWidgetX7::SimulatedUIWidgetX7(SimulatorInterface *simulator, QWidget
|
|||
|
||||
QPoint ctr(70, 91);
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "X7/left_page.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "X7/left_page.png", act));
|
||||
|
||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ MENU ]"));
|
||||
ui->leftbuttons->addArea(polyArc(ctr.x(), ctr.y(), 20), "X7/left_menu.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polyArc(ctr.x(), ctr.y(), 20), "X7/left_menu.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "X7/left_exit.png", act);
|
||||
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->leftbuttons->addArea(polygon, "X7/left_exit.png", act));
|
||||
|
||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("Rotary Selector")));
|
||||
m_scrollUpAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
|
||||
m_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
|
||||
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_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));
|
||||
connectScrollActions();
|
||||
|
||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("Selector Press"));
|
||||
ui->rightbuttons->addArea(polyArc(88, 92, 33), "X7/right_ent.png", act);
|
||||
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));
|
||||
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(166,247,159);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Taranis X7 Simulator</string>
|
||||
<string notr="true">Taranis X7 Simulator</string>
|
||||
</property>
|
||||
<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>
|
||||
|
|
|
@ -26,40 +26,46 @@ SimulatedUIWidgetX9::SimulatedUIWidgetX9(SimulatorInterface *simulator, QWidget
|
|||
ui(new Ui::SimulatedUIWidgetX9)
|
||||
{
|
||||
RadioUiAction * act;
|
||||
QPolygon polygon;
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
// add actions in order of appearance on the help menu
|
||||
|
||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ MENU ]"));
|
||||
polygon.setPoints(6, 20, 59, 27, 50, 45, 52, 56, 59, 50, 71, 26, 72);
|
||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l1.png", act);
|
||||
// button placement, size, spacing
|
||||
const int btop = 45, vsp = 17;
|
||||
QRect btn(16, btop, 46, 31);
|
||||
|
||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PAGE ]"));
|
||||
polygon.setPoints(6, 23, 107, 30, 99, 46, 100, 55, 106, 47, 117, 28, 117);
|
||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l2.png", act);
|
||||
// left side
|
||||
|
||||
act = addRadioUiAction(1, QList<int>() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, tr("DEL/BKSP/ESC"), tr("[ EXIT ]"));
|
||||
polygon.setPoints(6, 24, 154, 32, 144, 46, 146, 57, 156, 46, 167, 29, 166);
|
||||
ui->leftbuttons->addArea(polygon, "Taranis/x9l3.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(btn, "Taranis/x9l1.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("[ + ]"));
|
||||
m_scrollDnAction = addRadioUiAction(5, QList<int>() << Qt::Key_Minus << Qt::Key_Down, tr("-/DN"), 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));
|
||||
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);
|
||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r1.png", m_scrollUpAction);
|
||||
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->leftbuttons->addArea(btn, "Taranis/x9l3.png", act));
|
||||
|
||||
polygon.setPoints(6, 63, 109, 73, 100, 88, 100, 98, 109, 88, 119, 72, 119);
|
||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r2.png", m_scrollDnAction);
|
||||
m_scrollUpAction = new RadioUiAction(4, QList<int>() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_Left,
|
||||
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 ]"));
|
||||
polygon.setPoints(6, 63, 155, 72, 146, 90, 146, 98, 155, 88, 166, 72, 166);
|
||||
ui->rightbuttons->addArea(polygon, "Taranis/x9r3.png", act);
|
||||
// right side
|
||||
btn.moveTopLeft(QPoint(58, btop));
|
||||
|
||||
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(166,247,159);
|
||||
|
|
|
@ -35,28 +35,27 @@ SimulatedUIWidgetX9E::SimulatedUIWidgetX9E(SimulatorInterface *simulator, QWidge
|
|||
QPoint ctr(70, 100);
|
||||
|
||||
polygon << polyArc(ctr.x(), ctr.y(), 60, -90, 0) << ctr;
|
||||
act = addRadioUiAction(0, QList<int>() << Qt::Key_PageUp, tr("PG-UP"), tr("[ MENU ]"));
|
||||
ui->leftbuttons->addArea(polygon, "X9E/left_menu.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "X9E/left_menu.png", act));
|
||||
|
||||
polygon.clear();
|
||||
polygon << polyArc(ctr.x(), ctr.y(), 45, 0, 180);
|
||||
act = addRadioUiAction(3, QList<int>() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PAGE ]"));
|
||||
ui->leftbuttons->addArea(polygon, "X9E/left_page.png", act);
|
||||
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));
|
||||
addRadioWidget(ui->leftbuttons->addArea(polygon, "X9E/left_page.png", act));
|
||||
|
||||
polygon.clear();
|
||||
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 ]"));
|
||||
ui->leftbuttons->addArea(polygon, "X9E/left_exit.png", act);
|
||||
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->leftbuttons->addArea(polygon, "X9E/left_exit.png", act));
|
||||
|
||||
m_keymapHelp.append(keymapHelp_t(tr("WHEEL/PAD SCRL"), tr("Rotary Selector")));
|
||||
m_scrollUpAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
|
||||
m_scrollDnAction = addRadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
|
||||
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_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)));
|
||||
connectScrollActions();
|
||||
|
||||
act = addRadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, tr("ENTER/MOUSE-MID"), tr("Selector Press"));
|
||||
ui->rightbuttons->addArea(polyArc(90, 100, 50), "X9E/right_enter.png", act);
|
||||
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));
|
||||
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(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 <QMap>
|
||||
|
||||
struct TxInputs
|
||||
{
|
||||
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];
|
||||
};
|
||||
#define SIMULATOR_INTERFACE_HEARTBEAT_PERIOD 1000 // ms
|
||||
|
||||
class TxOutputs
|
||||
class SimulatorInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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
|
||||
{
|
||||
int values[CPN_MAX_TRIMS]; /* lh lv rv rh t5 t6 */
|
||||
bool extended;
|
||||
};
|
||||
enum InputSourceType {
|
||||
INPUT_SRC_NONE = 0,
|
||||
INPUT_SRC_ANALOG, // any analog source, index into g_anas[]
|
||||
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
|
||||
{
|
||||
public:
|
||||
enum OutputSourceType {
|
||||
OUTPUT_SRC_NONE = 0,
|
||||
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 void setSdPath(const QString & sdPath = "", const QString & settingsPath = "") { }
|
||||
|
||||
virtual void setVolumeGain(int value) { }
|
||||
|
||||
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 QString name() = 0;
|
||||
virtual bool isRunning() = 0;
|
||||
virtual void readRadioData(QByteArray & dest) = 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 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 installTraceHook(void (*callback)(const char *)) = 0;
|
||||
|
||||
virtual void setInputValue(int type, uint8_t index, int16_t value) = 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 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 {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~SimulatorFactory() { }
|
||||
|
||||
virtual QString name() = 0;
|
||||
|
||||
virtual Board::Type type() = 0;
|
||||
|
||||
virtual SimulatorInterface *create() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -69,6 +69,9 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa
|
|||
return;
|
||||
}
|
||||
|
||||
m_simulator->moveToThread(&simuThread);
|
||||
simuThread.start();
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
||||
|
@ -103,38 +106,42 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa
|
|||
ui->menuView->insertSeparator(ui->actionToggleMenuBar);
|
||||
ui->menuView->insertAction(ui->actionToggleMenuBar, ui->toolBar->toggleViewAction());
|
||||
|
||||
// Hide some actions based on board capabilities.
|
||||
Firmware * firmware = getCurrentFirmware();
|
||||
if(!firmware->getCapability(Capability(LuaInputsPerScript)))
|
||||
// Hide some actions based on simulator capabilities.
|
||||
if(!m_simulator->getCapability(SimulatorInterface::CAP_LUA))
|
||||
ui->actionReloadLua->setDisabled(true);
|
||||
if (!firmware->getCapability(Capability(SportTelemetry)))
|
||||
if(!m_simulator->getCapability(SimulatorInterface::CAP_TELEM_FRSKY_SPORT))
|
||||
m_telemetryDockWidget->toggleViewAction()->setDisabled(true);
|
||||
#ifndef JOYSTICKS
|
||||
ui->actionJoystickSettings->setDisabled(true);
|
||||
#endif
|
||||
|
||||
// Add radio-specific help text from simulator widget
|
||||
foreach (keymapHelp_t item, *m_simulatorWidget->getKeymapHelp())
|
||||
m_keymapHelp.append(item);
|
||||
|
||||
restoreUiState();
|
||||
|
||||
setStyleSheet(SimulatorStyle::styleSheet());
|
||||
|
||||
connect(ui->actionShowKeymap, &QAction::triggered, this, &SimulatorMainWindow::showHelp);
|
||||
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->actionFixedRadioWidth, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedWidth);
|
||||
connect(ui->actionFixedRadioHeight, &QAction::toggled, this, &SimulatorMainWindow::showRadioFixedHeight);
|
||||
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) {
|
||||
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->actionReloadRadioData, &QAction::triggered, m_simulatorWidget, &SimulatorWidget::restart);
|
||||
connect(m_simulatorWidget, &SimulatorWidget::windowTitleChanged, this, &SimulatorMainWindow::setWindowTitle);
|
||||
}
|
||||
if (m_outputsWidget)
|
||||
connect(ui->actionReloadRadioData, &QAction::triggered, m_outputsWidget, &RadioOutputsWidget::restart);
|
||||
|
||||
|
||||
}
|
||||
|
||||
SimulatorMainWindow::~SimulatorMainWindow()
|
||||
|
@ -154,9 +161,11 @@ SimulatorMainWindow::~SimulatorMainWindow()
|
|||
|
||||
delete ui;
|
||||
|
||||
if (m_simulator)
|
||||
if (m_simulator) {
|
||||
simuThread.quit();
|
||||
simuThread.wait();
|
||||
delete m_simulator;
|
||||
|
||||
}
|
||||
SimulatorLoader::unloadSimulator(m_simulatorId);
|
||||
}
|
||||
|
||||
|
@ -256,11 +265,6 @@ bool SimulatorMainWindow::setOptions(SimulatorOptions & options, bool withSave)
|
|||
|
||||
void SimulatorMainWindow::start()
|
||||
{
|
||||
if (m_simulatorWidget)
|
||||
m_simulatorWidget->start();
|
||||
if (m_outputsWidget)
|
||||
m_outputsWidget->start();
|
||||
|
||||
emit simulatorStart();
|
||||
}
|
||||
|
||||
|
@ -282,8 +286,6 @@ void SimulatorMainWindow::createDockWidgets()
|
|||
m_telemetryDockWidget->setWidget(telem);
|
||||
m_telemetryDockWidget->setObjectName("TELEMETRY_SIMULATOR");
|
||||
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) {
|
||||
|
@ -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)
|
||||
{
|
||||
#ifdef JOYSTICKS
|
||||
|
@ -472,19 +467,34 @@ void SimulatorMainWindow::openJoystickDialog(bool)
|
|||
|
||||
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 += tr("<tr><th>Key/Mouse</td><th>Action</td></tr>");
|
||||
QString keyTemplate = "<tr><td align='center'><pre>%1</pre></td><td align='center'>%2</td></tr>";
|
||||
foreach (keymapHelp_t pair, m_keymapHelp)
|
||||
helpText += tr("<tr><th>Key/Mouse</th><th>Action</th></tr>", "note: must match html layout of each table row (keyTemplate).");
|
||||
|
||||
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);
|
||||
// Add any radio-specific help text from simulator widget
|
||||
foreach (pair, m_simulatorWidget->getKeymapHelp())
|
||||
helpText += keyTemplate.arg(pair.first, pair.second);
|
||||
|
||||
helpText += "</table>";
|
||||
|
||||
QMessageBox * msgBox = new QMessageBox(this);
|
||||
msgBox->setObjectName("SimulatorHelpText");
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
msgBox->setStandardButtons( QMessageBox::Ok );
|
||||
msgBox->setWindowTitle(tr("Simulator Help"));
|
||||
msgBox->setTextFormat(Qt::RichText);
|
||||
msgBox->setText(helpText);
|
||||
msgBox->setModal(false);
|
||||
msgBox->show();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <QDockWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QThread>
|
||||
|
||||
class DebugOutput;
|
||||
class RadioData;
|
||||
|
@ -67,6 +68,7 @@ class SimulatorMainWindow : public QMainWindow
|
|||
|
||||
signals:
|
||||
void simulatorStart();
|
||||
void simulatorRestart();
|
||||
|
||||
protected slots:
|
||||
virtual void closeEvent(QCloseEvent *);
|
||||
|
@ -76,7 +78,6 @@ class SimulatorMainWindow : public QMainWindow
|
|||
void toggleMenuBar(bool show);
|
||||
void setRadioSizePolicy(int fixType);
|
||||
void toggleRadioDocked(bool dock);
|
||||
void luaReload(bool);
|
||||
void openJoystickDialog(bool);
|
||||
void showHelp(bool show);
|
||||
|
||||
|
@ -97,6 +98,7 @@ class SimulatorMainWindow : public QMainWindow
|
|||
QDockWidget * m_trainerDockWidget;
|
||||
QDockWidget * m_outputsDockWidget;
|
||||
|
||||
QThread simuThread;
|
||||
QVector<keymapHelp_t> m_keymapHelp;
|
||||
QString m_simulatorId;
|
||||
QString m_exitStatusMsg;
|
||||
|
|
|
@ -24,12 +24,13 @@
|
|||
#include "appdata.h"
|
||||
#include "appdebugmessagehandler.h"
|
||||
#include "radiofaderwidget.h"
|
||||
#include "radiokeywidget.h"
|
||||
#include "radioknobwidget.h"
|
||||
#include "radioswitchwidget.h"
|
||||
#include "radiotrimwidget.h"
|
||||
#include "radiouiaction.h"
|
||||
#include "sdcard.h"
|
||||
#include "simulateduiwidget.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "storage.h"
|
||||
#include "virtualjoystickwidget.h"
|
||||
#ifdef JOYSTICKS
|
||||
|
@ -41,36 +42,27 @@
|
|||
#include <QMessageBox>
|
||||
#include <iostream>
|
||||
|
||||
SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator, quint8 flags):
|
||||
using namespace Simulator;
|
||||
|
||||
SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulator, quint8 flags):
|
||||
QWidget(parent),
|
||||
ui(new Ui::SimulatorWidget),
|
||||
simulator(simulator),
|
||||
firmware(getCurrentFirmware()),
|
||||
radioSettings(GeneralSettings()),
|
||||
timer(new QTimer(this)),
|
||||
radioUiWidget(NULL),
|
||||
vJoyLeft(NULL),
|
||||
vJoyRight(NULL),
|
||||
m_board(getCurrentBoard()),
|
||||
flags(flags),
|
||||
lastPhase(-1),
|
||||
buttonPressed(0),
|
||||
trimPressed(255),
|
||||
startupFromFile(false),
|
||||
deleteTempRadioData(false),
|
||||
saveTempRadioData(false),
|
||||
middleButtonPressed(false),
|
||||
firstShow(true)
|
||||
{
|
||||
|
||||
saveTempRadioData(false)
|
||||
#ifdef JOYSTICKS
|
||||
joystick = NULL;
|
||||
, joystick(NULL)
|
||||
#endif
|
||||
|
||||
// defaults
|
||||
setRadioProfileId(g.sessionId());
|
||||
setSdPath(g.profile[radioProfileId].sdPath());
|
||||
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
windowName = tr("Radio Simulator (%1)").arg(firmware->getName());
|
||||
|
@ -96,7 +88,7 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
|||
break;
|
||||
}
|
||||
|
||||
foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp())
|
||||
foreach (keymapHelp_t item, radioUiWidget->getKeymapHelp())
|
||||
keymapHelp.append(item);
|
||||
|
||||
ui->radioUiWidget->layout()->removeItem(ui->radioUiTempSpacer);
|
||||
|
@ -105,6 +97,7 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
|||
radioUiWidget->setFocusPolicy(Qt::WheelFocus);
|
||||
radioUiWidget->setFocus();
|
||||
|
||||
connect(radioUiWidget, &SimulatedUIWidget::controlValueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||
connect(radioUiWidget, &SimulatedUIWidget::customStyleRequest, this, &SimulatorWidget::setUiAreaStyle);
|
||||
|
||||
vJoyLeft = new VirtualJoystickWidget(this, 'L');
|
||||
|
@ -113,25 +106,43 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface *simulator
|
|||
vJoyRight = new VirtualJoystickWidget(this, 'R');
|
||||
ui->rightStickLayout->addWidget(vJoyRight);
|
||||
|
||||
connect(vJoyLeft, &VirtualJoystickWidget::trimButtonPressed, this, &SimulatorWidget::onTrimPressed);
|
||||
connect(vJoyLeft, &VirtualJoystickWidget::trimButtonReleased, this, &SimulatorWidget::onTrimReleased);
|
||||
connect(vJoyLeft, &VirtualJoystickWidget::trimSliderMoved, this, &SimulatorWidget::onTrimSliderMoved);
|
||||
connect(vJoyLeft, &VirtualJoystickWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||
connect(vJoyRight, &VirtualJoystickWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
|
||||
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(vJoyRight, &VirtualJoystickWidget::trimButtonReleased, this, &SimulatorWidget::onTrimReleased);
|
||||
connect(vJoyRight, &VirtualJoystickWidget::trimSliderMoved, this, &SimulatorWidget::onTrimSliderMoved);
|
||||
connect(this, &SimulatorWidget::simulatorInit, simulator, &SimulatorInterface::init);
|
||||
connect(this, &SimulatorWidget::simulatorStart, simulator, &SimulatorInterface::start);
|
||||
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(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||
connect(timer, SIGNAL(timeout()), radioUiWidget, SLOT(updateUi()));
|
||||
connect(simulator, &SimulatorInterface::started, this, &SimulatorWidget::onSimulatorStarted);
|
||||
connect(simulator, &SimulatorInterface::stopped, this, &SimulatorWidget::onSimulatorStopped);
|
||||
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()
|
||||
{
|
||||
shutdown();
|
||||
|
||||
if (timer)
|
||||
timer->deleteLater();
|
||||
if (radioUiWidget)
|
||||
delete radioUiWidget;
|
||||
if (vJoyLeft)
|
||||
|
@ -142,10 +153,7 @@ SimulatorWidget::~SimulatorWidget()
|
|||
if (joystick)
|
||||
delete joystick;
|
||||
#endif
|
||||
|
||||
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.
|
||||
|
||||
firmware = NULL;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
@ -168,8 +176,7 @@ void SimulatorWidget::setPaths(const QString & sdPath, const QString & dataPath)
|
|||
{
|
||||
sdCardPath = sdPath;
|
||||
radioDataPath = dataPath;
|
||||
if (simulator)
|
||||
simulator->setSdPath(sdPath, dataPath);
|
||||
emit simulatorSdPathChange(sdPath, dataPath);
|
||||
}
|
||||
|
||||
void SimulatorWidget::setRadioSettings(const GeneralSettings settings)
|
||||
|
@ -264,7 +271,7 @@ bool SimulatorWidget::setRadioData(RadioData * radioData)
|
|||
|
||||
if (ret) {
|
||||
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) {
|
||||
ret = false;
|
||||
}
|
||||
|
@ -410,8 +417,7 @@ void SimulatorWidget::deleteTempData()
|
|||
void SimulatorWidget::saveState()
|
||||
{
|
||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||
//opts.windowGeometry = saveGeometry();
|
||||
opts.controlsState = saveRadioWidgetsState();
|
||||
saveRadioWidgetsState(opts.controlsState);
|
||||
g.profile[radioProfileId].simulatorOptions(opts);
|
||||
}
|
||||
|
||||
|
@ -432,35 +438,58 @@ void SimulatorWidget::captureScreenshot(bool)
|
|||
|
||||
void SimulatorWidget::start()
|
||||
{
|
||||
emit simulatorInit(); // init simulator default I/O values
|
||||
|
||||
setupRadioWidgets();
|
||||
setupJoysticks();
|
||||
restoreRadioWidgetsState();
|
||||
|
||||
if (startupData.isEmpty())
|
||||
simulator->start((const char *)0);
|
||||
else if (startupFromFile)
|
||||
simulator->start(startupData.constData());
|
||||
else
|
||||
simulator->start(startupData, (flags & SIMULATOR_FLAGS_NOTX) ? false : true);
|
||||
|
||||
setTrims();
|
||||
getValues();
|
||||
setupTimer();
|
||||
bool tests = !(flags & SIMULATOR_FLAGS_NOTX);
|
||||
if (!startupData.isEmpty()) {
|
||||
if (startupFromFile) {
|
||||
emit simulatorStart(startupData.constData(), tests);
|
||||
}
|
||||
else {
|
||||
simulator->setRadioData(startupData);
|
||||
emit simulatorStart((const char *)0, tests);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit simulatorStart((const char *)0, tests);
|
||||
}
|
||||
}
|
||||
|
||||
void SimulatorWidget::stop()
|
||||
{
|
||||
if (timer)
|
||||
timer->stop();
|
||||
if (simulator) {
|
||||
simulator->stop();
|
||||
if (saveTempRadioData) {
|
||||
startupData.fill(0, getEEpromSize(m_board));
|
||||
simulator->readEepromData(startupData);
|
||||
emit simulatorStop();
|
||||
QElapsedTimer tmout;
|
||||
tmout.start();
|
||||
// block until simulator stops or times out
|
||||
while (simulator->isRunning()) {
|
||||
if (tmout.hasExpired(2000)) {
|
||||
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()
|
||||
{
|
||||
stop();
|
||||
|
@ -486,100 +515,112 @@ void SimulatorWidget::shutdown()
|
|||
void SimulatorWidget::setRadioProfileId(int value)
|
||||
{
|
||||
radioProfileId = value;
|
||||
if (simulator)
|
||||
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
||||
emit simulatorVolumeGainChange(g.profile[radioProfileId].volumeGain());
|
||||
}
|
||||
|
||||
void SimulatorWidget::setupRadioWidgets()
|
||||
{
|
||||
int i, midpos, aIdx;
|
||||
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.
|
||||
if (switches.size()) {
|
||||
foreach (RadioWidget * w, switches) {
|
||||
ui->radioWidgetsHTLayout->removeWidget(w);
|
||||
w->deleteLater();
|
||||
foreach (RadioWidget * rw, m_radioWidgets) {
|
||||
switch(rw->getType()) {
|
||||
case RadioWidget::RADIO_WIDGET_SWITCH :
|
||||
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();
|
||||
}
|
||||
if (analogs.size()) {
|
||||
foreach (RadioWidget * w, analogs) {
|
||||
if (w->getType() == RadioWidget::RADIO_WIDGET_KNOB)
|
||||
ui->radioWidgetsHTLayout->removeWidget(w);
|
||||
else
|
||||
ui->VCGridLayout->removeWidget(w);
|
||||
w->deleteLater();
|
||||
}
|
||||
analogs.clear();
|
||||
disconnect(rw, 0, this, 0);
|
||||
disconnect(this, 0, rw, 0);
|
||||
rw->deleteLater();
|
||||
}
|
||||
m_radioWidgets.clear();
|
||||
|
||||
// Now set up new widgets.
|
||||
|
||||
// switches
|
||||
Board::SwitchInfo switchInfo;
|
||||
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)
|
||||
continue;
|
||||
|
||||
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
||||
|
||||
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
|
||||
switchInfo = getSwitchInfo(board, i);
|
||||
wname = QString(switchInfo.name);
|
||||
}
|
||||
wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(NULL, &radioSettings);
|
||||
RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT);
|
||||
sw->setIndex(i);
|
||||
ui->radioWidgetsHTLayout->addWidget(sw);
|
||||
switches.append(sw);
|
||||
|
||||
m_radioWidgets.append(sw);
|
||||
}
|
||||
|
||||
midpos = (int)floorf(switches.size() / 2.0f);
|
||||
aIdx = 0;
|
||||
midpos = (int)floorf(m_radioWidgets.size() / 2.0f);
|
||||
|
||||
// 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))
|
||||
continue;
|
||||
|
||||
if ((wname = QString(radioSettings.potName[i])).isEmpty())
|
||||
wname = firmware->getAnalogInputName(4 + aIdx + i);
|
||||
|
||||
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + i).toString(NULL, &radioSettings);
|
||||
RadioKnobWidget * pot = new RadioKnobWidget(Board::PotType(radioSettings.potConfig[i]), wname, 0, ui->radioWidgetsHT);
|
||||
pot->setIndex(aIdx + 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);
|
||||
pot->setIndex(i);
|
||||
ui->radioWidgetsHTLayout->insertWidget(midpos++, pot);
|
||||
analogs.append(pot);
|
||||
|
||||
m_radioWidgets.append(pot);
|
||||
}
|
||||
|
||||
aIdx += i;
|
||||
|
||||
// faders between sticks
|
||||
int r = 0, c = 0;
|
||||
for (i = 0; i < getBoardCapability(board, Board::Sliders) && i + aIdx < CPN_MAX_POTS; ++i) {
|
||||
int c = extraTrims / 2; // leave space for any extra trims
|
||||
for (i = 0; i < ttlFaders; ++i) {
|
||||
if (!radioSettings.isSliderAvailable(i))
|
||||
continue;
|
||||
|
||||
if ((wname = QString(radioSettings.sliderName[i])).isEmpty())
|
||||
wname = firmware->getAnalogInputName(4 + aIdx + i);
|
||||
|
||||
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + ttlKnobs + i).toString(NULL, &radioSettings);
|
||||
RadioFaderWidget * sl = new RadioFaderWidget(wname, 0, ui->radioWidgetsVC);
|
||||
sl->setIndex(aIdx + 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))
|
||||
sl->setInvertValue(true);
|
||||
/* 2-row option
|
||||
if (!(i % 2)) {
|
||||
++r;
|
||||
c = 0;
|
||||
} */
|
||||
ui->VCGridLayout->addWidget(sl, r, c++, 1, 1);
|
||||
analogs.append(sl);
|
||||
sl->setIndex(i);
|
||||
ui->VCGridLayout->addWidget(sl, 0, c++, 1, 1);
|
||||
|
||||
m_radioWidgets.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()
|
||||
|
@ -600,6 +641,10 @@ void SimulatorWidget::setupJoysticks()
|
|||
joystick->deadzones[j] = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
|
@ -609,164 +654,50 @@ void SimulatorWidget::setupJoysticks()
|
|||
else if (joystick) {
|
||||
joystick->close();
|
||||
disconnect(joystick, 0, this, 0);
|
||||
if (vJoyLeft)
|
||||
disconnect(this, 0, vJoyLeft, 0);
|
||||
if (vJoyRight)
|
||||
disconnect(this, 0, vJoyRight, 0);
|
||||
joystick->deleteLater();
|
||||
joystick = NULL;
|
||||
}
|
||||
if (vJoyRight) {
|
||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_X, joysticksEnabled);
|
||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, joysticksEnabled);
|
||||
}
|
||||
if (vJoyLeft) {
|
||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_X, joysticksEnabled);
|
||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, joysticksEnabled);
|
||||
}
|
||||
if (vJoyRight)
|
||||
vJoyRight->setStickConstraint((VirtualJoystickWidget::HOLD_X | VirtualJoystickWidget::HOLD_Y), joysticksEnabled);
|
||||
if (vJoyLeft)
|
||||
vJoyLeft->setStickConstraint((VirtualJoystickWidget::HOLD_X | VirtualJoystickWidget::HOLD_Y), joysticksEnabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SimulatorWidget::setupTimer()
|
||||
{
|
||||
if (!timer)
|
||||
return;
|
||||
|
||||
if (timer->isActive())
|
||||
timer->stop();
|
||||
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void SimulatorWidget::restoreRadioWidgetsState()
|
||||
{
|
||||
// All RadioWidgets
|
||||
RadioWidget::RadioWidgetState state;
|
||||
QMap<int, QByteArray> switchesMap;
|
||||
QMap<int, QByteArray> analogsMap;
|
||||
QList<QByteArray> states = g.profile[radioProfileId].simulatorOptions().controlsState;
|
||||
|
||||
foreach (QByteArray ba, states) {
|
||||
QDataStream stream(ba);
|
||||
stream >> state;
|
||||
if (state.type == RadioWidget::RADIO_WIDGET_SWITCH)
|
||||
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()));
|
||||
emit widgetStateChange(state);
|
||||
}
|
||||
|
||||
// Set throttle stick down and locked, side depends on mode
|
||||
if (radioSettings.stickMode & 1) {
|
||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyLeft->setStickY(1);
|
||||
}
|
||||
else {
|
||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyRight->setStickY(1);
|
||||
}
|
||||
emit stickModeChange(radioSettings.stickMode);
|
||||
|
||||
// TODO : custom voltages
|
||||
qint16 volts = radioSettings.vBatWarn + 2;
|
||||
if (firmware->getCapability(Capability::HasBatMeterRange))
|
||||
volts = (radioSettings.vBatMin + 90) + ((radioSettings.vBatMax + 30) - radioSettings.vBatMin) / 2;
|
||||
emit inputValueChange(SimulatorInterface::INPUT_SRC_TXVIN, 0, volts);
|
||||
}
|
||||
|
||||
QList<QByteArray> SimulatorWidget::saveRadioWidgetsState()
|
||||
void SimulatorWidget::saveRadioWidgetsState(QList<QByteArray> & state)
|
||||
{
|
||||
QList<QByteArray> states;
|
||||
|
||||
for (int i = 0; i < analogs.size(); ++i)
|
||||
states.append(analogs[i]->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));
|
||||
if (m_radioWidgets.size()) {
|
||||
state.clear();
|
||||
foreach (RadioWidget * rw, m_radioWidgets)
|
||||
state.append(rw->getStateData());
|
||||
}
|
||||
}
|
||||
|
||||
// "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
|
||||
|
@ -792,51 +723,95 @@ void SimulatorWidget::wheelEvent(QWheelEvent *event)
|
|||
|
||||
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()) {
|
||||
QMessageBox::critical(this, "Companion", tr("Firmware %1 error: %2").arg(firmware->getName()).arg(simulator->getError()));
|
||||
timer->stop();
|
||||
void SimulatorWidget::onSimulatorHeartbeat(qint32 loops, qint64 timestamp)
|
||||
{
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
emit inputValueChange(inpType, index, value);
|
||||
}
|
||||
|
||||
void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
||||
{
|
||||
#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;
|
||||
|
||||
if (!joystick || axis >= MAX_JOYSTICKS)
|
||||
|
@ -845,7 +820,7 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
|||
int dlta;
|
||||
int stick = g.joystick[axis].stick_axe();
|
||||
|
||||
if (stick < 0 || stick >= ttlSticks + analogs.count())
|
||||
if (stick < 0 || stick >= ttlSticks + ttlKnobs + ttlFaders)
|
||||
return;
|
||||
|
||||
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())
|
||||
stickval *= -1;
|
||||
|
||||
if (stick==1 ) {
|
||||
vJoyRight->setStickY(-stickval/1024.0);
|
||||
if (stick < ttlSticks) {
|
||||
emit stickValueChange(stick, stickval);
|
||||
}
|
||||
else if (stick==2) {
|
||||
vJoyRight->setStickX(stickval/1024.0);
|
||||
}
|
||||
else if (stick==3) {
|
||||
vJoyLeft->setStickY(-stickval/1024.0);
|
||||
}
|
||||
else if (stick==4) {
|
||||
vJoyLeft->setStickX(stickval/1024.0);
|
||||
}
|
||||
else if (stick > ttlSticks) {
|
||||
analogs[stick-ttlSticks-1]->setValue(stickval);
|
||||
else {
|
||||
stick -= ttlSticks;
|
||||
if (stick < ttlKnobs)
|
||||
emit widgetValueChange(RadioWidget::RADIO_WIDGET_KNOB, stick, stickval);
|
||||
else
|
||||
emit widgetValueChange(RadioWidget::RADIO_WIDGET_FADER, stick, stickval);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,24 +24,20 @@
|
|||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiowidget.h"
|
||||
#include "simulator.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
|
||||
#define FLASH_DURATION 10
|
||||
|
||||
#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
||||
#define CBEEP_OFF "QLabel { }"
|
||||
|
||||
void traceCb(const char * text);
|
||||
|
||||
class Firmware;
|
||||
class SimulatorInterface;
|
||||
class SimulatedUIWidget;
|
||||
class RadioWidget;
|
||||
class RadioSwitchWidget;
|
||||
class VirtualJoystickWidget;
|
||||
#ifdef JOYSTICKS
|
||||
class Joystick;
|
||||
|
@ -56,8 +52,6 @@ namespace Ui {
|
|||
class SimulatorWidget;
|
||||
}
|
||||
|
||||
using namespace Simulator;
|
||||
|
||||
class SimulatorWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -84,7 +78,7 @@ class SimulatorWidget : public QWidget
|
|||
|
||||
QString getSdPath() const { return sdCardPath; }
|
||||
QString getDataPath() const { return radioDataPath; }
|
||||
QVector<keymapHelp_t> * getKeymapHelp() { return &keymapHelp; }
|
||||
QVector<Simulator::keymapHelp_t> getKeymapHelp() const { return keymapHelp; }
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
@ -92,52 +86,18 @@ class SimulatorWidget : public QWidget
|
|||
void restart();
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
void setRadioProfileId(int value);
|
||||
void setupRadioWidgets();
|
||||
void setupTimer();
|
||||
void restoreRadioWidgetsState();
|
||||
QList<QByteArray> saveRadioWidgetsState();
|
||||
|
||||
void setValues();
|
||||
void getValues();
|
||||
void setTrims();
|
||||
|
||||
|
||||
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
|
||||
signals:
|
||||
void stickValueChange(int axis, int value);
|
||||
void stickModeChange(const unsigned mode);
|
||||
void widgetValueChange(const RadioWidget::RadioWidgetType type, const int index, const int value);
|
||||
void widgetStateChange(const RadioWidget::RadioWidgetState & state);
|
||||
void inputValueChange(int type, quint8 index, qint16 value);
|
||||
void simulatorSetData(const QByteArray & data);
|
||||
void simulatorInit();
|
||||
void simulatorStart(const char * filename, bool tests);
|
||||
void simulatorStop();
|
||||
void simulatorSdPathChange(const QString & sdPath, const QString & dataPath);
|
||||
void simulatorVolumeGainChange(const int gain);
|
||||
|
||||
private slots:
|
||||
virtual void mousePressEvent(QMouseEvent *event);
|
||||
|
@ -145,12 +105,50 @@ class SimulatorWidget : public QWidget
|
|||
virtual void wheelEvent(QWheelEvent *event);
|
||||
|
||||
void onTimerEvent();
|
||||
void onTrimPressed(int index);
|
||||
void onTrimReleased(int);
|
||||
void onTrimSliderMoved(int index, int value);
|
||||
void centerSticks();
|
||||
void onSimulatorStarted();
|
||||
void onSimulatorStopped();
|
||||
void onSimulatorHeartbeat(qint32 loops, qint64 timestamp);
|
||||
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 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_
|
||||
|
|
|
@ -27,25 +27,13 @@
|
|||
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||
QWidget(parent),
|
||||
ui(new Ui::TelemetrySimulator),
|
||||
simulator(simulator)
|
||||
simulator(simulator),
|
||||
m_simuStarted(false),
|
||||
m_telemEnable(false),
|
||||
m_logReplayEnable(false)
|
||||
{
|
||||
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->A2->setSpecialValueText(" ");
|
||||
ui->A3->setSpecialValueText(" ");
|
||||
|
@ -57,7 +45,27 @@ TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * si
|
|||
ui->A1_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);
|
||||
|
||||
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()
|
||||
|
@ -70,9 +78,15 @@ TelemetrySimulator::~TelemetrySimulator()
|
|||
|
||||
void TelemetrySimulator::onSimulatorStarted()
|
||||
{
|
||||
m_simuStarted = true;
|
||||
setupDataFields();
|
||||
}
|
||||
|
||||
void TelemetrySimulator::onSimulatorStopped()
|
||||
{
|
||||
m_simuStarted = false;
|
||||
}
|
||||
|
||||
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
||||
{
|
||||
if (isChecked) {
|
||||
|
@ -149,13 +163,23 @@ void TelemetrySimulator::onReplayRateChanged(int value)
|
|||
}
|
||||
}
|
||||
|
||||
void TelemetrySimulator::closeEvent(QCloseEvent *event)
|
||||
void TelemetrySimulator::hideEvent(QHideEvent *event)
|
||||
{
|
||||
timer.stop();
|
||||
logTimer.stop();
|
||||
m_telemEnable = ui->Simulate->isChecked();
|
||||
m_logReplayEnable = logTimer.isActive();
|
||||
|
||||
ui->Simulate->setChecked(false);
|
||||
ui->stop->click();
|
||||
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)))
|
||||
|
||||
void TelemetrySimulator::setupDataFields()
|
||||
|
@ -237,6 +261,9 @@ void TelemetrySimulator::generateTelemetryFrame()
|
|||
static FlvssEmulator *flvss = new FlvssEmulator();
|
||||
static GPSEmulator *gps = new GPSEmulator();
|
||||
|
||||
if (!m_simuStarted)
|
||||
return;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
switch (item++) {
|
||||
|
@ -405,7 +432,7 @@ void TelemetrySimulator::generateTelemetryFrame()
|
|||
}
|
||||
|
||||
if (ok && (buffer[2] || buffer[3]))
|
||||
simulator->sendTelemetry(buffer, FRSKY_SPORT_PACKET_SIZE);
|
||||
emit telemetryDataChanged(buffer, FRSKY_SPORT_PACKET_SIZE);
|
||||
else
|
||||
generateTelemetryFrame();
|
||||
}
|
||||
|
|
|
@ -45,14 +45,19 @@ class TelemetrySimulator : public QWidget
|
|||
|
||||
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||
virtual ~TelemetrySimulator();
|
||||
void onSimulatorStarted();
|
||||
|
||||
signals:
|
||||
|
||||
void telemetryDataChanged(uint8_t * data, unsigned int len);
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void hideEvent(QHideEvent *event);
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
void onSimulatorStarted();
|
||||
void onSimulatorStopped();
|
||||
void setupDataFields();
|
||||
void onSimulateToggled(bool isChecked);
|
||||
void generateTelemetryFrame();
|
||||
void onLogTimerEvent();
|
||||
void onLoadLogFile();
|
||||
void onPlay();
|
||||
|
@ -62,6 +67,7 @@ class TelemetrySimulator : public QWidget
|
|||
void onStop();
|
||||
void onPositionIndicatorChanged(int value);
|
||||
void onReplayRateChanged(int value);
|
||||
void generateTelemetryFrame();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -69,6 +75,9 @@ class TelemetrySimulator : public QWidget
|
|||
QTimer timer;
|
||||
QTimer logTimer;
|
||||
SimulatorInterface *simulator;
|
||||
bool m_simuStarted;
|
||||
bool m_telemEnable;
|
||||
bool m_logReplayEnable;
|
||||
|
||||
// protected classes follow
|
||||
|
||||
|
@ -81,7 +90,7 @@ class TelemetrySimulator : public QWidget
|
|||
void play();
|
||||
void stop();
|
||||
void rewind();
|
||||
void stepForward(bool focusOnStop);
|
||||
void stepForward(bool focusOnStop = false);
|
||||
void stepBack();
|
||||
void updatePositionLabel(int32_t percentage);
|
||||
void setUiDataValues();
|
||||
|
|
|
@ -24,32 +24,40 @@
|
|||
#include "helpers.h"
|
||||
#include "virtualjoystickwidget.h"
|
||||
|
||||
#define TRAINERSIMU_HEARTBEAT_PERIOD 500 // [ms]
|
||||
|
||||
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||
QWidget(parent),
|
||||
ui(new Ui::TrainerSimulator),
|
||||
simulator(simulator)
|
||||
simulator(simulator),
|
||||
m_simuStarted(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
vJoyLeft = new VirtualJoystickWidget(this, 'L', false);
|
||||
vJoyLeft->setStickColor(Qt::cyan);
|
||||
vJoyLeft->setStickScale(512);
|
||||
ui->leftStickLayout->addWidget(vJoyLeft);
|
||||
|
||||
vJoyRight = new VirtualJoystickWidget(this, 'R', false);
|
||||
vJoyRight->setStickColor(Qt::cyan);
|
||||
vJoyRight->setStickScale(512);
|
||||
ui->rightStickLayout->addWidget(vJoyRight);
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(10);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||
connect(vJoyLeft, &VirtualJoystickWidget::valueChange, this, &TrainerSimulator::onRadioWidgetValueChange);
|
||||
connect(vJoyRight, &VirtualJoystickWidget::valueChange, this, &TrainerSimulator::onRadioWidgetValueChange);
|
||||
|
||||
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()
|
||||
{
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
delete timer;
|
||||
}
|
||||
if (vJoyLeft)
|
||||
delete vJoyLeft;
|
||||
if (vJoyRight)
|
||||
|
@ -60,42 +68,44 @@ TrainerSimulator::~TrainerSimulator()
|
|||
|
||||
void TrainerSimulator::showEvent(QShowEvent *event)
|
||||
{
|
||||
timer->start();
|
||||
event->accept();
|
||||
start();
|
||||
}
|
||||
|
||||
void TrainerSimulator::closeEvent(QCloseEvent *event)
|
||||
void TrainerSimulator::hideEvent(QHideEvent *event)
|
||||
{
|
||||
timer->stop();
|
||||
event->accept();
|
||||
stop();
|
||||
}
|
||||
|
||||
void TrainerSimulator::centerSticks()
|
||||
void TrainerSimulator::start()
|
||||
{
|
||||
if (vJoyLeft)
|
||||
vJoyLeft->centerStick();
|
||||
|
||||
if (vJoyRight)
|
||||
vJoyRight->centerStick();
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void TrainerSimulator::onTimerEvent()
|
||||
void TrainerSimulator::stop()
|
||||
{
|
||||
centerSticks();
|
||||
setTrainerInputs();
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
void TrainerSimulator::setTrainerInputs()
|
||||
void TrainerSimulator::onSimulatorStarted()
|
||||
{
|
||||
if (!simulator)
|
||||
return;
|
||||
m_simuStarted = true;
|
||||
}
|
||||
|
||||
if (vJoyLeft) {
|
||||
simulator->setTrainerInput(0, int( 512 * vJoyLeft->getStickX())); // LEFT HORZ
|
||||
simulator->setTrainerInput(1, int(-512 * vJoyLeft->getStickY())); // LEFT VERT
|
||||
}
|
||||
if (vJoyRight) {
|
||||
simulator->setTrainerInput(2, int(-512 * vJoyRight->getStickY())); // RGHT VERT
|
||||
simulator->setTrainerInput(3, int( 512 * vJoyRight->getStickX())); // RGHT HORZ
|
||||
void TrainerSimulator::onSimulatorStopped()
|
||||
{
|
||||
m_simuStarted = false;
|
||||
stop();
|
||||
}
|
||||
|
||||
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 <QWidget>
|
||||
#include <QTimer>
|
||||
#include "radiowidget.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -42,21 +43,27 @@ class TrainerSimulator : public QWidget
|
|||
explicit TrainerSimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||
virtual ~TrainerSimulator();
|
||||
|
||||
signals:
|
||||
void trainerHeartbeat(quint16 ms);
|
||||
void trainerChannelChange(quint8 index, qint16 value);
|
||||
|
||||
protected slots:
|
||||
void start();
|
||||
void stop();
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
void centerSticks();
|
||||
void setTrainerInputs();
|
||||
void onTimerEvent();
|
||||
virtual void hideEvent(QHideEvent *event);
|
||||
void onSimulatorStarted();
|
||||
void onSimulatorStopped();
|
||||
void onRadioWidgetValueChange(RadioWidget::RadioWidgetType type, int index, int value);
|
||||
void emitHeartbeat();
|
||||
|
||||
protected:
|
||||
Ui::TrainerSimulator * ui;
|
||||
QTimer * timer;
|
||||
SimulatorInterface *simulator;
|
||||
|
||||
VirtualJoystickWidget * vJoyLeft;
|
||||
VirtualJoystickWidget * vJoyRight;
|
||||
QTimer timer;
|
||||
bool m_simuStarted;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -22,47 +22,12 @@
|
|||
#define _BUTTONSWIDGET_H_
|
||||
|
||||
#include "radiouiaction.h"
|
||||
#include "radiokeywidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtGui>
|
||||
#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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -80,18 +45,17 @@ class ButtonsWidget : public QWidget
|
|||
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;
|
||||
polygon.setPoints(4, x1, y1, x1, y2, x2, y2, x2, y1);
|
||||
addArea(polygon, image, action);
|
||||
return addArea(QPolygon(rect), 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);
|
||||
areas.push_back(area);
|
||||
connect(area, &Area::imageChanged, this, &ButtonsWidget::setBitmap);
|
||||
RadioKeyWidget * btn = new RadioKeyWidget(polygon, image, action, this);
|
||||
m_buttons.append(btn);
|
||||
connect(btn, &RadioKeyWidget::imageChanged, this, &ButtonsWidget::setBitmap);
|
||||
return btn;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -113,16 +77,14 @@ class ButtonsWidget : public QWidget
|
|||
return;
|
||||
}
|
||||
|
||||
foreach(Area * area, areas) {
|
||||
if (!area->action)
|
||||
continue;
|
||||
if (area->contains(event->x(), event->y())) {
|
||||
area->action->trigger(press);
|
||||
foreach(RadioKeyWidget * key, m_buttons) {
|
||||
if (key->contains(event->pos())) {
|
||||
key->toggle(press);
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
else if (area->action->isActive()) {
|
||||
area->action->trigger(false);
|
||||
else if (key->getValue()) {
|
||||
key->toggle(false);
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
|
@ -145,7 +107,7 @@ class ButtonsWidget : public QWidget
|
|||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
|
||||
QList<Area *> areas;
|
||||
QList<RadioKeyWidget *> m_buttons;
|
||||
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 <QMouseEvent>
|
||||
#include <QDebug>
|
||||
#include <QToolTip>
|
||||
#include <math.h>
|
||||
|
||||
class RadioKnobWidget : public RadioWidget
|
||||
|
@ -65,7 +65,6 @@ class RadioKnobWidget : public RadioWidget
|
|||
|
||||
Board::PotType m_potType;
|
||||
|
||||
|
||||
class KnobWidget : public QDial
|
||||
{
|
||||
public:
|
||||
|
@ -73,6 +72,8 @@ class RadioKnobWidget : public RadioWidget
|
|||
explicit KnobWidget(Board::PotType type, QWidget * parent = 0):
|
||||
QDial(parent)
|
||||
{
|
||||
m_toolTip = tr("<p>Value (input): <b>%1</b></p>");
|
||||
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setFixedSize(QSize(42, 42));
|
||||
setNotchesVisible(true);
|
||||
|
@ -88,7 +89,7 @@ class RadioKnobWidget : public RadioWidget
|
|||
}
|
||||
else {
|
||||
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);
|
||||
setMaximum(1024);
|
||||
setPageStep(128);
|
||||
|
@ -104,6 +105,19 @@ class RadioKnobWidget : public RadioWidget
|
|||
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)
|
||||
{
|
||||
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||
|
@ -129,6 +143,7 @@ class RadioKnobWidget : public RadioWidget
|
|||
}
|
||||
|
||||
quint16 m_stepSize;
|
||||
QString m_toolTip;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -110,9 +110,8 @@ class RadioSwitchWidget : public RadioWidget
|
|||
void setToggleLocked(bool lock)
|
||||
{
|
||||
if (m_flags != (quint16)lock) {
|
||||
m_flags = lock;
|
||||
setFlags((quint16)lock);
|
||||
setValue((int)lock);
|
||||
emit flagsChanged(m_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define _RADIOTRIMWIDGET_H_
|
||||
|
||||
#include "radiowidget.h"
|
||||
#include "boards.h"
|
||||
#include "sliderwidget.h"
|
||||
|
||||
#include <QToolButton>
|
||||
|
@ -38,12 +39,6 @@ class RadioTrimWidget : public RadioWidget
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
@ -58,11 +53,27 @@ class RadioTrimWidget : public RadioWidget
|
|||
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 trimButtonReleased(int index);
|
||||
void trimSliderMoved(int index, int value);
|
||||
void setTrimValue(const int index, const 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:
|
||||
|
||||
|
@ -75,20 +86,20 @@ class RadioTrimWidget : public RadioWidget
|
|||
setTrimRange(-125, 125);
|
||||
setIndices();
|
||||
|
||||
QSize btnIcnSz(12, 12);
|
||||
const QSize btnSz(18, 18);
|
||||
QWidget * trimWidget = new QWidget(this);
|
||||
QBoxLayout * trimLayout = new QVBoxLayout(trimWidget);
|
||||
trimLayout->setSpacing(5);
|
||||
trimLayout->setContentsMargins(8, 8, 8, 8);
|
||||
trimLayout->setSpacing(4);
|
||||
QToolButton * trimBtnInc = new QToolButton(trimWidget);
|
||||
trimBtnInc->setIconSize(btnIcnSz);
|
||||
trimBtnInc->setMaximumSize(btnSz);
|
||||
QToolButton * trimBtnDec = new QToolButton(trimWidget);
|
||||
trimBtnDec->setIconSize(btnIcnSz);
|
||||
trimBtnDec->setMaximumSize(btnSz);
|
||||
|
||||
Qt::Alignment algn;
|
||||
if (orientation == Qt::Horizontal) {
|
||||
trimWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
trimLayout->setDirection(QBoxLayout::RightToLeft);
|
||||
trimLayout->setContentsMargins(0, 8, 0, 8);
|
||||
trimBtnInc->setArrowType(Qt::RightArrow);
|
||||
trimBtnDec->setArrowType(Qt::LeftArrow);
|
||||
algn = Qt::AlignVCenter;
|
||||
|
@ -96,6 +107,7 @@ class RadioTrimWidget : public RadioWidget
|
|||
else {
|
||||
trimWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
trimLayout->setDirection(QBoxLayout::TopToBottom);
|
||||
trimLayout->setContentsMargins(8, 0, 8, 0);
|
||||
trimBtnInc->setArrowType(Qt::UpArrow);
|
||||
trimBtnDec->setArrowType(Qt::DownArrow);
|
||||
algn = Qt::AlignHCenter;
|
||||
|
@ -107,21 +119,11 @@ class RadioTrimWidget : public RadioWidget
|
|||
|
||||
setWidget(trimWidget, algn);
|
||||
|
||||
connect(m_slider, &SliderWidget::valueChanged, this, &RadioWidget::setValue);
|
||||
connect(this, &RadioWidget::valueChanged, this, &RadioTrimWidget::onValueChanged);
|
||||
|
||||
connect(trimBtnInc, &QToolButton::pressed, [this]() { emit trimButtonPressed(m_btnIncIndex); });
|
||||
connect(trimBtnInc, &QToolButton::released, [this]() { emit trimButtonReleased(m_btnIncIndex); });
|
||||
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);
|
||||
connect(m_slider, &SliderWidget::valueChanged, this, &RadioTrimWidget::setValue);
|
||||
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(trimBtnDec, &QToolButton::pressed, [this]() { emit valueChange(m_type, m_btnDecIndex, RADIO_TRIM_BTN_ON); });
|
||||
connect(trimBtnDec, &QToolButton::released, [this]() { emit valueChange(m_type, m_btnDecIndex, RADIO_TRIM_BTN_OFF); });
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -130,5 +132,4 @@ class RadioTrimWidget : public RadioWidget
|
|||
int m_btnIncIndex;
|
||||
};
|
||||
|
||||
|
||||
#endif // _RADIOTRIMWIDGET_H_
|
||||
|
|
|
@ -18,51 +18,66 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiouiaction.h"
|
||||
#include "radiowidget.h"
|
||||
|
||||
RadioWidget::RadioWidget(QWidget * parent, Qt::WindowFlags f) :
|
||||
QWidget(parent, f),
|
||||
m_gridLayout(NULL),
|
||||
m_controlWidget(NULL),
|
||||
m_nameLabel(NULL),
|
||||
m_action(NULL),
|
||||
m_value(0),
|
||||
m_flags(0),
|
||||
m_invertValue(false),
|
||||
m_valueReset(false),
|
||||
m_showLabel(false),
|
||||
m_labelText(""),
|
||||
m_type(RADIO_WIDGET_NONE)
|
||||
m_labelText("")
|
||||
{
|
||||
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) :
|
||||
QWidget(parent, f),
|
||||
m_value(value),
|
||||
m_flags(0),
|
||||
m_invertValue(false),
|
||||
m_showLabel(true),
|
||||
m_labelText(labelText),
|
||||
m_type(RADIO_WIDGET_NONE)
|
||||
RadioWidget(parent, f)
|
||||
{
|
||||
init();
|
||||
setValue(value);
|
||||
setLabelText(labelText);
|
||||
}
|
||||
|
||||
void RadioWidget::setIndex(int index)
|
||||
void RadioWidget::setIndex(const int & 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_valueReset = false;
|
||||
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) {
|
||||
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) {
|
||||
m_showLabel = show;
|
||||
|
@ -85,13 +100,12 @@ void RadioWidget::setLabelText(const QString & labelText, bool showLabel)
|
|||
addLabel();
|
||||
}
|
||||
|
||||
void RadioWidget::setStateData(const QByteArray & data)
|
||||
void RadioWidget::setStateData(const RadioWidgetState & state)
|
||||
{
|
||||
RadioWidgetState state;
|
||||
QDataStream stream(data);
|
||||
stream >> state;
|
||||
if (state.type != m_type || state.index != m_index)
|
||||
return;
|
||||
|
||||
//setIndex(state.index);
|
||||
m_valueReset = true;
|
||||
setValue(state.value);
|
||||
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
|
||||
{
|
||||
return m_value * (m_invertValue ? -1 : 1);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
int RadioWidget::getIndex() const
|
||||
|
@ -134,25 +165,34 @@ QByteArray RadioWidget::getStateData() 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);
|
||||
m_controlWidget = NULL;
|
||||
m_nameLabel = NULL;
|
||||
return m_action;
|
||||
}
|
||||
|
||||
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->setVerticalSpacing(4);
|
||||
m_gridLayout->setHorizontalSpacing(0);
|
||||
|
||||
addLabel();
|
||||
}
|
||||
|
||||
void RadioWidget::addLabel()
|
||||
{
|
||||
addLayout();
|
||||
if (m_nameLabel) {
|
||||
m_gridLayout->removeWidget(m_nameLabel);
|
||||
m_nameLabel->deleteLater();
|
||||
|
@ -168,6 +208,7 @@ void RadioWidget::addLabel()
|
|||
|
||||
void RadioWidget::setWidget(QWidget * widget, Qt::Alignment align)
|
||||
{
|
||||
addLayout();
|
||||
if (m_controlWidget) {
|
||||
m_gridLayout->removeWidget(m_controlWidget);
|
||||
m_controlWidget->deleteLater();
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#define RADIO_WIDGET_STATE_VERSION 1
|
||||
|
||||
class RadioUiAction;
|
||||
|
||||
class RadioWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -41,10 +43,14 @@ class RadioWidget : public QWidget
|
|||
RADIO_WIDGET_SWITCH,
|
||||
RADIO_WIDGET_KNOB,
|
||||
RADIO_WIDGET_FADER,
|
||||
RADIO_WIDGET_TRIM,
|
||||
RADIO_WIDGET_STICK // actually one axis of a stick
|
||||
RADIO_WIDGET_TRIM, // trim axis, usually 2 buttons & slider
|
||||
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 {
|
||||
public:
|
||||
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
|
||||
};
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
explicit RadioWidget(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());
|
||||
|
||||
virtual int getValue() const;
|
||||
int getIndex() const;
|
||||
int getType() const;
|
||||
QByteArray getStateData() const;
|
||||
RadioWidgetState getState() const;
|
||||
virtual int getIndex() const;
|
||||
virtual int getType() const;
|
||||
virtual QByteArray getStateData() 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:
|
||||
|
||||
void init();
|
||||
void addLayout();
|
||||
void addLabel();
|
||||
void setWidget(QWidget * widget = NULL, Qt::Alignment align = Qt::AlignHCenter);
|
||||
|
||||
int m_value;
|
||||
int m_index;
|
||||
quint16 m_flags;
|
||||
bool m_invertValue;
|
||||
bool m_showLabel;
|
||||
QString m_labelText;
|
||||
RadioWidgetType m_type;
|
||||
|
||||
private:
|
||||
virtual void onActionToggled(int index, bool active);
|
||||
|
||||
QGridLayout * m_gridLayout;
|
||||
QWidget * m_controlWidget;
|
||||
QLabel * m_nameLabel;
|
||||
RadioUiAction * m_action;
|
||||
|
||||
signals:
|
||||
|
||||
void valueChanged(int value);
|
||||
void flagsChanged(quint16 flags);
|
||||
int m_value;
|
||||
int m_index;
|
||||
quint16 m_flags;
|
||||
bool m_valueReset;
|
||||
bool m_showLabel;
|
||||
QString m_labelText;
|
||||
RadioWidgetType m_type;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(RadioWidget::RadioWidgetState)
|
||||
|
||||
#endif // _RADIOWIDGET_H_
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <QtGui>
|
||||
#include <QSlider>
|
||||
#include <QToolTip>
|
||||
|
||||
class SliderWidget : public QSlider
|
||||
{
|
||||
|
@ -33,11 +34,23 @@ class SliderWidget : public QSlider
|
|||
explicit SliderWidget(QWidget * parent = 0):
|
||||
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:
|
||||
|
||||
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)
|
||||
{
|
||||
if (event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||
|
@ -47,6 +60,8 @@ class SliderWidget : public QSlider
|
|||
}
|
||||
QSlider::mousePressEvent(event);
|
||||
}
|
||||
|
||||
QString m_toolTip;
|
||||
};
|
||||
|
||||
#endif // _SLIDERWIDGET_H_
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
#define GBALL_SIZE 25
|
||||
#define GBALL_SIZE_MN 20
|
||||
#define GBALL_SIZE_MX 35
|
||||
#define CENTER_INTERVAL 50 // ms
|
||||
|
||||
#include "virtualjoystickwidget.h"
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "modeledit/node.h"
|
||||
#include "helpers.h"
|
||||
#include "radiotrimwidget.h"
|
||||
|
@ -43,6 +43,7 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
|||
btnFixY(NULL),
|
||||
nodeLabelX(NULL),
|
||||
nodeLabelY(NULL),
|
||||
m_stickScale(1024),
|
||||
m_stickPressed(false)
|
||||
{
|
||||
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), 3, 0, 1, 5); // r4 c0-4: bot v spacer
|
||||
|
||||
connect(node, &Node::xChanged, this, &VirtualJoystickWidget::updateNodeValueLabels);
|
||||
connect(node, &Node::yChanged, this, &VirtualJoystickWidget::updateNodeValueLabels);
|
||||
setStickIndices(getStickIndex('H'), getStickIndex('V'));
|
||||
|
||||
connect(node, &Node::xChanged, this, &VirtualJoystickWidget::onNodeXChanged);
|
||||
connect(node, &Node::yChanged, this, &VirtualJoystickWidget::onNodeYChanged);
|
||||
|
||||
connect(scene, &CustomGraphicsScene::mouseEvent, this, &VirtualJoystickWidget::onGsMouseEvent);
|
||||
|
||||
setSize(prefSize, frameSize());
|
||||
|
||||
centerStickTimer.setInterval(CENTER_INTERVAL);
|
||||
connect(¢erStickTimer, &QTimer::timeout, this, &VirtualJoystickWidget::centerStick);
|
||||
centerStickTimer.start();
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setStickX(qreal x)
|
||||
|
@ -158,6 +165,31 @@ void VirtualJoystickWidget::setStickPos(QPointF 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()
|
||||
{
|
||||
node->stepToCenter();
|
||||
|
@ -178,20 +210,55 @@ QPointF VirtualJoystickWidget::getStickPos()
|
|||
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) {
|
||||
trim->setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setTrimRange(int which, int min, int max)
|
||||
int VirtualJoystickWidget::getStickScale() const
|
||||
{
|
||||
RadioTrimWidget * trim = getTrimWidget(which);
|
||||
if (trim) {
|
||||
trim->setTrimRange(min, max);
|
||||
}
|
||||
return m_stickScale;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -203,27 +270,25 @@ int VirtualJoystickWidget::getTrimValue(int which)
|
|||
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
|
||||
|
||||
switch (which) {
|
||||
case HOLD_X:
|
||||
if (index & HOLD_X)
|
||||
btnHoldX->setChecked(active);
|
||||
break;
|
||||
case HOLD_Y:
|
||||
if (index & HOLD_Y)
|
||||
btnHoldY->setChecked(active);
|
||||
break;
|
||||
case FIX_X:
|
||||
if (index & FIX_X)
|
||||
btnFixX->setChecked(active);
|
||||
break;
|
||||
case FIX_Y:
|
||||
if (index & FIX_Y)
|
||||
btnFixY->setChecked(active);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setStickColor(const QColor & color)
|
||||
|
@ -231,6 +296,15 @@ void VirtualJoystickWidget::setStickColor(const QColor & 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 {
|
||||
return prefSize;
|
||||
}
|
||||
|
@ -241,6 +315,18 @@ void VirtualJoystickWidget::resizeEvent(QResizeEvent * event)
|
|||
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 &)
|
||||
{
|
||||
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);
|
||||
trimWidget->setIndices(getTrimSliderType(type), getTrimButtonType(type, 0), getTrimButtonType(type, 1));
|
||||
|
||||
connect(trimWidget, &RadioTrimWidget::trimButtonPressed, this, &VirtualJoystickWidget::trimButtonPressed);
|
||||
connect(trimWidget, &RadioTrimWidget::trimButtonReleased, this, &VirtualJoystickWidget::trimButtonReleased);
|
||||
connect(trimWidget, &RadioTrimWidget::trimSliderMoved, this, &VirtualJoystickWidget::trimSliderMoved);
|
||||
connect(trimWidget, &RadioTrimWidget::valueChange, this, &VirtualJoystickWidget::valueChange);
|
||||
|
||||
return trimWidget;
|
||||
}
|
||||
|
@ -371,6 +455,24 @@ QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valL
|
|||
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)
|
||||
{
|
||||
using namespace Board;
|
||||
|
@ -426,10 +528,12 @@ int VirtualJoystickWidget::getTrimButtonType(QChar type, int pos)
|
|||
|
||||
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;
|
||||
else
|
||||
else if ((stickSide == 'L' && which == Board::TRIM_AXIS_LV) || (stickSide == 'R' && which == Board::TRIM_AXIS_RV))
|
||||
return vTrimWidget;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::onButtonChange(bool checked)
|
||||
|
@ -456,9 +560,9 @@ void VirtualJoystickWidget::onButtonChange(bool checked)
|
|||
void VirtualJoystickWidget::updateNodeValueLabels()
|
||||
{
|
||||
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)
|
||||
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)
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef VIRTUALJOYSTICKWIDGET_H
|
||||
#define VIRTUALJOYSTICKWIDGET_H
|
||||
|
||||
#include "radiowidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QResizeEvent>
|
||||
#include <QBoxLayout>
|
||||
|
@ -28,6 +30,7 @@
|
|||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
#include <QToolButton>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
|
||||
class CustomGraphicsScene;
|
||||
|
@ -40,38 +43,47 @@ class VirtualJoystickWidget : public QWidget
|
|||
|
||||
public:
|
||||
enum ConstraintTypes {
|
||||
HOLD_X = 0,
|
||||
HOLD_Y,
|
||||
FIX_X,
|
||||
FIX_Y
|
||||
HOLD_X = 0x01,
|
||||
HOLD_Y = 0x02,
|
||||
FIX_X = 0x04,
|
||||
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));
|
||||
|
||||
void setStickX(qreal x);
|
||||
void setStickY(qreal y);
|
||||
void setStickPos(QPointF xy);
|
||||
void centerStick();
|
||||
qreal getStickX();
|
||||
qreal getStickY();
|
||||
QPointF getStickPos();
|
||||
|
||||
void setTrimValue(int which, int value);
|
||||
void setTrimRange(int which, int min, int max);
|
||||
int getTrimValue(int which);
|
||||
|
||||
void setStickConstraint(int which, bool active);
|
||||
void setStickColor(const QColor & color);
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
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:
|
||||
void trimButtonPressed(int index);
|
||||
void trimButtonReleased(int index);
|
||||
void trimSliderMoved(int index, int value);
|
||||
void valueChange(const RadioWidget::RadioWidgetType type, const int index, int value);
|
||||
|
||||
protected slots:
|
||||
void onNodeXChanged();
|
||||
void onNodeYChanged();
|
||||
void onButtonChange(bool checked);
|
||||
void updateNodeValueLabels();
|
||||
void onGsMouseEvent(QGraphicsSceneMouseEvent * event);
|
||||
|
@ -81,6 +93,7 @@ class VirtualJoystickWidget : public QWidget
|
|||
RadioTrimWidget * createTrimWidget(QChar type);
|
||||
QToolButton * createButtonWidget(int type);
|
||||
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
||||
int getStickIndex(QChar type);
|
||||
int getTrimSliderType(QChar type);
|
||||
int getTrimButtonType(QChar type, int pos);
|
||||
RadioTrimWidget * getTrimWidget(int which);
|
||||
|
@ -97,7 +110,11 @@ class VirtualJoystickWidget : public QWidget
|
|||
QToolButton * btnFixX, * btnFixY;
|
||||
QLabel * nodeLabelX, * nodeLabelY;
|
||||
QSize extraSize;
|
||||
QTimer centerStickTimer;
|
||||
float ar; // aspect ratio
|
||||
int m_xIndex;
|
||||
int m_yIndex;
|
||||
int m_stickScale;
|
||||
bool m_stickPressed;
|
||||
};
|
||||
|
||||
|
|
|
@ -442,7 +442,7 @@ void evalInputs(uint8_t mode)
|
|||
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?
|
||||
if (i==POT1 || i==SLIDER1) {
|
||||
v = -v;
|
||||
|
|
|
@ -68,7 +68,6 @@ uint32_t readTrims()
|
|||
result |= 0x40;
|
||||
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
|
||||
result |= 0x80;
|
||||
#if !defined(SIMU)
|
||||
if (~TRIMS_GPIO_REG_LSD & TRIMS_GPIO_PIN_LSD)
|
||||
result |= 0x100;
|
||||
if (~TRIMS_GPIO_REG_LSU & TRIMS_GPIO_PIN_LSU)
|
||||
|
@ -77,7 +76,6 @@ uint32_t readTrims()
|
|||
result |= 0x400;
|
||||
if (~TRIMS_GPIO_REG_RSU & TRIMS_GPIO_PIN_RSU)
|
||||
result |= 0x800;
|
||||
#endif
|
||||
// TRACE("readTrims(): result=0x%04x", result);
|
||||
|
||||
return result;
|
||||
|
|
|
@ -26,7 +26,9 @@ if(Qt5Widgets_FOUND)
|
|||
set(SIMULATOR_TARGET ${SIMULATOR_FLAVOUR}-simulator)
|
||||
add_definitions(-DSIMULATOR_FLAVOUR="${SIMULATOR_FLAVOUR}")
|
||||
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})
|
||||
target_compile_definitions(${SIMULATOR_TARGET} PUBLIC ${APP_COMMON_DEFINES}) # set in top-level CMakeLists
|
||||
target_link_libraries(${SIMULATOR_TARGET} ${SDL_LIBRARY})
|
||||
|
|
|
@ -18,7 +18,23 @@
|
|||
#include "opentx.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];
|
||||
QVector<QIODevice *> OpenTxSimulator::tracebackDevices;
|
||||
|
||||
uint16_t anaIn(uint8_t chan)
|
||||
{
|
||||
|
@ -30,36 +46,135 @@ uint16_t getAnalogValue(uint8_t 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)
|
||||
{
|
||||
QMutexLocker lckr(&m_mtxSettings);
|
||||
simuSdDirectory = sdPath;
|
||||
simuSettingsDirectory = settingsPath;
|
||||
}
|
||||
|
||||
void OpenTxSimulator::setVolumeGain(int value)
|
||||
void OpenTxSimulator::setVolumeGain(const int value)
|
||||
{
|
||||
QMutexLocker lckr(&m_mtxSettings);
|
||||
volumeGain = value;
|
||||
}
|
||||
|
||||
bool OpenTxSimulator::timer10ms()
|
||||
void OpenTxSimulator::setRadioData(const QByteArray & data)
|
||||
{
|
||||
#define TIMER10MS_IMPORT
|
||||
#include "simulatorimport.h"
|
||||
#if defined(EEPROM_SIZE)
|
||||
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()
|
||||
|
@ -67,126 +182,139 @@ uint8_t * OpenTxSimulator::getLcd()
|
|||
return (uint8_t *)simuLcdBuf;
|
||||
}
|
||||
|
||||
bool OpenTxSimulator::lcdChanged(bool & lightEnable)
|
||||
void OpenTxSimulator::setAnalogValue(uint8_t index, int16_t value)
|
||||
{
|
||||
#define LCDCHANGED_IMPORT
|
||||
#include "simulatorimport.h"
|
||||
static int dim = DIM(g_anas);
|
||||
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)
|
||||
memcpy(eeprom, ee.data(), std::min<int>(EEPROM_SIZE, ee.size()));
|
||||
#endif
|
||||
start((const char *)0, tests);
|
||||
simuSetSwitch(swtch, state);
|
||||
}
|
||||
|
||||
void OpenTxSimulator::start(const char * filename, bool tests)
|
||||
void OpenTxSimulator::setKey(uint8_t key, bool state)
|
||||
{
|
||||
if (main_thread_running)
|
||||
return;
|
||||
|
||||
StartEepromThread(filename);
|
||||
StartAudioThread(volumeGain);
|
||||
StartSimu(tests, simuSdDirectory.toLatin1().constData(), simuSettingsDirectory.toLatin1().constData());
|
||||
simuSetKey(key, state);
|
||||
}
|
||||
|
||||
void OpenTxSimulator::stop()
|
||||
void OpenTxSimulator::setTrimSwitch(uint8_t trim, bool state)
|
||||
{
|
||||
if (!main_thread_running)
|
||||
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"
|
||||
simuSetTrim(trim, state);
|
||||
}
|
||||
|
||||
void OpenTxSimulator::setTrim(unsigned int idx, int value)
|
||||
{
|
||||
idx = modn12x3[4*getStickMode() + idx];
|
||||
uint8_t phase = getTrimFlightMode(getFlightMode(), idx);
|
||||
setTrimValue(phase, idx, value);
|
||||
unsigned i = idx;
|
||||
if (i < 4) // swap axes
|
||||
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();
|
||||
trims.extended = hasExtendedTrims();
|
||||
for (uint8_t idx=0; idx < CPN_MAX_TRIMS; idx++) {
|
||||
trims.values[idx] = getTrimValue(getTrimFlightMode(phase, idx), idx);
|
||||
}
|
||||
static unsigned dim = DIM(ppmInput);
|
||||
//setTrainerTimeout(100);
|
||||
if (inputNumber < dim)
|
||||
ppmInput[inputNumber] = qMin(qMax((int16_t)-512, value), (int16_t)512);
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++) {
|
||||
uint8_t idx = modn12x3[4*getStickMode() + i];
|
||||
int16_t tmp = trims.values[i];
|
||||
trims.values[i] = trims.values[idx];
|
||||
trims.values[idx] = tmp;
|
||||
void OpenTxSimulator::setInputValue(int type, uint8_t index, int16_t value)
|
||||
{
|
||||
//qDebug() << type << index << value << this->thread();
|
||||
switch (type) {
|
||||
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)
|
||||
ROTARY_ENCODER_NAVIGATION_VALUE += steps * ROTARY_ENCODER_GRANULARITY;
|
||||
#else
|
||||
// TODO : this should probably be handled in the GUI
|
||||
int key;
|
||||
if (steps > 0)
|
||||
simuSetKey(KEY_MINUS, 1);
|
||||
key = KEY_MINUS;
|
||||
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)
|
||||
}
|
||||
|
||||
unsigned int OpenTxSimulator::getPhase()
|
||||
void OpenTxSimulator::setTrainerTimeout(uint16_t ms)
|
||||
{
|
||||
return getFlightMode();
|
||||
}
|
||||
|
||||
const char * OpenTxSimulator::getPhaseName(unsigned int phase)
|
||||
{
|
||||
static char buff[sizeof(g_model.flightModeData[0].name)+1];
|
||||
zchar2str(buff, g_model.flightModeData[phase].name, sizeof(g_model.flightModeData[0].name));
|
||||
return buff;
|
||||
}
|
||||
|
||||
const char * OpenTxSimulator::getError()
|
||||
{
|
||||
#define GETERROR_IMPORT
|
||||
#include "simulatorimport.h"
|
||||
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
|
||||
}
|
||||
|
||||
uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
|
||||
{
|
||||
#if defined(TELEMETRY_FRSKY_SPORT)
|
||||
for (int i = 0; i<MAX_TELEMETRY_SENSORS; i++) {
|
||||
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
|
||||
if (isTelemetryFieldAvailable(i)) {
|
||||
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
||||
if (sensor->id == id) {
|
||||
|
@ -194,6 +322,8 @@ uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(id)
|
||||
#endif
|
||||
return defaultValue;
|
||||
}
|
||||
|
@ -201,7 +331,7 @@ uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
|
|||
uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
|
||||
{
|
||||
#if defined(TELEMETRY_FRSKY_SPORT)
|
||||
for (int i = 0; i<MAX_TELEMETRY_SENSORS; i++) {
|
||||
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
|
||||
if (isTelemetryFieldAvailable(i)) {
|
||||
TelemetrySensor * sensor = &g_model.telemetrySensors[i];
|
||||
if (sensor->id == id) {
|
||||
|
@ -209,14 +339,41 @@ uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(id)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value)
|
||||
const int OpenTxSimulator::getCapability(Capability cap)
|
||||
{
|
||||
#define SETTRAINER_IMPORT
|
||||
#include "simulatorimport.h"
|
||||
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()
|
||||
|
@ -226,11 +383,206 @@ void OpenTxSimulator::setLuaStateReloadPermanentScripts()
|
|||
#endif
|
||||
}
|
||||
|
||||
void OpenTxSimulator::installTraceHook(void (*callback)(const char *))
|
||||
void OpenTxSimulator::addTracebackDevice(QIODevice * device)
|
||||
{
|
||||
traceCallback = callback;
|
||||
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)
|
||||
{
|
||||
static char buff[sizeof(g_model.flightModeData[0].name)+1];
|
||||
zchar2str(buff, g_model.flightModeData[phase].name, sizeof(g_model.flightModeData[0].name));
|
||||
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()
|
||||
{
|
||||
return main_thread_error;
|
||||
}
|
||||
|
||||
const int OpenTxSimulator::voltageToAdc(const int volts)
|
||||
{
|
||||
int ret = 0;
|
||||
#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
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* OpenTxSimulatorFactory
|
||||
*/
|
||||
|
||||
class OpenTxSimulatorFactory: public SimulatorFactory
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -19,68 +19,84 @@
|
|||
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#if defined __GNUC__
|
||||
#define DLLEXPORT
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
class DLLEXPORT OpenTxSimulator : public SimulatorInterface {
|
||||
|
||||
private:
|
||||
int volumeGain;
|
||||
QString simuSdDirectory;
|
||||
QString simuSettingsDirectory;
|
||||
class DLLEXPORT OpenTxSimulator : public SimulatorInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
OpenTxSimulator();
|
||||
virtual ~OpenTxSimulator();
|
||||
|
||||
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "");
|
||||
|
||||
virtual void setVolumeGain(int value);
|
||||
|
||||
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 QString name();
|
||||
virtual bool isRunning();
|
||||
virtual void readRadioData(QByteArray & dest);
|
||||
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 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 installTraceHook(void (*callback)(const char *));
|
||||
|
||||
virtual void setInputValue(int type, uint8_t index, int16_t value);
|
||||
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 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_
|
||||
|
|
|
@ -257,10 +257,10 @@ void simuSetTrim(uint8_t trim, bool state)
|
|||
TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL)
|
||||
TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR)
|
||||
#if defined(PCBHORUS)
|
||||
TRIM_CASE(8, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU)
|
||||
TRIM_CASE(9, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_RVU)
|
||||
TRIM_CASE(10, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RHL)
|
||||
TRIM_CASE(11, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RHR)
|
||||
TRIM_CASE(8, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_LSD)
|
||||
TRIM_CASE(9, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU)
|
||||
TRIM_CASE(10, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RSD)
|
||||
TRIM_CASE(11, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RSU)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue