diff --git a/companion/src/appdebugmessagehandler.cpp b/companion/src/appdebugmessagehandler.cpp
index 816ad2057..ab2ee3858 100644
--- a/companion/src/appdebugmessagehandler.cpp
+++ b/companion/src/appdebugmessagehandler.cpp
@@ -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
diff --git a/companion/src/appdebugmessagehandler.h b/companion/src/appdebugmessagehandler.h
index 1e79ef63e..648090b16 100644
--- a/companion/src/appdebugmessagehandler.h
+++ b/companion/src/appdebugmessagehandler.h
@@ -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.
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index 5b68fcd0b..26c8f57d2 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -12,6 +12,7 @@
images/track.png
images/track0.png
images/taranison.png
+ images/simulator/icons/svg/arrow_click.svg
images/simulator/icons/svg/camera.svg
images/simulator/icons/svg/camera-active.svg
images/simulator/icons/svg/console.svg
@@ -32,6 +33,7 @@
images/simulator/icons/svg/joystick_settings.svg
images/simulator/icons/svg/joystick_settings-active.svg
images/simulator/icons/svg/line_horiz.svg
+ images/simulator/icons/svg/mouse.svg
images/simulator/icons/svg/toggle_lock.svg
images/simulator/icons/svg/toggle_lock-on.svg
images/simulator/icons/svg/radio_outputs.svg
diff --git a/companion/src/images/simulator/icons/svg/arrow_click.svg b/companion/src/images/simulator/icons/svg/arrow_click.svg
new file mode 100644
index 000000000..a6433b6fe
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/arrow_click.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/mouse.svg b/companion/src/images/simulator/icons/svg/mouse.svg
new file mode 100644
index 000000000..c6eac360c
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/mouse.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt
index d29ed78a9..210f6a44f 100644
--- a/companion/src/simulation/CMakeLists.txt
+++ b/companion/src/simulation/CMakeLists.txt
@@ -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
diff --git a/companion/src/simulation/debugoutput.cpp b/companion/src/simulation/debugoutput.cpp
index 2bba42b9f..c031084f0 100644
--- a/companion/src/simulation/debugoutput.cpp
+++ b/companion/src/simulation/debugoutput.cpp
@@ -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"));
}
}
diff --git a/companion/src/simulation/debugoutput.h b/companion/src/simulation/debugoutput.h
index 6cf67acdc..b7a325b46 100644
--- a/companion/src/simulation/debugoutput.h
+++ b/companion/src/simulation/debugoutput.h
@@ -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;
diff --git a/companion/src/simulation/radiooutputswidget.cpp b/companion/src/simulation/radiooutputswidget.cpp
index d2cdd686d..775a517e6 100644
--- a/companion/src/simulation/radiooutputswidget.cpp
+++ b/companion/src/simulation/radiooutputswidget.cpp
@@ -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;
- QFont font;
-
- m_simulator->getValues(outputs);
- currentPhase = m_simulator->getPhase();
-
- if (ui->channelsWidget->isVisible()) {
- QHash >::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 (m_channelsMap.contains(index)) {
+ QPair ch = m_channelsMap.value(index);
+ ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
+ ch.second->setValue(qMin(1024, qMax(-1024, value)));
}
+ //qDebug() << index << value;
+}
- if (ui->logicalSwitchesWidget->isVisible()) {
- QHash::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()];
- }
+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 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;
+ QHash >::const_iterator gv;
+ QHash::const_iterator fm;
- if (ui->globalVarsWidget->isVisible()) {
- QPalette::ColorRole bgrole;
- QHash >::const_iterator gv;
- QHash::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()];
- }
+ 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);
}
}
-
- m_lastFlightPhase = currentPhase;
+ //qDebug() << phase;
}
diff --git a/companion/src/simulation/radiooutputswidget.h b/companion/src/simulation/radiooutputswidget.h
index dbcd82d90..1f699e99d 100644
--- a/companion/src/simulation/radiooutputswidget.h
+++ b/companion/src/simulation/radiooutputswidget.h
@@ -22,6 +22,7 @@
#define RADIOOUTPUTSWIDGET_H
#include "simulator.h"
+#include "simulatorinterface.h"
#include
#include
@@ -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 > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
QHash 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:
diff --git a/companion/src/simulation/radiouiaction.h b/companion/src/simulation/radiouiaction.h
index cc3a4b5e1..d2904c491 100644
--- a/companion/src/simulation/radiouiaction.h
+++ b/companion/src/simulation/radiouiaction.h
@@ -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()),
@@ -50,36 +50,50 @@ 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 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 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 & keys)
+ {
+ foreach (int key, keys)
+ addKey(key);
}
void addShortcut()
{
- if (m_parent)
- m_parent->installEventFilter(this);
+ 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(parent);
+ if (w && w != m_parent) {
+ m_parent = w;
+ addShortcut();
+ }
}
void setDescription(const QString & description) { m_description = description; }
diff --git a/companion/src/simulation/simulateduiwidget.cpp b/companion/src/simulation/simulateduiwidget.cpp
index fc4ed35bb..c3db6f4ef 100644
--- a/companion/src/simulation/simulateduiwidget.cpp
+++ b/companion/src/simulation/simulateduiwidget.cpp
@@ -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(&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 SimulatedUIWidget::getKeymapHelp() const
{
- return addRadioUiAction(new RadioUiAction(index, key, m_parent, text, descript));
-}
-
-RadioUiAction * SimulatedUIWidget::addRadioUiAction(int index, QList keys, const QString & text, const QString & descript)
-{
- return addRadioUiAction(new RadioUiAction(index, keys, m_parent, text, descript));
+ QVector 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()
{
- connect(m_scrollUpAction, static_cast(&RadioUiAction::pushed), [this](void) {
- this->simulatorWheelEvent(-1);
- m_scrollUpAction->toggle(false);
- });
+ if (m_scrollUpAction) {
+ addRadioAction(m_scrollUpAction);
+ connect(m_scrollUpAction, static_cast(&RadioUiAction::pushed), [this](void) {
+ emit simulatorWheelEvent(-1);
+ m_scrollUpAction->toggle(false);
+ });
+ }
- connect(m_scrollDnAction, static_cast(&RadioUiAction::pushed), [this](void) {
- simulatorWheelEvent(1);
- m_scrollDnAction->toggle(false);
- });
+ if (m_scrollDnAction) {
+ addRadioAction(m_scrollDnAction);
+ connect(m_scrollDnAction, static_cast(&RadioUiAction::pushed), [this](void) {
+ emit simulatorWheelEvent(1);
+ m_scrollDnAction->toggle(false);
+ });
+ }
}
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index dba6e7435..225fb65fe 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -23,17 +23,18 @@
#include "boards.h"
#include "constants.h"
+#include "radiowidget.h"
#include "simulator.h"
+#include "simulator_strings.h"
#include
#include
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 keys, const QString &text = "", const QString &descript = "");
+ RadioWidget * addRadioWidget(RadioWidget * keyWidget);
+ RadioUiAction * addRadioAction(RadioUiAction * act);
- QVector * getKeymapHelp() { return &m_keymapHelp; }
- QList getActions() const { return m_actions; }
- RadioUiAction * getRotEncAction() const { return m_rotEncClickAction; }
+ QVector 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 m_backlightColors;
- QVector m_keymapHelp;
QList m_actions;
+ QList 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);
-
};
diff --git a/companion/src/simulation/simulateduiwidget9X.cpp b/companion/src/simulation/simulateduiwidget9X.cpp
index 725511528..daa809a20 100644
--- a/companion/src/simulation/simulateduiwidget9X.cpp
+++ b/companion/src/simulation/simulateduiwidget9X.cpp
@@ -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() << 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() << 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() << 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() << 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() << 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() << 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() << Qt::Key_Left << Qt::Key_Minus, tr("LEFT/-"), tr("[ - ]"));
- ui->leftbuttons->addArea(polygon, "9X/9xcursplus.png", act);
+ act = new RadioUiAction(5, QList() << 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() << 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() << 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() << 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() << 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);
diff --git a/companion/src/simulation/simulateduiwidgetX12.cpp b/companion/src/simulation/simulateduiwidgetX12.cpp
index 7a3658799..6b58fd962 100644
--- a/companion/src/simulation/simulateduiwidgetX12.cpp
+++ b/companion/src/simulation/simulateduiwidgetX12.cpp
@@ -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() << Qt::Key_PageUp, tr("PG-UP"), tr("[ PgUp ]"));
- ui->leftbuttons->addArea(polygon, "Horus/left_btn1.png", act);
+ act = new RadioUiAction(0, QList() << 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() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PgDn ]"));
- ui->leftbuttons->addArea(polygon, "Horus/left_btn2.png", act);
+ act = new RadioUiAction(1, QList() << 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() << 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() << 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() << 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() << Qt::Key_Left, tr("LEFT"), tr("[ SYS ]"));
- ui->rightbuttons->addArea(polygon, "Horus/right_btnL.png", act);
+ act = new RadioUiAction(6, QList() << 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() << Qt::Key_Right, tr("RIGHT"), tr("[ TELE ]"));
- ui->rightbuttons->addArea(polygon, "Horus/right_btnR.png", act);
+ act = new RadioUiAction(5, QList() << 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() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace,
+ tr(SIMU_STR_HLP_KEY_DN " " 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() << Qt::Key_Minus << Qt::Key_X, tr("-/X"), tr("Rotary UP"));
- m_scrollDnAction = addRadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_C, tr("+/C"), tr("Rotary DOWN"));
+ m_scrollUpAction = new RadioUiAction(-1, QList() << 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() << 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() << 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() << 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()
diff --git a/companion/src/simulation/simulateduiwidgetX7.cpp b/companion/src/simulation/simulateduiwidgetX7.cpp
index 993d01460..0da8dc89e 100644
--- a/companion/src/simulation/simulateduiwidgetX7.cpp
+++ b/companion/src/simulation/simulateduiwidgetX7.cpp
@@ -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() << Qt::Key_PageUp, tr("PG-UP"), tr("[ PAGE ]"));
- ui->leftbuttons->addArea(polygon, "X7/left_page.png", act);
+ act = new RadioUiAction(3, QList() << 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() << 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() << 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() << 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() << 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() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
- m_scrollDnAction = addRadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
+ m_scrollUpAction = new RadioUiAction(-1, QList() << 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() << 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() << 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() << 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);
diff --git a/companion/src/simulation/simulateduiwidgetX7.ui b/companion/src/simulation/simulateduiwidgetX7.ui
index 573be197b..46d6092ea 100644
--- a/companion/src/simulation/simulateduiwidgetX7.ui
+++ b/companion/src/simulation/simulateduiwidgetX7.ui
@@ -29,7 +29,7 @@
- Taranis X7 Simulator
+ Taranis X7 Simulator
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));
diff --git a/companion/src/simulation/simulateduiwidgetX9.cpp b/companion/src/simulation/simulateduiwidgetX9.cpp
index a3767fb7d..0e3e3948c 100644
--- a/companion/src/simulation/simulateduiwidgetX9.cpp
+++ b/companion/src/simulation/simulateduiwidgetX9.cpp
@@ -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() << 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() << 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() << 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() << 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() << Qt::Key_Plus << Qt::Key_Equal << Qt::Key_Up, tr("+/UP"), tr("[ + ]"));
- m_scrollDnAction = addRadioUiAction(5, QList() << Qt::Key_Minus << Qt::Key_Down, tr("-/DN"), tr("[ - ]"));
+ act = new RadioUiAction(3, QList() << 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() << 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() << 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() << 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() << 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() << 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);
diff --git a/companion/src/simulation/simulateduiwidgetX9E.cpp b/companion/src/simulation/simulateduiwidgetX9E.cpp
index 8f3f97008..58d307d3d 100644
--- a/companion/src/simulation/simulateduiwidgetX9E.cpp
+++ b/companion/src/simulation/simulateduiwidgetX9E.cpp
@@ -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() << Qt::Key_PageUp, tr("PG-UP"), tr("[ MENU ]"));
- ui->leftbuttons->addArea(polygon, "X9E/left_menu.png", act);
+ act = new RadioUiAction(0, QList() << 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() << Qt::Key_PageDown, tr("PG-DN"), tr("[ PAGE ]"));
- ui->leftbuttons->addArea(polygon, "X9E/left_page.png", act);
+ act = new RadioUiAction(3, QList() << 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() << 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() << 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() << Qt::Key_Minus << Qt::Key_Equal << Qt::Key_Up, tr("-/UP"), tr("Rotary UP"));
- m_scrollDnAction = addRadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Down, tr("+/DN"), tr("Rotary DOWN"));
+ m_scrollUpAction = addRadioAction(new RadioUiAction(-1, QList() << 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() << 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() << 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() << 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);
diff --git a/companion/src/simulation/simulator_strings.h b/companion/src/simulation/simulator_strings.h
new file mode 100644
index 000000000..4a6982d77
--- /dev/null
+++ b/companion/src/simulation/simulator_strings.h
@@ -0,0 +1,66 @@
+#ifndef SIMULATOR_STRINGS_H
+#define SIMULATOR_STRINGS_H
+
+#include
+
+#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", "+ ")
+#define SIMU_STR_HLP_KEY_MIN QT_TRANSLATE_NOOP("SimulatedUIWidget", "- ")
+
+#define SIMU_STR_HLP_KEY_LFT QT_TRANSLATE_NOOP("SimulatedUIWidget", "← ") // ←
+#define SIMU_STR_HLP_KEY_RGT QT_TRANSLATE_NOOP("SimulatedUIWidget", "→ ") // →
+#define SIMU_STR_HLP_KEY_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "↑ ") // ↑
+#define SIMU_STR_HLP_KEY_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "↓ ") // ↓
+
+#define SIMU_STR_HLP_ROTENC QT_TRANSLATE_NOOP("SimulatedUIWidget", "⚆ ") // ⚆
+#define SIMU_STR_HLP_ROTENC_LFT QT_TRANSLATE_NOOP("SimulatedUIWidget", "↶ ") // ↶
+#define SIMU_STR_HLP_ROTENC_RGT QT_TRANSLATE_NOOP("SimulatedUIWidget", "↷ ") // ↷
+#define SIMU_STR_HLP_ROTENC_LR QT_TRANSLATE_NOOP("SimulatedUIWidget", "⇆ ") // ⇆
+#define SIMU_STR_HLP_ROTENC_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "⇓ ") // ⇓
+
+#define SIMU_STR_HLP_SCRL_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "⇑ ") // ⇑
+#define SIMU_STR_HLP_SCRL_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "⇓ ") // ⇓
+#define SIMU_STR_HLP_SCRL_UD QT_TRANSLATE_NOOP("SimulatedUIWidget", "⇕ ") // ⇕
+
+#define SIMU_STR_HLP_MOUSE QT_TRANSLATE_NOOP("SimulatedUIWidget", " ")
+#define SIMU_STR_HLP_CLICK QT_TRANSLATE_NOOP("SimulatedUIWidget", " ")
+#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", "[ MENU ] ")
+#define SIMU_STR_HLP_ACT_PAGE QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ PAGE ] ")
+#define SIMU_STR_HLP_ACT_EXIT QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ EXIT ] ")
+#define SIMU_STR_HLP_ACT_ENT QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ ENT ] ")
+#define SIMU_STR_HLP_ACT_UP QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ UP ] ")
+#define SIMU_STR_HLP_ACT_DN QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ DN ] ")
+#define SIMU_STR_HLP_ACT_PLS QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ + ] ")
+#define SIMU_STR_HLP_ACT_MIN QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ - ] ")
+#define SIMU_STR_HLP_ACT_PGUP QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ PgUp ] ")
+#define SIMU_STR_HLP_ACT_PGDN QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ PgDn ] ")
+#define SIMU_STR_HLP_ACT_MDL QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ MDL ] ")
+#define SIMU_STR_HLP_ACT_RTN QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ RTN ] ")
+#define SIMU_STR_HLP_ACT_SYS QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ SYS ] ")
+#define SIMU_STR_HLP_ACT_TELE QT_TRANSLATE_NOOP("SimulatedUIWidget", "[ TELE ] ")
+#define SIMU_STR_HLP_ACT_MENU_ICN QT_TRANSLATE_NOOP("SimulatedUIWidget", "≡ ") // ≡
+
+
+#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
diff --git a/companion/src/simulation/simulatorimport.h b/companion/src/simulation/simulatorimport.h
deleted file mode 100644
index 3ec4527fa..000000000
--- a/companion/src/simulation/simulatorimport.h
+++ /dev/null
@@ -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
-
-#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; iPIO_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
#include
-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;
};
diff --git a/companion/src/simulation/simulatormainwindow.cpp b/companion/src/simulation/simulatormainwindow.cpp
index 41a708e5c..9fe5e969e 100644
--- a/companion/src/simulation/simulatormainwindow.cpp
+++ b/companion/src/simulation/simulatormainwindow.cpp
@@ -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 = ""
+ "";
+ helpText += tr("Simulator Controls: ");
helpText += "";
- helpText += tr("Key/Mouse Action ");
- QString keyTemplate = "%1 %2 ";
- foreach (keymapHelp_t pair, m_keymapHelp)
+ helpText += tr("Key/Mouse Action ", "note: must match html layout of each table row (keyTemplate).");
+
+ QString keyTemplate = tr("%1 %2 ", "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 += "
";
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();
diff --git a/companion/src/simulation/simulatormainwindow.h b/companion/src/simulation/simulatormainwindow.h
index 5e9da9a3f..eb134a63f 100644
--- a/companion/src/simulation/simulatormainwindow.h
+++ b/companion/src/simulation/simulatormainwindow.h
@@ -25,6 +25,7 @@
#include
#include
+#include
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 m_keymapHelp;
QString m_simulatorId;
QString m_exitStatusMsg;
diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp
index 058c3516a..c687c2226 100644
--- a/companion/src/simulation/simulatorwidget.cpp
+++ b/companion/src/simulation/simulatorwidget.cpp
@@ -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
#include
-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 : 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 switchesMap;
- QMap analogsMap;
QList 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 SimulatorWidget::saveRadioWidgetsState()
+void SimulatorWidget::saveRadioWidgetsState(QList & state)
{
- QList 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
diff --git a/companion/src/simulation/simulatorwidget.h b/companion/src/simulation/simulatorwidget.h
index e7398039a..e3377084b 100644
--- a/companion/src/simulation/simulatorwidget.h
+++ b/companion/src/simulation/simulatorwidget.h
@@ -24,24 +24,20 @@
#include "constants.h"
#include "helpers.h"
#include "radiodata.h"
+#include "radiowidget.h"
#include "simulator.h"
+#include "simulatorinterface.h"
+#include
#include
#include
#include
-#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 * getKeymapHelp() { return &keymapHelp; }
+ QVector 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 saveRadioWidgetsState();
-
- void setValues();
- void getValues();
- void setTrims();
-
-
- Ui::SimulatorWidget * ui;
- SimulatorInterface * simulator;
- Firmware * firmware;
- GeneralSettings radioSettings;
-
- QTimer * timer;
- QString windowName;
- QVector keymapHelp;
-
- SimulatedUIWidget * radioUiWidget;
- VirtualJoystickWidget * vJoyLeft;
- VirtualJoystickWidget * vJoyRight;
-
- QVector switches;
- QVector 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 & state);
+
+ Ui::SimulatorWidget * ui;
+ SimulatorInterface * simulator;
+ Firmware * firmware;
+ GeneralSettings radioSettings;
+
+ QTimer m_timer;
+ QString windowName;
+ QVector keymapHelp;
+ QElapsedTimer m_heartbeatTimer;
+
+ SimulatedUIWidget * radioUiWidget;
+ VirtualJoystickWidget * vJoyLeft;
+ VirtualJoystickWidget * vJoyRight;
+ QVector 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_
diff --git a/companion/src/simulation/telemetrysimu.cpp b/companion/src/simulation/telemetrysimu.cpp
index 258b6cee0..28e330a72 100644
--- a/companion/src/simulation/telemetrysimu.cpp
+++ b/companion/src/simulation/telemetrysimu.cpp
@@ -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();
}
diff --git a/companion/src/simulation/telemetrysimu.h b/companion/src/simulation/telemetrysimu.h
index 5c1af2e42..23fc8948c 100644
--- a/companion/src/simulation/telemetrysimu.h
+++ b/companion/src/simulation/telemetrysimu.h
@@ -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();
diff --git a/companion/src/simulation/trainersimu.cpp b/companion/src/simulation/trainersimu.cpp
index 50a506669..f26fa05af 100644
--- a/companion/src/simulation/trainersimu.cpp
+++ b/companion/src/simulation/trainersimu.cpp
@@ -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();
}
}
diff --git a/companion/src/simulation/trainersimu.h b/companion/src/simulation/trainersimu.h
index 520df6d6c..ec1198c5b 100644
--- a/companion/src/simulation/trainersimu.h
+++ b/companion/src/simulation/trainersimu.h
@@ -26,6 +26,7 @@
#include
#include
#include
+#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;
};
diff --git a/companion/src/simulation/widgets/buttonswidget.h b/companion/src/simulation/widgets/buttonswidget.h
index 074ca0851..4fef883e6 100644
--- a/companion/src/simulation/widgets/buttonswidget.h
+++ b/companion/src/simulation/widgets/buttonswidget.h
@@ -22,47 +22,12 @@
#define _BUTTONSWIDGET_H_
#include "radiouiaction.h"
+#include "radiokeywidget.h"
#include
#include
#include
-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 areas;
+ QList m_buttons;
QString defaultStyleSheet;
};
diff --git a/companion/src/simulation/widgets/radiokeywidget.h b/companion/src/simulation/widgets/radiokeywidget.h
new file mode 100644
index 000000000..ee63c3b71
--- /dev/null
+++ b/companion/src/simulation/widgets/radiokeywidget.h
@@ -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
+
+
diff --git a/companion/src/simulation/widgets/radioknobwidget.h b/companion/src/simulation/widgets/radioknobwidget.h
index be74a9ee9..d66eddf18 100644
--- a/companion/src/simulation/widgets/radioknobwidget.h
+++ b/companion/src/simulation/widgets/radioknobwidget.h
@@ -26,7 +26,7 @@
#include
#include
-#include
+#include
#include
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("Value (input): %1
");
+
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(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;
};
};
diff --git a/companion/src/simulation/widgets/radioswitchwidget.h b/companion/src/simulation/widgets/radioswitchwidget.h
index 45c50d710..39878a648 100644
--- a/companion/src/simulation/widgets/radioswitchwidget.h
+++ b/companion/src/simulation/widgets/radioswitchwidget.h
@@ -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);
}
}
diff --git a/companion/src/simulation/widgets/radiotrimwidget.h b/companion/src/simulation/widgets/radiotrimwidget.h
index a6f46bc89..54659b0a4 100644
--- a/companion/src/simulation/widgets/radiotrimwidget.h
+++ b/companion/src/simulation/widgets/radiotrimwidget.h
@@ -22,6 +22,7 @@
#define _RADIOTRIMWIDGET_H_
#include "radiowidget.h"
+#include "boards.h"
#include "sliderwidget.h"
#include
@@ -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(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_
diff --git a/companion/src/simulation/widgets/radiowidget.cpp b/companion/src/simulation/widgets/radiowidget.cpp
index 2e6d213dd..9e4d9177a 100644
--- a/companion/src/simulation/widgets/radiowidget.cpp
+++ b/companion/src/simulation/widgets/radiowidget.cpp
@@ -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();
+ 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();
diff --git a/companion/src/simulation/widgets/radiowidget.h b/companion/src/simulation/widgets/radiowidget.h
index aa9bb81ab..af218495b 100644
--- a/companion/src/simulation/widgets/radiowidget.h
+++ b/companion/src/simulation/widgets/radiowidget.h
@@ -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_
diff --git a/companion/src/simulation/widgets/sliderwidget.h b/companion/src/simulation/widgets/sliderwidget.h
index f99ce570e..1ed285ba8 100644
--- a/companion/src/simulation/widgets/sliderwidget.h
+++ b/companion/src/simulation/widgets/sliderwidget.h
@@ -23,6 +23,7 @@
#include
#include
+#include
class SliderWidget : public QSlider
{
@@ -33,20 +34,34 @@ class SliderWidget : public QSlider
explicit SliderWidget(QWidget * parent = 0):
QSlider(parent)
{
- setToolTip(tr("Right-double-click to reset to center."));
+ m_toolTip = tr("Value (input): %1
") % tr("Right-double-click to reset to center.");
}
- protected:
+ protected:
- void mousePressEvent(QMouseEvent * event)
- {
- if (event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
- setValue(0);
- emit sliderMoved(0);
- event->accept();
- }
- QSlider::mousePressEvent(event);
- }
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::ToolTip) {
+ QHelpEvent * helpEvent = static_cast(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) {
+ setValue(0);
+ emit sliderMoved(0);
+ event->accept();
+ }
+ QSlider::mousePressEvent(event);
+ }
+
+ QString m_toolTip;
};
#endif // _SLIDERWIDGET_H_
diff --git a/companion/src/simulation/widgets/virtualjoystickwidget.cpp b/companion/src/simulation/widgets/virtualjoystickwidget.cpp
index dd250dcad..8e9a4fa45 100644
--- a/companion/src/simulation/widgets/virtualjoystickwidget.cpp
+++ b/companion/src/simulation/widgets/virtualjoystickwidget.cpp
@@ -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:
- btnHoldX->setChecked(active);
- break;
- case HOLD_Y:
- btnHoldY->setChecked(active);
- break;
- case FIX_X:
- btnFixX->setChecked(active);
- break;
- case FIX_Y:
- btnFixY->setChecked(active);
- break;
- default:
- break;
- }
+ if (index & HOLD_X)
+ btnHoldX->setChecked(active);
+ if (index & HOLD_Y)
+ btnHoldY->setChecked(active);
+ if (index & FIX_X)
+ btnFixX->setChecked(active);
+ if (index & FIX_Y)
+ btnFixY->setChecked(active);
}
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)
diff --git a/companion/src/simulation/widgets/virtualjoystickwidget.h b/companion/src/simulation/widgets/virtualjoystickwidget.h
index 69faeddc1..5507d46e2 100644
--- a/companion/src/simulation/widgets/virtualjoystickwidget.h
+++ b/companion/src/simulation/widgets/virtualjoystickwidget.h
@@ -21,6 +21,8 @@
#ifndef VIRTUALJOYSTICKWIDGET_H
#define VIRTUALJOYSTICKWIDGET_H
+#include "radiowidget.h"
+
#include
#include
#include
@@ -28,6 +30,7 @@
#include
#include
#include
+#include
#include
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;
};
diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp
index d3ec9d021..c7dd57f21 100644
--- a/radio/src/mixer.cpp
+++ b/radio/src/mixer.cpp
@@ -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;
diff --git a/radio/src/targets/horus/keys_driver.cpp b/radio/src/targets/horus/keys_driver.cpp
index 728aa1e4e..e881727ba 100644
--- a/radio/src/targets/horus/keys_driver.cpp
+++ b/radio/src/targets/horus/keys_driver.cpp
@@ -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;
@@ -164,7 +162,7 @@ uint8_t keyState(uint8_t index)
uint32_t switchState(uint8_t index)
{
uint32_t xxx = 0;
-
+
switch (index) {
ADD_3POS_CASE(A, 0);
ADD_3POS_CASE(B, 1);
diff --git a/radio/src/targets/simu/CMakeLists.txt b/radio/src/targets/simu/CMakeLists.txt
index 5c5ea5234..332c3b78d 100644
--- a/radio/src/targets/simu/CMakeLists.txt
+++ b/radio/src/targets/simu/CMakeLists.txt
@@ -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})
diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp
index f85be7b9e..70cde32c4 100644
--- a/radio/src/targets/simu/opentxsimulator.cpp
+++ b/radio/src/targets/simu/opentxsimulator.cpp
@@ -18,7 +18,23 @@
#include "opentx.h"
#include "simulcd.h"
+#include
+#include
+
+#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 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(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(EEPROM_SIZE, data.size()));
+#endif
+}
+
+void OpenTxSimulator::readRadioData(QByteArray & dest)
+{
+#if defined(EEPROM_SIZE)
+ QMutexLocker lckr(&m_mtxRadioData);
+ memcpy(dest.data(), eeprom, std::min(EEPROM_SIZE, dest.size()));
+#endif
}
uint8_t * OpenTxSimulator::getLcd()
@@ -67,100 +182,364 @@ 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(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(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)
+}
+
+void OpenTxSimulator::setTrainerTimeout(uint16_t ms)
+{
+ ppmInputValidityTimer = ms;
+}
+
+void OpenTxSimulator::sendTelemetry(uint8_t * data, unsigned int len)
+{
+ Q_UNUSED(len)
+#if defined(TELEMETRY_FRSKY_SPORT)
+ sportProcessTelemetryPacket(data);
+#else
+ Q_UNUSED(data)
#endif
}
-unsigned int OpenTxSimulator::getPhase()
+uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
{
- return getFlightMode();
+#if defined(TELEMETRY_FRSKY_SPORT)
+ for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
+ if (isTelemetryFieldAvailable(i)) {
+ TelemetrySensor * sensor = &g_model.telemetrySensors[i];
+ if (sensor->id == id) {
+ return sensor->instance;
+ }
+ }
+ }
+#else
+ Q_UNUSED(id)
+#endif
+ return defaultValue;
+}
+
+uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
+{
+#if defined(TELEMETRY_FRSKY_SPORT)
+ for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
+ if (isTelemetryFieldAvailable(i)) {
+ TelemetrySensor * sensor = &g_model.telemetrySensors[i];
+ if (sensor->id == id) {
+ return sensor->custom.ratio;
+ }
+ }
+ }
+#else
+ Q_UNUSED(id)
+#endif
+ return 0;
+}
+
+const int OpenTxSimulator::getCapability(Capability cap)
+{
+ int ret = 0;
+ switch(cap) {
+ case CAP_LUA :
+ #ifdef LUA
+ ret = 1;
+ #endif
+ break;
+
+ case CAP_ROTARY_ENC :
+ #ifdef ROTARY_ENCODERS
+ ret = ROTARY_ENCODERS;
+ #endif
+ break;
+
+ case CAP_ROTARY_ENC_NAV :
+ #ifdef ROTARY_ENCODER_NAVIGATION
+ ret = 1;
+ #endif
+ break;
+
+ case CAP_TELEM_FRSKY_SPORT :
+ #ifdef TELEMETRY_FRSKY_SPORT
+ ret = 1;
+ #endif
+ break;
+ }
+ return ret;
+}
+
+void OpenTxSimulator::setLuaStateReloadPermanentScripts()
+{
+#if defined(LUA)
+ luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
+#endif
+}
+
+void OpenTxSimulator::addTracebackDevice(QIODevice * device)
+{
+ QMutexLocker lckr(&m_mtxTbDevices);
+ if (device && !tracebackDevices.contains(device))
+ tracebackDevices.append(device);
+}
+
+void OpenTxSimulator::removeTracebackDevice(QIODevice * device)
+{
+ if (device) {
+ QMutexLocker lckr(&m_mtxTbDevices);
+ // no QVector::removeAll() in Qt < 5.4
+ int i = 0;
+ foreach (QIODevice * d, tracebackDevices) {
+ if (d == device)
+ tracebackDevices.remove(i);
+ ++i;
+ }
+ }
+}
+
+
+/*** Protected classes ***/
+
+void OpenTxSimulator::run()
+{
+ static uint32_t loops = 0;
+ static QElapsedTimer ts;
+
+ if (!loops)
+ ts.start();
+
+ if (isStopRequested()) {
+ return;
+ }
+ if (!isRunning()) {
+ QString err(getError());
+ emit runtimeError(err);
+ emit stopped();
+ return;
+ }
+
+ ++loops;
+
+ per10ms();
+
+ checkLcdChanged();
+
+ if (!(loops % 5)) {
+ checkOutputsChanged();
+ }
+
+ if (!(loops % (SIMULATOR_INTERFACE_HEARTBEAT_PERIOD / 10))) {
+ emit heartbeat(loops, simuTimerMicros() / 1000);
+ }
+}
+
+bool OpenTxSimulator::isStopRequested()
+{
+ QMutexLocker lckr(&m_mtxStopReq);
+ return m_stopRequested;
+}
+
+void OpenTxSimulator::setStopRequested(bool stop)
+{
+ QMutexLocker lckr(&m_mtxStopReq);
+ m_stopRequested = stop;
+}
+
+bool OpenTxSimulator::checkLcdChanged()
+{
+ if (simuLcdRefresh) {
+ simuLcdRefresh = false;
+ emit lcdChange(isBacklightEnabled());
+ return true;
+ }
+ return false;
+}
+
+void OpenTxSimulator::checkOutputsChanged()
+{
+ static TxOutputs lastOutputs;
+ static size_t chansDim = DIM(channelOutputs);
+ qint32 tmpVal;
+ uint8_t i, idx;
+ uint8_t phase = getFlightMode(); // opentx.cpp
+ uint8_t mode = getStickMode();
+
+ for (i=0; i < chansDim; i++) {
+ if (lastOutputs.chans[i] != channelOutputs[i] || m_resetOutputsData) {
+ emit channelOutValueChange(i, channelOutputs[i]);
+ emit channelMixValueChange(i, ex_chans[i]);
+ emit outputValueChange(OUTPUT_SRC_CHAN_OUT, i, channelOutputs[i]);
+ emit outputValueChange(OUTPUT_SRC_CHAN_MIX, i, ex_chans[i]);
+ lastOutputs.chans[i] = channelOutputs[i];
+ }
+ }
+
+ for (i=0; i < MAX_LOGICAL_SWITCHES; i++) {
+ tmpVal = (qint32)GET_SWITCH_BOOL(SWSRC_SW1+i);
+ if (lastOutputs.vsw[i] != (bool)tmpVal || m_resetOutputsData) {
+ emit virtualSwValueChange(i, tmpVal);
+ emit outputValueChange(OUTPUT_SRC_VIRTUAL_SW, i, tmpVal);
+ lastOutputs.vsw[i] = tmpVal;
+ }
+ }
+
+ for (i=0; i < Board::TRIM_AXIS_COUNT; i++) {
+ if (i < 4) // swap axes
+ idx = modn12x3[4 * mode + i];
+ else
+ idx = i;
+
+ tmpVal = getTrimValue(getTrimFlightMode(phase, idx), idx);
+ if (lastOutputs.trims[i] != tmpVal || m_resetOutputsData) {
+ emit trimValueChange(i, tmpVal);
+ emit outputValueChange(OUTPUT_SRC_TRIM_VALUE, i, tmpVal);
+ lastOutputs.trims[i] = tmpVal;
+ }
+ }
+
+ tmpVal = g_model.extendedTrims ? TRIM_EXTENDED_MAX : TRIM_MAX;
+ if (lastOutputs.trimRange != tmpVal || m_resetOutputsData) {
+ emit trimRangeChange(Board::TRIM_AXIS_COUNT, -tmpVal, tmpVal);
+ emit outputValueChange(OUTPUT_SRC_TRIM_RANGE, Board::TRIM_AXIS_COUNT, tmpVal);
+ lastOutputs.trimRange = tmpVal;
+ }
+
+ if (lastOutputs.phase != phase || m_resetOutputsData) {
+ emit phaseChanged(phase, getCurrentPhaseName());
+ emit outputValueChange(OUTPUT_SRC_PHASE, 0, qint16(phase));
+ lastOutputs.phase = phase;
+ }
+
+#if defined(GVAR_VALUE) && defined(GVARS)
+ gVarMode_t gvar;
+ for (uint8_t fm=0; fm < MAX_FLIGHT_MODES; fm++) {
+ gvar.mode = fm;
+ for (uint8_t gv=0; gv < MAX_GVARS; gv++) {
+ tmpVal = GVAR_VALUE(gv, getGVarFlightMode(fm, gv));
+ if (lastOutputs.gvars[fm][gv] != tmpVal || m_resetOutputsData) {
+ lastOutputs.gvars[fm][gv] = tmpVal;
+ gvar.value = (int16_t)tmpVal;
+ tmpVal = gvar;
+ emit gVarValueChange(gv, tmpVal);
+ emit outputValueChange(OUTPUT_SRC_GVAR, gv, tmpVal);
+ }
+ }
+ }
+#endif
+
+ m_resetOutputsData = false;
+}
+
+uint8_t OpenTxSimulator::getStickMode()
+{
+ return limit(0, g_eeGeneral.stickMode, 3);
}
const char * OpenTxSimulator::getPhaseName(unsigned int phase)
@@ -170,66 +549,39 @@ const char * OpenTxSimulator::getPhaseName(unsigned int phase)
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()
{
-#define GETERROR_IMPORT
-#include "simulatorimport.h"
+ return main_thread_error;
}
-void OpenTxSimulator::sendTelemetry(uint8_t * data, unsigned int len)
+const int OpenTxSimulator::voltageToAdc(const int volts)
{
-#if defined(TELEMETRY_FRSKY_SPORT)
- sportProcessTelemetryPacket(data);
+ 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;
}
-uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue)
-{
-#if defined(TELEMETRY_FRSKY_SPORT)
- for (int i = 0; iid == id) {
- return sensor->instance;
- }
- }
- }
-#endif
- return defaultValue;
-}
-uint16_t OpenTxSimulator::getSensorRatio(uint16_t id)
-{
-#if defined(TELEMETRY_FRSKY_SPORT)
- for (int i = 0; iid == id) {
- return sensor->custom.ratio;
- }
- }
- }
-#endif
- return 0;
-}
-
-void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value)
-{
-#define SETTRAINER_IMPORT
-#include "simulatorimport.h"
-}
-
-void OpenTxSimulator::setLuaStateReloadPermanentScripts()
-{
-#if defined(LUA)
- luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
-#endif
-}
-
-void OpenTxSimulator::installTraceHook(void (*callback)(const char *))
-{
- traceCallback = callback;
-}
+/*
+ * OpenTxSimulatorFactory
+ */
class OpenTxSimulatorFactory: public SimulatorFactory
{
diff --git a/radio/src/targets/simu/opentxsimulator.h b/radio/src/targets/simu/opentxsimulator.h
index 700a56ef3..d3ba6689a 100644
--- a/radio/src/targets/simu/opentxsimulator.h
+++ b/radio/src/targets/simu/opentxsimulator.h
@@ -19,68 +19,84 @@
#include "simulatorinterface.h"
+#include
+#include
+#include
+
#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 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_
diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp
index 23ba0aa09..de5d90df2 100644
--- a/radio/src/targets/simu/simpgmspace.cpp
+++ b/radio/src/targets/simu/simpgmspace.cpp
@@ -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
}
}