feat: New advanced joystick mode on radio, improvements to Companion and Simulator joystick support (#3111)

* Allow switches on the connected radio to control switches in the simulator via the joystick interface.

* Merge configurable radio joystick interface from banyaszg.

* Add two more 'axis' channels to companion.

* Fix 6POS from USB joystick to simulator.

* Reduce data size.

* Fix build error on B&W radios.

* Add 'Companion' button mode to work with the button logic in the Companion app.

* Build Companion joystick setup layout at runtime.
Change #define names for simulator joystick.
Allow 15 axes and 32 buttons.
Initial support for trim sliders.

* Remove custom joystick button type for companion - use 3 buttons per switch in companion to control simulator switch state.

* Fix joystick constructor calls parameters. Connect some radio joystick trims to simulator widgets.

* Restore 'companion' button type to reduce number of buttons needed. Make trims work via buttons in USB joystick.

* Connect joystick trim buttons to simulator widgets.

* Use companion source names for trims.

* Add encode / decode of usb joystick custom settings to Companion.

* Convert to lvgl layouts.
Update language files.

* Fix generated YAML storage files.

* Fix initialisation error when editing button channel. Cleanup code.

* Fix rebase.

* Fix refresh of joystick channel list view after editing an entry.
Companion joystick config window uses two columns.

* Fix vertical joystick inversion bug.
Change stick axis labels.

---------

Co-authored-by: Phil Mitchell <phil.a.mitchell@gmail.com>
This commit is contained in:
philmoz
2023-03-22 10:31:29 +10:00
committed by GitHub
co-authored by Phil Mitchell
parent a1178f83a6
commit 661657feca
81 changed files with 3501 additions and 572 deletions
+2 -2
View File
@@ -273,7 +273,7 @@ void AppPreferencesDialog::initSettings()
if (ui->joystickChkB->isChecked()) {
QStringList joystickNames;
joystickNames << tr("No joysticks found");
joystick = new Joystick(0,false,0,0);
joystick = new Joystick(0,0,false,0);
ui->joystickcalButton->setDisabled(true);
ui->joystickCB->setDisabled(true);
@@ -591,7 +591,7 @@ void AppPreferencesDialog::on_joystickChkB_clicked() {
if (ui->joystickChkB->isChecked()) {
QStringList joystickNames;
joystickNames << tr("No joysticks found");
joystick = new Joystick(0,false,0,0);
joystick = new Joystick(0,0,false,0);
ui->joystickcalButton->setDisabled(true);
ui->joystickCB->setDisabled(true);
+1
View File
@@ -46,6 +46,7 @@ set(firmwares_SRCS
edgetx/yaml_customfunctiondata.cpp
edgetx/yaml_sensordata.cpp
edgetx/yaml_screendata.cpp
edgetx/yaml_usbjoystickdata.cpp
datahelpers.cpp
customisation_data.cpp
)
@@ -29,6 +29,7 @@
#include "yaml_customfunctiondata.h"
#include "yaml_sensordata.h"
#include "yaml_screendata.h"
#include "yaml_usbjoystickdata.h"
#include "modeldata.h"
#include "output_data.h"
@@ -79,6 +80,12 @@ static const YamlLookupTable jitterFilterLut = {
{ 2, "ON" },
};
static const YamlLookupTable usbJoystickIfModeLut = {
{ 0, "JOYSTICK" },
{ 1, "GAMEPAD" },
{ 2, "MULTIAXIS" },
};
struct YamlTrim {
int mode = 0;
int ref = 0;
@@ -1008,6 +1015,16 @@ Node convert<ModelData>::encode(const ModelData& rhs)
}
}
// Custom USB joytsick mapping
node["usbJoystickExtMode"] = rhs.usbJoystickExtMode;
node["usbJoystickIfMode"] = usbJoystickIfModeLut << rhs.usbJoystickIfMode;
node["usbJoystickCircularCut"] = rhs.usbJoystickCircularCut;
for (int i = 0; i < CPN_USBJ_MAX_JOYSTICK_CHANNELS; i++) {
if (rhs.usbJoystickCh[i].mode > 0) {
node["usbJoystickCh"][std::to_string(i)] = rhs.usbJoystickCh[i];
}
}
return node;
}
@@ -1194,6 +1211,12 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
node["functionSwitchLogicalState"] >> rhs.functionSwitchLogicalState;
node["switchNames"] >> rhs.functionSwitchNames;
// Custom USB joytsick mapping
node["usbJoystickExtMode"] >> rhs.usbJoystickExtMode;
node["usbJoystickIfMode"] >> usbJoystickIfModeLut >> rhs.usbJoystickIfMode;
node["usbJoystickCircularCut"] >> rhs.usbJoystickCircularCut;
node["usbJoystickCh"] >> rhs.usbJoystickCh;
// preferably perform conversions here to avoid cluttering the field decodes
if (SemanticVersion(QString(rhs.semver)) < SemanticVersion("2.8.0")) {
@@ -0,0 +1,56 @@
/*
* Copyright (C) EdgeTX
*
* 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 "yaml_usbjoystickdata.h"
#include "generalsettings.h"
#include "modeldata.h"
const YamlLookupTable usbJoystickChMode = {
{0, "CH_NONE"},
{1, "CH_BUTTON"},
{2, "CH_AXIS"},
{3, "CH_SIM"},
};
namespace YAML
{
Node convert<USBJoystickChData>::encode(const USBJoystickChData& rhs)
{
Node node;
node["mode"] = usbJoystickChMode << rhs.mode;
node["inversion"] = rhs.inversion;
node["param"] = rhs.param;
node["btn_num"] = rhs.btn_num;
node["switch_npos"] = rhs.switch_npos;
return node;
}
bool convert<USBJoystickChData>::decode(const Node& node, USBJoystickChData& rhs)
{
node["mode"] >> usbJoystickChMode >> rhs.mode;
node["inversion"] >> rhs.inversion;
node["param"] >> rhs.param;
node["btn_num"] >> rhs.btn_num;
node["switch_npos"] >> rhs.switch_npos;
return true;
}
} // namespace YAML
@@ -0,0 +1,35 @@
/*
* Copyright (C) EdgeTX
*
* 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 "yaml_ops.h"
#include "generalsettings.h"
extern const YamlLookupTable usbJoystickChMode;
class USBJoystickChData;
namespace YAML
{
template <>
struct convert<USBJoystickChData> {
static Node encode(const USBJoystickChData& rhs);
static bool decode(const Node& node, USBJoystickChData& rhs);
};
} // namespace YAML
+19
View File
@@ -90,6 +90,19 @@ enum TrainerMode {
#define INPUT_NAME_LEN 4
#define CPN_MAX_BITMAP_LEN 14
#define CPN_USBJ_MAX_JOYSTICK_CHANNELS 26
class USBJoystickChData {
public:
USBJoystickChData() { clear(); }
unsigned int mode;
unsigned int inversion;
unsigned int param;
unsigned int btn_num;
unsigned int switch_npos;
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(USBJoystickChData)); }
};
class ModelData {
Q_DECLARE_TR_FUNCTIONS(ModelData)
@@ -201,6 +214,12 @@ class ModelData {
unsigned int functionSwitchLogicalState;
char functionSwitchNames[CPN_MAX_FUNCTION_SWITCHES][HARDWARE_NAME_LEN + 1];
// Custom USB joytsick mapping
unsigned int usbJoystickExtMode;
unsigned int usbJoystickIfMode;
unsigned int usbJoystickCircularCut;
USBJoystickChData usbJoystickCh[CPN_USBJ_MAX_JOYSTICK_CHANNELS];
void clear();
bool isEmpty() const;
void setDefaultInputs(const GeneralSettings & settings);
+2 -2
View File
@@ -116,7 +116,7 @@ qreal Node::getY()
if(scene())
{
QRectF rect = scene()->sceneRect();
return 1+((y()-rect.bottom())*2/rect.height());
return ((rect.bottom()-y())*2/rect.height())-1;
}
return 0;
}
@@ -126,7 +126,7 @@ void Node::setY(qreal newY)
if(scene())
{
QRectF rect = scene()->sceneRect();
QGraphicsObject::setY(rect.top() + (newY+1) * rect.height()/2);
QGraphicsObject::setY(rect.top() + (1-newY) * rect.height()/2);
}
}
+6 -3
View File
@@ -63,6 +63,9 @@ bool Joystick::open(int stick)
numHats = SDL_JoystickNumHats(joystick);
numTrackballs = SDL_JoystickNumBalls(joystick);
joystickTimer.start(eventTimeout);
for (int i = 0; i < numButtons; i += 1) {
buttons[i] = -1;
}
return true;
}
else {
@@ -109,9 +112,9 @@ void Joystick::processEvents()
axisRepeatTimers[i].restart();
}
}
else {
emit axisValueChanged(i, 0);
}
// else {
// emit axisValueChanged(i, 0);
// }
}
for (i = 0; i < numButtons; i++) {
Uint8 changed = SDL_JoystickGetButton(joystick, i);
+154 -42
View File
@@ -20,6 +20,7 @@
#include "joystickdialog.h"
#include "ui_joystickdialog.h"
#include "eeprominterface.h"
#include "boards.h"
#include "constants.h"
@@ -33,40 +34,71 @@ joystickDialog::joystickDialog(QWidget *parent, int stick) :
{
ui->setupUi(this);
int jscaltmp[8][3] = {
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767},
{32767, 0, -32767}
};
memcpy(jscal, jscaltmp, sizeof (jscal));
int i;
char s[20];
foreach(QComboBox *cb, findChildren<QComboBox *>(QRegularExpression("jsmapCB_[0-9]+"))) {
populateSourceCombo(cb);
sticks[cb->property("channel").toUInt()] = cb;
}
foreach(QCheckBox *ib, findChildren<QCheckBox *>(QRegularExpression("ChInv_[0-9]+"))) {
invert[ib->property("channel").toUInt()] = ib;
}
foreach(QSlider *sl, findChildren<QSlider *>(QRegularExpression("Ch_[0-9]+"))) {
sliders[sl->property("channel").toUInt()] = sl;
for (i = 0; i < MAX_JS_AXES; i += 1) {
jscal[i][0] = 32767;
jscal[i][1] = 0;
jscal[i][2] = -32767;
}
for (int i = 0; i < MAX_JOYSTICKS; ++i) {
if (!g.joystick[i].existsOnDisk())
continue;
QGridLayout *grid = findChild<QGridLayout*>("gridLayout");
int row = 0;
int col = 0;
if (grid) {
for (i = 0; i < MAX_JS_AXES; i += 1, row += 1) {
col = (i & 1) * 4;
sprintf(s, "Ch%d", i + 1);
QLabel *l = new QLabel(s);
grid->addWidget(l, row/2, col+0, 1, 1);
QSlider *s = new QSlider(Qt::Horizontal);
s->setMinimum(-32767);
s->setMaximum(32767);
sliders[row] = s;
grid->addWidget(s, row/2, col+1, 1, 1);
QCheckBox *c = new QCheckBox("");
invert[row] = c;
grid->addWidget(c, row/2, col+2, 1, 1);
QComboBox *d = new QComboBox();
populateSourceCombo(d);
sticks[row] = d;
grid->addWidget(d, row/2, col+3, 1, 1);
}
if (row & 1) row += 1;
for (i = 0; i < MAX_JS_BUTTONS; i += 1, row += 1) {
col = (i & 1) * 4;
sprintf(s, "Btn%d", i + 1);
QLabel *l = new QLabel(s);
grid->addWidget(l, row/2, col+0, 1, 1);
QSlider *s = new QSlider(Qt::Horizontal);
s->setMinimum(0);
s->setMaximum(1);
sliders[row] = s;
grid->addWidget(s, row/2, col+1, 1, 1);
QComboBox *d = new QComboBox();
populateButtonCombo(d);
sticks[row] = d;
grid->addWidget(d, row/2, col+3, 1, 1);
}
}
jscal[i][0] = g.joystick[i].stick_min();
jscal[i][1] = g.joystick[i].stick_med();
jscal[i][2] = g.joystick[i].stick_max();
sliders[i]->setMinimum(jscal[i][0]);
sliders[i]->setMaximum(jscal[i][2]);
invert[i]->setChecked(g.joystick[i].stick_inv());
sticks[i]->setCurrentIndex(sticks[i]->findData(g.joystick[i].stick_axe()));
for (int i = 0; i < MAX_JS_AXES; ++i) {
if (g.joystick[i].existsOnDisk()) {
jscal[i][0] = g.joystick[i].stick_min();
jscal[i][1] = g.joystick[i].stick_med();
jscal[i][2] = g.joystick[i].stick_max();
sliders[i]->setMinimum(jscal[i][0]);
sliders[i]->setMaximum(jscal[i][2]);
invert[i]->setChecked(g.joystick[i].stick_inv());
sticks[i]->setCurrentIndex(sticks[i]->findData(g.joystick[i].stick_axe()));
}
}
for (int i = 0; i < MAX_JS_BUTTONS; ++i) {
if (g.jsButton[i].existsOnDisk()) {
sticks[i+MAX_JS_AXES]->setCurrentIndex(sticks[i+MAX_JS_AXES]->findData(g.jsButton[i].button_idx()));
}
}
ui->backButton->setEnabled(false);
@@ -86,6 +118,7 @@ joystickDialog::joystickDialog(QWidget *parent, int stick) :
loadStep();
connect(joystick, SIGNAL(axisValueChanged(int, int)), this, SLOT(onjoystickAxisValueChanged(int, int)));
connect(joystick, SIGNAL(buttonValueChanged(int, bool)), this, SLOT(onjoystickButtonValueChanged(int, bool)));
connect(ui->joystickCB, SIGNAL(currentIndexChanged(int)), this, SLOT(joystickOpen(int)));
connect(ui->joystickChkB, SIGNAL(toggled(bool)), this, SLOT(joystickSetEnabled(bool)));
}
@@ -98,13 +131,75 @@ joystickDialog::~joystickDialog()
void joystickDialog::populateSourceCombo(QComboBox * cb)
{
int i;
QString wname;
Board::Type m_board = getCurrentBoard();
GeneralSettings radioSettings = GeneralSettings();
int ttlSticks = Boards::getCapability(m_board, Board::Sticks);
int ttlKnobs = Boards::getCapability(m_board, Board::Pots);
int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
cb->clear();
cb->addItem(tr("Not Assigned"), -1);
for (i=0; i < Board::STICK_AXIS_COUNT; ++i) {
cb->addItem(Boards::getAxisName(i) % tr(" Stick"), i);
for (i=0; i < ttlSticks; ++i) {
wname = Boards::getAxisName(i);
cb->addItem(wname, i);
}
for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS + CPN_MAX_SLIDERS; ++i) {
cb->addItem(tr("Knob/Slider %1").arg(i - Board::STICK_AXIS_COUNT + 1), i);
for (i = 0; i < ttlKnobs; ++i) {
if (radioSettings.isPotAvailable(i)) {
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + i).toString(nullptr, &radioSettings);
cb->addItem(wname, i + ttlSticks);
}
}
for (i = 0; i < ttlFaders; ++i) {
if (radioSettings.isSliderAvailable(i)) {
wname = RawSource(RawSourceType::SOURCE_TYPE_STICK, ttlSticks + ttlKnobs + i).toString(nullptr, &radioSettings);
cb->addItem(wname, i + ttlSticks + ttlKnobs);
}
}
}
void joystickDialog::populateButtonCombo(QComboBox * cb)
{
int i;
QString wname;
Board::Type m_board = getCurrentBoard();
GeneralSettings radioSettings = GeneralSettings();
int ttlSwitches = Boards::getCapability(m_board, Board::Switches);
int ttlTrims = Boards::getCapability(m_board, Board::NumTrims);
cb->clear();
cb->addItem(tr("Not Assigned"), -1);
Board::SwitchType swcfg;
for (i = 0; i < ttlSwitches; ++i) {
if (radioSettings.switchConfig[i] != Board::SWITCH_NOT_AVAILABLE) {
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
wname = RawSource(RawSourceType::SOURCE_TYPE_SWITCH, i).toString(nullptr, &radioSettings);
if (swcfg == Board::SWITCH_3POS) {
cb->addItem(wname + CPN_STR_SW_INDICATOR_UP, i | JS_BUTTON_3POS_UP);
cb->addItem(wname + CPN_STR_SW_INDICATOR_DN, i | JS_BUTTON_3POS_DN);
} else {
cb->addItem(wname, i | JS_BUTTON_TOGGLE);
}
}
}
for (i = 0; i < ttlTrims; i += 1) {
wname = RawSource(RawSourceType::SOURCE_TYPE_TRIM, i).toString(nullptr, &radioSettings);
if ((i == 0) || (i == 3)) {
cb->addItem(wname + " Left", i + ttlSwitches | JS_BUTTON_3POS_DN);
cb->addItem(wname + " Right", i + ttlSwitches | JS_BUTTON_3POS_UP);
} else {
cb->addItem(wname + " Down", i + ttlSwitches | JS_BUTTON_3POS_DN);
cb->addItem(wname + " Up", i + ttlSwitches | JS_BUTTON_3POS_UP);
}
}
}
@@ -115,7 +210,7 @@ bool joystickDialog::loadJoysticks(int stick)
ui->joystickCB->clear();
joystickNames << tr("No joysticks found");
joystick = new Joystick(0, false, 0, 0);
joystick = new Joystick(0, 0, false, 0);
if ( joystick ) {
if ( joystick->joystickNames.count() > 0 ) {
joystickNames = joystick->joystickNames;
@@ -140,10 +235,10 @@ void joystickDialog::joystickOpen(int stick)
joystick = new Joystick(this, 1, false, 0);
if (joystick && joystick->open(stick)) {
numAxes = std::min(joystick->numAxes, MAX_JOYSTICKS);
numAxes = std::min(joystick->numAxes, MAX_JS_AXES);
for (int j=0; j<numAxes; j++) {
joystick->sensitivities[j] = 0;
joystick->deadzones[j]=20;
joystick->deadzones[j] = 20;
}
}
else {
@@ -161,7 +256,7 @@ void joystickDialog::joystickSetEnabled(bool enable)
void joystickDialog::onjoystickAxisValueChanged(int axis, int value)
{
if (axis >= MAX_JOYSTICKS)
if (axis >= MAX_JS_AXES)
return;
if (started) {
@@ -177,6 +272,14 @@ void joystickDialog::onjoystickAxisValueChanged(int axis, int value)
sliders[axis]->setValue(value);
}
void joystickDialog::onjoystickButtonValueChanged(int button, bool state)
{
if (button >= MAX_JS_BUTTONS)
return;
sliders[button + MAX_JS_AXES]->setValue(state);
}
void joystickDialog::loadStep()
{
switch (step) {
@@ -241,8 +344,6 @@ void joystickDialog::on_cancelButton_clicked()
void joystickDialog::on_okButton_clicked()
{
int stick;
g.jsSupport(ui->joystickChkB->isChecked());
g.jsCtrl(ui->joystickCB->currentIndex());
@@ -261,8 +362,8 @@ void joystickDialog::on_okButton_clicked()
return;
}
for (int i = 0; i < MAX_JOYSTICKS; ++i) {
stick = sticks[i]->currentData().toInt();
for (int i = 0; i < MAX_JS_AXES; ++i) {
auto stick = sticks[i]->currentData().toInt();
if (stick < 0) {
g.joystick[i].stick_axe(-1);
}
@@ -276,5 +377,16 @@ void joystickDialog::on_okButton_clicked()
}
}
for (int i = 0; i < MAX_JS_BUTTONS; ++i) {
auto btn = sticks[i+MAX_JS_AXES]->currentData().toInt();
if (btn < 0) {
g.jsButton[i].button_idx(-1);
}
else {
g.jsButton[i].button_idx(btn);
qDebug() << "joystick button mapping " << sticks[i+MAX_JS_AXES]->objectName() << "stick:" << i << "idx:" << btn;
}
}
this->accept();
}
+14 -4
View File
@@ -29,6 +29,14 @@ class QCheckBox;
class QComboBox;
class QSlider;
enum JSButtonFlag {
JS_BUTTON_TOGGLE = 0x1000,
JS_BUTTON_3POS_UP = 0x2000,
JS_BUTTON_3POS_DN = 0x4000,
JS_BUTTON_TYPE_MASK = 0xF000,
JS_BUTTON_SWITCH_MASK = 0x1F
};
namespace Ui {
class joystickDialog;
}
@@ -44,20 +52,22 @@ class joystickDialog : public QDialog
private:
Ui::joystickDialog *ui;
int jscal[MAX_JOYSTICKS][3];
QCheckBox * invert[MAX_JOYSTICKS];
QComboBox * sticks[MAX_JOYSTICKS];
QSlider * sliders[MAX_JOYSTICKS];
int jscal[MAX_JS_AXES][3];
QCheckBox * invert[MAX_JS_AXES];
QComboBox * sticks[MAX_JS_AXES + MAX_JS_BUTTONS];
QSlider * sliders[MAX_JS_AXES + MAX_JS_BUTTONS];
int step;
int numAxes;
bool started;
private slots:
void populateSourceCombo(QComboBox * cb);
void populateButtonCombo(QComboBox * cb);
bool loadJoysticks(int stick = -1);
void joystickOpen(int stick);
void joystickSetEnabled(bool enable);
void onjoystickAxisValueChanged(int axis, int value);
void onjoystickButtonValueChanged(int button, bool state);
void loadStep();
void on_backButton_clicked();
void on_nextButton_clicked();
+25 -484
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>351</height>
<width>709</width>
<height>195</height>
</rect>
</property>
<property name="sizePolicy">
@@ -20,495 +20,23 @@
<string>Configure Joystick</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="2" rowspan="4">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QWidget" name="calibrationWidget" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>640</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Ch2</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSlider" name="Ch_3">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QComboBox" name="jsmapCB_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Ch1</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="jsmapCB_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="Ch_2">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="jsmapCB_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Ch4</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSlider" name="Ch_5">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>4</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Ch6</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ch3</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QComboBox" name="jsmapCB_5">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>4</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSlider" name="Ch_4">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>3</number>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="jsmapCB_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>3</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSlider" name="Ch_6">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>5</number>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QComboBox" name="jsmapCB_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>5</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Ch5</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Ch7</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSlider" name="Ch_7">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>6</number>
</property>
</widget>
</item>
<item row="6" column="3">
<widget class="QComboBox" name="jsmapCB_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>6</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Ch8</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSlider" name="Ch_8">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>7</number>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QComboBox" name="jsmapCB_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="channel" stdset="0">
<number>7</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="Ch_1">
<property name="minimum">
<number>-32767</number>
</property>
<property name="maximum">
<number>32676</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>0</number>
</property>
<property name="channel" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="ChInv_1">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="ChInv_2">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>1</number>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="ChInv_3">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="ChInv_4">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>3</number>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QCheckBox" name="ChInv_5">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>4</number>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="ChInv_6">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>5</number>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="ChInv_7">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>6</number>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QCheckBox" name="ChInv_8">
<property name="text">
<string notr="true"/>
</property>
<property name="channel" stdset="0">
<number>7</number>
</property>
</widget>
</item>
</layout>
<layout class="QGridLayout" name="gridLayout"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="howtoLabel">
@@ -544,6 +72,19 @@
</layout>
</widget>
</item>
<item row="0" column="2" rowspan="4">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -587,7 +128,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>198</width>
<width>360</width>
<height>20</height>
</size>
</property>
@@ -647,7 +188,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<width>1</width>
<height>0</height>
</size>
</property>
@@ -661,7 +202,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
<height>1</height>
</size>
</property>
</spacer>
+63 -10
View File
@@ -21,7 +21,6 @@
#include "simulatorwidget.h"
#include "ui_simulatorwidget.h"
#include "appdata.h"
#include "appdebugmessagehandler.h"
#include "radiofaderwidget.h"
#include "radiokeywidget.h"
@@ -619,7 +618,6 @@ void SimulatorWidget::setupRadioWidgets()
RadioKnobWidget * pot = new RadioKnobWidget(Board::PotType(radioSettings.potConfig[i]), wname, 0, ui->radioWidgetsHT);
pot->setIndex(i);
ui->radioWidgetsHTLayout->insertWidget(midpos++, pot);
m_radioWidgets.append(pot);
}
@@ -661,6 +659,7 @@ void SimulatorWidget::setupRadioWidgets()
foreach (RadioWidget * rw, m_radioWidgets) {
connect(rw, &RadioWidget::valueChange, this, &SimulatorWidget::onRadioWidgetValueChange);
connect(this, &SimulatorWidget::widgetValueChange, rw, &RadioWidget::setValueQual);
connect(this, &SimulatorWidget::widgetValueAdjust, rw, &RadioWidget::chgValueQual);
connect(this, &SimulatorWidget::widgetStateChange, rw, &RadioWidget::setStateData);
}
@@ -673,21 +672,28 @@ void SimulatorWidget::setupJoysticks()
if (g.jsSupport() && g.jsCtrl() > -1) {
if (!joystick)
joystick = new Joystick(this);
joystick = new Joystick(this, SDL_JOYSTICK_DEFAULT_EVENT_TIMEOUT, false, SDL_JOYSTICK_DEFAULT_AUTOREPEAT_DELAY);
else
joystick->close();
if (joystick && joystick->open(g.jsCtrl())) {
int numAxes = std::min(joystick->numAxes, MAX_JOYSTICKS);
int numAxes = std::min(joystick->numAxes, MAX_JS_AXES);
for (int j=0; j<numAxes; j++) {
joystick->sensitivities[j] = 0;
joystick->deadzones[j] = 0;
}
connect(joystick, &Joystick::axisValueChanged, this, &SimulatorWidget::onjoystickAxisValueChanged);
if (vJoyLeft)
connect(joystick, &Joystick::buttonValueChanged, this, &SimulatorWidget::onjoystickButtonValueChanged);
if (vJoyLeft) {
connect(this, &SimulatorWidget::stickValueChange, vJoyLeft, &VirtualJoystickWidget::setStickAxisValue);
if (vJoyRight)
connect(this, &SimulatorWidget::widgetValueAdjust, vJoyLeft->horizontalTrim(), &RadioWidget::chgValueQual);
connect(this, &SimulatorWidget::widgetValueAdjust, vJoyLeft->verticalTrim(), &RadioWidget::chgValueQual);
}
if (vJoyRight) {
connect(this, &SimulatorWidget::stickValueChange, vJoyRight, &VirtualJoystickWidget::setStickAxisValue);
connect(this, &SimulatorWidget::widgetValueAdjust, vJoyRight->horizontalTrim(), &RadioWidget::chgValueQual);
connect(this, &SimulatorWidget::widgetValueAdjust, vJoyRight->verticalTrim(), &RadioWidget::chgValueQual);
}
joysticksEnabled = true;
}
else {
@@ -858,7 +864,7 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
static const int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
static const int valueRange = 1024;
if (!joystick || axis >= MAX_JOYSTICKS)
if (!joystick || axis >= MAX_JS_AXES)
return;
int dlta;
@@ -885,11 +891,58 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
}
else {
stick -= ttlSticks;
if (stick < ttlKnobs)
if (stick < ttlKnobs) {
GeneralSettings radioSettings = GeneralSettings();
if (Board::PotType(radioSettings.potConfig[stick]) == Board::POT_MULTIPOS_SWITCH)
stickval += 1024;
emit widgetValueChange(RadioWidget::RADIO_WIDGET_KNOB, stick, stickval);
else
emit widgetValueChange(RadioWidget::RADIO_WIDGET_FADER, stick - ttlKnobs, stickval);
} else {
stick -= ttlKnobs;
emit widgetValueChange(RadioWidget::RADIO_WIDGET_FADER, stick, stickval);
}
}
#endif
}
void SimulatorWidget::onjoystickButtonValueChanged(int button, bool state)
{
#ifdef JOYSTICKS
if (!joystick || button >= MAX_JS_BUTTONS)
return;
int ttlSwitches = Boards::getCapability(m_board, Board::Switches);
int btn = g.jsButton[button].button_idx();
if (g.jsButton[button].button_inv())
state = !state;
int swtch = btn & JS_BUTTON_SWITCH_MASK;
if (swtch < ttlSwitches) {
if (btn & JS_BUTTON_3POS_DN) {
// 3POS Down
if (state || (switchDirection[swtch] == 0) || (switchDirection[swtch] == (btn & JS_BUTTON_TYPE_MASK))) {
emit widgetValueChange(RadioWidget::RADIO_WIDGET_SWITCH, swtch, state ? 1 : 0);
switchDirection[swtch] = (btn & JS_BUTTON_TYPE_MASK);
}
} else if (btn & JS_BUTTON_3POS_UP) {
// 3POS Up
if (state || (switchDirection[swtch] == 0) || (switchDirection[swtch] == (btn & JS_BUTTON_TYPE_MASK))) {
emit widgetValueChange(RadioWidget::RADIO_WIDGET_SWITCH, swtch, state ? -1 : 0);
switchDirection[swtch] = (btn & JS_BUTTON_TYPE_MASK);
}
} else if (btn & JS_BUTTON_TOGGLE) {
// Toggle or momentary
emit widgetValueChange(RadioWidget::RADIO_WIDGET_SWITCH, swtch, state ? 1 : - 1);
}
} else {
// Trim
swtch -= ttlSwitches;
int offset = (btn & JS_BUTTON_3POS_DN) ? -1 : 1;
emit widgetValueAdjust(RadioWidget::RADIO_WIDGET_TRIM, swtch, offset, state);
}
#endif
}
@@ -21,6 +21,7 @@
#ifndef _SIMULATORWIDGET_H_
#define _SIMULATORWIDGET_H_
#include "appdata.h"
#include "constants.h"
#include "helpers.h"
#include "radiodata.h"
@@ -88,6 +89,7 @@ class SimulatorWidget : public QWidget
void stickValueChange(int axis, int value);
void stickModeChange(const unsigned mode);
void widgetValueChange(const RadioWidget::RadioWidgetType type, const int index, const int value);
void widgetValueAdjust(const RadioWidget::RadioWidgetType type, const int index, const int offset, const bool state);
void widgetStateChange(const RadioWidget::RadioWidgetState & state);
void inputValueChange(int type, quint8 index, qint16 value);
void simulatorSetData(const QByteArray & data);
@@ -110,6 +112,7 @@ class SimulatorWidget : public QWidget
void onSimulatorError(const QString & error);
void onRadioWidgetValueChange(const RadioWidget::RadioWidgetType type, const int index, int value);
void onjoystickAxisValueChanged(int axis, int value);
void onjoystickButtonValueChanged(int button, bool state);
void setRadioProfileId(int value);
void setupRadioWidgets();
@@ -145,6 +148,7 @@ class SimulatorWidget : public QWidget
#ifdef JOYSTICKS
Joystick * joystick = nullptr;
int switchDirection[MAX_JS_BUTTONS];
#endif
};
@@ -65,7 +65,7 @@ class RadioTrimWidget : public RadioWidget
setValue(value);
}
void setValue(const int & value)
void setValue(const int & value) override
{
if (sender() && qobject_cast<SliderWidget *>(sender())) {
RadioWidget::setValue(value);
@@ -75,6 +75,12 @@ class RadioTrimWidget : public RadioWidget
}
}
void chgValueQual(const RadioWidgetType & type, const int & index, const int offset, const bool state) override {
if (type == m_type && index == m_index) {
emit valueChange(m_type, (offset < 0) ? m_btnDecIndex : m_btnIncIndex, state ? RADIO_TRIM_BTN_ON : RADIO_TRIM_BTN_OFF);
}
}
protected slots:
void init(Qt::Orientation orientation)
@@ -88,6 +88,7 @@ class RadioWidget : public QWidget
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 chgValueQual(const RadioWidgetType & type, const int & index, const int offset, const bool state) {}
virtual void setFlags(const quint16 & flags);
virtual void setShowLabel(const bool show);
virtual void setLabelText(const QString & labelText, bool showLabel = true);
@@ -323,7 +323,7 @@ void VirtualJoystickWidget::onNodeXChanged()
void VirtualJoystickWidget::onNodeYChanged()
{
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_yIndex, int(-m_stickScale * getStickY()));
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_yIndex, int(m_stickScale * getStickY()));
updateNodeValueLabels();
}
@@ -564,9 +564,9 @@ void VirtualJoystickWidget::onButtonChange(bool checked)
void VirtualJoystickWidget::updateNodeValueLabels()
{
if (nodeLabelX)
nodeLabelX->setText(QString("%1").arg(node->getX() * 100.0f, 2, 'f', 0));
nodeLabelX->setText(QString("%1").arg(getStickX() * 100.0f, 2, 'f', 0));
if (nodeLabelY)
nodeLabelY->setText(QString("%1").arg(node->getY() * -100.0f, 2, 'f', 0));
nodeLabelY->setText(QString("%1").arg(getStickY() * 100.0f, 2, 'f', 0));
}
void VirtualJoystickWidget::onGsMouseEvent(QGraphicsSceneMouseEvent * event)
@@ -61,6 +61,9 @@ class VirtualJoystickWidget : public QWidget
int getStickScale() const;
void setStickScale(int stickScale);
const RadioTrimWidget *horizontalTrim() { return hTrimWidget; }
const RadioTrimWidget *verticalTrim() { return vTrimWidget; }
public slots:
void setStickX(qreal x);
void setStickY(qreal y);
+22 -4
View File
@@ -256,6 +256,16 @@ bool JStickData::existsOnDisk()
return (m_settings.value(settingsPath() % stick_axe_key(), -1).toInt() > -1);
}
JButtonData::JButtonData() : CompStoreObj(), index(-1)
{
CompStoreObj::addObjectMapping(propertyGroup(), this);
}
bool JButtonData::existsOnDisk()
{
return (m_settings.value(settingsPath() % button_idx_key(), -1).toInt() > -1);
}
// ** Profile class********************
@@ -397,8 +407,10 @@ AppData::AppData() :
profile[i].setIndex(i);
// Configure the joysticks
for (int i = 0; i < MAX_JOYSTICKS; i++)
for (int i = 0; i < MAX_JS_AXES; i++)
joystick[i].setIndex(i);
for (int i = 0; i < MAX_JS_BUTTONS; i++)
jsButton[i].setIndex(i);
// Configure the updates
for (int i = 0; i < MAX_COMPONENTS; i++) {
@@ -436,8 +448,10 @@ void AppData::initAll()
for (int i = 0; i < MAX_PROFILES; i++)
profile[i].init();
// Initialize the joysticks
for (int i = 0; i < MAX_JOYSTICKS; i++)
for (int i = 0; i < MAX_JS_AXES; i++)
joystick[i].init();
for (int i = 0; i < MAX_JS_BUTTONS; i++)
jsButton[i].init();
// Initialize the updatess
for (int i = 0; i < MAX_COMPONENTS; i++) {
component[i].init();
@@ -453,8 +467,10 @@ void AppData::resetAllSettings()
fwRev.resetAll();
for (int i = 0; i < MAX_PROFILES; i++)
profile[i].resetAll();
for (int i = 0; i < MAX_JOYSTICKS; i++)
for (int i = 0; i < MAX_JS_AXES; i++)
joystick[i].resetAll();
for (int i = 0; i < MAX_JS_BUTTONS; i++)
jsButton[i].resetAll();
for (int i = 0; i < MAX_COMPONENTS; i++) {
component[i].resetAll();
for (int j = 0; j < MAX_COMPONENT_ASSETS; j++) {
@@ -469,8 +485,10 @@ void AppData::storeAllSettings()
storeAll();
for (int i = 0; i < MAX_PROFILES; i++)
profile[i].storeAll();
for (int i = 0; i < MAX_JOYSTICKS; i++)
for (int i = 0; i < MAX_JS_AXES; i++)
joystick[i].storeAll();
for (int i = 0; i < MAX_JS_BUTTONS; i++)
jsButton[i].storeAll();
for (int i = 0; i < MAX_COMPONENTS; i++) {
component[i].storeAll();
for (int j = 0; j < MAX_COMPONENT_ASSETS; j++)
+24 -2
View File
@@ -59,7 +59,8 @@
#define CPN_SETTINGS_INI_PATH QString(CPN_SETTINGS_BACKUP_DIR % "/" % CPN_SETTINGS_INI_FILE)
#define MAX_PROFILES 20
#define MAX_JOYSTICKS 8
#define MAX_JS_AXES 10
#define MAX_JS_BUTTONS 32
#define MAX_COMPONENTS 10
#define MAX_COMPONENT_ASSETS 5
@@ -347,6 +348,26 @@ class JStickData: public CompStoreObj
int index;
};
class JButtonData: public CompStoreObj
{
Q_OBJECT
public slots:
bool existsOnDisk();
protected:
explicit JButtonData();
void setIndex(int idx) { index = idx; }
inline QString propertyGroup() const override { return QStringLiteral("JsButton"); }
inline QString settingsPath() const override { return QString("%1/%2/").arg(propertyGroup()).arg(index); }
friend class AppData;
private:
PROPERTY(int, button_idx, -1)
PROPERTY(int, button_inv, 0)
int index;
};
//! \brief Profile class stores properties related to each Radio Profile.
//! \todo TODO: Remove or refactor stored radio settings system (#4583)
@@ -592,7 +613,8 @@ class AppData: public CompStoreObj
bool exportSettingsToFile(const QString & expFile, QString & resultMsg);
Profile profile[MAX_PROFILES];
JStickData joystick[MAX_JOYSTICKS];
JStickData joystick[MAX_JS_AXES];
JButtonData jsButton[MAX_JS_BUTTONS];
FwRevision fwRev;
ComponentData component[MAX_COMPONENTS];
+14
View File
@@ -61,6 +61,12 @@ option(HARDWARE_TRAINER_MULTI "Allow multi trainer" OFF)
option(BOOTLOADER "Include Bootloader" ON)
option(FWDRIVE "Attach also firmware drive with USB" OFF)
if(PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019)
option(USBJ_EX "Enable USB Joystick Extension" OFF)
else()
option(USBJ_EX "Enable USB Joystick Extension" ON)
endif()
# since we reset all default CMAKE compiler flags for firmware builds, provide an alternate way for user to specify additional flags.
set(FIRMWARE_C_FLAGS "" CACHE STRING "Additional flags for firmware target c compiler (note: all CMAKE_C_FLAGS[_*] are ignored for firmware/bootloader).")
set(FIRMWARE_C_FLAGS_DEBUG "-g" CACHE STRING "Additional flags for firmware target (Debug config) c compiler (note: CMAKE_C_FLAGS_DEBUG is ignored for firmware/bootloader).")
@@ -418,6 +424,14 @@ if(GUI)
endforeach()
endif()
if(USBJ_EX)
add_definitions(-DUSBJ_EX)
set(SRC
${SRC}
usb_joystick.cpp
)
endif()
foreach(FILE ${TARGET_SRC})
set(SRC targets/${TARGET_DIR}/${FILE} ${SRC})
endforeach()
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

+10 -10
View File
@@ -118,36 +118,36 @@ static inline void check_struct()
#if defined(PCBXLITES)
CHKSIZE(RadioData, 862);
CHKSIZE(ModelData, 6164);
CHKSIZE(ModelData, 6217);
#elif defined(PCBXLITE)
CHKSIZE(RadioData, 860);
CHKSIZE(ModelData, 6164);
CHKSIZE(ModelData, 6217);
#elif defined(RADIO_TPRO)
CHKSIZE(RadioData, 843);
CHKSIZE(ModelData, 6189);
CHKSIZE(ModelData, 6242);
#elif defined(RADIO_BOXER)
CHKSIZE(RadioData, 875);
CHKSIZE(ModelData, 6165);
CHKSIZE(ModelData, 6218);
#elif defined(PCBX7)
CHKSIZE(RadioData, 866);
CHKSIZE(ModelData, 6164);
CHKSIZE(ModelData, 6217);
#elif defined(PCBX9E)
CHKSIZE(RadioData, 956);
CHKSIZE(ModelData, 6616);
CHKSIZE(ModelData, 6669);
#elif defined(PCBX9D) || defined(PCBX9DP)
CHKSIZE(RadioData, 898);
CHKSIZE(ModelData, 6608);
CHKSIZE(ModelData, 6661);
#elif defined(PCBHORUS)
#if defined(PCBX10)
CHKSIZE(RadioData, 924);
CHKSIZE(ModelData, 15378);
CHKSIZE(ModelData, 15431);
#else
CHKSIZE(RadioData, 906);
CHKSIZE(ModelData, 15376);
CHKSIZE(ModelData, 15429);
#endif
#elif defined(PCBNV14)
CHKSIZE(RadioData, 852);
CHKSIZE(ModelData, 15192);
CHKSIZE(ModelData, 15245);
#endif
#undef CHKSIZE
+36
View File
@@ -29,6 +29,7 @@
#include "opentx_types.h"
#include "globals.h"
#include "serial.h"
#include "usb_joystick.h"
#if defined(PCBTARANIS)
#define N_TARANIS_FIELD(x)
@@ -624,6 +625,36 @@ PACK(struct PartialModel {
TimerData timers[MAX_TIMERS];
});
/*
* USB Joystick channel structure
*/
PACK(struct USBJoystickChData {
uint8_t mode:3 ENUM(USBJoystickCh);
uint8_t inversion:1;
uint8_t param:4;
uint8_t btn_num:5;
uint8_t switch_npos:3;
#if defined(USBJ_EX)
NOBACKUP(
uint8_t lastBtnNumNoCLip() {
uint8_t last = btn_num + switch_npos;
// Use one less joystick button for 2POS and 3POS switches for Companion mode
if ((param == USBJOYS_BTN_MODE_COMPANION) && (switch_npos > 0) && (switch_npos < 3)) last -= 1;
return last;
}
uint8_t lastBtnNum() {
uint8_t last = lastBtnNumNoCLip();
if (last >= USBJ_BUTTON_SIZE) {
last = USBJ_BUTTON_SIZE - 1;
}
return last;
}
);
#endif
});
PACK(struct ModelData {
CUST_ATTR(semver,nullptr,w_semver);
ModelHeader header;
@@ -725,6 +756,11 @@ PACK(struct ModelData {
break;
}
}
uint8_t usbJoystickExtMode:1;
uint8_t usbJoystickIfMode:3 ENUM(USBJoystickIfMode);
uint8_t usbJoystickCircularCut:4;
USBJoystickChData usbJoystickCh[USBJ_MAX_JOYSTICK_CHANNELS];
});
/*
+3
View File
@@ -131,6 +131,9 @@ void menuModelSensor(event_t event);
void menuModelDisplay(event_t event);
void menuModelTemplates(event_t event);
void menuModelGVarOne(event_t event);
#if defined(USBJ_EX)
void menuModelUSBJoystick(event_t event);
#endif
static const MenuHandlerFunc menuTabModel[] = {
menuModelSelect,
+68 -1
View File
@@ -22,6 +22,10 @@
#include "opentx.h"
#include "mixer_scheduler.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
#if !defined(EEPROM)
#include "storage/sdcard_common.h"
#include "storage/modelslist.h"
@@ -193,6 +197,15 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_TRAINER_CHANNELS,
ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS,
#endif
#if defined(USBJ_EX)
ITEM_MODEL_SETUP_USBJOYSTICK_LABEL,
ITEM_MODEL_SETUP_USBJOYSTICK_MODE,
ITEM_MODEL_SETUP_USBJOYSTICK_IF_MODE,
ITEM_MODEL_SETUP_USBJOYSTICK_CIRC_CUTOUT,
ITEM_MODEL_SETUP_USBJOYSTICK_CH_BUTTON,
ITEM_MODEL_SETUP_USBJOYSTICK_APPLY,
#endif
ITEM_MODEL_SETUP_LINES_COUNT
};
@@ -443,6 +456,25 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
NUM_SWITCHES - 1, /* Switch warning */
#endif
#if defined(USBJ_EX)
inline uint8_t USB_JOYSTICK_EXTROW()
{
return (usbJoystickExtMode() ? (uint8_t)0 : HIDDEN_ROW);
}
inline uint8_t USB_JOYSTICK_APPLYROW()
{
if(!usbJoystickExtMode()) return HIDDEN_ROW;
if(usbJoystickSettingsChanged()) return (uint8_t)0;
return READONLY_ROW;
}
#define USB_JOYSTICK_ROWS LABEL(USBJoystick), (uint8_t)0, USB_JOYSTICK_EXTROW(), \
USB_JOYSTICK_EXTROW(), USB_JOYSTICK_EXTROW(), USB_JOYSTICK_APPLYROW()
#else
#define USB_JOYSTICK_ROWS
#endif
#if defined(FUNCTION_SWITCHES)
static const char* _fct_sw_start[] = { STR_CHAR_UP, STR_CHAR_DOWN, "=" };
#endif
@@ -491,7 +523,9 @@ void menuModelSetup(event_t event)
EXTRA_MODULE_ROWS
TRAINER_ROWS
TRAINER_ROWS,
USB_JOYSTICK_ROWS
});
MENU_CHECK(menuTabModel, MENU_MODEL_SETUP, HEADER_LINE + ITEM_MODEL_SETUP_LINES_COUNT);
@@ -2053,6 +2087,39 @@ void menuModelSetup(event_t event)
}
break;
#endif
#if defined(USBJ_EX)
case ITEM_MODEL_SETUP_USBJOYSTICK_LABEL:
lcdDrawTextAlignedLeft(y, STR_USBJOYSTICK_LABEL);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_MODE:
g_model.usbJoystickExtMode = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_EXTMODE, STR_VUSBJOYSTICK_EXTMODE, g_model.usbJoystickExtMode, 0, 1, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_IF_MODE:
g_model.usbJoystickIfMode = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_IF_MODE, STR_VUSBJOYSTICK_IF_MODE, g_model.usbJoystickIfMode, 0, USBJOYS_LAST, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_CIRC_CUTOUT:
g_model.usbJoystickCircularCut = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_CIRC_COUTOUT, STR_VUSBJOYSTICK_CIRC_COUTOUT, g_model.usbJoystickCircularCut, 0, 2, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_CH_BUTTON:
lcdDrawText(INDENT_WIDTH, y, BUTTON(TR_USBJOYSTICK_SETTINGS), attr);
if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) {
pushMenu(menuModelUSBJoystick);
}
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_APPLY:
lcdDrawText(INDENT_WIDTH, y, BUTTON(TR_USBJOYSTICK_APPLY_CHANGES), attr);
if (attr && !READ_ONLY() && event == EVT_KEY_FIRST(KEY_ENTER)) {
killEvents(event);
onUSBJoystickModelChanged();
}
break;
#endif
}
}
+3
View File
@@ -122,6 +122,9 @@ void menuModelCustomScripts(event_t event);
void menuModelTelemetry(event_t event);
void menuModelSensor(event_t event);
void menuModelDisplay(event_t event);
#if defined(USBJ_EX)
void menuModelUSBJoystick(event_t event);
#endif
extern const MenuHandlerFunc menuTabModel[MENU_MODEL_PAGES_COUNT];
+68 -1
View File
@@ -22,6 +22,10 @@
#include "opentx.h"
#include "mixer_scheduler.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
#if defined(CROSSFIRE)
#include "telemetry/crossfire.h"
#endif
@@ -153,6 +157,15 @@ enum MenuModelSetupItems {
#endif
ITEM_MODEL_SETUP_TRAINER_CHANNELS,
ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS,
#if defined(USBJ_EX)
ITEM_MODEL_SETUP_USBJOYSTICK_LABEL,
ITEM_MODEL_SETUP_USBJOYSTICK_MODE,
ITEM_MODEL_SETUP_USBJOYSTICK_IF_MODE,
ITEM_MODEL_SETUP_USBJOYSTICK_CIRC_CUTOUT,
ITEM_MODEL_SETUP_USBJOYSTICK_CH_BUTTON,
ITEM_MODEL_SETUP_USBJOYSTICK_APPLY,
#endif
ITEM_MODEL_SETUP_LINES_COUNT
};
@@ -392,6 +405,25 @@ void onBluetoothConnectMenu(const char * result)
#include "common/stdlcd/model_setup_afhds3.cpp"
#endif
#if defined(USBJ_EX)
inline uint8_t USB_JOYSTICK_EXTROW()
{
return (usbJoystickExtMode() ? (uint8_t)0 : HIDDEN_ROW);
}
inline uint8_t USB_JOYSTICK_APPLYROW()
{
if(!usbJoystickExtMode()) return HIDDEN_ROW;
if(usbJoystickSettingsChanged()) return (uint8_t)0;
return READONLY_ROW;
}
#define USB_JOYSTICK_ROWS LABEL(USBJoystick), (uint8_t)0, USB_JOYSTICK_EXTROW(), \
USB_JOYSTICK_EXTROW(), USB_JOYSTICK_EXTROW(), USB_JOYSTICK_APPLYROW()
#else
#define USB_JOYSTICK_ROWS
#endif
void menuModelSetup(event_t event)
{
horzpos_t l_posHorz = menuHorizontalPosition;
@@ -470,7 +502,9 @@ void menuModelSetup(event_t event)
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3
TRAINER_ROWS
TRAINER_ROWS,
USB_JOYSTICK_ROWS
});
MENU_CHECK(menuTabModel, MENU_MODEL_SETUP, ITEM_MODEL_SETUP_LINES_COUNT);
@@ -1768,6 +1802,39 @@ void menuModelSetup(event_t event)
modelSetupModulePxx2ReceiverLine(CURRENT_MODULE_EDITED(k), CURRENT_RECEIVER_EDITED(k), y, event, attr);
break;
#endif
#if defined(USBJ_EX)
case ITEM_MODEL_SETUP_USBJOYSTICK_LABEL:
lcdDrawTextAlignedLeft(y, STR_USBJOYSTICK_LABEL);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_MODE:
g_model.usbJoystickExtMode = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_EXTMODE, STR_VUSBJOYSTICK_EXTMODE, g_model.usbJoystickExtMode, 0, 1, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_IF_MODE:
g_model.usbJoystickIfMode = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_IF_MODE, STR_VUSBJOYSTICK_IF_MODE, g_model.usbJoystickIfMode, 0, USBJOYS_LAST, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_CIRC_CUTOUT:
g_model.usbJoystickCircularCut = editChoice(MODEL_SETUP_2ND_COLUMN, y, INDENT TR_USBJOYSTICK_CIRC_COUTOUT, STR_VUSBJOYSTICK_CIRC_COUTOUT, g_model.usbJoystickCircularCut, 0, 2, attr, event);
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_CH_BUTTON:
lcdDrawText(INDENT_WIDTH, y, BUTTON(TR_USBJOYSTICK_SETTINGS), attr);
if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) {
pushMenu(menuModelUSBJoystick);
}
break;
case ITEM_MODEL_SETUP_USBJOYSTICK_APPLY:
lcdDrawText(INDENT_WIDTH, y, BUTTON(TR_USBJOYSTICK_APPLY_CHANGES), attr);
if (attr && !READ_ONLY() && event == EVT_KEY_FIRST(KEY_ENTER)) {
killEvents(event);
onUSBJoystickModelChanged();
}
break;
#endif
}
}
+5
View File
@@ -222,3 +222,8 @@ add_gui_src(lvgl_widgets/input_mix_group.c)
if(HARDWARE_TOUCH)
add_gui_src(keyboard_curve.cpp)
endif()
if(USBJ_EX)
add_gui_src(model_usbjoystick.cpp)
endif()
+4
View File
@@ -83,6 +83,9 @@ static const uint8_t mask_model_special_functions[] = {
static const uint8_t mask_model_telemetry[] = {
#include "mask_model_telemetry.lbm"
};
static const uint8_t mask_model_usb[] = {
#include "mask_model_usb.lbm"
};
static const uint8_t mask_menu_model_select[] = {
#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon
};
@@ -343,6 +346,7 @@ static const _BuiltinIcon _builtinIcons[] = {
{ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions},
{ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts},
{ICON_MODEL_TELEMETRY, mask_model_telemetry},
{ICON_MODEL_USB, mask_model_usb},
{ICON_MODEL_SELECT, mask_menu_model_select},
{ICON_MODEL_SELECT_CATEGORY, mask_model_select_category},
{ICON_THEME, mask_menu_theme},
+1
View File
@@ -56,6 +56,7 @@ enum MenuIcons {
ICON_MODEL_SPECIAL_FUNCTIONS,
ICON_MODEL_LUA_SCRIPTS,
ICON_MODEL_TELEMETRY,
ICON_MODEL_USB,
ICON_MODEL_SELECT,
ICON_MODEL_SELECT_CATEGORY,
ICON_THEME,
+13
View File
@@ -33,6 +33,10 @@
#include "throttle_params.h"
#include "preflight_checks.h"
#if defined(USBJ_EX)
#include "model_usbjoystick.h"
#endif
#include <algorithm>
#define SET_DIRTY() storageDirty(EE_MODEL)
@@ -329,6 +333,15 @@ void ModelSetupPage::build(FormWindow * window)
btn = new SubScreenButton(form, STR_THROTTLE_LABEL, []() { new ThrottleParams(); });
lv_obj_set_grid_cell(btn->getLvObj(), LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
#if defined(USBJ_EX)
form = new FormGroup(oform, rect_t{});
form->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(PAGE_PADDING));
lv_obj_set_grid_dsc_array(form->getLvObj(), col_dsc, row_dsc);
btn = new SubScreenButton(form, STR_USBJOYSTICK_LABEL, []() { new ModelUSBJoystickPage(); });
lv_obj_set_grid_cell(btn->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
#endif
}
#define MAX_SUBSCREEN_BTNS 9
@@ -0,0 +1,601 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "model_usbjoystick.h"
#include "usb_joystick.h"
#include "channel_bar.h"
#include "button_matrix.h"
#include "lvgl_widgets/input_mix_line.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
#if LCD_W > LCD_H // Landscape
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
#define USBCH_EDIT_STATUS_BAR_WIDTH 250
#define USBCH_EDIT_STATUS_BAR_MARGIN 3
#define USBCH_EDIT_RIGHT_MARGIN 0
#define USBCH_COLS 4
static const lv_coord_t ch_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
LV_GRID_FR(1), LV_GRID_FR(2),
LV_GRID_TEMPLATE_LAST};
#define USBCH_CHN_ROWS 1
#define USBCH_BTN_MODE_COL 4
#define USBCH_BTN_MODE_ROW 0
#define USBCH_LINE_HEIGHT PAGE_LINE_HEIGHT + 14
static const lv_coord_t b_col_dsc[] = {LV_GRID_FR(10), 20, LV_GRID_FR(10), LV_GRID_FR(12),
LV_GRID_FR(9), LV_GRID_FR(9), LV_GRID_TEMPLATE_LAST};
static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
#else // Portrait
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
#define USBCH_EDIT_STATUS_BAR_WIDTH 160
#define USBCH_EDIT_STATUS_BAR_MARGIN 0
#define USBCH_EDIT_RIGHT_MARGIN 3
#define USBCH_COLS 2
static const lv_coord_t ch_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3),
LV_GRID_TEMPLATE_LAST};
#define USBCH_CHN_ROWS 2
#define USBCH_BTN_MODE_COL 2
#define USBCH_BTN_MODE_ROW 1
#define USBCH_LINE_HEIGHT 2 * PAGE_LINE_HEIGHT + 10
static const lv_coord_t b_col_dsc[] = {LV_GRID_FR(1), 20, LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
#endif
#define USBCH_BTNMX_COL 8
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
class USBChannelEditStatusBar : public Window
{
public:
USBChannelEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) :
Window(parent, rect), _channel(channel)
{
channelBar = new ComboChannelBar(this, {USBCH_EDIT_STATUS_BAR_MARGIN, 0, rect.w - (USBCH_EDIT_STATUS_BAR_MARGIN * 2), rect.h}, channel);
channelBar->setLeftMargin(0);
channelBar->setTextColor(COLOR_THEME_PRIMARY2);
channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT);
}
protected:
ComboChannelBar *channelBar;
int8_t _channel;
};
static void btnsel_event_cb(lv_event_t* e);
class USBChannelButtonSel : public ButtonMatrix
{
public:
USBChannelButtonSel(Window* parent, const rect_t& rect, uint8_t channel,
std::function<void(int)> _setValue) :
ButtonMatrix(parent, rect),
m_channel(channel),
m_setValue(std::move(_setValue))
{
initBtnMap(USBCH_BTNMX_COL, USBJ_BUTTON_SIZE);
char snum[5];
for (uint8_t btn = 0; btn < USBJ_BUTTON_SIZE; btn++) {
snprintf(snum, 5, "%u", btn);
setText(btn, snum);
}
update();
lv_obj_add_event_cb(lvobj, btnsel_event_cb, LV_EVENT_DRAW_PART_BEGIN, this);
memset(m_btns, 0, USBJ_BUTTON_SIZE);
for (uint8_t ch = 0; ch < USBJ_MAX_JOYSTICK_CHANNELS; ch++) {
if (ch != m_channel) {
USBJoystickChData * cch = usbJChAddress(ch);
if (cch->mode == USBJOYS_CH_BUTTON) {
uint8_t last = cch->lastBtnNum();
for(uint8_t b = cch->btn_num; b <= last; b++) {
m_btns[b] = 1;
}
}
}
}
updateState();
}
void setValue(int val)
{
if (m_setValue) {
m_setValue(val);
}
}
void onPress(uint8_t btn_id) override
{
setValue(btn_id);
updateState();
}
bool isActive(uint8_t btn_id) override { return false; }
uint8_t getBtnState(uint8_t id)
{
if (id < USBJ_BUTTON_SIZE) return m_btns[id];
return 0;
}
void updateState()
{
USBJoystickChData * cch = usbJChAddress(m_channel);
for(uint8_t i = 0; i < USBJ_BUTTON_SIZE; i++) m_btns[i] &= 1;
uint8_t last = cch->lastBtnNum();
for(uint8_t b = cch->btn_num; b <= last; b++) m_btns[b] |= 2;
}
protected:
uint8_t m_channel = 0;
std::function<void(int)> m_setValue;
uint8_t m_btns[USBJ_BUTTON_SIZE];
};
static void btnsel_event_cb(lv_event_t* e)
{
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_DRAW_PART_BEGIN) {
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
if(dsc->class_p == &lv_btnmatrix_class && dsc->type == LV_BTNMATRIX_DRAW_PART_BTN) {
dsc->rect_dsc->radius = LV_RADIUS_CIRCLE;
auto btsel = (USBChannelButtonSel*)lv_event_get_user_data(e);
uint8_t state = btsel->getBtnState((uint8_t)dsc->id);
if (state == 1) {
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_DISABLED);
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY1);
}
else if (state == 2) {
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_EDIT);
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY2);
}
else if (state == 3) {
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_WARNING);
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY2);
}
else {
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
dsc->label_dsc->color = makeLvColor(COLOR_THEME_SECONDARY1);
}
}
}
}
#define USBCH_LINES 3
#define SET_VALUE_WUPDATE(value) [=](int32_t newValue) { value = newValue; SET_DIRTY(); this->update(); }
class USBChannelEditWindow : public Page
{
public:
USBChannelEditWindow(uint8_t channel) :
Page(ICON_MODEL_USB), channel(channel)
{
auto form = new FormWindow(&body, rect_t{});
form->padAll(4);
form->padLeft(8);
form->padRight(8);
buildHeader(&header);
buildBody(form);
}
protected:
uint8_t channel;
USBChannelEditStatusBar* statusBar = nullptr;
FormWindow* m_btnModeFrame = nullptr;
Window* m_axisModeLine = nullptr;
Window* m_simModeLine = nullptr;
USBChannelButtonSel* _BtnNumSel = nullptr;
StaticText* collisionText = nullptr;
Choice* m_btnPosChoice = nullptr;
protected:
void update()
{
USBJoystickChData * cch = usbJChAddress(channel);
lv_obj_add_flag(m_btnModeFrame->getLvObj(), LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(m_axisModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(m_simModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN);
if (cch->mode == USBJOYS_CH_BUTTON)
lv_obj_clear_flag(m_btnModeFrame->getLvObj(), LV_OBJ_FLAG_HIDDEN);
else if (cch->mode == USBJOYS_CH_AXIS)
lv_obj_clear_flag(m_axisModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN);
else if (cch->mode == USBJOYS_CH_SIM)
lv_obj_clear_flag(m_simModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN);
if(m_btnPosChoice)
m_btnPosChoice->enable((cch->param != USBJOYS_BTN_MODE_SW_EMU) && (cch->param != USBJOYS_BTN_MODE_DELTA));
if(collisionText) {
collisionText->setText("");
lv_obj_add_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
if (cch->mode == USBJOYS_CH_BUTTON) {
if (isUSBBtnNumCollision(channel)) {
collisionText->setText(STR_USBJOYSTICK_BTN_COLLISION);
lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
}
}
else if (cch->mode == USBJOYS_CH_AXIS) {
if (isUSBAxisCollision(channel)) {
collisionText->setText(STR_USBJOYSTICK_AXIS_COLLISION);
lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
}
}
else if (cch->mode == USBJOYS_CH_SIM) {
if (isUSBSimCollision(channel)) {
collisionText->setText(STR_USBJOYSTICK_AXIS_COLLISION);
lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
}
}
}
_BtnNumSel->updateState();
}
void buildHeader(Window *window)
{
header.setTitle(STR_USBJOYSTICK_LABEL);
header.setTitle2(getSourceString(MIXSRC_CH1 + channel));
statusBar = new USBChannelEditStatusBar(
window,
{window->getRect().w - USBCH_EDIT_STATUS_BAR_WIDTH - USBCH_EDIT_RIGHT_MARGIN,
0, USBCH_EDIT_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT + 3},
channel);
}
void buildBody(FormWindow* form)
{
FlexGridLayout grid(ch_col_dsc, row_dsc, 2);
form->setFlexLayout();
USBJoystickChData * cch = usbJChAddress(channel);
auto line = form->newLine(&grid);
line->padTop(0);
line->padBottom(0);
collisionText = new StaticText(line, rect_t{}, "", OPAQUE, FONT(BOLD) | COLOR_THEME_PRIMARY2 | CENTERED);
collisionText->setBackgroundColor(COLOR_THEME_WARNING);
lv_obj_set_grid_cell(collisionText->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, USBCH_COLS, LV_GRID_ALIGN_CENTER, 0, 1);
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_MODE, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_MODE, 0, USBJOYS_CH_LAST,
GET_DEFAULT(cch->mode), SET_VALUE_WUPDATE(cch->mode));
#if LCD_H > LCD_W
line = form->newLine(&grid);
#endif
new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_INVERSION, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(cch->inversion));
line = form->newLine(&grid);
m_btnModeFrame = new FormWindow(line, rect_t{});
m_btnModeFrame->setFlexLayout();
line = m_btnModeFrame->newLine(&grid);
new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNMODE, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_BTNMODE, 0, USBJOYS_BTN_MODE_LAST,
GET_DEFAULT(cch->param),
[=](int32_t newValue)
{
cch->param = newValue;
if(cch->param == USBJOYS_BTN_MODE_SW_EMU) m_btnPosChoice->setValue(0);
else if(cch->param == USBJOYS_BTN_MODE_DELTA) m_btnPosChoice->setValue(1);
SET_DIRTY();
this->update();
});
#if LCD_H > LCD_W
line = m_btnModeFrame->newLine(&grid);
#endif
new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_SWPOS, 0, COLOR_THEME_PRIMARY1);
m_btnPosChoice = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_SWPOS, 0, 7,
GET_DEFAULT(cch->switch_npos), SET_VALUE_WUPDATE(cch->switch_npos));
line = m_btnModeFrame->newLine(&grid);
new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNNUM, 0, COLOR_THEME_PRIMARY1);
#if LCD_H > LCD_W
line = m_btnModeFrame->newLine(&grid);
#endif
_BtnNumSel = new USBChannelButtonSel(line, rect_t{},
channel, SET_VALUE_WUPDATE(cch->btn_num));
m_axisModeLine = form->newLine(&grid);
new StaticText(m_axisModeLine, rect_t{}, STR_USBJOYSTICK_CH_AXIS, 0, COLOR_THEME_PRIMARY1);
new Choice(m_axisModeLine, rect_t{}, STR_VUSBJOYSTICK_CH_AXIS, 0, USBJOYS_AXIS_LAST,
GET_DEFAULT(cch->param), SET_VALUE_WUPDATE(cch->param));
m_simModeLine = form->newLine(&grid);
new StaticText(m_simModeLine, rect_t{}, STR_USBJOYSTICK_CH_SIM, 0, COLOR_THEME_PRIMARY1);
new Choice(m_simModeLine, rect_t{}, STR_VUSBJOYSTICK_CH_SIM, 0, USBJOYS_SIM_LAST,
GET_DEFAULT(cch->param), SET_VALUE_WUPDATE(cch->param));
update();
}
};
class USBChannelLineButton : public Button
{
public:
USBChannelLineButton(Window* parent, uint8_t index) :
Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create), index(index)
{
setHeight(USBCH_LINE_HEIGHT);
lv_obj_set_layout(lvobj, LV_LAYOUT_GRID);
lv_obj_set_grid_dsc_array(lvobj, b_col_dsc, b_row_dsc);
lv_obj_set_style_pad_row(lvobj, 0, 0);
lv_obj_set_style_pad_column(lvobj, 4, 0);
lv_obj_add_event_cb(lvobj, USBChannelLineButton::on_draw,
LV_EVENT_DRAW_MAIN_BEGIN, nullptr);
}
static void on_draw(lv_event_t* e)
{
lv_obj_t* target = lv_event_get_target(e);
auto line = (USBChannelLineButton*)lv_obj_get_user_data(target);
if (line) {
if (!line->init)
line->delayed_init(e);
else
line->refresh();
}
}
void delayed_init(lv_event_t* e)
{
m_chn = lv_label_create(lvobj);
lv_obj_set_grid_cell(m_chn, LV_GRID_ALIGN_START, 0, 1,
LV_GRID_ALIGN_CENTER, 0, USBCH_CHN_ROWS);
m_inverse = new StaticBitmap(this, rect_t{0, 0, 11, 16}, chanMonInvertedBitmap, COLOR_THEME_SECONDARY1, false);
lv_obj_set_grid_cell(m_inverse->getLvObj(), LV_GRID_ALIGN_START, 1, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
m_mode = lv_label_create(lvobj);
lv_obj_set_grid_cell(m_mode, LV_GRID_ALIGN_START, 2, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
m_param = lv_label_create(lvobj);
lv_obj_set_grid_cell(m_param, LV_GRID_ALIGN_START, 3, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
m_btn_mode = lv_label_create(lvobj);
lv_obj_set_grid_cell(m_btn_mode, LV_GRID_ALIGN_START, USBCH_BTN_MODE_COL, 1,
LV_GRID_ALIGN_CENTER, USBCH_BTN_MODE_ROW, 1);
m_btns = lv_label_create(lvobj);
lv_obj_set_grid_cell(m_btns, LV_GRID_ALIGN_START, USBCH_BTN_MODE_COL+1, 1,
LV_GRID_ALIGN_CENTER, USBCH_BTN_MODE_ROW, 1);
lv_label_set_text(m_chn, getSourceString(MIXSRC_CH1 + index));
lv_label_set_text(m_mode, "");
lv_label_set_text(m_param, "");
lv_label_set_text(m_btn_mode, "");
lv_label_set_text(m_btns, "");
init = true;
refresh();
lv_obj_update_layout(lvobj);
if (e) {
auto param = lv_event_get_param(e);
lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param);
}
}
void refresh()
{
if (!init) return;
USBJoystickChData * cch = usbJChAddress(index);
lv_label_set_text(m_mode, STR_VUSBJOYSTICK_CH_MODE[cch->mode]);
if (cch->inversion)
lv_obj_clear_flag(m_inverse->getLvObj(), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_add_flag(m_inverse->getLvObj(), LV_OBJ_FLAG_HIDDEN);
LcdFlags warn = COLOR_THEME_SECONDARY1;
LcdFlags font = FONT(STD);
const char* param = "";
if (cch->mode == USBJOYS_CH_BUTTON) {
param = STR_VUSBJOYSTICK_CH_BTNMODE[cch->param];
}
else if (cch->mode == USBJOYS_CH_AXIS) {
param = STR_VUSBJOYSTICK_CH_AXIS[cch->param];
if (isUSBAxisCollision(index)) {
warn = COLOR_THEME_WARNING;
font = FONT(BOLD);
}
}
else if (cch->mode == USBJOYS_CH_SIM) {
param = STR_VUSBJOYSTICK_CH_SIM[cch->param];
if (isUSBSimCollision(index)) {
warn = COLOR_THEME_WARNING;
font = FONT(BOLD);
}
}
lv_label_set_text(m_param, param);
lv_obj_set_style_text_color(m_param, makeLvColor(warn), 0);
lv_obj_set_style_text_font(m_param, getFont(font), 0);
if (cch->mode == USBJOYS_CH_BUTTON) {
lv_label_set_text(m_btn_mode, STR_VUSBJOYSTICK_CH_SWPOS[cch->switch_npos]);
char str[20];
uint8_t last = cch->lastBtnNum();
if (last > cch->btn_num)
snprintf(str, 20, "%u..%u", cch->btn_num, last);
else
snprintf(str, 20, "%u", cch->btn_num);
lv_label_set_text(m_btns, str);
if (isUSBBtnNumCollision(index)) {
warn = COLOR_THEME_WARNING;
font = FONT(BOLD);
}
lv_obj_set_style_text_color(m_btns, makeLvColor(warn), 0);
lv_obj_set_style_text_font(m_btns, getFont(font), 0);
} else {
lv_label_set_text(m_btn_mode, "");
lv_label_set_text(m_btns, "");
}
}
protected:
bool init = false;
uint8_t index;
lv_obj_t* m_chn;
lv_obj_t* m_mode;
lv_obj_t* m_param;
lv_obj_t* m_btn_mode;
lv_obj_t* m_btns;
StaticBitmap* m_inverse;
};
ModelUSBJoystickPage::ModelUSBJoystickPage() :
Page(ICON_MODEL_USB)
{
header.setTitle(STR_USBJOYSTICK_LABEL);
auto form = new FormWindow(&body, rect_t{});
form->padAll(lv_dpx(8));
form->setFlexLayout();
FlexGridLayout grid(line_col_dsc, row_dsc, 2);
// Extended mode
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_USBJOYSTICK_EXTMODE, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VUSBJOYSTICK_EXTMODE, 0, 1,
GET_DEFAULT(g_model.usbJoystickExtMode), SET_VALUE_WUPDATE(g_model.usbJoystickExtMode));
#if LCD_H > LCD_W
line = form->newLine(&grid);
#endif
_IfModeLabel = new StaticText(line, rect_t{}, STR_USBJOYSTICK_IF_MODE, 0, COLOR_THEME_PRIMARY1);
_IfMode = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_IF_MODE, 0, USBJOYS_LAST,
GET_DEFAULT(g_model.usbJoystickIfMode), SET_VALUE_WUPDATE(g_model.usbJoystickIfMode));
line = form->newLine(&grid);
_CircCoutoutLabel = new StaticText(line, rect_t{}, STR_USBJOYSTICK_CIRC_COUTOUT, 0, COLOR_THEME_PRIMARY1);
_CircCoutout = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CIRC_COUTOUT, 0, USBJOYS_LAST,
GET_DEFAULT(g_model.usbJoystickCircularCut), SET_VALUE_WUPDATE(g_model.usbJoystickCircularCut));
#if LCD_H > LCD_W
line = form->newLine(&grid);
#endif
_ApplyBtn = new TextButton(line, rect_t{}, STR_USBJOYSTICK_APPLY_CHANGES,
[=]() { onUSBJoystickModelChanged(); this->update(); return 0; });
auto btngrp = new FormGroup(form, rect_t{});
_ChannelsGroup = btngrp;
btngrp->setFlexLayout();
btngrp->padRow(lv_dpx(4));
for (uint8_t ch = 0; ch < USBJ_MAX_JOYSTICK_CHANNELS; ch++) {
// Channel settings
auto btn = new USBChannelLineButton(btngrp, ch);
USBJoystickChData * cch = usbJChAddress(ch);
btn->setPressHandler([=]() -> uint8_t {
if (cch->mode == USBJOYS_CH_NONE) {
editChannel(ch, btn);
}
else {
Menu *menu = new Menu(parent);
menu->addLine(STR_EDIT, [=]() {
editChannel(ch, btn);
});
menu->addLine(STR_CLEAR, [=]() {
memset(cch, 0, sizeof(USBJoystickChData));
SET_DIRTY();
btn->invalidate();
});
}
return 0;
});
}
update();
}
void ModelUSBJoystickPage::update()
{
const uint8_t usbj_ctrls = 6;
Window* ctrls[usbj_ctrls] = { _IfModeLabel, _IfMode, _CircCoutoutLabel, _CircCoutout, _ApplyBtn, _ChannelsGroup };
for(uint8_t i = 0; i < usbj_ctrls; i++) {
if(usbJoystickExtMode()) {
lv_obj_clear_flag(ctrls[i]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
_ApplyBtn->enable(usbJoystickSettingsChanged());
}
else {
lv_obj_add_flag(ctrls[i]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
}
}
}
void ModelUSBJoystickPage::editChannel(uint8_t channel, USBChannelLineButton* btn)
{
auto chedit = new USBChannelEditWindow(channel);
chedit->setCloseHandler(
[=]() { this->update(); });
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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.
*/
#pragma once
#include "page.h"
class FormGroup;
class USBChannelLineButton;
class ModelUSBJoystickPage : public Page
{
public:
ModelUSBJoystickPage();
protected:
void update();
void editChannel(uint8_t channel, USBChannelLineButton* btn);
protected:
Window* _IfModeLabel;
Window* _IfMode;
Window* _CircCoutoutLabel;
Window* _CircCoutout;
TextButton* _ApplyBtn;
Window* _ChannelsGroup;
};
@@ -62,3 +62,11 @@ if(PXX2)
../common/stdlcd/model_receiver_options.cpp
)
endif()
if(USBJ_EX)
set(GUI_SRC
${GUI_SRC}
../common/stdlcd/model_usbjoystick.cpp
)
endif()
@@ -0,0 +1,255 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "opentx.h"
#include "usb_joystick.h"
#define _STR_MAX(x) "/" #x
#define STR_MAX(x) _STR_MAX(x)
#if LCD_W >= 212
#define MODE_POS 5*FW
#define SUBMODE_POS MODE_POS+2*FW
#define USBJ_ONE_2ND_COLUMN (12*FW)
#define BTNMODE_POS SUBMODE_POS+5*FW
#define BTNNUM_POS BTNMODE_POS+12*FW
#else
#define MODE_POS 5*FW
#define SUBMODE_POS MODE_POS+2*FW
#define USBJ_ONE_2ND_COLUMN (12*FW)
#define BTNMODE_POS SUBMODE_POS+5*FW
#define BTNNUM_POS LCD_W
#endif
enum USBJFields {
USBJ_FIELD_MODE,
USBJ_FIELD_INVERSION,
USBJ_FIELD_SUBMODE,
USBJ_FIELD_BTNPOS,
USBJ_FIELD_BTNNUM,
USBJ_FIELD_MAX
};
void menuModelUSBJoystickOne(event_t event)
{
#if defined(KEYS_GPIO_REG_MDL)
if (event == EVT_KEY_FIRST(KEY_MODEL)) {
pushMenu(menuChannelsView);
killEvents(event);
}
#elif defined(NAVIGATION_X7)
if (event == EVT_KEY_FIRST(KEY_MENU)) {
pushMenu(menuChannelsView);
killEvents(event);
}
#elif defined(NAVIGATION_XLITE)
if (event == EVT_KEY_FIRST(KEY_ENTER) && IS_SHIFT_PRESSED()) {
pushMenu(menuChannelsView);
killEvents(event);
}
#endif
USBJoystickChData * cch = usbJChAddress(s_currIdx);
putsChn(12*FW, 0, s_currIdx+1, 0);
lcdDrawNumber(20*FW, 0, channelOutputs[s_currIdx], RIGHT);
SUBMENU(STR_USBJOYSTICK_LABEL, USBJ_FIELD_MAX, {
0,
(cch->mode != USBJOYS_CH_NONE) ? (uint8_t)0 : (uint8_t)HIDDEN_ROW,
(cch->mode != USBJOYS_CH_NONE) ? (uint8_t)0 : (uint8_t)HIDDEN_ROW,
(cch->mode == USBJOYS_CH_BUTTON) ?
(((cch->param == USBJOYS_BTN_MODE_SW_EMU) || (cch->param == USBJOYS_BTN_MODE_DELTA)) ? (uint8_t)READONLY_ROW : (uint8_t)0)
: (uint8_t)HIDDEN_ROW,
(cch->mode == USBJOYS_CH_BUTTON) ? (uint8_t)0 : (uint8_t)HIDDEN_ROW });
int8_t sub = menuVerticalPosition;
char str[20];
for (uint8_t i=0; i<(NUM_BODY_LINES-1); i++) {
coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH;
uint8_t k = i + menuVerticalOffset;
for (int j=0; j<=k; ++j) {
if (j<(int)DIM(mstate_tab) && mstate_tab[j] == HIDDEN_ROW) {
++k;
}
}
LcdFlags attr = (sub==k ? (s_editMode>0 ? BLINK|INVERS : INVERS) : 0);
switch (k) {
case USBJ_FIELD_MODE:
cch->mode = editChoice(USBJ_ONE_2ND_COLUMN, y, STR_USBJOYSTICK_CH_MODE, STR_VUSBJOYSTICK_CH_MODE, cch->mode, 0, USBJOYS_CH_LAST, attr, event);
break;
case USBJ_FIELD_INVERSION:
lcdDrawTextAlignedLeft(y, TR_USBJOYSTICK_CH_INVERSION);
drawCheckBox(USBJ_ONE_2ND_COLUMN, y, cch->inversion, attr);
if (attr) cch->inversion = checkIncDecModel(event, cch->inversion, 0, 1);
break;
case USBJ_FIELD_SUBMODE:
if(cch->mode == USBJOYS_CH_BUTTON) {
cch->param = editChoice(USBJ_ONE_2ND_COLUMN, y, STR_USBJOYSTICK_CH_BTNMODE, STR_VUSBJOYSTICK_CH_BTNMODE, cch->param, 0, USBJOYS_BTN_MODE_LAST, attr, event);
if(cch->param == USBJOYS_BTN_MODE_SW_EMU) cch->switch_npos = 0;
else if(cch->param == USBJOYS_BTN_MODE_DELTA) cch->switch_npos = 1;
}
else if(cch->mode == USBJOYS_CH_AXIS) {
cch->param = editChoice(USBJ_ONE_2ND_COLUMN, y, STR_USBJOYSTICK_CH_AXIS, STR_VUSBJOYSTICK_CH_AXIS, cch->param, 0, USBJOYS_AXIS_LAST, attr, event);
}
else if(cch->mode == USBJOYS_CH_SIM) {
cch->param = editChoice(USBJ_ONE_2ND_COLUMN, y, STR_USBJOYSTICK_CH_SIM, STR_VUSBJOYSTICK_CH_SIM, cch->param, 0, USBJOYS_SIM_LAST, attr, event);
}
break;
case USBJ_FIELD_BTNPOS:
if(cch->param == USBJOYS_BTN_MODE_SW_EMU) {
lcdDrawTextAlignedLeft(y, STR_USBJOYSTICK_CH_SWPOS);
lcdDrawText(USBJ_ONE_2ND_COLUMN, y, STR_VUSBJOYSTICK_CH_SWPOS[0], attr);
}
else if(cch->param == USBJOYS_BTN_MODE_DELTA) {
lcdDrawTextAlignedLeft(y, STR_USBJOYSTICK_CH_SWPOS);
lcdDrawText(USBJ_ONE_2ND_COLUMN, y, STR_VUSBJOYSTICK_CH_SWPOS[1], attr);
}
else {
cch->switch_npos = editChoice(USBJ_ONE_2ND_COLUMN, y, STR_USBJOYSTICK_CH_SWPOS, STR_VUSBJOYSTICK_CH_SWPOS, cch->switch_npos, 0, 7, attr, event);
}
break;
case USBJ_FIELD_BTNNUM:
lcdDrawTextAlignedLeft(y, TR_USBJOYSTICK_CH_BTNNUM);
uint8_t last = cch->lastBtnNumNoCLip();
uint8_t limited = 0;
if(last >= USBJ_BUTTON_SIZE) {
limited = 1;
last = USBJ_BUTTON_SIZE-1;
}
if (last > cch->btn_num)
snprintf(str, 20, "%u..%u%c", cch->btn_num, last, limited ? '!' : ' ');
else
snprintf(str, 20, "%u%c", cch->btn_num, limited ? '!' : ' ');
lcdDrawText(USBJ_ONE_2ND_COLUMN, y, str, attr);
if (attr) {
CHECK_INCDEC_MODELVAR(event, cch->btn_num, 0, USBJ_BUTTON_SIZE);
}
break;
}
}
if (cch->mode == USBJOYS_CH_BUTTON) {
if (isUSBBtnNumCollision(s_currIdx)) {
lcdDrawText(LCD_W/2, LCD_H-FH, STR_USBJOYSTICK_BTN_COLLISION, INVERS | CENTERED);
}
}
else if (cch->mode == USBJOYS_CH_AXIS) {
if (isUSBAxisCollision(s_currIdx)) {
lcdDrawText(LCD_W/2, LCD_H-FH, STR_USBJOYSTICK_AXIS_COLLISION, INVERS | CENTERED);
}
}
else if (cch->mode == USBJOYS_CH_SIM) {
if (isUSBSimCollision(s_currIdx)) {
lcdDrawText(LCD_W/2, LCD_H-FH, STR_USBJOYSTICK_AXIS_COLLISION, INVERS | CENTERED);
}
}
}
void onUSBJoystickMenu(const char *result)
{
int8_t sub = menuVerticalPosition - HEADER_LINE;
USBJoystickChData * cs = usbJChAddress(sub);
if (result == STR_EDIT) {
s_currIdx = sub;
pushMenu(menuModelUSBJoystickOne);
}
else if (result == STR_CLEAR) {
memset(cs, 0, sizeof(USBJoystickChData));
storageDirty(EE_MODEL);
}
}
void menuModelUSBJoystick(event_t event)
{
check_submenu_simple(event, USBJ_MAX_JOYSTICK_CHANNELS - HEADER_LINE);
title(STR_USBJOYSTICK_LABEL);
if (s_editMode > 0) s_editMode = 0;
int8_t sub = menuVerticalPosition - HEADER_LINE;
coord_t y = 0;
uint8_t k = 0;
if (event == EVT_KEY_FIRST(KEY_ENTER)) {
killEvents(event);
USBJoystickChData * cch = usbJChAddress(sub);
s_currIdx = sub;
if (sub >= 0)
POPUP_MENU_ADD_ITEM(STR_EDIT);
if (cch->mode != USBJOYS_CH_NONE)
POPUP_MENU_ADD_ITEM(STR_CLEAR);
if (popupMenuItemsCount == 1) {
popupMenuItemsCount = 0;
s_currIdx = sub;
pushMenu(menuModelUSBJoystickOne);
}
else {
POPUP_MENU_START(onUSBJoystickMenu);
}
}
char str[20];
for (uint8_t i=0; i<NUM_BODY_LINES; i++) {
y = MENU_HEADER_HEIGHT + 1 + i*FH;
k = i + menuVerticalOffset;
LcdFlags attr = (sub==k) ? INVERS : 0;
USBJoystickChData * cch = usbJChAddress(k);
putsChn(0, y, k+1, attr);
lcdDrawChar(4*FW, y, cch->inversion ? '{' : ' ', 0);
lcdDrawTextAtIndex(MODE_POS, y, STR_VUSBJOYSTICK_CH_MODE_S, cch->mode, 0);
if (cch->mode == USBJOYS_CH_BUTTON) {
lcdDrawTextAtIndex(SUBMODE_POS, y, STR_VUSBJOYSTICK_CH_SWPOS, cch->switch_npos, 0);
lcdDrawTextAtIndex(BTNMODE_POS, y, STR_VUSBJOYSTICK_CH_BTNMODE_S, cch->param, 0);
uint8_t last = cch->lastBtnNum();
if (last > cch->btn_num)
sprintf(str, "%u..%u", cch->btn_num, last);
else
sprintf(str, "%u", cch->btn_num);
LcdFlags warn = 0;
if (isUSBBtnNumCollision(k)) warn = INVERS;
lcdDrawText(BTNNUM_POS, y, str, RIGHT|warn);
}
else if (cch->mode == USBJOYS_CH_AXIS) {
LcdFlags warn = 0;
if (isUSBAxisCollision(k)) warn = INVERS;
lcdDrawTextAtIndex(SUBMODE_POS, y, STR_VUSBJOYSTICK_CH_AXIS, cch->param, warn);
}
else if (cch->mode == USBJOYS_CH_SIM) {
LcdFlags warn = 0;
if (isUSBSimCollision(k)) warn = INVERS;
lcdDrawTextAtIndex(SUBMODE_POS, y, STR_VUSBJOYSTICK_CH_SIM, cch->param, warn);
}
}
}
+5
View File
@@ -293,6 +293,11 @@ LimitData *limitAddress(uint8_t idx)
return &g_model.limitData[idx];
}
USBJoystickChData *usbJChAddress(uint8_t idx)
{
return &g_model.usbJoystickCh[idx];
}
void memswap(void * a, void * b, uint8_t size)
{
+1
View File
@@ -690,6 +690,7 @@ ExpoData * expoAddress(uint8_t idx);
MixData * mixAddress(uint8_t idx);
LimitData * limitAddress(uint8_t idx);
LogicalSwitchData * lswAddress(uint8_t idx);
USBJoystickChData * usbJChAddress(uint8_t idx);
void applyDefaultTemplate();
void instantTrim();
+8
View File
@@ -35,6 +35,10 @@ using std::list;
#endif
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
#include <cstring>
#include "datastructs.h"
@@ -1330,6 +1334,10 @@ void ModelsList::setCurrentModel(ModelCell *cell)
gettime(&t);
cell->lastOpened = gmktime(&t);
modelslabels.setDirty();
#if defined(USBJ_EX) && defined(STM32) && !defined(SIMU)
onUSBJoystickModelChanged();
#endif
}
/**
+8
View File
@@ -22,6 +22,10 @@
#include "opentx.h"
#include "timers_driver.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
#if defined(MULTIMODULE)
#include "pulses/multi.h"
#if defined(MULTI_PROTOLIST)
@@ -214,6 +218,10 @@ void selectModel(uint8_t idx)
g_eeGeneral.currModel = idx;
storageDirty(EE_GENERAL);
loadModel(idx);
#if defined(USBJ_EX) && defined(STM32) && !defined(SIMU)
onUSBJoystickModelChanged();
#endif
}
uint8_t findEmptyModel(uint8_t id, bool down)
@@ -261,6 +261,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -812,6 +825,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -865,6 +887,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -271,6 +271,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -842,6 +855,15 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
@@ -895,6 +917,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_STRUCT("topbarData", 1248, struct_TopBarPersistentData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -268,6 +268,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -817,6 +830,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -875,6 +897,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_UNSIGNED( "functionSwitchStartConfig", 16 ),
YAML_UNSIGNED( "functionSwitchLogicalState", 8 ),
YAML_ARRAY("switchNames", 24, 6, struct_string_24, NULL),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -302,6 +302,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -873,6 +886,15 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
@@ -926,6 +948,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_STRUCT("topbarData", 2400, struct_TopBarPersistentData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -300,6 +300,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -871,6 +884,15 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
@@ -924,6 +946,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_STRUCT("topbarData", 2400, struct_TopBarPersistentData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -267,6 +267,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -824,6 +837,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 192, struct_ModelHeader, NULL),
@@ -879,6 +901,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -306,6 +306,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -863,6 +876,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 192, struct_ModelHeader, NULL),
@@ -919,6 +941,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -247,6 +247,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -796,6 +809,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -849,6 +871,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -255,6 +255,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -806,6 +819,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -859,6 +881,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -252,6 +252,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -803,6 +816,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -856,6 +878,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -254,6 +254,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -807,6 +820,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -860,6 +882,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -260,6 +260,19 @@ const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
@@ -811,6 +824,15 @@ static const struct YamlNode struct_TelemetryScreenData[] = {
YAML_UNION("u", 192, union_TelemetryScreenData_u_elmts, select_tele_screen_data),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 96, struct_ModelHeader, NULL),
@@ -864,6 +886,10 @@ static const struct YamlNode struct_ModelData[] = {
YAML_ARRAY("screens", 192, 4, struct_TelemetryScreenData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
@@ -21,6 +21,10 @@
#include "usb_driver.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
extern "C" {
#include "usb_conf.h"
#include "usb_dcd_int.h"
@@ -83,6 +87,9 @@ void usbStart()
#if !defined(BOOT)
case USB_JOYSTICK_MODE:
// initialize USB as HID device
#if defined(USBJ_EX)
setupUSBJoystick();
#endif
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_HID_cb, &USR_cb);
break;
#endif
@@ -108,6 +115,18 @@ void usbStop()
USBD_DeInit(&USB_OTG_dev);
}
#if defined(USBJ_EX)
void usbJoystickRestart()
{
if (getSelectedUsbMode() != USB_JOYSTICK_MODE) return;
USBD_DeInit(&USB_OTG_dev);
DCD_DevDisconnect(&USB_OTG_dev);
DCD_DevConnect(&USB_OTG_dev);
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_HID_cb, &USR_cb);
}
#endif
bool usbStarted()
{
return usbDriverStarted;
@@ -125,6 +144,7 @@ bool usbStarted()
*/
void usbJoystickUpdate()
{
#if !defined(USBJ_EX)
static uint8_t HID_Buffer[HID_IN_PACKET];
// test to se if TX buffer is free
@@ -158,5 +178,12 @@ void usbJoystickUpdate()
}
USBD_HID_SendReport(&USB_OTG_dev, HID_Buffer, HID_IN_PACKET);
}
#else
// test to se if TX buffer is free
if (USBD_HID_SendReport(&USB_OTG_dev, 0, 0) == USBD_OK) {
usbReport_t ret = usbReport();
USBD_HID_SendReport(&USB_OTG_dev, ret.ptr, ret.size);
}
#endif
}
#endif
@@ -48,6 +48,9 @@ int usbPlugged();
void usbInit();
void usbStart();
void usbStop();
#if defined(USBJ_EX)
void usbJoystickRestart();
#endif
bool usbStarted();
EXTERN_C(int getSelectedUsbMode());
@@ -48,7 +48,9 @@
#define HID_IN_EP 0x81
#define HID_OUT_EP 0x01
#if !defined(USBJ_EX)
#define HID_IN_PACKET 19
#endif
#define HID_OUT_PACKET 9
#define CDC_IN_EP 0x81 /* EP1 for data IN */
@@ -22,6 +22,9 @@
#include "usbd_desc.h"
#include "usbd_hid_core.h"
#include "usbd_req.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
#endif
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
@@ -88,6 +91,8 @@ static uint8_t USBD_HID_DataIn (void *pdev, uint8_t epnum);
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
#if !defined(USBJ_EX)
/*
This USB HID endpoint report description defines a device with:
* 24 digital buttons
@@ -140,7 +145,7 @@ __ALIGN_BEGIN static const uint8_t HID_JOYSTICK_ReportDesc[] __ALIGN_END =
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
#endif
/** @defgroup USBD_HID_Private_Variables
* @{
@@ -191,7 +196,7 @@ __ALIGN_BEGIN static uint32_t USBD_HID_IdleState __ALIGN_END = 0;
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/* USB HID device Configuration Descriptor */
__ALIGN_BEGIN static const uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
@@ -225,7 +230,11 @@ __ALIGN_BEGIN static const uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __A
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
#if !defined(USBJ_EX)
sizeof(HID_JOYSTICK_ReportDesc),/*wItemLength: Total length of Report descriptor*/
#else
0,/*wItemLength: Total length of Report descriptor*/
#endif
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
@@ -234,7 +243,11 @@ __ALIGN_BEGIN static const uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __A
HID_IN_EP, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
#if !defined(USBJ_EX)
HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
#else
0,/*HID_IN_PACKET,*/ /*wMaxPacketSize*/
#endif
0x00,
0x01, /*bInterval: Polling Interval (1 ms)*/
/* 34 */
@@ -262,11 +275,18 @@ static uint8_t ReportSent;
static uint8_t USBD_HID_Init (void *pdev,
uint8_t cfgidx)
{
#if defined(USBJ_EX)
uint8_t hid_in_pkt_size = usbReportSize();
#endif
/* Open EP IN */
DCD_EP_Open(pdev,
HID_IN_EP,
#if !defined(USBJ_EX)
HID_IN_PACKET,
#else
hid_in_pkt_size /*HID_IN_PACKET*/,
#endif
USB_OTG_EP_INT);
/* Open EP OUT */
@@ -349,8 +369,14 @@ static uint8_t USBD_HID_Setup (void *pdev,
case USB_REQ_GET_DESCRIPTOR:
if( req->wValue >> 8 == HID_REPORT_DESC)
{
#if !defined(USBJ_EX)
len = MIN(sizeof(HID_JOYSTICK_ReportDesc) , req->wLength);
pbuf = HID_JOYSTICK_ReportDesc; // wiiccReportDescriptor; //
#else
struct usbReport_t ret = usbReportDesc();
len = MIN(ret.size, req->wLength);
pbuf = ret.ptr;
#endif
}
else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
{
@@ -414,6 +440,12 @@ uint8_t USBD_HID_SendReport(USB_OTG_CORE_HANDLE *pdev, uint8_t * report, uint16
*/
static const uint8_t *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length)
{
#if defined(USBJ_EX)
struct usbReport_t ret = usbReportDesc();
USBD_HID_CfgDesc[25] = ret.size;
USBD_HID_CfgDesc[31] = usbReportSize();
#endif
*length = sizeof (USBD_HID_CfgDesc);
return USBD_HID_CfgDesc;
}
+28
View File
@@ -949,3 +949,31 @@ const char STR_MAIN_MENU_STATISTICS[] = TR_MAIN_MENU_STATISTICS;
const char STR_MAIN_MENU_ABOUT_EDGETX[] = TR_MAIN_MENU_ABOUT_EDGETX;
#endif
#if defined(USBJ_EX)
const char STR_USBJOYSTICK_LABEL[] = TR_USBJOYSTICK_LABEL;
const char STR_USBJOYSTICK_EXTMODE[] = TR_USBJOYSTICK_EXTMODE;
ISTR(VUSBJOYSTICK_EXTMODE);
const char STR_USBJOYSTICK_SETTINGS[] = TR_USBJOYSTICK_SETTINGS;
const char STR_USBJOYSTICK_IF_MODE[] = TR_USBJOYSTICK_IF_MODE;
ISTR(VUSBJOYSTICK_IF_MODE);
const char STR_USBJOYSTICK_CH_MODE[] = TR_USBJOYSTICK_CH_MODE;
ISTR(VUSBJOYSTICK_CH_MODE);
ISTR(VUSBJOYSTICK_CH_MODE_S);
const char STR_USBJOYSTICK_CH_BTNMODE[] = TR_USBJOYSTICK_CH_BTNMODE;
ISTR(VUSBJOYSTICK_CH_BTNMODE);
ISTR(VUSBJOYSTICK_CH_BTNMODE_S);
const char STR_USBJOYSTICK_CH_SWPOS[] = TR_USBJOYSTICK_CH_SWPOS;
ISTR(VUSBJOYSTICK_CH_SWPOS);
const char STR_USBJOYSTICK_CH_AXIS[] = TR_USBJOYSTICK_CH_AXIS;
ISTR(VUSBJOYSTICK_CH_AXIS);
const char STR_USBJOYSTICK_CH_SIM[] = TR_USBJOYSTICK_CH_SIM;
ISTR(VUSBJOYSTICK_CH_SIM);
const char STR_USBJOYSTICK_CH_INVERSION[] = TR_USBJOYSTICK_CH_INVERSION;
const char STR_USBJOYSTICK_CH_BTNNUM[] = TR_USBJOYSTICK_CH_BTNNUM;
const char STR_USBJOYSTICK_BTN_COLLISION[] = TR_USBJOYSTICK_BTN_COLLISION;
const char STR_USBJOYSTICK_AXIS_COLLISION[] = TR_USBJOYSTICK_AXIS_COLLISION;
const char STR_USBJOYSTICK_CIRC_COUTOUT[] = TR_USBJOYSTICK_CIRC_COUTOUT;
ISTR(VUSBJOYSTICK_CIRC_COUTOUT);
const char STR_USBJOYSTICK_APPLY_CHANGES[] = TR_USBJOYSTICK_APPLY_CHANGES;
#endif
+28
View File
@@ -1122,5 +1122,33 @@ extern const char STR_MAIN_MENU_ABOUT_EDGETX[];
#endif
#if defined(USBJ_EX)
extern const char STR_USBJOYSTICK_LABEL[];
extern const char STR_USBJOYSTICK_EXTMODE[];
extern const char* const STR_VUSBJOYSTICK_EXTMODE[];
extern const char STR_USBJOYSTICK_SETTINGS[];
extern const char STR_USBJOYSTICK_IF_MODE[];
extern const char* const STR_VUSBJOYSTICK_IF_MODE[];
extern const char STR_USBJOYSTICK_CH_MODE[];
extern const char* const STR_VUSBJOYSTICK_CH_MODE[];
extern const char* const STR_VUSBJOYSTICK_CH_MODE_S[];
extern const char STR_USBJOYSTICK_CH_BTNMODE[];
extern const char* const STR_VUSBJOYSTICK_CH_BTNMODE[];
extern const char* const STR_VUSBJOYSTICK_CH_BTNMODE_S[];
extern const char STR_USBJOYSTICK_CH_SWPOS[];
extern const char* const STR_VUSBJOYSTICK_CH_SWPOS[];
extern const char STR_USBJOYSTICK_CH_AXIS[];
extern const char* const STR_VUSBJOYSTICK_CH_AXIS[];
extern const char STR_USBJOYSTICK_CH_SIM[];
extern const char* const STR_VUSBJOYSTICK_CH_SIM[];
extern const char STR_USBJOYSTICK_CH_INVERSION[];
extern const char STR_USBJOYSTICK_CH_BTNNUM[];
extern const char STR_USBJOYSTICK_BTN_COLLISION[];
extern const char STR_USBJOYSTICK_AXIS_COLLISION[];
extern const char STR_USBJOYSTICK_CIRC_COUTOUT[];
extern const char* const STR_VUSBJOYSTICK_CIRC_COUTOUT[];
extern const char STR_USBJOYSTICK_APPLY_CHANGES[];
#endif
#endif // _TRANSLATIONS_H_
+26
View File
@@ -1237,3 +1237,29 @@
#define TR_VOICE_SWEDISH "瑞典语"
#define TR_VOICE_TAIWANESE "中文-台湾国语"
#define TR_VOICE_JAPANESE "日文"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1239,3 +1239,29 @@
#define TR_VOICE_SWEDISH "Švédština"
#define TR_VOICE_TAIWANESE "Tchajwanština"
#define TR_VOICE_JAPANESE "Japonština"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1252,3 +1252,29 @@
#define TR_VOICE_SWEDISH "Svensk"
#define TR_VOICE_TAIWANESE "Taiwanesisk"
#define TR_VOICE_JAPANESE "Japansk"
#define TR_USBJOYSTICK_LABEL "USB joystik"
#define TR_USBJOYSTICK_EXTMODE "Tilstand"
#define TR_VUSBJOYSTICK_EXTMODE "Klassisk","Advanceret"
#define TR_USBJOYSTICK_SETTINGS "Kanal indstillinger"
#define TR_USBJOYSTICK_IF_MODE TR("Intf. tils.","Interface tilstand")
#define TR_VUSBJOYSTICK_IF_MODE "Joystik","Gamepad","MultiAkse"
#define TR_USBJOYSTICK_CH_MODE "Tilstand"
#define TR_VUSBJOYSTICK_CH_MODE "Ingen","Knap","Akse","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Knap tilstand"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positioner"
#define TR_VUSBJOYSTICK_CH_SWPOS "Skub","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Akse"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Skyder","Drej","Hjul"
#define TR_USBJOYSTICK_CH_SIM "Sim akse"
#define TR_VUSBJOYSTICK_CH_SIM "Kræ","Høj","Sid","Gas"
#define TR_USBJOYSTICK_CH_INVERSION "Omvendt"
#define TR_USBJOYSTICK_CH_BTNNUM "Knap #"
#define TR_USBJOYSTICK_BTN_COLLISION "!Knap # kollision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Akse kollision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Cirk. klip", "Cikulær klip")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "Ingen","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Gem ændringer"
+26
View File
@@ -1238,3 +1238,29 @@
#define TR_VOICE_SWEDISH "Schwedisch"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanisch"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1231,3 +1231,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1242,3 +1242,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1255,3 +1255,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1260,3 +1260,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1247,3 +1247,29 @@
#define TR_VOICE_SWEDISH "Svedese"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Giapponese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1232,3 +1232,29 @@
#define TR_VOICE_SWEDISH "スウェーデン-SV"
#define TR_VOICE_TAIWANESE "中文-TW"
#define TR_VOICE_JAPANESE "日本-JP"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1252,3 +1252,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1236,3 +1236,29 @@
#define TR_VOICE_SWEDISH "Szwedzki"
#define TR_VOICE_TAIWANESE "Tajwański"
#define TR_VOICE_JAPANESE "Japonês"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1245,3 +1245,29 @@
#define TR_VOICE_SWEDISH "Swedish"
#define TR_VOICE_TAIWANESE "Taiwanese"
#define TR_VOICE_JAPANESE "Japanese"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1278,3 +1278,29 @@
#define TR_VOICE_SWEDISH "Svenska"
#define TR_VOICE_TAIWANESE "Taiwanesiska"
#define TR_VOICE_JAPANESE "Japanska"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+26
View File
@@ -1235,3 +1235,29 @@
#define TR_VOICE_SWEDISH "瑞典語"
#define TR_VOICE_TAIWANESE "中文-台灣國語"
#define TR_VOICE_JAPANESE "日文"
#define TR_USBJOYSTICK_LABEL "USB Joystick"
#define TR_USBJOYSTICK_EXTMODE "Mode"
#define TR_VUSBJOYSTICK_EXTMODE "Classic","Advanced"
#define TR_USBJOYSTICK_SETTINGS "Channel Settings"
#define TR_USBJOYSTICK_IF_MODE TR("If. mode","Interface mode")
#define TR_VUSBJOYSTICK_IF_MODE "Joystick","Gamepad","MultiAxis"
#define TR_USBJOYSTICK_CH_MODE "Mode"
#define TR_VUSBJOYSTICK_CH_MODE "None","Btn","Axis","Sim"
#define TR_VUSBJOYSTICK_CH_MODE_S "-","B","A","S"
#define TR_USBJOYSTICK_CH_BTNMODE "Button Mode"
#define TR_VUSBJOYSTICK_CH_BTNMODE "Normal","Pulse","SWEmu","Delta","Companion"
#define TR_VUSBJOYSTICK_CH_BTNMODE_S TR("Norm","Normal"),TR("Puls","Pulse"),TR("SWEm","SWEmul"),TR("Delt","Delta"),TR("CPN","Companion")
#define TR_USBJOYSTICK_CH_SWPOS "Positions"
#define TR_VUSBJOYSTICK_CH_SWPOS "Push","2POS","3POS","4POS","5POS","6POS","7POS","8POS"
#define TR_USBJOYSTICK_CH_AXIS "Axis"
#define TR_VUSBJOYSTICK_CH_AXIS "X","Y","Z","rotX","rotY","rotZ","Slider","Dial","Wheel"
#define TR_USBJOYSTICK_CH_SIM "Sim axis"
#define TR_VUSBJOYSTICK_CH_SIM "Ail","Ele","Rud","Thr"
#define TR_USBJOYSTICK_CH_INVERSION "Inversion"
#define TR_USBJOYSTICK_CH_BTNNUM "Button no."
#define TR_USBJOYSTICK_BTN_COLLISION "!Button no. collision!"
#define TR_USBJOYSTICK_AXIS_COLLISION "!Axis collision!"
#define TR_USBJOYSTICK_CIRC_COUTOUT TR("Circ. cut", "Circular cutout")
#define TR_VUSBJOYSTICK_CIRC_COUTOUT "None","X-Y, Z-rX","X-Y, rX-rY"
#define TR_USBJOYSTICK_APPLY_CHANGES "Apply changes"
+758
View File
@@ -0,0 +1,758 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "opentx.h"
#include "usb_joystick.h"
#define MAX_HID_REPORTDESC 160
#define MAX_HID_REPORT 80
uint8_t _hidReportDesc[MAX_HID_REPORTDESC] = { };
uint8_t _hidReportDescSize = 0;
uint8_t _hidReport[MAX_HID_REPORT] = { };
uint8_t _hidReportSize = 0;
static uint8_t _buttonState[USBJ_BUTTON_SIZE >> 3] = { };
static uint16_t _usbLastChannelOutput[USBJ_MAX_JOYSTICK_CHANNELS] = { };
static uint8_t _usbChannelTimerActive[USBJ_MAX_JOYSTICK_CHANNELS] = { };
static uint8_t _usbChannelTimer[USBJ_MAX_JOYSTICK_CHANNELS] = { };
static uint8_t _usbJoystickIfMode = 0;
static uint8_t _usbJoystickCircularCut = 0;
static USBJoystickChData _usbJoystickCh[USBJ_MAX_JOYSTICK_CHANNELS];
#define USBJ_CC_XYZrX 1
#define USBJ_CC_XYrXrZ 2
static uint8_t _usbJoystickButtonChannels[USBJ_MAX_JOYSTICK_CHANNELS] = { };
static uint8_t _usbJoystickButtonCount = 0;
static uint8_t _usbJoystickAxisChannels[USBJ_MAX_JOYSTICK_CHANNELS] = { };
static uint8_t _usbJoystickAxisCount = 0;
static uint8_t _usbJoystickAxisPairs[3][2] = { };
static const uint8_t _usbJoystickUniqueAxis[USBJOYS_AXIS_LAST + 1] =
{ 1, 1, 1, 1, 1, 1, 0, 0, 0 };
static const uint8_t _usbJoystickUniqueSims[USBJOYS_SIM_LAST + 1] =
{ 1, 1, 1, 1 };
/*
This USB HID endpoint report description defines a device with:
* 24 digital buttons
* 8 analog axes with 8bit resolution
Repot packet described as C struct is:
struct {
uint8_t buttons1; //bit 0 - button 1, bit 1 - button 2, ..., mapped to channels 9-16, on if channel > 0
uint8_t buttons2; // mapped to channels 17-24, on if channel > 0
uint8_t buttons3; // mapped to channels 25-32, on if channel > 0
uint8_t X; //analog value, mapped to channel 1
uint8_t Y; //analog value, mapped to channel 2
uint8_t Z; //analog value, mapped to channel 3
uint8_t Rx; //analog value, mapped to channel 4
uint8_t Ry //analog value, mapped to channel 5
uint8_t Rz; //analog value, mapped to channel 6
uint8_t S1; //analog value, mapped to channel 7
uint8_t S2; //analog value, mapped to channel 8
}
*/
static const uint8_t HID_JOYSTICK_ReportDesc[] =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x18, // USAGE_MAXIMUM (Button 24)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x18, // REPORT_COUNT (24)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x09, 0x36, // USAGE (Slider)
0x09, 0x36, // USAGE (Slider)
0x16, 0x00, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xFF, 0x07, // LOGICAL_MAXIMUM (2047)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
int usbJoystickExtMode()
{
return g_model.usbJoystickExtMode;
}
int usbJoystickActive()
{
return (usbPlugged() && getSelectedUsbMode() == USB_JOYSTICK_MODE);
}
int usbJoystickSettingsChanged()
{
if (!usbJoystickActive()) return false;
if((_usbJoystickIfMode != g_model.usbJoystickIfMode)
|| (_usbJoystickCircularCut != g_model.usbJoystickCircularCut)) return true;
if(memcmp(_usbJoystickCh, g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh)) != 0) return true;
return false;
}
int setupUSBJoystick()
{
static const uint8_t axisTypeCodes[USBJOYS_AXIS_LAST + 1] =
{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
static const uint8_t simTypeCodes[USBJOYS_SIM_LAST + 1] =
{ 0xb0, 0xb8, 0xba, 0xbb };
static uint8_t oldHIDReportDesc[MAX_HID_REPORTDESC] = { };
static uint8_t oldHIDReportDescSize = 0;
// copy old to compare
memcpy(oldHIDReportDesc, _hidReportDesc, MAX_HID_REPORTDESC);
oldHIDReportDescSize = _hidReportDescSize;
// copy the model snapshot
_usbJoystickIfMode = g_model.usbJoystickIfMode;
_usbJoystickCircularCut = g_model.usbJoystickCircularCut;
memcpy(_usbJoystickCh, g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh));
// Init data
memset(_hidReportDesc, 0, MAX_HID_REPORTDESC);
_hidReportDescSize = 0;
memset(_hidReport, 0, MAX_HID_REPORT);
_hidReportSize = 0;
memset(_buttonState, 0, (USBJ_BUTTON_SIZE >> 3));
memset(_usbLastChannelOutput, 0xff, sizeof(_usbLastChannelOutput));
memset(_usbChannelTimer, 0, sizeof(_usbChannelTimer));
memset(_usbChannelTimerActive, 0, sizeof(_usbChannelTimerActive));
memset(_usbJoystickButtonChannels, 0, USBJ_MAX_JOYSTICK_CHANNELS);
_usbJoystickButtonCount = 0;
memset(_usbJoystickAxisChannels, 0, USBJ_MAX_JOYSTICK_CHANNELS);
_usbJoystickAxisCount = 0;
memset(_usbJoystickAxisPairs, 0xff, sizeof(_usbJoystickAxisPairs));
if (!usbJoystickExtMode()) {
// Classic USB Joystick report description
memcpy(_hidReportDesc, HID_JOYSTICK_ReportDesc, sizeof(HID_JOYSTICK_ReportDesc));
_hidReportDescSize = sizeof(HID_JOYSTICK_ReportDesc);
_hidReportSize = 19;
} else {
uint8_t genAxisCount = 0;
uint8_t simAxisCount = 0;
// sort channels by type
uint8_t typeCount[USBJOYS_CH_LAST + 1] = { };
uint8_t axisCount[USBJOYS_AXIS_LAST + 1] = { };
uint8_t simCount[USBJOYS_SIM_LAST + 1] = { };
uint8_t axisIx[USBJOYS_AXIS_LAST + 1] = { };
uint8_t simIx[USBJOYS_SIM_LAST + 1] = { };
uint8_t mode = 0;
uint8_t submode = 0;
for (uint8_t i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
mode = _usbJoystickCh[i].mode;
if (_usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
typeCount[mode]++;
}
else if (_usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
submode = _usbJoystickCh[i].param;
if (submode <= USBJOYS_AXIS_LAST) {
if ((_usbJoystickUniqueAxis[submode] == 0) || (axisCount[submode] == 0)) {
axisCount[submode]++;
typeCount[mode]++;
}
}
}
else if (_usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
submode = _usbJoystickCh[i].param;
if (submode <= USBJOYS_SIM_LAST) {
if ((_usbJoystickUniqueSims[submode] == 0) || (simCount[submode] == 0)) {
simCount[submode]++;
typeCount[mode]++;
}
}
}
}
uint8_t ixcount = 0;
for (uint8_t i = 0; i <= USBJOYS_AXIS_LAST; i++) {
axisIx[i] = ixcount;
ixcount += axisCount[i];
}
ixcount = 0;
for (uint8_t i = 0; i <= USBJOYS_SIM_LAST; i++) {
simIx[i] = ixcount;
ixcount += simCount[i];
}
ixcount = 0;
for (uint8_t i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
mode = _usbJoystickCh[i].mode;
if (_usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
_usbJoystickButtonChannels[ixcount] = i;
ixcount++;
}
else if (_usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
submode = _usbJoystickCh[i].param;
if (submode <= USBJOYS_AXIS_LAST) {
_usbJoystickAxisChannels[axisIx[submode]] = i;
if (_usbJoystickUniqueAxis[submode] == 0) {
axisIx[submode]++;
}
// save axis pairs
if(submode == USBJOYS_AXIS_X) {
_usbJoystickAxisPairs[0][0] = i;
}
else if(submode == USBJOYS_AXIS_Y) {
_usbJoystickAxisPairs[0][1] = i;
}
else if(submode == USBJOYS_AXIS_Z) {
_usbJoystickAxisPairs[1][0] = i;
}
else if(submode == USBJOYS_AXIS_RX) {
_usbJoystickAxisPairs[1][1] = i;
_usbJoystickAxisPairs[2][0] = i;
}
else if(submode == USBJOYS_AXIS_RY) {
_usbJoystickAxisPairs[2][1] = i;
}
}
}
else if (_usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
submode = _usbJoystickCh[i].param;
if (submode <= USBJOYS_SIM_LAST) {
_usbJoystickAxisChannels[simIx[submode]] = i;
if (_usbJoystickUniqueSims[submode] == 0) {
simIx[submode]++;
}
}
}
}
// store counts
_usbJoystickButtonCount = typeCount[USBJOYS_CH_BUTTON];
genAxisCount = typeCount[USBJOYS_CH_AXIS];
simAxisCount = typeCount[USBJOYS_CH_SIM];
_usbJoystickAxisCount = typeCount[USBJOYS_CH_AXIS] + typeCount[USBJOYS_CH_SIM];
// generate report desc
// USAGE_PAGE (Generic Desktop)
_hidReportDesc[_hidReportDescSize++] = 0x05;
_hidReportDesc[_hidReportDescSize++] = 0x01;
// USAGE (Joystick=0x04, Gamepad=0x05, Multi-axis Controller=0x08)
uint8_t joystickType = 0x04;
if (_usbJoystickIfMode == USBJOYS_GAMEPAD) joystickType = 0x05;
else if (_usbJoystickIfMode == USBJOYS_MULTIAXIS) joystickType = 0x08;
_hidReportDesc[_hidReportDescSize++] = 0x09;
_hidReportDesc[_hidReportDescSize++] = joystickType;
// COLLECTION (Application)
_hidReportDesc[_hidReportDescSize++] = 0xa1;
_hidReportDesc[_hidReportDescSize++] = 0x01;
// COLLECTION (Physical)
_hidReportDesc[_hidReportDescSize++] = 0xa1;
_hidReportDesc[_hidReportDescSize++] = 0x00;
// REPORT_ID (1)
// _hidReportDesc[_hidReportDescSize++] = 0x85;
// _hidReportDesc[_hidReportDescSize++] = 0x01;
// button types
// USAGE_PAGE (Button)
_hidReportDesc[_hidReportDescSize++] = 0x05;
_hidReportDesc[_hidReportDescSize++] = 0x09;
// USAGE_MINIMUM (Button 1)
_hidReportDesc[_hidReportDescSize++] = 0x19;
_hidReportDesc[_hidReportDescSize++] = 0x01;
// USAGE_MAXIMUM (Button USBJ_BUTTON_SIZE)
_hidReportDesc[_hidReportDescSize++] = 0x29;
_hidReportDesc[_hidReportDescSize++] = USBJ_BUTTON_SIZE;
// LOGICAL_MINIMUM (0)
_hidReportDesc[_hidReportDescSize++] = 0x15;
_hidReportDesc[_hidReportDescSize++] = 0x00;
// LOGICAL_MAXIMUM (1)
_hidReportDesc[_hidReportDescSize++] = 0x25;
_hidReportDesc[_hidReportDescSize++] = 0x01;
// REPORT_COUNT (#)
_hidReportDesc[_hidReportDescSize++] = 0x95;
_hidReportDesc[_hidReportDescSize++] = USBJ_BUTTON_SIZE;
// REPORT_SIZE (1)
_hidReportDesc[_hidReportDescSize++] = 0x75;
_hidReportDesc[_hidReportDescSize++] = 0x01;
// INPUT (Data,Var,Abs,Preferred)
_hidReportDesc[_hidReportDescSize++] = 0x81;
_hidReportDesc[_hidReportDescSize++] = 0x02;
// generic axis types
if (genAxisCount > 0) {
// USAGE_PAGE (Generic Desktop)
_hidReportDesc[_hidReportDescSize++] = 0x05;
_hidReportDesc[_hidReportDescSize++] = 0x01;
for (uint8_t i = 0; i <= USBJOYS_AXIS_LAST; i++) {
for (uint8_t cnt = 0; cnt < axisCount[i]; cnt++) {
// USAGE (#)
_hidReportDesc[_hidReportDescSize++] = 0x09;
_hidReportDesc[_hidReportDescSize++] = axisTypeCodes[i];
}
}
// LOGICAL_MINIMUM (0)
_hidReportDesc[_hidReportDescSize++] = 0x16;
_hidReportDesc[_hidReportDescSize++] = 0x00;
_hidReportDesc[_hidReportDescSize++] = 0x00;
// LOGICAL_MAXIMUM (2047)
_hidReportDesc[_hidReportDescSize++] = 0x26;
_hidReportDesc[_hidReportDescSize++] = 0xFF;
_hidReportDesc[_hidReportDescSize++] = 0x07;
// REPORT_SIZE (16)
_hidReportDesc[_hidReportDescSize++] = 0x75;
_hidReportDesc[_hidReportDescSize++] = 0x10;
// REPORT_COUNT (#)
_hidReportDesc[_hidReportDescSize++] = 0x95;
_hidReportDesc[_hidReportDescSize++] = genAxisCount;
// INPUT (Data,Var,Abs)
_hidReportDesc[_hidReportDescSize++] = 0x81;
_hidReportDesc[_hidReportDescSize++] = 0x02;
}
// sim axis types
if (simAxisCount > 0) {
// USAGE_PAGE (Simulation Controls)
_hidReportDesc[_hidReportDescSize++] = 0x05;
_hidReportDesc[_hidReportDescSize++] = 0x02;
for (uint8_t i = 0; i <= USBJOYS_SIM_LAST; i++) {
for (uint8_t cnt = 0; cnt < simCount[i]; cnt++) {
// USAGE (#)
_hidReportDesc[_hidReportDescSize++] = 0x09;
_hidReportDesc[_hidReportDescSize++] = simTypeCodes[i];
}
}
// LOGICAL_MINIMUM (0)
_hidReportDesc[_hidReportDescSize++] = 0x16;
_hidReportDesc[_hidReportDescSize++] = 0x00;
_hidReportDesc[_hidReportDescSize++] = 0x00;
// LOGICAL_MAXIMUM (2047)
_hidReportDesc[_hidReportDescSize++] = 0x26;
_hidReportDesc[_hidReportDescSize++] = 0xFF;
_hidReportDesc[_hidReportDescSize++] = 0x07;
// REPORT_SIZE (16)
_hidReportDesc[_hidReportDescSize++] = 0x75;
_hidReportDesc[_hidReportDescSize++] = 0x10;
// REPORT_COUNT (#)
_hidReportDesc[_hidReportDescSize++] = 0x95;
_hidReportDesc[_hidReportDescSize++] = simAxisCount;
// INPUT (Data,Var,Abs)
_hidReportDesc[_hidReportDescSize++] = 0x81;
_hidReportDesc[_hidReportDescSize++] = 0x02;
}
// END_COLLECTION
_hidReportDesc[_hidReportDescSize++] = 0xc0;
// END_COLLECTION
_hidReportDesc[_hidReportDescSize++] = 0xc0;
// end of report desc
_hidReportSize = (USBJ_BUTTON_SIZE / 8) + (_usbJoystickAxisCount * 2);
}
//compare with the old description
if (_hidReportDescSize != oldHIDReportDescSize) return true;
if (memcmp(_hidReportDesc, oldHIDReportDesc, _hidReportDescSize) != 0) return true;
return false;
}
extern "C" struct usbReport_t usbReportDesc()
{
usbReport_t res = { _hidReportDesc, _hidReportDescSize };
return res;
}
void usbClassicStateUpdate()
{
memset(_hidReport, 0, MAX_HID_REPORT);
//buttons
_hidReport[0] = 0;
_hidReport[1] = 0;
_hidReport[2] = 0;
for (int i = 0; i < 8; ++i) {
if ( channelOutputs[i+8] > 0 ) {
_hidReport[0] |= (1 << i);
}
if ( channelOutputs[i+16] > 0 ) {
_hidReport[1] |= (1 << i);
}
if ( channelOutputs[i+24] > 0 ) {
_hidReport[2] |= (1 << i);
}
}
//analog values
//uint8_t * p = HID_Buffer + 1;
for (int i = 0; i < 8; ++i) {
int16_t value = channelOutputs[i] + 1024;
if ( value > 2047 ) value = 2047;
else if ( value < 0 ) value = 0;
_hidReport[i*2 +3] = static_cast<uint8_t>(value & 0xFF);
_hidReport[i*2 +4] = static_cast<uint8_t>((value >> 8) & 0x07);
}
}
static void setBtnBits(uint8_t ix, uint8_t value, uint8_t size)
{
for(uint8_t i = 0; i < size; i++) {
uint8_t bitix = ix + i;
if(bitix >= USBJ_BUTTON_SIZE) break;
if(value & (1 << i)) {
_buttonState[(bitix / 8)] |= 1 << (bitix % 8);
}
else {
_buttonState[(bitix / 8)] &= ~(1 << (bitix % 8));
}
}
}
static void toggleBtnBit(uint8_t bitix)
{
if(bitix >= USBJ_BUTTON_SIZE) return;
_buttonState[(bitix / 8)] ^= 1 << (bitix % 8);
}
#define g_usbTmr10ms (*(uint8_t*)&g_tmr10ms)
#define BTNPUSH_TIME 20 /* x10ms */
static int16_t circularCutoutValue(uint8_t chix)
{
int32_t value = channelOutputs[chix];
uint8_t chpair = 0xff;
const int32_t limit = 1048576; /* 1024^2 */
if(_usbJoystickCircularCut == USBJ_CC_XYZrX) {
if(chix == _usbJoystickAxisPairs[0][0]) chpair = _usbJoystickAxisPairs[0][1];
else if(chix == _usbJoystickAxisPairs[0][1]) chpair = _usbJoystickAxisPairs[0][0];
else if(chix == _usbJoystickAxisPairs[1][0]) chpair = _usbJoystickAxisPairs[1][1];
else if(chix == _usbJoystickAxisPairs[1][1]) chpair = _usbJoystickAxisPairs[1][0];
}
else if(_usbJoystickCircularCut == USBJ_CC_XYrXrZ) {
if(chix == _usbJoystickAxisPairs[0][0]) chpair = _usbJoystickAxisPairs[0][1];
else if(chix == _usbJoystickAxisPairs[0][1]) chpair = _usbJoystickAxisPairs[0][0];
else if(chix == _usbJoystickAxisPairs[2][0]) chpair = _usbJoystickAxisPairs[2][1];
else if(chix == _usbJoystickAxisPairs[2][1]) chpair = _usbJoystickAxisPairs[2][0];
}
if(chpair != 0xff) {
int32_t pval = channelOutputs[chpair];
int32_t sum = ((value*value) + (pval*pval));
if(sum > limit) {
double ratio = sqrt((double)limit / (double)sum);
value *= ratio;
}
}
return value;
}
void usbStateUpdate()
{
const uint8_t button_ix = 0;
const uint8_t axis_ix = button_ix + (USBJ_BUTTON_SIZE >> 3);
memset(_hidReport, 0, MAX_HID_REPORT);
uint8_t chix = 0;
int16_t value = 0;
uint8_t swpos = 0;
uint8_t btnval = 0;
for (uint8_t i = 0; i < _usbJoystickButtonCount; i++) {
chix = _usbJoystickButtonChannels[i];
value = channelOutputs[chix] + 1024;
if ( value > 2047 ) value = 2047;
else if ( value < 0 ) value = 0;
if (_usbJoystickCh[chix].inversion) value = 2047 - value;
swpos = _usbJoystickCh[chix].switch_npos + 1;
// Quantization of the values
if ((_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_NORMAL)
|| (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE)) {
if (swpos == 1) {
btnval = (value > 1024);
} else {
btnval = static_cast<uint16_t>(value) / (2048 / swpos);
if (btnval >= swpos) btnval = swpos - 1;
}
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_SW_EMU) {
btnval = (value > 1024);
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
btnval = (value >> 6);
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
if (swpos == 1 || swpos == 2) {
btnval = (value > 1024);
} else if (swpos == 3) {
btnval = (value < 1024) ? 1 : (value > 1024) ? 2 : 0;
} else {
btnval = static_cast<uint16_t>(value) / (2048 / swpos);
if (btnval >= swpos) btnval = swpos - 1;
}
}
// Channel Output value changed
if ((_usbLastChannelOutput[chix] == 0xffff) || (_usbLastChannelOutput[chix] != btnval)) {
if ((_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_NORMAL)
|| (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE)) {
if (swpos == 1) {
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 1);
} else {
setBtnBits(_usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
}
// Timer
if(_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
_usbChannelTimerActive[chix] = 1;
_usbChannelTimer[chix] = g_usbTmr10ms;
}
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_SW_EMU) {
if ((_usbLastChannelOutput[chix] != 0xffff) && (_usbLastChannelOutput[chix] < btnval)) {
toggleBtnBit(_usbJoystickCh[chix].btn_num);
}
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
if (_usbLastChannelOutput[chix] != 0xffff) {
if (_usbLastChannelOutput[chix] < btnval) {
setBtnBits(_usbJoystickCh[chix].btn_num, 2, 2);
}
else if (_usbLastChannelOutput[chix] > btnval) {
setBtnBits(_usbJoystickCh[chix].btn_num, 1, 2);
}
_usbChannelTimerActive[chix] = 1;
_usbChannelTimer[chix] = g_usbTmr10ms;
}
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
if (swpos == 1 || swpos == 2) {
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 1);
} else if (swpos == 3) {
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 2);
} else {
setBtnBits(_usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
}
}
_usbLastChannelOutput[chix] = btnval;
}
// Timer check
if((_usbChannelTimerActive[chix]) && (((uint8_t)(g_usbTmr10ms - _usbChannelTimer[chix]) >= BTNPUSH_TIME))) {
_usbChannelTimerActive[chix] = 0;
if(_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
setBtnBits(_usbJoystickCh[chix].btn_num, 0, swpos);
}
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
setBtnBits(_usbJoystickCh[chix].btn_num, 0, 2);
}
}
}
memcpy(_hidReport + button_ix, _buttonState, (USBJ_BUTTON_SIZE >> 3));
for (uint8_t i = 0; i < _usbJoystickAxisCount; i++) {
chix = _usbJoystickAxisChannels[i];
value = circularCutoutValue(chix) + 1024;
if ( value > 2047 ) value = 2047;
else if ( value < 0 ) value = 0;
if (_usbJoystickCh[chix].inversion) value = 2047 - value;
_hidReport[i*2 + axis_ix] = static_cast<uint8_t>(value & 0xFF);
_hidReport[i*2 + axis_ix+1] = static_cast<uint8_t>((value >> 8) & 0x07);
}
}
uint8_t usbReportSize()
{
return _hidReportSize;
}
struct usbReport_t usbReport()
{
if (!usbJoystickExtMode()) {
// Classic USB Joystick report
usbClassicStateUpdate();
} else {
usbStateUpdate();
}
usbReport_t res = { _hidReport, _hidReportSize };
return res;
}
void onUSBJoystickModelChanged()
{
if (!usbJoystickActive()) return;
if (setupUSBJoystick()) {
#if defined(STM32) && !defined(SIMU)
usbJoystickRestart();
#endif
}
}
int isUSBAxisCollision(uint8_t chIdx)
{
USBJoystickChData * cch = usbJChAddress(chIdx);
// non axis
if (cch->mode != USBJOYS_CH_AXIS) return false;
// non-unique axis check
if (_usbJoystickUniqueAxis[cch->param] == 0) {
return false;
}
// collision check
for (int i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
if (i == chIdx) continue;
USBJoystickChData * och = usbJChAddress(i);
if (cch->mode != och->mode) continue;
if (cch->param == och->param) {
return true;
}
}
return false;
}
int isUSBSimCollision(uint8_t chIdx)
{
USBJoystickChData * cch = usbJChAddress(chIdx);
// non axis
if (cch->mode != USBJOYS_CH_SIM) return false;
// non-unique axis check
if (_usbJoystickUniqueSims[cch->param] == 0) {
return false;
}
// collision check
for (int i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
if (i == chIdx) continue;
USBJoystickChData * och = usbJChAddress(i);
if (cch->mode != och->mode) continue;
if (cch->param == och->param) {
return true;
}
}
return false;
}
int isUSBBtnNumCollision(uint8_t chIdx)
{
USBJoystickChData * cch = usbJChAddress(chIdx);
// non button
if (cch->mode != USBJOYS_CH_BUTTON) return false;
// collision check
uint8_t cfirst = cch->btn_num;
uint8_t clast = cch->lastBtnNum();
for (int i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
if (i == chIdx) continue;
USBJoystickChData * och = usbJChAddress(i);
if (och->mode != USBJOYS_CH_BUTTON) continue;
uint8_t ofirst = och->btn_num;
uint8_t olast = och->lastBtnNum();
// overlap
if ((cfirst <= olast) && (ofirst <= clast)) return true;
}
return false;
}
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 _USB_JOYSTICK_H_
#define _USB_JOYSTICK_H_
#include "storage/yaml/yaml_defs.h"
enum USBJoystickIfMode
{
USBJOYS_JOYSTICK,
USBJOYS_GAMEPAD,
USBJOYS_MULTIAXIS,
USBJOYS_LAST SKIP = USBJOYS_MULTIAXIS
};
enum USBJoystickCh
{
USBJOYS_CH_NONE,
USBJOYS_CH_BUTTON,
USBJOYS_CH_AXIS,
USBJOYS_CH_SIM,
USBJOYS_CH_LAST SKIP = USBJOYS_CH_SIM
};
enum USBJoystickBtnMode
{
USBJOYS_BTN_MODE_NORMAL,
USBJOYS_BTN_MODE_ON_PULSE,
USBJOYS_BTN_MODE_SW_EMU,
USBJOYS_BTN_MODE_DELTA,
USBJOYS_BTN_MODE_COMPANION,
USBJOYS_BTN_MODE_LAST SKIP = USBJOYS_BTN_MODE_COMPANION
};
enum USBJoystickAxis
{
USBJOYS_AXIS_X,
USBJOYS_AXIS_Y,
USBJOYS_AXIS_Z,
USBJOYS_AXIS_RX,
USBJOYS_AXIS_RY,
USBJOYS_AXIS_RZ,
USBJOYS_AXIS_SLIDER,
USBJOYS_AXIS_DIAL,
USBJOYS_AXIS_WHEEL,
USBJOYS_AXIS_LAST SKIP = USBJOYS_AXIS_WHEEL
};
enum USBJoystickSim
{
USBJOYS_SIM_AILERON,
USBJOYS_SIM_ELEVATOR,
USBJOYS_SIM_RUDDER,
USBJOYS_SIM_THROTTLE,
USBJOYS_SIM_LAST SKIP = USBJOYS_SIM_THROTTLE
};
#define USBJ_BUTTON_SIZE 32
#define USBJ_MAX_JOYSTICK_CHANNELS 26
#ifdef __cplusplus
extern "C" {
#endif
struct usbReport_t {
uint8_t * ptr;
uint8_t size;
};
#ifdef __cplusplus
}
#endif
int usbJoystickExtMode();
int usbJoystickActive();
int usbJoystickSettingsChanged();
// Initializes the data based on the model settings
// Return value (true = description changed, false = desc. update not needed)
int setupUSBJoystick();
void onUSBJoystickModelChanged();
#ifdef __cplusplus
extern "C" {
#endif
struct usbReport_t usbReportDesc();
uint8_t usbReportSize();
#ifdef __cplusplus
}
#endif
struct usbReport_t usbReport();
int isUSBAxisCollision(uint8_t chIdx);
int isUSBSimCollision(uint8_t chIdx);
int isUSBBtnNumCollision(uint8_t chIdx);
#endif // _USB_JOYSTICK_H_