Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Toggle Joystick Add-on #1131

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ src/addons/keyboard_host_listener.cpp
src/addons/i2canalog1219.cpp
src/addons/i2c_gpio_pcf8575.cpp
src/addons/jslider.cpp
src/addons/togglejoystick.cpp
src/addons/display.cpp
src/addons/neopicoleds.cpp
src/addons/playernum.cpp
Expand Down
68 changes: 68 additions & 0 deletions headers/addons/togglejoystick.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#ifndef _ToggleJoystick_H
#define _ToggleJoystick_H

#include "gpaddon.h"

#include "GamepadEnums.h"
#include "types.h"

#ifndef TOGGLE_JOYSTICK_ENABLED
#define TOGGLE_JOYSTICK_ENABLED 0
#endif

#ifndef TOGGLE_JOYSTICK_PRIMARY_TOGGLE
#define TOGGLE_JOYSTICK_PRIMARY_TOGGLE DPAD_MODE_RIGHT_ANALOG
#endif

#ifndef TOGGLE_JOYSTICK_SECONDARY_TOGGLE
#define TOGGLE_JOYSTICK_SECONDARY_TOGGLE DPAD_MODE_DIGITAL
#endif

// ToggleJoystick Module Name
#define ToggleJoystickName "ToggleJoystick"

class ToggleJoystickAddon : public GPAddon {
public:
virtual bool available();
virtual void setup(); // ToggleJoystick Setup
virtual void update(); // ToggleJoystick Setup
virtual void reinit();
virtual void preprocess() {}
virtual void process(); // ToggleJoystick process
virtual std::string name() { return ToggleJoystickName; }

private:
void toggleJoystick(Gamepad *gamepad, DpadMode currentDpadMode,
DpadMode toggle, bool toggleSwapped, bool bothStatesHeld);
void setPrevJoystick(Gamepad *gamepad, DpadMode toggle);

DpadMode defaultDpadMode;
DpadMode prevDpadMode;
DpadMode primaryToggle;
DpadMode secondaryToggle;

uint32_t primaryToggleMask;
uint32_t secondaryToggleMask;
uint32_t prevDpad;
uint32_t prev2Dpad;

uint16_t prevLX;
uint16_t prevLY;
uint16_t prevRX;
uint16_t prevRY;
uint16_t prev2LX;
uint16_t prev2LY;
uint16_t prev2RX;
uint16_t prev2RY;

uint8_t prevToggleState;

bool primaryToggleState;
bool secondaryToggleState;
bool onStateChange;
bool joystickChanged;
bool holdSecondary;
bool freezeInputs;
};

#endif // _ToggleJoystick_H_
10 changes: 8 additions & 2 deletions proto/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ message ProfileOptions
message DisplayOptions
{
optional bool enabled = 1;

optional int32 deprecatedI2cBlock = 2 [deprecated = true];
optional int32 deprecatedI2cSDAPin = 3 [deprecated = true];
optional int32 deprecatedI2cSCLPin = 4 [deprecated = true];
Expand Down Expand Up @@ -422,7 +421,6 @@ message ReverseOptions
message AnalogADS1219Options
{
optional bool enabled = 1;

optional int32 deprecatedI2cBlock = 2 [deprecated = true];
optional int32 deprecatedI2cSDAPin = 3 [deprecated = true];
optional int32 deprecatedI2cSCLPin = 4 [deprecated = true];
Expand Down Expand Up @@ -455,6 +453,13 @@ message DualDirectionalOptions
optional bool fourWayMode = 8;
}

message ToggleJoystickOptions
{
optional bool enabled = 1;
optional DpadMode primaryToggle = 2;
optional DpadMode secondaryToggle = 3;
}

message TiltOptions
{
optional bool enabled = 1;
Expand Down Expand Up @@ -801,6 +806,7 @@ message AddonOptions
optional PCF8575Options pcf8575Options = 25;
optional DRV8833RumbleOptions drv8833RumbleOptions = 26;
optional ReactiveLEDOptions reactiveLEDOptions = 27;
optional ToggleJoystickOptions toggleJoystickOptions = 28;
}

message MigrationHistory
Expand Down
2 changes: 2 additions & 0 deletions proto/enums.proto
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ enum GpioAction
BUTTON_PRESS_E10 = 52;
BUTTON_PRESS_E11 = 53;
BUTTON_PRESS_E12 = 54;
BUTTON_PRESS_TJ_TOGGLE_1 = 55;
BUTTON_PRESS_TJ_TOGGLE_2 = 56;
}

enum GpioDirection
Expand Down
213 changes: 213 additions & 0 deletions src/addons/togglejoystick.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include "addons/togglejoystick.h"

#include "storagemanager.h"
#include "types.h"

#include "GamepadEnums.h"
#include "config.pb.h"
#include "gamepad/GamepadState.h"
#include "helper.h"

bool ToggleJoystickAddon::available() {
const ToggleJoystickOptions &options =
Storage::getInstance().getAddonOptions().toggleJoystickOptions;
GpioMappingInfo *pinMappings = Storage::getInstance().getProfilePinMappings();
bool pinSet = false;
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
switch (pinMappings[pin].action) {
case GpioAction::BUTTON_PRESS_TJ_TOGGLE_1:
case GpioAction::BUTTON_PRESS_TJ_TOGGLE_2:
pinSet = true;
default:
break;
}
}
return options.enabled && pinSet;
}

void ToggleJoystickAddon::setup() {
GpioMappingInfo *pinMappings = Storage::getInstance().getProfilePinMappings();
primaryToggleMask = 0;
secondaryToggleMask = 0;
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
switch (pinMappings[pin].action) {
case GpioAction::BUTTON_PRESS_TJ_TOGGLE_1:
primaryToggleMask = 1 << pin;
break;
case GpioAction::BUTTON_PRESS_TJ_TOGGLE_2:
secondaryToggleMask = 1 << pin;
break;
default:
break;
}
}
const ToggleJoystickOptions &options =
Storage::getInstance().getAddonOptions().toggleJoystickOptions;
primaryToggle = options.primaryToggle;
secondaryToggle = options.secondaryToggle;

Gamepad *gamepad = Storage::getInstance().GetGamepad();
prevLX = gamepad->state.lx;
prevLY = gamepad->state.ly;
prevRX = gamepad->state.rx;
prevRY = gamepad->state.ry;
prevDpad = gamepad->state.dpad;
prev2LX = gamepad->state.lx;
prev2LY = gamepad->state.ly;
prev2RX = gamepad->state.rx;
prev2RY = gamepad->state.ry;
prev2Dpad = gamepad->state.dpad;

defaultDpadMode = gamepad->getOptions().dpadMode;
prevDpadMode = gamepad->getOptions().dpadMode;

primaryToggleState = false;
secondaryToggleState = false;
onStateChange = false;
joystickChanged = false;
holdSecondary = false;
freezeInputs = true;

prevToggleState = 0;
}

void ToggleJoystickAddon::update() {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
Mask_t allPins = gamepad->debouncedGpio;
primaryToggleState = allPins & primaryToggleMask;
secondaryToggleState = allPins & secondaryToggleMask;
}

void ToggleJoystickAddon::reinit() { this->setup(); }

void ToggleJoystickAddon::toggleJoystick(Gamepad *gamepad,
DpadMode currentDpadMode,
DpadMode toggle, bool toggleSwapped,
bool bothStatesHeld) {
// On the first change from default state to primary or secondary state
if (!onStateChange) {
onStateChange = true;
prevDpadMode = currentDpadMode;
defaultDpadMode = currentDpadMode;
joystickChanged = false;
// Save previous inputs
prevLX = gamepad->state.lx;
prevLY = gamepad->state.ly;
prevRX = gamepad->state.rx;
prevRY = gamepad->state.ry;
prevDpad = gamepad->state.dpad;
}
// On change from secondary state to primary and secondary state
else if (toggleSwapped && bothStatesHeld) {
prev2LX = gamepad->state.lx;
prev2LY = gamepad->state.ly;
prev2RX = gamepad->state.rx;
prev2RY = gamepad->state.ry;
prev2Dpad = gamepad->state.dpad;
// hold secondary input if any
holdSecondary =
(secondaryToggle == DPAD_MODE_LEFT_ANALOG &&
(prevLX != prev2LX || prevLY != prev2LY)) ||
(secondaryToggle == DPAD_MODE_RIGHT_ANALOG &&
(prevRX != prev2RX || prevRY != prev2RY)) ||
(secondaryToggle == DPAD_MODE_DIGITAL && (prevDpad != prev2Dpad));
joystickChanged = holdSecondary ? false : joystickChanged;
}
// Release secondary frozen inputs when secondaryToggleState is false
holdSecondary &= bothStatesHeld;
// Only toggle joystick once the joystick has changed direction at least once
if (!joystickChanged &&
// joystick changes from default state
(holdSecondary ||
((prevDpadMode == DPAD_MODE_LEFT_ANALOG &&
(gamepad->state.lx != prevLX || gamepad->state.ly != prevLY)) ||
(prevDpadMode == DPAD_MODE_RIGHT_ANALOG &&
(gamepad->state.rx != prevRX || gamepad->state.ry != prevRY)) ||
(prevDpadMode == DPAD_MODE_DIGITAL &&
(gamepad->state.dpad != prevDpad)))) &&
// joystick changes from secondary state
(!holdSecondary ||
((secondaryToggle == DPAD_MODE_LEFT_ANALOG &&
(gamepad->state.lx != prev2LX || gamepad->state.ly != prev2LY)) ||
(secondaryToggle == DPAD_MODE_RIGHT_ANALOG &&
(gamepad->state.rx != prev2RX || gamepad->state.ry != prev2RY)) ||
(secondaryToggle == DPAD_MODE_DIGITAL &&
(gamepad->state.dpad != prev2Dpad))))) {
joystickChanged = true;
gamepad->setDpadMode(toggle);
}
// If the joystick has changed direction at least once, make sure gamepad
// dpadmode is set to toggle and set defaultDpadMode to currentDpadMode
else if (joystickChanged && currentDpadMode != toggle) {
// When swapping between toggles, prevent the previous toggle from
// overwriting defaultDpadMode
if (!toggleSwapped) {
defaultDpadMode = currentDpadMode;
}
gamepad->setDpadMode(toggle);
}
// If the joystick has not changed direction at least once and the dpad mode
// has changed, change default dpadmode to the new one and set gamepad
// dpadmode to prevDpadMode
if (!joystickChanged && !holdSecondary && currentDpadMode != prevDpadMode) {
defaultDpadMode = currentDpadMode;
gamepad->setDpadMode(prevDpadMode);
} else if (!joystickChanged && holdSecondary &&
currentDpadMode != secondaryToggle) {
defaultDpadMode = currentDpadMode;
gamepad->setDpadMode(secondaryToggle);
}
}

void ToggleJoystickAddon::setPrevJoystick(Gamepad *gamepad, DpadMode toggle) {
if (!freezeInputs)
return;
// Set gamepad to frozen inputs
if (prevDpadMode == DPAD_MODE_LEFT_ANALOG &&
toggle != DPAD_MODE_LEFT_ANALOG) {
gamepad->state.lx = prevLX;
gamepad->state.ly = prevLY;
} else if (prevDpadMode == DPAD_MODE_RIGHT_ANALOG &&
toggle != DPAD_MODE_RIGHT_ANALOG) {
gamepad->state.rx = prevRX;
gamepad->state.ry = prevRY;
} else if (prevDpadMode == DPAD_MODE_DIGITAL && toggle != DPAD_MODE_DIGITAL) {
gamepad->state.dpad = prevDpad;
}
if (!holdSecondary)
return;
if (secondaryToggle == DPAD_MODE_LEFT_ANALOG &&
toggle != DPAD_MODE_LEFT_ANALOG) {
gamepad->state.lx = prev2LX;
gamepad->state.ly = prev2LY;
} else if (secondaryToggle == DPAD_MODE_RIGHT_ANALOG &&
toggle != DPAD_MODE_RIGHT_ANALOG) {
gamepad->state.rx = prev2RX;
gamepad->state.ry = prev2RY;
} else if (secondaryToggle == DPAD_MODE_DIGITAL &&
toggle != DPAD_MODE_DIGITAL) {
gamepad->state.dpad = prev2Dpad;
}
}

void ToggleJoystickAddon::process() {
update();

Gamepad *gamepad = Storage::getInstance().GetGamepad();
DpadMode currentDpadMode = gamepad->getOptions().dpadMode;

if (primaryToggleState) {
toggleJoystick(gamepad, currentDpadMode, primaryToggle,
prevToggleState == 1, secondaryToggleState);
setPrevJoystick(gamepad, primaryToggle);
} else if (secondaryToggleState) {
toggleJoystick(gamepad, currentDpadMode, secondaryToggle,
prevToggleState >= 2, false);
setPrevJoystick(gamepad, secondaryToggle);
// On pin release
} else if (onStateChange) {
onStateChange = false;
gamepad->setDpadMode(defaultDpadMode);
}
prevToggleState = (primaryToggleState << 1) + secondaryToggleState;
}
8 changes: 8 additions & 0 deletions src/config_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "addons/i2canalog1219.h"
#include "addons/display.h"
#include "addons/jslider.h"
#include "addons/togglejoystick.h"
#include "addons/keyboard_host.h"
#include "addons/neopicoleds.h"
#include "addons/playernum.h"
Expand Down Expand Up @@ -573,6 +574,11 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.addonOptions.sliderOptions, deprecatedModeTwo, SLIDER_MODE_TWO);
INIT_UNSET_PROPERTY(config.addonOptions.sliderOptions, modeDefault, SLIDER_MODE_ZERO);

// addonOptions.toggleJoystickOptions
INIT_UNSET_PROPERTY(config.addonOptions.toggleJoystickOptions, enabled, !!TOGGLE_JOYSTICK_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.toggleJoystickOptions, primaryToggle, TOGGLE_JOYSTICK_PRIMARY_TOGGLE);
INIT_UNSET_PROPERTY(config.addonOptions.toggleJoystickOptions, secondaryToggle, TOGGLE_JOYSTICK_SECONDARY_TOGGLE);

// addonOptions.reverseOptions
INIT_UNSET_PROPERTY(config.addonOptions.reverseOptions, enabled, !!REVERSE_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.reverseOptions, buttonPin, (Pin_t)-1);
Expand Down Expand Up @@ -1070,6 +1076,7 @@ void gpioMappingsMigrationCore(Config& config)
markAddonPinIfUsed(peripheralOptions.blockI2C0.sda);

peripheralOptions.blockI2C0.scl = (

isValidPin(config.displayOptions.deprecatedI2cSCLPin) && (config.displayOptions.deprecatedI2cBlock == 0) ?
config.displayOptions.deprecatedI2cSCLPin :
(
Expand All @@ -1086,6 +1093,7 @@ void gpioMappingsMigrationCore(Config& config)

// option configuration
peripheralOptions.blockI2C0.speed = (

isValidPin(config.displayOptions.deprecatedI2cSpeed) && (config.displayOptions.deprecatedI2cBlock == 0) ?
config.displayOptions.deprecatedI2cSpeed :
(
Expand Down
10 changes: 10 additions & 0 deletions src/configs/webconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,11 @@ std::string setAddonOptions()
docToValue(sliderOptions.modeDefault, doc, "sliderModeZero");
docToValue(sliderOptions.enabled, doc, "JSliderInputEnabled");

ToggleJoystickOptions& toggleJoystickOptions = Storage::getInstance().getAddonOptions().toggleJoystickOptions;
docToValue(toggleJoystickOptions.primaryToggle, doc, "toggleJoystickPrimaryToggle");
docToValue(toggleJoystickOptions.secondaryToggle, doc, "toggleJoystickSecondaryToggle");
docToValue(toggleJoystickOptions.enabled, doc, "ToggleJoystickAddonEnabled");

PlayerNumberOptions& playerNumberOptions = Storage::getInstance().getAddonOptions().playerNumberOptions;
docToValue(playerNumberOptions.number, doc, "playerNumber");
docToValue(playerNumberOptions.enabled, doc, "PlayerNumAddonEnabled");
Expand Down Expand Up @@ -1882,6 +1887,11 @@ std::string getAddonOptions()
writeDoc(doc, "sliderModeZero", sliderOptions.modeDefault);
writeDoc(doc, "JSliderInputEnabled", sliderOptions.enabled);

const ToggleJoystickOptions& toggleJoystickOptions = Storage::getInstance().getAddonOptions().toggleJoystickOptions;
writeDoc(doc, "toggleJoystickPrimaryToggle", toggleJoystickOptions.primaryToggle);
writeDoc(doc, "toggleJoystickSecondaryToggle", toggleJoystickOptions.secondaryToggle);
writeDoc(doc, "ToggleJoystickAddonEnabled", toggleJoystickOptions.enabled);

const PlayerNumberOptions& playerNumberOptions = Storage::getInstance().getAddonOptions().playerNumberOptions;
writeDoc(doc, "playerNumber", playerNumberOptions.number);
writeDoc(doc, "PlayerNumAddonEnabled", playerNumberOptions.enabled);
Expand Down
Loading