Skip to content
Closed
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 @@ -121,6 +121,7 @@ src/addons/playernum.cpp
src/addons/playerleds.cpp
src/addons/ps4mode.cpp
src/addons/reverse.cpp
src/addons/sidewindergp.cpp
src/addons/turbo.cpp
src/addons/slider_socd.cpp
src/addons/wiiext.cpp
Expand Down
Binary file added docs/assets/images/gpc-add-ons-sidewindergp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/web-configurator.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,37 @@ Classic Controller support includes Classic, Classic Pro, and NES/SNES Mini Cont

Original Classic Controller L & R triggers are analog sensitive, where Pro triggers are not.

### Sidewinder Gamepad

![GP2040 Configurator - Sidewinder Gamepad](assets/images/gpc-add-ons-sidewindergp.png)

Designed to be mapped on DA-15 gameport of the Sidewinder Gamepad.

Connections:

- DA-15 pins 1, 8, 9, 15 to +5V
- DA-15 pins 4, 5, 12 to GND
- DA-15 pin 2 to Clock pin
- DA-15 pin 3 to Trigger pin
- DA-15 pin 7 to Data pin

Mapping is a follows:

| Sidewinder GP | GP2040-CE |
|---------------|-----------|
| D-Pad | Analog |
| A | B1 |
| B | B2 |
| C | L3 |
| X | B3 |
| Y | B4 |
| Z | R3 |
| LT | L1 |
| RT | R1 |
| Start | S2 |
| M | S1 |


## Data Backup and Restoration

![GP2040-CE Configurator - Add-Ons Backup and Restore](assets/images/gpc-backup-and-restore.png)
Expand Down
43 changes: 43 additions & 0 deletions headers/addons/sidewindergp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef _SidewinderGP_H
#define _SidewinderGP_H

#include "gpaddon.h"

#include "GamepadEnums.h"

#include "BoardConfig.h"

#ifndef SIDEWINDERGP_INPUT_ENABLED
#define SIDEWINDERGP_INPUT_ENABLED 0
#endif

#ifndef SIDEWINDERGP_PIN_TRIGGER
#define SIDEWINDERGP_PIN_TRIGGER -1
#endif

#ifndef SIDEWINDERGP_PIN_CLOCK
#define SIDEWINDERGP_PIN_CLOCK -1
#endif

#ifndef SIDEWINDERGP_PIN_DATA
#define SIDEWINDERGP_PIN_DATA -1
#endif


// SidewinderGP Module Name
#define SideWinderGPName "Sidewinder Gamepad"

class SidewinderGPInput : public GPAddon {
public:
virtual bool available();
virtual void setup(); // Setup
virtual void process(); // Process
virtual void preprocess() {}
virtual std::string name() { return SideWinderGPName; }
private:
uint8_t sidewinderGPPinTrigger;
uint8_t sidewinderGPPinClock;
uint8_t sidewinderGPPinData;
};

#endif // _SidewinderGP_H_
1 change: 1 addition & 0 deletions headers/configs/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/

#include <string>
#include <stdint.h>

class Base64 {
public:
Expand Down
4 changes: 4 additions & 0 deletions headers/storagemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ struct AddonOptions {
uint8_t wiiExtensionSCLPin;
int wiiExtensionBlock;
uint32_t wiiExtensionSpeed;
uint8_t sidewinderGPPinTrigger;
uint8_t sidewinderGPPinClock;
uint8_t sidewinderGPPinData;
uint8_t AnalogInputEnabled;
uint8_t BoardLedAddonEnabled;
uint8_t BootselButtonAddonEnabled;
Expand All @@ -161,6 +164,7 @@ struct AddonOptions {
uint8_t TurboInputEnabled;
uint8_t SliderSOCDInputEnabled;
uint8_t WiiExtensionAddonEnabled;
uint8_t SidewinderGPEnabled;
uint32_t checksum;
};

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


uint32_t SidewinderGPInputMapping[14] = {
GAMEPAD_MASK_DU,
GAMEPAD_MASK_DD,
GAMEPAD_MASK_DR,
GAMEPAD_MASK_DL,
GAMEPAD_MASK_B1,
GAMEPAD_MASK_B2,
GAMEPAD_MASK_L3,
GAMEPAD_MASK_B3,
GAMEPAD_MASK_B4,
GAMEPAD_MASK_R3,
GAMEPAD_MASK_L1,
GAMEPAD_MASK_R1,
GAMEPAD_MASK_S2,
GAMEPAD_MASK_S1
};

bool SidewinderGPInput::available() {
const AddonOptions& options = Storage::getInstance().getAddonOptions();
sidewinderGPPinTrigger = Storage::getInstance().getAddonOptions().sidewinderGPPinTrigger;
sidewinderGPPinClock = Storage::getInstance().getAddonOptions().sidewinderGPPinClock;
sidewinderGPPinData = Storage::getInstance().getAddonOptions().sidewinderGPPinData;
return options.SidewinderGPEnabled;
}

void SidewinderGPInput::setup() {
gpio_init(sidewinderGPPinTrigger);
gpio_set_dir(sidewinderGPPinTrigger, GPIO_OUT);
gpio_put(sidewinderGPPinTrigger, 1);

gpio_init(sidewinderGPPinClock);
gpio_set_dir(sidewinderGPPinClock, GPIO_IN);
gpio_pull_up(sidewinderGPPinClock);

gpio_init(sidewinderGPPinData);
gpio_set_dir(sidewinderGPPinData, GPIO_IN);
gpio_pull_up(sidewinderGPPinData);
}

void SidewinderGPInput::process()
{
Gamepad * gamepad = Storage::getInstance().GetGamepad();

gpio_put(sidewinderGPPinTrigger, 0);
sleep_us(225);
gpio_put(sidewinderGPPinTrigger, 1);

bool btns[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool checksum = 0;
bool ok = 0;

for (int i=0; i < 15; i++) {
// Wait for clock falling edge
uint16_t timeout = 10000;
while (timeout-- && !gpio_get(sidewinderGPPinClock)) {}
while (timeout-- && gpio_get(sidewinderGPPinClock)) {}
if (!timeout)
break;
if (i < 14) {
btns[i] = !gpio_get(sidewinderGPPinData);
checksum ^= btns[i];
} else {
ok = (checksum == gpio_get(sidewinderGPPinData));
}
}
if (!ok)
return;

gamepad->state.lx = 0x8000;
gamepad->state.ly = 0x8000;
for (int i=0; i < 14; i++) {
if (!btns[i])
continue;
uint32_t btnMap = SidewinderGPInputMapping[i];
if (btnMap > (GAMEPAD_MASK_A2)) {
switch (btnMap) {
case (GAMEPAD_MASK_DU):
gamepad->state.ly = 0x0;
break;
case (GAMEPAD_MASK_DD):
gamepad->state.ly = 0xffff;
break;
case (GAMEPAD_MASK_DL):
gamepad->state.lx = 0x0;
break;
case (GAMEPAD_MASK_DR):
gamepad->state.lx = 0xffff;
break;
}
}
else gamepad->state.buttons |= btnMap;
}
}
8 changes: 8 additions & 0 deletions src/configs/webconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,9 @@ std::string setAddonOptions()
docToPin(addonOptions.wiiExtensionSDAPin, doc, "wiiExtensionSDAPin");
docToPin(addonOptions.wiiExtensionSCLPin, doc, "wiiExtensionSCLPin");
docToValue(addonOptions.wiiExtensionBlock, doc, "wiiExtensionBlock");
docToPin(addonOptions.sidewinderGPPinTrigger, doc, "sidewinderGPPinTrigger");
docToPin(addonOptions.sidewinderGPPinClock, doc, "sidewinderGPPinClock");
docToPin(addonOptions.sidewinderGPPinData, doc, "sidewinderGPPinData");
docToValue(addonOptions.wiiExtensionSpeed, doc, "wiiExtensionSpeed");
docToValue(addonOptions.AnalogInputEnabled, doc, "AnalogInputEnabled");
docToValue(addonOptions.BoardLedAddonEnabled, doc, "BoardLedAddonEnabled");
Expand All @@ -841,6 +844,7 @@ std::string setAddonOptions()
docToValue(addonOptions.ReverseInputEnabled, doc, "ReverseInputEnabled");
docToValue(addonOptions.TurboInputEnabled, doc, "TurboInputEnabled");
docToValue(addonOptions.WiiExtensionAddonEnabled, doc, "WiiExtensionAddonEnabled");
docToValue(addonOptions.SidewinderGPEnabled, doc, "SidewinderGPEnabled");

Storage::getInstance().setAddonOptions(addonOptions);

Expand Down Expand Up @@ -1002,6 +1006,9 @@ std::string getAddonOptions()
writeDoc(doc, "wiiExtensionSCLPin", addonOptions.wiiExtensionSCLPin == 0xFF ? -1 : addonOptions.wiiExtensionSCLPin);
writeDoc(doc, "wiiExtensionBlock", addonOptions.wiiExtensionBlock);
writeDoc(doc, "wiiExtensionSpeed", addonOptions.wiiExtensionSpeed);
writeDoc(doc, "sidewinderGPPinTrigger", addonOptions.sidewinderGPPinTrigger == 0xFF ? -1 : addonOptions.sidewinderGPPinTrigger);
writeDoc(doc, "sidewinderGPPinClock", addonOptions.sidewinderGPPinClock == 0xFF ? -1 : addonOptions.sidewinderGPPinClock);
writeDoc(doc, "sidewinderGPPinData", addonOptions.sidewinderGPPinData == 0xFF ? -1 : addonOptions.sidewinderGPPinData);
writeDoc(doc, "AnalogInputEnabled", addonOptions.AnalogInputEnabled);
writeDoc(doc, "BoardLedAddonEnabled", addonOptions.BoardLedAddonEnabled);
writeDoc(doc, "BuzzerSpeakerAddonEnabled", addonOptions.BuzzerSpeakerAddonEnabled);
Expand All @@ -1016,6 +1023,7 @@ std::string getAddonOptions()
writeDoc(doc, "ReverseInputEnabled", addonOptions.ReverseInputEnabled);
writeDoc(doc, "TurboInputEnabled", addonOptions.TurboInputEnabled);
writeDoc(doc, "WiiExtensionAddonEnabled", addonOptions.WiiExtensionAddonEnabled);
writeDoc(doc, "SidewinderGPEnabled", addonOptions.SidewinderGPEnabled);

return serialize_json(doc);
}
Expand Down
2 changes: 2 additions & 0 deletions src/gp2040.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "addons/turbo.h"
#include "addons/slider_socd.h"
#include "addons/wiiext.h"
#include "addons/sidewindergp.h"

// Pico includes
#include "pico/bootrom.h"
Expand Down Expand Up @@ -108,6 +109,7 @@ void GP2040::setup() {
addons.LoadAddon(new WiiExtensionInput(), CORE0_INPUT);
addons.LoadAddon(new PlayerNumAddon(), CORE0_USBREPORT);
addons.LoadAddon(new SliderSOCDInput(), CORE0_INPUT);
addons.LoadAddon(new SidewinderGPInput(), CORE0_INPUT);
}

void GP2040::run() {
Expand Down
5 changes: 5 additions & 0 deletions src/storagemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "addons/pleds.h"
#include "addons/reverse.h"
#include "addons/turbo.h"
#include "addons/sidewindergp.h"
#include "addons/slider_socd.h"
#include "addons/wiiext.h"

Expand Down Expand Up @@ -200,6 +201,9 @@ void Storage::setDefaultAddonOptions()
addonOptions.wiiExtensionSCLPin = WII_EXTENSION_I2C_SCL_PIN;
addonOptions.wiiExtensionBlock = (WII_EXTENSION_I2C_BLOCK == i2c0) ? 0 : 1;
addonOptions.wiiExtensionSpeed = WII_EXTENSION_I2C_SPEED;
addonOptions.sidewinderGPPinTrigger = SIDEWINDERGP_PIN_TRIGGER;
addonOptions.sidewinderGPPinClock = SIDEWINDERGP_PIN_CLOCK;
addonOptions.sidewinderGPPinData = SIDEWINDERGP_PIN_DATA;
addonOptions.AnalogInputEnabled = ANALOG_INPUT_ENABLED;
addonOptions.BoardLedAddonEnabled = BOARD_LED_ENABLED;
addonOptions.BootselButtonAddonEnabled = BOOTSEL_BUTTON_ENABLED;
Expand All @@ -214,6 +218,7 @@ void Storage::setDefaultAddonOptions()
addonOptions.ReverseInputEnabled = REVERSE_ENABLED;
addonOptions.TurboInputEnabled = TURBO_ENABLED;
addonOptions.WiiExtensionAddonEnabled = WII_EXTENSION_ENABLED;
addonOptions.SidewinderGPEnabled = SIDEWINDERGP_INPUT_ENABLED;
setAddonOptions(addonOptions);
}

Expand Down
4 changes: 4 additions & 0 deletions www/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ app.get("/api/getAddonsOptions", (req, res) => {
wiiExtensionSCLPin: -1,
wiiExtensionBlock: 0,
wiiExtensionSpeed: 400000,
sidewinderGPPinTrigger: -1,
sidewinderGPPinClock: -1,
sidewinderGPPinData: -1,
AnalogInputEnabled: 1,
BoardLedAddonEnabled: 1,
BuzzerSpeakerAddonEnabled: 1,
Expand All @@ -237,6 +240,7 @@ app.get("/api/getAddonsOptions", (req, res) => {
SliderSOCDInputEnabled: 1,
TurboInputEnabled: 1,
WiiExtensionAddonEnabled: 1,
SidewinderGPEnabled: 1,
usedPins: Object.values(picoController),
});
});
Expand Down
Loading