feat(radio,cpn): Updates for new joystick system (#3400)
* Reduce RAM usage for advanced joystick system on radio: - Don't allocate memory blocks unless joystick mode is being used. Support multiple radio joystick configurations in Companion: - Save configured joystick settings by joystick name in Companion settings. - Save last joystick name used in each profile. - Reload joystick settings by name when profile is changed. * Only show configuration for used axes and buttons in Companion. Send actual number of configured joystick buttons from radio in USB packet. * Fix issue where USB joystick not recognised if no buttons configured. * Fix compiler warnings. * Remove debugging. * Fix crash in Companion. * Change channel 8 to type 'dial', workaround for Linux mapping issue. --------- Co-authored-by: Phil Mitchell <phil.a.mitchell@gmail.com>
This commit is contained in:
@@ -97,12 +97,13 @@ void AppPreferencesDialog::accept()
|
||||
if (ui->joystickChkB ->isChecked()) {
|
||||
g.jsSupport(ui->joystickChkB ->isChecked());
|
||||
// Don't overwrite selected joystick if not connected. Avoid surprising the user.
|
||||
if (ui->joystickCB->isEnabled())
|
||||
g.jsCtrl(ui->joystickCB ->currentIndex());
|
||||
if (ui->joystickCB->isEnabled()) {
|
||||
profile.jsName(ui->joystickCB->currentText());
|
||||
g.loadNamedJS();
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.jsSupport(false);
|
||||
g.jsCtrl(0);
|
||||
}
|
||||
|
||||
// Updates tab
|
||||
@@ -287,7 +288,8 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
ui->joystickCB->clear();
|
||||
ui->joystickCB->insertItems(0, joystickNames);
|
||||
ui->joystickCB->setCurrentIndex(g.jsCtrl());
|
||||
int stick = joystick->findCurrent(g.currentProfile().jsName());
|
||||
ui->joystickCB->setCurrentIndex(stick);
|
||||
}
|
||||
else {
|
||||
ui->joystickCB->clear();
|
||||
@@ -614,8 +616,9 @@ void AppPreferencesDialog::on_joystickChkB_clicked() {
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_joystickcalButton_clicked() {
|
||||
joystickDialog * jd=new joystickDialog(this, ui->joystickCB->currentIndex());
|
||||
jd->exec();
|
||||
g.currentProfile().jsName(ui->joystickCB->currentText());
|
||||
joystickDialog * jd = new joystickDialog(this);
|
||||
jd->exec();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -167,3 +167,13 @@ int Joystick::getAxisValue(int axis)
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Joystick::findCurrent(QString jsName)
|
||||
{
|
||||
for (int i = 0; i < joystickNames.size(); i += 1) {
|
||||
if (joystickNames[i] == jsName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ class Joystick : public QObject
|
||||
}
|
||||
int getAxisValue(int);
|
||||
|
||||
int findCurrent(QString jsName);
|
||||
|
||||
private:
|
||||
QMap<int, Sint16> axes;
|
||||
QMap<int, Uint8> buttons;
|
||||
|
||||
@@ -25,90 +25,29 @@
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
joystickDialog::joystickDialog(QWidget *parent, int stick) :
|
||||
joystickDialog::joystickDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::joystickDialog),
|
||||
step(0),
|
||||
numAxes(0),
|
||||
numButtons(0),
|
||||
started(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
int i;
|
||||
char s[20];
|
||||
|
||||
for (i = 0; i < MAX_JS_AXES; i += 1) {
|
||||
jscal[i][0] = 32767;
|
||||
jscal[i][1] = 0;
|
||||
jscal[i][2] = -32767;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
jscal[i][2] = -32768;
|
||||
}
|
||||
|
||||
ui->backButton->setEnabled(false);
|
||||
|
||||
ui->joystickChkB->setChecked(g.jsSupport() || stick > -1);
|
||||
ui->joystickChkB->setChecked(g.jsSupport());
|
||||
|
||||
if (stick < 0)
|
||||
stick = g.jsCtrl();
|
||||
|
||||
if (loadJoysticks(stick)) {
|
||||
if (loadJoysticks()) {
|
||||
joystickSetEnabled(ui->joystickChkB->isChecked());
|
||||
joystickOpen(ui->joystickCB->currentIndex());
|
||||
}
|
||||
@@ -128,6 +67,82 @@ joystickDialog::~joystickDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void joystickDialog::loadGrid()
|
||||
{
|
||||
int i;
|
||||
char s[20];
|
||||
|
||||
QGridLayout *grid = findChild<QGridLayout*>("gridLayout");
|
||||
|
||||
QLayoutItem* item;
|
||||
while ((item = grid->takeAt(0)) != NULL)
|
||||
{
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
|
||||
memset(sliders, 0, sizeof(sliders));
|
||||
memset(sticks, 0, sizeof(sliders));
|
||||
memset(invert, 0, sizeof(sliders));
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
if (grid) {
|
||||
for (i = 0; i < numAxes; 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[i] = s;
|
||||
grid->addWidget(s, row/2, col+1, 1, 1);
|
||||
QCheckBox *c = new QCheckBox("");
|
||||
invert[i] = c;
|
||||
grid->addWidget(c, row/2, col+2, 1, 1);
|
||||
QComboBox *d = new QComboBox();
|
||||
populateSourceCombo(d);
|
||||
sticks[i] = d;
|
||||
grid->addWidget(d, row/2, col+3, 1, 1);
|
||||
}
|
||||
if (row & 1) row += 1;
|
||||
for (i = 0; i < numButtons; 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[i+numAxes] = s;
|
||||
grid->addWidget(s, row/2, col+1, 1, 1);
|
||||
QComboBox *d = new QComboBox();
|
||||
populateButtonCombo(d);
|
||||
sticks[i+numAxes] = d;
|
||||
grid->addWidget(d, row/2, col+3, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numAxes; ++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 < numButtons; ++i) {
|
||||
if (g.jsButton[i].existsOnDisk()) {
|
||||
sticks[i+numAxes]->setCurrentIndex(sticks[i+numAxes]->findData(g.jsButton[i].button_idx()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void joystickDialog::populateSourceCombo(QComboBox * cb)
|
||||
{
|
||||
int i;
|
||||
@@ -194,16 +209,16 @@ void joystickDialog::populateButtonCombo(QComboBox * cb)
|
||||
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);
|
||||
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);
|
||||
cb->addItem(wname + " Down", (i + ttlSwitches) | JS_BUTTON_3POS_DN);
|
||||
cb->addItem(wname + " Up", (i + ttlSwitches) | JS_BUTTON_3POS_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool joystickDialog::loadJoysticks(int stick)
|
||||
bool joystickDialog::loadJoysticks()
|
||||
{
|
||||
QStringList joystickNames;
|
||||
bool found = false;
|
||||
@@ -219,7 +234,8 @@ bool joystickDialog::loadJoysticks(int stick)
|
||||
joystick->close();
|
||||
}
|
||||
ui->joystickCB->insertItems(0, joystickNames);
|
||||
if (found && stick < joystickNames.size()) {
|
||||
if (found) {
|
||||
int stick = joystick->findCurrent(g.currentProfile().jsName());
|
||||
ui->joystickCB->setCurrentIndex(stick);
|
||||
}
|
||||
else if (!found) {
|
||||
@@ -230,12 +246,16 @@ bool joystickDialog::loadJoysticks(int stick)
|
||||
|
||||
void joystickDialog::joystickOpen(int stick)
|
||||
{
|
||||
numAxes = 0;
|
||||
numButtons = 0;
|
||||
|
||||
if (stick < 0)
|
||||
return;
|
||||
|
||||
joystick = new Joystick(this, 1, false, 0);
|
||||
if (joystick && joystick->open(stick)) {
|
||||
numAxes = std::min(joystick->numAxes, MAX_JS_AXES);
|
||||
numButtons = std::min(joystick->numButtons, MAX_JS_BUTTONS);
|
||||
for (int j=0; j<numAxes; j++) {
|
||||
joystick->sensitivities[j] = 0;
|
||||
joystick->deadzones[j] = 20;
|
||||
@@ -244,6 +264,9 @@ void joystickDialog::joystickOpen(int stick)
|
||||
else {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Cannot open joystick."));
|
||||
}
|
||||
g.currentProfile().jsName(ui->joystickCB->currentText());
|
||||
g.loadNamedJS();
|
||||
loadGrid();
|
||||
}
|
||||
|
||||
void joystickDialog::joystickSetEnabled(bool enable)
|
||||
@@ -256,7 +279,7 @@ void joystickDialog::joystickSetEnabled(bool enable)
|
||||
|
||||
void joystickDialog::onjoystickAxisValueChanged(int axis, int value)
|
||||
{
|
||||
if (axis >= MAX_JS_AXES)
|
||||
if (axis >= numAxes)
|
||||
return;
|
||||
|
||||
if (started) {
|
||||
@@ -274,10 +297,10 @@ void joystickDialog::onjoystickAxisValueChanged(int axis, int value)
|
||||
|
||||
void joystickDialog::onjoystickButtonValueChanged(int button, bool state)
|
||||
{
|
||||
if (button >= MAX_JS_BUTTONS)
|
||||
if (button >= numButtons)
|
||||
return;
|
||||
|
||||
sliders[button + MAX_JS_AXES]->setValue(state);
|
||||
sliders[button + numAxes]->setValue(state);
|
||||
}
|
||||
|
||||
void joystickDialog::loadStep()
|
||||
@@ -290,6 +313,10 @@ void joystickDialog::loadStep()
|
||||
break;
|
||||
case 1:
|
||||
started = true;
|
||||
for (int i=0; i < numAxes; i++) {
|
||||
jscal[i][0] = 0;
|
||||
jscal[i][2] = 0;
|
||||
}
|
||||
ui->howtoLabel->setText(tr("Move sticks and pots in every direction making full movement\nPress Next when finished"));
|
||||
ui->nextButton->setText(tr("Next"));
|
||||
ui->backButton->setDisabled(true);
|
||||
@@ -345,12 +372,12 @@ void joystickDialog::on_cancelButton_clicked()
|
||||
void joystickDialog::on_okButton_clicked()
|
||||
{
|
||||
g.jsSupport(ui->joystickChkB->isChecked());
|
||||
g.jsCtrl(ui->joystickCB->currentIndex());
|
||||
g.currentProfile().jsName(ui->joystickCB->currentText());
|
||||
|
||||
if (joystick)
|
||||
joystick->close();
|
||||
|
||||
if (!g.jsSupport() || g.jsCtrl() < 0) {
|
||||
if (!g.jsSupport()) {
|
||||
this->accept();
|
||||
return;
|
||||
}
|
||||
@@ -362,7 +389,9 @@ void joystickDialog::on_okButton_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_JS_AXES; ++i) {
|
||||
g.clearJSData();
|
||||
|
||||
for (int i = 0; i < numAxes; ++i) {
|
||||
auto stick = sticks[i]->currentData().toInt();
|
||||
if (stick < 0) {
|
||||
g.joystick[i].stick_axe(-1);
|
||||
@@ -373,20 +402,22 @@ void joystickDialog::on_okButton_clicked()
|
||||
g.joystick[i].stick_med(jscal[i][1]);
|
||||
g.joystick[i].stick_min(jscal[i][0]);
|
||||
g.joystick[i].stick_inv(invert[i]->isChecked() );
|
||||
qDebug() << "joystick mapping " << sticks[i]->objectName() << "stick:" << i << "axe:" << stick;
|
||||
qDebug() << "joystick mapping " << sticks[i]->currentText() << "stick:" << i << "axe:" << stick << jscal[i][0] << jscal[i][1] << jscal[i][2];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; ++i) {
|
||||
auto btn = sticks[i+MAX_JS_AXES]->currentData().toInt();
|
||||
for (int i = 0; i < numButtons; ++i) {
|
||||
auto btn = sticks[i+numAxes]->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;
|
||||
qDebug() << "joystick button mapping " << sticks[i+numAxes]->currentText() << "button:" << i << "idx:" << btn;
|
||||
}
|
||||
}
|
||||
|
||||
g.saveNamedJS();
|
||||
|
||||
this->accept();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class joystickDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit joystickDialog(QWidget *parent = 0, int stick=-1);
|
||||
explicit joystickDialog(QWidget *parent = 0);
|
||||
~joystickDialog();
|
||||
Joystick *joystick;
|
||||
|
||||
@@ -58,12 +58,15 @@ class joystickDialog : public QDialog
|
||||
QSlider * sliders[MAX_JS_AXES + MAX_JS_BUTTONS];
|
||||
int step;
|
||||
int numAxes;
|
||||
int numButtons;
|
||||
bool started;
|
||||
|
||||
void loadGrid();
|
||||
|
||||
private slots:
|
||||
void populateSourceCombo(QComboBox * cb);
|
||||
void populateButtonCombo(QComboBox * cb);
|
||||
bool loadJoysticks(int stick = -1);
|
||||
bool loadJoysticks();
|
||||
void joystickOpen(int stick);
|
||||
void joystickSetEnabled(bool enable);
|
||||
void onjoystickAxisValueChanged(int axis, int value);
|
||||
|
||||
@@ -670,13 +670,15 @@ void SimulatorWidget::setupJoysticks()
|
||||
#ifdef JOYSTICKS
|
||||
bool joysticksEnabled = false;
|
||||
|
||||
if (g.jsSupport() && g.jsCtrl() > -1) {
|
||||
if (g.jsSupport()) {
|
||||
if (!joystick)
|
||||
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 stick = joystick->findCurrent(g.currentProfile().jsName());
|
||||
|
||||
if (joystick && joystick->open(stick)) {
|
||||
int numAxes = std::min(joystick->numAxes, MAX_JS_AXES);
|
||||
for (int j=0; j<numAxes; j++) {
|
||||
joystick->sensitivities[j] = 0;
|
||||
@@ -860,8 +862,8 @@ void SimulatorWidget::onjoystickAxisValueChanged(int axis, int value)
|
||||
{
|
||||
#ifdef JOYSTICKS
|
||||
static const int ttlSticks = 4;
|
||||
static const int ttlKnobs = Boards::getCapability(m_board, Board::Pots);
|
||||
static const int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
|
||||
const int ttlKnobs = Boards::getCapability(m_board, Board::Pots);
|
||||
const int ttlFaders = Boards::getCapability(m_board, Board::Sliders);
|
||||
static const int valueRange = 1024;
|
||||
|
||||
if (!joystick || axis >= MAX_JS_AXES)
|
||||
@@ -916,9 +918,6 @@ void SimulatorWidget::onjoystickButtonValueChanged(int button, bool state)
|
||||
|
||||
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) {
|
||||
|
||||
@@ -266,6 +266,36 @@ bool JButtonData::existsOnDisk()
|
||||
return (m_settings.value(settingsPath() % button_idx_key(), -1).toInt() > -1);
|
||||
}
|
||||
|
||||
NamedJStickData::NamedJStickData() : CompStoreObj(), index(-1)
|
||||
{
|
||||
CompStoreObj::addObjectMapping(propertyGroup(), this);
|
||||
}
|
||||
|
||||
bool NamedJStickData::existsOnDisk()
|
||||
{
|
||||
return (m_settings.value(settingsPath() % stick_axe_key(), -1).toInt() > -1);
|
||||
}
|
||||
|
||||
NamedJButtonData::NamedJButtonData() : CompStoreObj(), index(-1)
|
||||
{
|
||||
CompStoreObj::addObjectMapping(propertyGroup(), this);
|
||||
}
|
||||
|
||||
bool NamedJButtonData::existsOnDisk()
|
||||
{
|
||||
return (m_settings.value(settingsPath() % button_idx_key(), -1).toInt() > -1);
|
||||
}
|
||||
|
||||
NamedJSData::NamedJSData() : CompStoreObj(), index(-1)
|
||||
{
|
||||
CompStoreObj::addObjectMapping(propertyGroup(), this);
|
||||
}
|
||||
|
||||
bool NamedJSData::existsOnDisk()
|
||||
{
|
||||
return (m_settings.value(settingsPath() % jsName(), -1).toInt() > -1);
|
||||
}
|
||||
|
||||
|
||||
// ** Profile class********************
|
||||
|
||||
@@ -411,6 +441,13 @@ AppData::AppData() :
|
||||
joystick[i].setIndex(i);
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; i++)
|
||||
jsButton[i].setIndex(i);
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i++) {
|
||||
namedJS[i].setIndex(i);
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1)
|
||||
namedJS[i].joystick[a].setIndex(a, i);
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1)
|
||||
namedJS[i].jsButton[b].setIndex(b, i);
|
||||
}
|
||||
|
||||
// Configure the updates
|
||||
for (int i = 0; i < MAX_COMPONENTS; i++) {
|
||||
@@ -421,6 +458,74 @@ AppData::AppData() :
|
||||
}
|
||||
}
|
||||
|
||||
void AppData::saveNamedJS(int i)
|
||||
{
|
||||
namedJS[i].jsName(currentProfile().jsName());
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1) {
|
||||
namedJS[i].joystick[a].stick_axe(joystick[a].stick_axe());
|
||||
namedJS[i].joystick[a].stick_max(joystick[a].stick_max());
|
||||
namedJS[i].joystick[a].stick_med(joystick[a].stick_med());
|
||||
namedJS[i].joystick[a].stick_min(joystick[a].stick_min());
|
||||
namedJS[i].joystick[a].stick_min(joystick[a].stick_min());
|
||||
}
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1) {
|
||||
namedJS[i].jsButton[b].button_idx(jsButton[b].button_idx());
|
||||
}
|
||||
namedJS[i].jsLastUsed(time(NULL));
|
||||
}
|
||||
|
||||
void AppData::saveNamedJS()
|
||||
{
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i += 1) {
|
||||
if (namedJS[i].jsName() == currentProfile().jsName()) {
|
||||
saveNamedJS(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i += 1) {
|
||||
if (namedJS[i].jsName() == "") {
|
||||
saveNamedJS(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int oldestTime = namedJS[0].jsLastUsed();
|
||||
int oldestN = 0;
|
||||
for (int i = 1; i < MAX_NAMED_JOYSTICKS; i += 1) {
|
||||
if (namedJS[i].jsLastUsed() < oldestTime) {
|
||||
oldestTime = namedJS[i].jsLastUsed();
|
||||
oldestN = i;
|
||||
}
|
||||
}
|
||||
saveNamedJS(oldestN);
|
||||
}
|
||||
|
||||
void AppData::loadNamedJS(int i)
|
||||
{
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1) {
|
||||
joystick[a].stick_axe(namedJS[i].joystick[a].stick_axe());
|
||||
joystick[a].stick_max(namedJS[i].joystick[a].stick_max());
|
||||
joystick[a].stick_med(namedJS[i].joystick[a].stick_med());
|
||||
joystick[a].stick_min(namedJS[i].joystick[a].stick_min());
|
||||
joystick[a].stick_min(namedJS[i].joystick[a].stick_min());
|
||||
}
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1) {
|
||||
jsButton[b].button_idx(namedJS[i].jsButton[b].button_idx());
|
||||
}
|
||||
namedJS[i].jsLastUsed(time(NULL));
|
||||
}
|
||||
|
||||
void AppData::loadNamedJS()
|
||||
{
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i += 1) {
|
||||
if (namedJS[i].jsName() == currentProfile().jsName()) {
|
||||
loadNamedJS(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QString fmtHex(quint32 num)
|
||||
{
|
||||
return QString::number(num, 16).toUpper();
|
||||
@@ -452,7 +557,14 @@ void AppData::initAll()
|
||||
joystick[i].init();
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; i++)
|
||||
jsButton[i].init();
|
||||
// Initialize the updatess
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i++) {
|
||||
namedJS[i].init();
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1)
|
||||
namedJS[i].joystick[a].init();
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1)
|
||||
namedJS[i].jsButton[b].init();
|
||||
}
|
||||
// Initialize the updates
|
||||
for (int i = 0; i < MAX_COMPONENTS; i++) {
|
||||
component[i].init();
|
||||
for (int j = 0; j < MAX_COMPONENT_ASSETS; j++) {
|
||||
@@ -471,6 +583,13 @@ void AppData::resetAllSettings()
|
||||
joystick[i].resetAll();
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; i++)
|
||||
jsButton[i].resetAll();
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i++) {
|
||||
namedJS[i].resetAll();
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1)
|
||||
namedJS[i].joystick[a].resetAll();
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1)
|
||||
namedJS[i].jsButton[b].resetAll();
|
||||
}
|
||||
for (int i = 0; i < MAX_COMPONENTS; i++) {
|
||||
component[i].resetAll();
|
||||
for (int j = 0; j < MAX_COMPONENT_ASSETS; j++) {
|
||||
@@ -489,6 +608,13 @@ void AppData::storeAllSettings()
|
||||
joystick[i].storeAll();
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; i++)
|
||||
jsButton[i].storeAll();
|
||||
for (int i = 0; i < MAX_NAMED_JOYSTICKS; i++) {
|
||||
namedJS[i].storeAll();
|
||||
for (int a = 0; a < MAX_JS_AXES; a += 1)
|
||||
namedJS[i].joystick[a].storeAll();
|
||||
for (int b = 0; b < MAX_JS_BUTTONS; b += 1)
|
||||
namedJS[i].jsButton[b].storeAll();
|
||||
}
|
||||
for (int i = 0; i < MAX_COMPONENTS; i++) {
|
||||
component[i].storeAll();
|
||||
for (int j = 0; j < MAX_COMPONENT_ASSETS; j++)
|
||||
@@ -506,6 +632,7 @@ void AppData::sessionId(int index)
|
||||
if (index < 0 || index >= MAX_PROFILES || index == m_sessionId)
|
||||
return;
|
||||
m_sessionId = index;
|
||||
loadNamedJS();
|
||||
emit sessionIdChanged(index);
|
||||
emit currentProfileChanged();
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#define MAX_JS_BUTTONS 32
|
||||
#define MAX_COMPONENTS 10
|
||||
#define MAX_COMPONENT_ASSETS 5
|
||||
#define MAX_NAMED_JOYSTICKS 10
|
||||
|
||||
// It important that these function names are consistent everywhere.
|
||||
#define PROP_FSIG_INIT_IMPL _init()
|
||||
@@ -331,12 +332,22 @@ class JStickData: public CompStoreObj
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
stick_axe(-1);
|
||||
stick_med(-32768);
|
||||
stick_max(32767);
|
||||
stick_med(0);
|
||||
stick_inv(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit JStickData();
|
||||
void setIndex(int idx) { index = idx; }
|
||||
inline QString propertyGroup() const override { return QStringLiteral("JsCalibration"); }
|
||||
inline QString settingsPath() const override { return QString("%1/%2/").arg(propertyGroup()).arg(index); }
|
||||
friend class AppData;
|
||||
friend class NamedJSData;
|
||||
|
||||
private:
|
||||
PROPERTY(int, stick_axe, -1)
|
||||
@@ -348,22 +359,100 @@ class JStickData: public CompStoreObj
|
||||
int index;
|
||||
};
|
||||
|
||||
//! \brief JButtonData class stores properties related to each joystick button (button number).
|
||||
class JButtonData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
button_idx(-1);
|
||||
}
|
||||
|
||||
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;
|
||||
friend class NamedJSData;
|
||||
|
||||
private:
|
||||
PROPERTY(int, button_idx, -1)
|
||||
PROPERTY(int, button_inv, 0)
|
||||
|
||||
int index;
|
||||
};
|
||||
|
||||
//! \brief NamedJStickData class stores properties related to each joystick axis (calibration/assignment/direction).
|
||||
class NamedJStickData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
protected:
|
||||
explicit NamedJStickData();
|
||||
void setIndex(int idx, int nmIdx) { index = idx; namedIdx = nmIdx; }
|
||||
inline QString propertyGroup() const override { return QStringLiteral("NamedJSData/%1").arg(namedIdx); }
|
||||
inline QString settingsPath() const override { return QString("%1/JsCalibration/%2/").arg(propertyGroup()).arg(index); }
|
||||
friend class AppData;
|
||||
friend class NamedJSData;
|
||||
|
||||
private:
|
||||
PROPERTY(int, stick_axe, -1)
|
||||
PROPERTY(int, stick_min, -32768)
|
||||
PROPERTY(int, stick_med, 0)
|
||||
PROPERTY(int, stick_max, 32767)
|
||||
PROPERTY(int, stick_inv, 0)
|
||||
|
||||
int namedIdx;
|
||||
int index;
|
||||
};
|
||||
|
||||
//! \brief NamedJButtonData class stores properties related to each joystick button (button number).
|
||||
class NamedJButtonData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
protected:
|
||||
explicit NamedJButtonData();
|
||||
void setIndex(int idx, int nmIdx) { index = idx; namedIdx = nmIdx; }
|
||||
inline QString propertyGroup() const override { return QStringLiteral("NamedJSData/%1").arg(namedIdx); }
|
||||
inline QString settingsPath() const override { return QString("%1/JsButton/%2/").arg(propertyGroup()).arg(index); }
|
||||
friend class AppData;
|
||||
friend class NamedJSData;
|
||||
|
||||
private:
|
||||
PROPERTY(int, button_idx, -1)
|
||||
|
||||
int namedIdx;
|
||||
int index;
|
||||
};
|
||||
|
||||
class NamedJSData: public CompStoreObj
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
|
||||
protected:
|
||||
explicit NamedJSData();
|
||||
void setIndex(int idx) { index = idx; }
|
||||
inline QString propertyGroup() const override { return QStringLiteral("NamedJSData"); }
|
||||
inline QString settingsPath() const override { return QString("%1/%2/").arg(propertyGroup()).arg(index); }
|
||||
friend class AppData;
|
||||
|
||||
public:
|
||||
NamedJStickData joystick[MAX_JS_AXES];
|
||||
NamedJButtonData jsButton[MAX_JS_BUTTONS];
|
||||
|
||||
private:
|
||||
PROPERTYSTRD(jsName, "")
|
||||
PROPERTY(unsigned int, jsLastUsed, 0)
|
||||
|
||||
int index;
|
||||
};
|
||||
@@ -432,6 +521,8 @@ class Profile: public CompStoreObj
|
||||
PROPERTY4(int, txCurrentCalibration, "currentCalib", 0)
|
||||
PROPERTY4(int, txVoltageCalibration, "VbatCalib", 0)
|
||||
|
||||
PROPERTYSTRD(jsName, "")
|
||||
|
||||
int index;
|
||||
|
||||
static const QStringList fwVarsList() //! for resetFwVariables()... TODO: make this go away
|
||||
@@ -615,9 +706,19 @@ class AppData: public CompStoreObj
|
||||
Profile profile[MAX_PROFILES];
|
||||
JStickData joystick[MAX_JS_AXES];
|
||||
JButtonData jsButton[MAX_JS_BUTTONS];
|
||||
NamedJSData namedJS[MAX_NAMED_JOYSTICKS];
|
||||
FwRevision fwRev;
|
||||
ComponentData component[MAX_COMPONENTS];
|
||||
|
||||
void clearJSData() {
|
||||
for (int i = 0; i < MAX_JS_AXES; i += 1)
|
||||
joystick[i].clear();
|
||||
for (int i = 0; i < MAX_JS_BUTTONS; i += 1)
|
||||
jsButton[i].clear();
|
||||
}
|
||||
void saveNamedJS();
|
||||
void loadNamedJS();
|
||||
|
||||
signals:
|
||||
void currentProfileChanged();
|
||||
|
||||
@@ -625,6 +726,9 @@ class AppData: public CompStoreObj
|
||||
inline QString propertyGroup() const override { return QStringLiteral("General"); }
|
||||
inline QString settingsPath() const override { return QString(); }
|
||||
|
||||
void saveNamedJS(int i);
|
||||
void loadNamedJS(int i);
|
||||
|
||||
private:
|
||||
|
||||
PROPERTY_META(int, sessionId, 0) // currently active radio profile ID, NOT saved to persistent storage -- Initialize before profileId!
|
||||
@@ -679,7 +783,6 @@ class AppData: public CompStoreObj
|
||||
PROPERTY4(int, embedSplashes, "embedded_splashes", 0)
|
||||
PROPERTY4(int, fwServerFails, "fwserver", 0)
|
||||
PROPERTY4(int, iconSize, "icon_size", 2)
|
||||
PROPERTY4(int, jsCtrl, "js_ctrl", 0)
|
||||
PROPERTY4(int, historySize, "history_size", 10)
|
||||
PROPERTY (int, generalEditTab, 0)
|
||||
PROPERTY (int, theme, 1)
|
||||
|
||||
@@ -638,6 +638,12 @@ PACK(struct USBJoystickChData {
|
||||
|
||||
#if defined(USBJ_EX)
|
||||
NOBACKUP(
|
||||
uint8_t btnCount() {
|
||||
// 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))
|
||||
return switch_npos;
|
||||
return switch_npos + 1;
|
||||
}
|
||||
uint8_t lastBtnNumNoCLip() {
|
||||
uint8_t last = btn_num + switch_npos;
|
||||
// Use one less joystick button for 2POS and 3POS switches for Companion mode
|
||||
|
||||
+153
-194
@@ -25,43 +25,40 @@
|
||||
#define MAX_HID_REPORTDESC 160
|
||||
#define MAX_HID_REPORT 80
|
||||
|
||||
uint8_t _hidReportDesc[MAX_HID_REPORTDESC] = { };
|
||||
uint8_t* _hidReportDesc = nullptr;
|
||||
uint8_t _hidReportDescSize = 0;
|
||||
uint8_t _hidReport[MAX_HID_REPORT] = { };
|
||||
uint8_t* _hidReport = nullptr;
|
||||
uint8_t _hidReportSize = 0;
|
||||
|
||||
static uint8_t _buttonState[USBJ_BUTTON_SIZE >> 3] = { };
|
||||
struct _usbJSData {
|
||||
uint16_t _usbLastChannelOutput[USBJ_MAX_JOYSTICK_CHANNELS];
|
||||
uint8_t _usbChannelTimerActive[USBJ_MAX_JOYSTICK_CHANNELS];
|
||||
uint8_t _usbChannelTimer[USBJ_MAX_JOYSTICK_CHANNELS];
|
||||
uint8_t _usbJoystickButtonChannels[USBJ_MAX_JOYSTICK_CHANNELS];
|
||||
uint8_t _usbJoystickAxisChannels[USBJ_MAX_JOYSTICK_CHANNELS];
|
||||
};
|
||||
|
||||
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 struct _usbJSData* _usbJS = nullptr;
|
||||
|
||||
static uint8_t _buttonState[(USBJ_BUTTON_SIZE+7) >> 3] = { };
|
||||
|
||||
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:
|
||||
Report 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
|
||||
@@ -99,7 +96,7 @@ static const uint8_t HID_JOYSTICK_ReportDesc[] =
|
||||
0x09, 0x34, // USAGE (Ry)
|
||||
0x09, 0x35, // USAGE (Rz)
|
||||
0x09, 0x36, // USAGE (Slider)
|
||||
0x09, 0x36, // USAGE (Slider)
|
||||
0x09, 0x37, // USAGE (Dial)
|
||||
0x16, 0x00, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xFF, 0x07, // LOGICAL_MAXIMUM (2047)
|
||||
0x75, 0x10, // REPORT_SIZE (16)
|
||||
@@ -109,6 +106,26 @@ static const uint8_t HID_JOYSTICK_ReportDesc[] =
|
||||
0xc0 // END_COLLECTION
|
||||
};
|
||||
|
||||
static bool isUniqueAxisType(int type) { return type < 6; }
|
||||
static bool isUniqueSimType(int type) { return true; }
|
||||
|
||||
const uint32_t MOD_ADLER = 65521;
|
||||
|
||||
uint32_t adler32(uint8_t *data, size_t len)
|
||||
{
|
||||
uint32_t a = 1, b = 0;
|
||||
size_t index;
|
||||
|
||||
// Process each byte of the data in order
|
||||
for (index = 0; index < len; ++index)
|
||||
{
|
||||
a = (a + data[index]) % MOD_ADLER;
|
||||
b = (b + a) % MOD_ADLER;
|
||||
}
|
||||
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
||||
int usbJoystickExtMode()
|
||||
{
|
||||
return g_model.usbJoystickExtMode;
|
||||
@@ -121,13 +138,19 @@ int usbJoystickActive()
|
||||
|
||||
int usbJoystickSettingsChanged()
|
||||
{
|
||||
if (!usbJoystickActive()) return false;
|
||||
static uint32_t settingsChecksum = 0;
|
||||
|
||||
if((_usbJoystickIfMode != g_model.usbJoystickIfMode)
|
||||
|| (_usbJoystickCircularCut != g_model.usbJoystickCircularCut)) return true;
|
||||
if(memcmp(_usbJoystickCh, g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh)) != 0) return true;
|
||||
if (!usbJoystickActive())
|
||||
return false;
|
||||
|
||||
return false;
|
||||
if ((_usbJoystickIfMode != g_model.usbJoystickIfMode) ||
|
||||
(_usbJoystickCircularCut != g_model.usbJoystickCircularCut))
|
||||
return true;
|
||||
|
||||
uint32_t oldChecksum = settingsChecksum;
|
||||
settingsChecksum = adler32((uint8_t*)&g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh));
|
||||
|
||||
return oldChecksum != settingsChecksum;
|
||||
}
|
||||
|
||||
int setupUSBJoystick()
|
||||
@@ -137,31 +160,42 @@ int setupUSBJoystick()
|
||||
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;
|
||||
if (_hidReportDesc == nullptr) {
|
||||
_hidReportDesc = (uint8_t*)malloc(MAX_HID_REPORTDESC);
|
||||
if (_hidReportDesc == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy old to compare
|
||||
memcpy(oldHIDReportDesc, _hidReportDesc, MAX_HID_REPORTDESC);
|
||||
oldHIDReportDescSize = _hidReportDescSize;
|
||||
if (_hidReport == nullptr) {
|
||||
_hidReport = (uint8_t*)malloc(MAX_HID_REPORT);
|
||||
if (_hidReport == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_usbJS == nullptr) {
|
||||
_usbJS = (struct _usbJSData*)malloc(sizeof(struct _usbJSData));
|
||||
if (_usbJS == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
// properties to detect change
|
||||
uint8_t oldHIDReportDescSize = _hidReportDescSize;
|
||||
uint32_t oldChecksum = adler32(_hidReportDesc, _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(_buttonState, 0, ((USBJ_BUTTON_SIZE+7) >> 3));
|
||||
memset(_usbJS, 0, sizeof(struct _usbJSData));
|
||||
memset(_usbJS->_usbLastChannelOutput, 0xff, sizeof(_usbJS->_usbLastChannelOutput));
|
||||
|
||||
memset(_usbJoystickButtonChannels, 0, USBJ_MAX_JOYSTICK_CHANNELS);
|
||||
_usbJoystickButtonCount = 0;
|
||||
memset(_usbJoystickAxisChannels, 0, USBJ_MAX_JOYSTICK_CHANNELS);
|
||||
_usbJoystickAxisCount = 0;
|
||||
memset(_usbJoystickAxisPairs, 0xff, sizeof(_usbJoystickAxisPairs));
|
||||
|
||||
@@ -175,6 +209,7 @@ int setupUSBJoystick()
|
||||
|
||||
uint8_t genAxisCount = 0;
|
||||
uint8_t simAxisCount = 0;
|
||||
uint8_t buttonCount = 0;
|
||||
|
||||
// sort channels by type
|
||||
uint8_t typeCount[USBJOYS_CH_LAST + 1] = { };
|
||||
@@ -185,24 +220,25 @@ int setupUSBJoystick()
|
||||
uint8_t mode = 0;
|
||||
uint8_t submode = 0;
|
||||
for (uint8_t i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
|
||||
mode = _usbJoystickCh[i].mode;
|
||||
mode = g_model.usbJoystickCh[i].mode;
|
||||
|
||||
if (_usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
|
||||
if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
|
||||
buttonCount += g_model.usbJoystickCh[i].btnCount();
|
||||
typeCount[mode]++;
|
||||
}
|
||||
else if (_usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
|
||||
submode = _usbJoystickCh[i].param;
|
||||
else if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
|
||||
submode = g_model.usbJoystickCh[i].param;
|
||||
if (submode <= USBJOYS_AXIS_LAST) {
|
||||
if ((_usbJoystickUniqueAxis[submode] == 0) || (axisCount[submode] == 0)) {
|
||||
if (!isUniqueAxisType(submode) || (axisCount[submode] == 0)) {
|
||||
axisCount[submode]++;
|
||||
typeCount[mode]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
|
||||
submode = _usbJoystickCh[i].param;
|
||||
else if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
|
||||
submode = g_model.usbJoystickCh[i].param;
|
||||
if (submode <= USBJOYS_SIM_LAST) {
|
||||
if ((_usbJoystickUniqueSims[submode] == 0) || (simCount[submode] == 0)) {
|
||||
if (!isUniqueSimType(submode) || (simCount[submode] == 0)) {
|
||||
simCount[submode]++;
|
||||
typeCount[mode]++;
|
||||
}
|
||||
@@ -221,17 +257,17 @@ int setupUSBJoystick()
|
||||
}
|
||||
ixcount = 0;
|
||||
for (uint8_t i = 0; i < USBJ_MAX_JOYSTICK_CHANNELS; i++) {
|
||||
mode = _usbJoystickCh[i].mode;
|
||||
mode = g_model.usbJoystickCh[i].mode;
|
||||
|
||||
if (_usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
|
||||
_usbJoystickButtonChannels[ixcount] = i;
|
||||
if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_BUTTON) {
|
||||
_usbJS->_usbJoystickButtonChannels[ixcount] = i;
|
||||
ixcount++;
|
||||
}
|
||||
else if (_usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
|
||||
submode = _usbJoystickCh[i].param;
|
||||
else if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_AXIS) {
|
||||
submode = g_model.usbJoystickCh[i].param;
|
||||
if (submode <= USBJOYS_AXIS_LAST) {
|
||||
_usbJoystickAxisChannels[axisIx[submode]] = i;
|
||||
if (_usbJoystickUniqueAxis[submode] == 0) {
|
||||
_usbJS->_usbJoystickAxisChannels[axisIx[submode]] = i;
|
||||
if (!isUniqueAxisType(submode)) {
|
||||
axisIx[submode]++;
|
||||
}
|
||||
// save axis pairs
|
||||
@@ -253,11 +289,11 @@ int setupUSBJoystick()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
|
||||
submode = _usbJoystickCh[i].param;
|
||||
else if (g_model.usbJoystickCh[i].mode == USBJOYS_CH_SIM) {
|
||||
submode = g_model.usbJoystickCh[i].param;
|
||||
if (submode <= USBJOYS_SIM_LAST) {
|
||||
_usbJoystickAxisChannels[simIx[submode]] = i;
|
||||
if (_usbJoystickUniqueSims[submode] == 0) {
|
||||
_usbJS->_usbJoystickAxisChannels[simIx[submode]] = i;
|
||||
if (!isUniqueSimType(submode)) {
|
||||
simIx[submode]++;
|
||||
}
|
||||
}
|
||||
@@ -273,61 +309,17 @@ int setupUSBJoystick()
|
||||
// generate report desc
|
||||
|
||||
// USAGE_PAGE (Generic Desktop)
|
||||
_hidReportDesc[_hidReportDescSize++] = 0x05;
|
||||
_hidReportDesc[_hidReportDescSize++] = 0x01;
|
||||
memcpy(_hidReportDesc, HID_JOYSTICK_ReportDesc, 24);
|
||||
_hidReportDescSize = 24;
|
||||
|
||||
// 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;
|
||||
_hidReportDesc[3] = joystickType;
|
||||
_hidReportDesc[13] = buttonCount ? buttonCount : 1;
|
||||
_hidReportDesc[19] = USBJ_BUTTON_SIZE;
|
||||
|
||||
// generic axis types
|
||||
if (genAxisCount > 0) {
|
||||
@@ -344,27 +336,9 @@ int setupUSBJoystick()
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
memcpy(_hidReportDesc+_hidReportDescSize, HID_JOYSTICK_ReportDesc+42, 12);
|
||||
_hidReportDesc[_hidReportDescSize+9] = genAxisCount;
|
||||
_hidReportDescSize += 12;
|
||||
}
|
||||
|
||||
// sim axis types
|
||||
@@ -382,27 +356,9 @@ int setupUSBJoystick()
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
memcpy(_hidReportDesc+_hidReportDescSize, HID_JOYSTICK_ReportDesc+42, 12);
|
||||
_hidReportDesc[_hidReportDescSize+9] = simAxisCount;
|
||||
_hidReportDescSize += 12;
|
||||
}
|
||||
|
||||
// END_COLLECTION
|
||||
@@ -413,14 +369,13 @@ int setupUSBJoystick()
|
||||
|
||||
// end of report desc
|
||||
|
||||
_hidReportSize = (USBJ_BUTTON_SIZE / 8) + (_usbJoystickAxisCount * 2);
|
||||
_hidReportSize = ((USBJ_BUTTON_SIZE+7) / 8) + (_usbJoystickAxisCount * 2);
|
||||
}
|
||||
|
||||
|
||||
//compare with the old description
|
||||
if (_hidReportDescSize != oldHIDReportDescSize) return true;
|
||||
if (memcmp(_hidReportDesc, oldHIDReportDesc, _hidReportDescSize) != 0) return true;
|
||||
|
||||
return false;
|
||||
uint32_t newChecksum = adler32(_hidReportDesc, _hidReportDescSize);
|
||||
return oldChecksum != newChecksum;
|
||||
}
|
||||
|
||||
extern "C" struct usbReport_t usbReportDesc()
|
||||
@@ -431,6 +386,8 @@ extern "C" struct usbReport_t usbReportDesc()
|
||||
|
||||
void usbClassicStateUpdate()
|
||||
{
|
||||
if (_hidReport == nullptr) return;
|
||||
|
||||
memset(_hidReport, 0, MAX_HID_REPORT);
|
||||
|
||||
//buttons
|
||||
@@ -519,8 +476,10 @@ static int16_t circularCutoutValue(uint8_t chix)
|
||||
|
||||
void usbStateUpdate()
|
||||
{
|
||||
if (_hidReport == nullptr) return;
|
||||
|
||||
const uint8_t button_ix = 0;
|
||||
const uint8_t axis_ix = button_ix + (USBJ_BUTTON_SIZE >> 3);
|
||||
const uint8_t axis_ix = button_ix + ((USBJ_BUTTON_SIZE+7) >> 3);
|
||||
|
||||
memset(_hidReport, 0, MAX_HID_REPORT);
|
||||
|
||||
@@ -532,19 +491,19 @@ void usbStateUpdate()
|
||||
uint8_t btnval = 0;
|
||||
|
||||
for (uint8_t i = 0; i < _usbJoystickButtonCount; i++) {
|
||||
chix = _usbJoystickButtonChannels[i];
|
||||
chix = _usbJS->_usbJoystickButtonChannels[i];
|
||||
|
||||
value = channelOutputs[chix] + 1024;
|
||||
if ( value > 2047 ) value = 2047;
|
||||
else if ( value < 0 ) value = 0;
|
||||
|
||||
if (_usbJoystickCh[chix].inversion) value = 2047 - value;
|
||||
if (g_model.usbJoystickCh[chix].inversion) value = 2047 - value;
|
||||
|
||||
swpos = _usbJoystickCh[chix].switch_npos + 1;
|
||||
swpos = g_model.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 ((g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_NORMAL)
|
||||
|| (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE)) {
|
||||
|
||||
if (swpos == 1) {
|
||||
btnval = (value > 1024);
|
||||
@@ -553,13 +512,13 @@ void usbStateUpdate()
|
||||
if (btnval >= swpos) btnval = swpos - 1;
|
||||
}
|
||||
}
|
||||
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_SW_EMU) {
|
||||
else if (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_SW_EMU) {
|
||||
btnval = (value > 1024);
|
||||
}
|
||||
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
|
||||
else if (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
|
||||
btnval = (value >> 6);
|
||||
}
|
||||
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
|
||||
else if (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
|
||||
if (swpos == 1 || swpos == 2) {
|
||||
btnval = (value > 1024);
|
||||
} else if (swpos == 3) {
|
||||
@@ -571,76 +530,76 @@ void usbStateUpdate()
|
||||
}
|
||||
|
||||
// Channel Output value changed
|
||||
if ((_usbLastChannelOutput[chix] == 0xffff) || (_usbLastChannelOutput[chix] != btnval)) {
|
||||
if ((_usbJS->_usbLastChannelOutput[chix] == 0xffff) || (_usbJS->_usbLastChannelOutput[chix] != btnval)) {
|
||||
|
||||
if ((_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_NORMAL)
|
||||
|| (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE)) {
|
||||
if ((g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_NORMAL)
|
||||
|| (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE)) {
|
||||
|
||||
if (swpos == 1) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 1);
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, btnval, 1);
|
||||
} else {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
|
||||
}
|
||||
|
||||
// Timer
|
||||
if(_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
|
||||
_usbChannelTimerActive[chix] = 1;
|
||||
_usbChannelTimer[chix] = g_usbTmr10ms;
|
||||
if(g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
|
||||
_usbJS->_usbChannelTimerActive[chix] = 1;
|
||||
_usbJS->_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 (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_SW_EMU) {
|
||||
if ((_usbJS->_usbLastChannelOutput[chix] != 0xffff) && (_usbJS->_usbLastChannelOutput[chix] < btnval)) {
|
||||
toggleBtnBit(g_model.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 (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
|
||||
if (_usbJS->_usbLastChannelOutput[chix] != 0xffff) {
|
||||
if (_usbJS->_usbLastChannelOutput[chix] < btnval) {
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 2, 2);
|
||||
}
|
||||
else if (_usbLastChannelOutput[chix] > btnval) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, 1, 2);
|
||||
else if (_usbJS->_usbLastChannelOutput[chix] > btnval) {
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 1, 2);
|
||||
}
|
||||
_usbChannelTimerActive[chix] = 1;
|
||||
_usbChannelTimer[chix] = g_usbTmr10ms;
|
||||
_usbJS->_usbChannelTimerActive[chix] = 1;
|
||||
_usbJS->_usbChannelTimer[chix] = g_usbTmr10ms;
|
||||
}
|
||||
}
|
||||
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
|
||||
else if (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_COMPANION) {
|
||||
if (swpos == 1 || swpos == 2) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 1);
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, btnval, 1);
|
||||
} else if (swpos == 3) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, btnval, 2);
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, btnval, 2);
|
||||
} else {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 1 << btnval, swpos);
|
||||
}
|
||||
}
|
||||
|
||||
_usbLastChannelOutput[chix] = btnval;
|
||||
_usbJS->_usbLastChannelOutput[chix] = btnval;
|
||||
}
|
||||
|
||||
// Timer check
|
||||
if((_usbChannelTimerActive[chix]) && (((uint8_t)(g_usbTmr10ms - _usbChannelTimer[chix]) >= BTNPUSH_TIME))) {
|
||||
_usbChannelTimerActive[chix] = 0;
|
||||
if((_usbJS->_usbChannelTimerActive[chix]) && (((uint8_t)(g_usbTmr10ms - _usbJS->_usbChannelTimer[chix]) >= BTNPUSH_TIME))) {
|
||||
_usbJS->_usbChannelTimerActive[chix] = 0;
|
||||
|
||||
if(_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, 0, swpos);
|
||||
if(g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_ON_PULSE) {
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 0, swpos);
|
||||
}
|
||||
else if (_usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
|
||||
setBtnBits(_usbJoystickCh[chix].btn_num, 0, 2);
|
||||
else if (g_model.usbJoystickCh[chix].param == USBJOYS_BTN_MODE_DELTA) {
|
||||
setBtnBits(g_model.usbJoystickCh[chix].btn_num, 0, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_hidReport + button_ix, _buttonState, (USBJ_BUTTON_SIZE >> 3));
|
||||
|
||||
memcpy(_hidReport + button_ix, _buttonState, ((USBJ_BUTTON_SIZE+7) >> 3));
|
||||
|
||||
for (uint8_t i = 0; i < _usbJoystickAxisCount; i++) {
|
||||
chix = _usbJoystickAxisChannels[i];
|
||||
chix = _usbJS->_usbJoystickAxisChannels[i];
|
||||
|
||||
value = circularCutoutValue(chix) + 1024;
|
||||
if ( value > 2047 ) value = 2047;
|
||||
else if ( value < 0 ) value = 0;
|
||||
|
||||
if (_usbJoystickCh[chix].inversion) value = 2047 - value;
|
||||
if (g_model.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);
|
||||
@@ -684,7 +643,7 @@ int isUSBAxisCollision(uint8_t chIdx)
|
||||
if (cch->mode != USBJOYS_CH_AXIS) return false;
|
||||
|
||||
// non-unique axis check
|
||||
if (_usbJoystickUniqueAxis[cch->param] == 0) {
|
||||
if (!isUniqueAxisType(cch->param)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -711,7 +670,7 @@ int isUSBSimCollision(uint8_t chIdx)
|
||||
if (cch->mode != USBJOYS_CH_SIM) return false;
|
||||
|
||||
// non-unique axis check
|
||||
if (_usbJoystickUniqueSims[cch->param] == 0) {
|
||||
if (!isUniqueSimType(cch->param)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user