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

SNES Controller Input Support #252

Merged
merged 4 commits into from
May 25, 2023
Merged
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ src/addons/reverse.cpp
src/addons/turbo.cpp
src/addons/slider_socd.cpp
src/addons/wiiext.cpp
src/addons/snes_input.cpp
src/gamepad/GamepadDebouncer.cpp
src/gamepad/GamepadDescriptors.cpp
)
Expand All @@ -147,6 +148,7 @@ ArduinoJson
rndis
hardware_adc
WiiExtension
SNESpad
pico_mbedtls
TinyUSB_Gamepad
)
Expand Down
8 changes: 8 additions & 0 deletions configs/KB2040/BoardConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,12 @@
#define HOTKEY_F2_RIGHT_MASK GAMEPAD_MASK_RIGHT
#define HOTKEY_F2_RIGHT_ACTION HOTKEY_INVERT_Y_AXIS

// SNESpad Settings
// Basic SNES controller clock, latch(strobe), and data IO: https://github.com/gilligan/snesdev/blob/master/docs/fullsnes.txt#L16048
// CLOCK == SNES_CTRL_PIN_2, LATCH == SNES_CTRL_PIN_3, and DATA = SNES_CTRL_PIN_4
#define SNES_PAD_ENABLED 0
#define SNES_PAD_CLOCK_PIN -1
#define SNES_PAD_LATCH_PIN -1
#define SNES_PAD_DATA_PIN -1

#endif
Binary file added docs/assets/images/gpc-add-ons-snespad-input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions docs/web-configurator.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,32 @@ 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.

### SNES Input

![GP2040 Configurator - SNES Input](assets/images/gpc-add-ons-snespad-input.png)

* `CLOCK Pin` - The GPIO pin used for SNES CLOCK.
* `LATCH Pin` - The GPIO pin used for SNES LATCH.
* `DATA Pin` - The GPIO pin used for SNES DATA.

Supported controller types and their mapping is as follows:

| GP2040-CE | NES | SNES | Super NES Mouse |
|-----------|----------|--------------|--------------------|
| B1 | B | B | Left Click |
| B2 | A | A | Right Click |
| B3 | | Y | |
| B4 | | X | |
| L1 | | L | |
| L2 | | | |
| R1 | | R | |
| R2 | | | |
| S1 | Select | Select | |
| S2 | Start | Start | |
| A1 | | | |
| D-Pad | D-Pad | D-Pad | |
| Analog | | | Mouse Movement |

## Data Backup and Restoration

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

#include <string>
#include <stdint.h>
#include "BoardConfig.h"
#include "gpaddon.h"
#include "gamepad.h"
#include "storagemanager.h"
#include "SNESpad.h"

// SNESpad Module Name
#define SNESpadName "SNESpad"

#ifndef SNES_PAD_ENABLED
#define SNES_PAD_ENABLED 0
#endif

#ifndef SNES_PAD_LATCH_PIN
#define SNES_PAD_LATCH_PIN -1
#endif

#ifndef SNES_PAD_CLOCK_PIN
#define SNES_PAD_CLOCK_PIN -1
#endif

#ifndef SNES_PAD_DATA_PIN
#define SNES_PAD_DATA_PIN -1
#endif

class SNESpadInput : public GPAddon {
public:
virtual bool available();
virtual void setup(); // SNESpad Setup
virtual void process(); // SNESpad Process
virtual void preprocess() {}
virtual std::string name() { return SNESpadName; }
private:
SNESpad * snes;
uint32_t uIntervalMS;
uint32_t nextTimer;

bool buttonA = false;
bool buttonB = false;
bool buttonX = false;
bool buttonY = false;
bool buttonL = false;
bool buttonR = false;

bool buttonSelect = false;
bool buttonStart = false;

bool dpadUp = false;
bool dpadDown = false;
bool dpadLeft = false;
bool dpadRight = false;

uint16_t leftX = 0;
uint16_t leftY = 0;
uint16_t rightX = 0;
uint16_t rightY = 0;

uint16_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max);
};

#endif // _SNESpadAddon_H
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 snesPadLatchPin;
uint8_t snesPadClockPin;
uint8_t snesPadDataPin;
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 SNESpadAddonEnabled;
uint32_t checksum;
};

Expand Down
3 changes: 2 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ add_subdirectory(OneBitDisplay)
add_subdirectory(PlayerLEDs)
add_subdirectory(rndis)
add_subdirectory(TinyUSB_Gamepad)
add_subdirectory(WiiExtension)
add_subdirectory(WiiExtension)
add_subdirectory(SNESpad)
6 changes: 6 additions & 0 deletions lib/SNESpad/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_library(SNESpad SNESpad.cpp)
target_link_libraries(SNESpad PUBLIC pico_stdlib)
target_include_directories(SNESpad INTERFACE .)
target_include_directories(SNESpad PUBLIC
pico_stdlib
)
121 changes: 121 additions & 0 deletions lib/SNESpad/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# SNESpad for Arduino and PicoSDK

This is a library for the Raspberry Pi Pico that allows it to interface with a SNES controller. This library was adapted from the Arduino SNESpad library, with changes and optimizations made for better performance and compatibility with the Pico SDK.

## Original Library

This library is based on the [nespad](https://github.com/rahji/nespad) library developed by rahji. The original library was designed for the Arduino platform.

## Features

This library allows for the reading of button states from a SNES controller connected to a Pico or Arduino. It supports standard SNES controller, the NES controller, and the SNES Mouse. Each of these devices can be identified and read by this library.

## Usage

1. Include the SNESpad.h header in your program.
2. Create a SNESpad object, specifying the clock, latch, and data pin numbers.
3. Use the `begin()` and `start()` function to initialize the SNESpad.
4. Use the `poll()` function to update the state of the SNESpad.
5. You can then read the state of the buttons and the direction pad using the appropriate members of the SNESpad class.

## Button Variables

Here are the members of the SNESpad class that hold the state of the buttons:

- `buttonA`
- `buttonB`
- `buttonX`
- `buttonY`
- `buttonStart`
- `buttonSelect`
- `buttonL`
- `buttonR`
- `directionUp`
- `directionDown`
- `directionLeft`
- `directionRight`

For the SNES Mouse, these additional variables are available:

- `mouseX`
- `mouseY`

## Example

Here is an example of how to create a SNESpad object and read the state of the buttons:

```cpp
#include "SNESpad.h"

#define CLOCK 0
#define LATCH 1
#define DATA 2

SNESpad snespad(CLOCK, LATCH, DATA);

void setup() {
snespad.begin();
snespad.start();
}

void loop() {
snespad.poll();

if (snespad.buttonA) {
printf("Button A is pressed.\n");
}

if (snespad.buttonB) {
printf("Button B is pressed.\n");
}

// Add more button checks as needed.
}
```

This example will print a message to the console whenever button A or B is pressed.

## Author

This library was ported and substantially rewritten by Robert Dale Smith.

Email: <[email protected]>

## Examples

Included in this repository are three examples that demonstrate different use cases for the SNESpad library.

1. [serial.ino](examples/serial/serial.ino) - Demonstrates how to use the SNESpad library to monitor a SNES controller over a USB serial connection.

2. [hid.ino](examples/hid/hid.ino) - Demonstrates how to use the SNESpad library to create HID mouse and HID joystick USB devices using a SNES controller.

3. [xinput.ino](examples/xinput/xinput.ino) - Demonstrates how to use the SNESpad library to create an XInput USB controller using a SNES controller or mouse.

## Changes and Enhancements

This version of the library is optimized for performance and compatibility. Notable changes from the original Arduino version include:

- The control polling methods have been optimized to closely match the specifications of the original console.
- Added support for the Super Nintendo mouse and the original NES controllers.

## Version History

- Version: 2.0 (2023)
- Extended to Pico SDK (Robert Dale Smith)
- Total refactor of class structure. (Robert Dale Smith)
- Mouse and NES controller support (Robert Dale Smith)

Below is a history of the original SNESpad library:

- Version: 1.3 (11/12/2010) - Removed shortcut constructor which was causing issues.
- Version: 1.2 (05/25/2009) - Put pin numbers in constructor (Pascal Hahn)
- Version: 1.1 (09/22/2008) - Fixed compilation errors in Arduino 0012 (Rob Duarte)
- Version: 1.0 (09/20/2007) - Created (Rob Duarte)

## License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
Loading