mirror of
https://github.com/ravinrabbid/DonCon2040.git
synced 2025-02-12 00:43:07 +01:00
Add support for additional controller buttons
This commit is contained in:
parent
d1de918629
commit
68457c60fe
@ -22,8 +22,14 @@ target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME} PUBLIC tinyusb_device tinyusb_board pico_stdlib hardware_adc
|
||||
pico_multicore pio_ws2812)
|
||||
${PROJECT_NAME}
|
||||
PUBLIC tinyusb_device
|
||||
tinyusb_board
|
||||
pico_stdlib
|
||||
hardware_adc
|
||||
pico_multicore
|
||||
pio_ws2812
|
||||
mcp23017)
|
||||
|
||||
pico_enable_stdio_usb(${PROJECT_NAME} 1)
|
||||
pico_enable_stdio_uart(${PROJECT_NAME} 0)
|
||||
|
@ -1,9 +1,12 @@
|
||||
#ifndef _GLOBALCONFIGURATION_H_
|
||||
#define _GLOBALCONFIGURATION_H_
|
||||
|
||||
#include "peripherals/Buttons.h"
|
||||
#include "peripherals/Drum.h"
|
||||
#include "peripherals/StatusLed.h"
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
namespace Doncon::Config::Default {
|
||||
|
||||
const Peripherals::Drum::Config drum_config = {
|
||||
@ -19,6 +22,41 @@ const Peripherals::Drum::Config drum_config = {
|
||||
17, // Debounce delay in milliseconds
|
||||
};
|
||||
|
||||
const Peripherals::Buttons::Config button_config = {
|
||||
// I2C config
|
||||
{
|
||||
6, // SDA Pin
|
||||
7, // SCL Pin
|
||||
i2c1, // Block
|
||||
1000000, // Speed
|
||||
0x20, // Address
|
||||
},
|
||||
|
||||
// Pins
|
||||
{{
|
||||
0, // Up
|
||||
1, // Down
|
||||
2, // Left
|
||||
3, // Right
|
||||
},
|
||||
{
|
||||
8, // North
|
||||
9, // East
|
||||
10, // South
|
||||
11, // West
|
||||
|
||||
4, // L
|
||||
12, // R
|
||||
|
||||
13, // Start
|
||||
5, // Select
|
||||
14, // Home
|
||||
6, // Share
|
||||
}},
|
||||
|
||||
20, // Debounce delay in milliseconds
|
||||
};
|
||||
|
||||
const Peripherals::StatusLed::Config led_config = {
|
||||
{255, 0, 0}, // Don Left Color
|
||||
{0, 0, 255}, // Ka Left Color
|
||||
|
110
include/peripherals/Buttons.h
Normal file
110
include/peripherals/Buttons.h
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef _PERIPHERALS_BUTTONS_H_
|
||||
#define _PERIPHERALS_BUTTONS_H_
|
||||
|
||||
#include "utils/InputState.h"
|
||||
|
||||
#include <mcp23017/Mcp23017.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Doncon::Peripherals {
|
||||
|
||||
class Buttons {
|
||||
public:
|
||||
struct Config {
|
||||
|
||||
struct {
|
||||
uint8_t sda_pin;
|
||||
uint8_t scl_pin;
|
||||
i2c_inst_t *block;
|
||||
uint speed_hz;
|
||||
uint8_t address;
|
||||
} i2c;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint8_t up;
|
||||
uint8_t down;
|
||||
uint8_t left;
|
||||
uint8_t right;
|
||||
} dpad;
|
||||
|
||||
struct {
|
||||
uint8_t north;
|
||||
uint8_t east;
|
||||
uint8_t south;
|
||||
uint8_t west;
|
||||
|
||||
uint8_t l;
|
||||
uint8_t r;
|
||||
|
||||
uint8_t start;
|
||||
uint8_t select;
|
||||
uint8_t home;
|
||||
uint8_t share;
|
||||
} buttons;
|
||||
} pins;
|
||||
|
||||
uint8_t debounce_delay_ms;
|
||||
};
|
||||
|
||||
private:
|
||||
enum class Id {
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
NORTH,
|
||||
EAST,
|
||||
SOUTH,
|
||||
WEST,
|
||||
L,
|
||||
R,
|
||||
START,
|
||||
SELECT,
|
||||
HOME,
|
||||
SHARE,
|
||||
};
|
||||
|
||||
class Button {
|
||||
private:
|
||||
uint8_t gpio_pin;
|
||||
uint16_t gpio_mask;
|
||||
|
||||
uint32_t last_change;
|
||||
bool active;
|
||||
|
||||
public:
|
||||
Button(uint8_t pin);
|
||||
|
||||
uint8_t getGpioPin() const { return gpio_pin; };
|
||||
uint16_t getGpioMask() const { return gpio_mask; };
|
||||
|
||||
bool getState() const { return active; };
|
||||
void setState(bool state, uint8_t debounce_delay);
|
||||
};
|
||||
|
||||
struct SocdState {
|
||||
Id lastVertical;
|
||||
Id lastHorizontal;
|
||||
};
|
||||
|
||||
Config m_config;
|
||||
SocdState m_socd_state;
|
||||
std::map<Id, Button> m_buttons;
|
||||
|
||||
std::unique_ptr<Mcp23017> m_mcp23017;
|
||||
|
||||
void socdClean(Utils::InputState &input_state);
|
||||
|
||||
public:
|
||||
Buttons(const Config &config);
|
||||
|
||||
void updateInputState(Utils::InputState &input_state);
|
||||
};
|
||||
|
||||
} // namespace Doncon::Peripherals
|
||||
|
||||
#endif // _PERIPHERALS_BUTTONS_H_
|
@ -20,8 +20,20 @@ struct InputState {
|
||||
Pad don_left, ka_left, don_right, ka_right;
|
||||
};
|
||||
|
||||
struct DPad {
|
||||
bool up, down, left, right;
|
||||
};
|
||||
|
||||
struct Buttons {
|
||||
bool north, east, south, west;
|
||||
bool l, r;
|
||||
bool start, select, home, share;
|
||||
};
|
||||
|
||||
public:
|
||||
Drum drum;
|
||||
DPad dpad;
|
||||
Buttons buttons;
|
||||
|
||||
private:
|
||||
xinput_report_t m_xinput_report;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "peripherals/Buttons.h"
|
||||
#include "peripherals/Drum.h"
|
||||
#include "peripherals/StatusLed.h"
|
||||
#include "usb/usb_driver.h"
|
||||
@ -36,6 +37,7 @@ int main() {
|
||||
|
||||
Utils::InputState input_state;
|
||||
Peripherals::Drum drum(Config::Default::drum_config);
|
||||
Peripherals::Buttons buttons(Config::Default::button_config); // Move to core 1?
|
||||
usb_mode_t mode = USB_MODE_XBOX360;
|
||||
|
||||
usb_driver_init(mode);
|
||||
@ -46,6 +48,7 @@ int main() {
|
||||
|
||||
while (true) {
|
||||
drum.updateInputState(input_state);
|
||||
buttons.updateInputState(input_state);
|
||||
|
||||
usb_driver_send_and_receive_report(input_state.getReport(mode));
|
||||
usb_driver_task();
|
||||
|
102
src/peripherals/Buttons.cpp
Normal file
102
src/peripherals/Buttons.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include "peripherals/Buttons.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
namespace Doncon::Peripherals {
|
||||
|
||||
Buttons::Button::Button(uint8_t pin) : gpio_pin(pin), gpio_mask(1 << pin), last_change(0), active(false) {}
|
||||
|
||||
void Buttons::Button::setState(bool state, uint8_t debounce_delay) {
|
||||
if (active == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Immediately change the input state, but only allow a change every debounce_delay milliseconds.
|
||||
uint32_t now = to_ms_since_boot(get_absolute_time());
|
||||
if (last_change + debounce_delay <= now) {
|
||||
active = state;
|
||||
last_change = now;
|
||||
}
|
||||
}
|
||||
|
||||
void Buttons::socdClean(Utils::InputState &input_state) {
|
||||
|
||||
// Last input has priority
|
||||
if (input_state.dpad.up && input_state.dpad.down) {
|
||||
if (m_socd_state.lastVertical == Id::DOWN) {
|
||||
input_state.dpad.down = false;
|
||||
} else if (m_socd_state.lastVertical == Id::UP) {
|
||||
input_state.dpad.up = false;
|
||||
}
|
||||
} else if (input_state.dpad.up) {
|
||||
m_socd_state.lastVertical = Id::UP;
|
||||
} else {
|
||||
m_socd_state.lastVertical = Id::DOWN;
|
||||
}
|
||||
|
||||
if (input_state.dpad.left && input_state.dpad.right) {
|
||||
if (m_socd_state.lastHorizontal == Id::RIGHT) {
|
||||
input_state.dpad.right = false;
|
||||
} else if (m_socd_state.lastHorizontal == Id::LEFT) {
|
||||
input_state.dpad.left = false;
|
||||
}
|
||||
} else if (input_state.dpad.left) {
|
||||
m_socd_state.lastHorizontal = Id::LEFT;
|
||||
} else {
|
||||
m_socd_state.lastHorizontal = Id::RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
Buttons::Buttons(const Config &config) : m_config(config), m_socd_state{Id::DOWN, Id::RIGHT} {
|
||||
i2c_init(m_config.i2c.block, m_config.i2c.speed_hz);
|
||||
gpio_set_function(m_config.i2c.sda_pin, GPIO_FUNC_I2C);
|
||||
gpio_set_function(m_config.i2c.scl_pin, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(m_config.i2c.sda_pin);
|
||||
gpio_pull_up(m_config.i2c.scl_pin);
|
||||
|
||||
m_mcp23017 = std::make_unique<Mcp23017>(m_config.i2c.address, m_config.i2c.block);
|
||||
m_mcp23017->setDirection(0xFFFF); // All inputs
|
||||
m_mcp23017->setPullup(0xFFFF); // All on
|
||||
|
||||
m_buttons.emplace(Id::UP, config.pins.dpad.up);
|
||||
m_buttons.emplace(Id::DOWN, config.pins.dpad.down);
|
||||
m_buttons.emplace(Id::LEFT, config.pins.dpad.left);
|
||||
m_buttons.emplace(Id::RIGHT, config.pins.dpad.right);
|
||||
m_buttons.emplace(Id::NORTH, config.pins.buttons.north);
|
||||
m_buttons.emplace(Id::EAST, config.pins.buttons.east);
|
||||
m_buttons.emplace(Id::SOUTH, config.pins.buttons.south);
|
||||
m_buttons.emplace(Id::WEST, config.pins.buttons.west);
|
||||
m_buttons.emplace(Id::L, config.pins.buttons.l);
|
||||
m_buttons.emplace(Id::R, config.pins.buttons.r);
|
||||
m_buttons.emplace(Id::START, config.pins.buttons.start);
|
||||
m_buttons.emplace(Id::SELECT, config.pins.buttons.select);
|
||||
m_buttons.emplace(Id::HOME, config.pins.buttons.home);
|
||||
m_buttons.emplace(Id::SHARE, config.pins.buttons.share);
|
||||
}
|
||||
|
||||
void Buttons::updateInputState(Utils::InputState &input_state) {
|
||||
uint16_t gpio_state = ~m_mcp23017->read();
|
||||
|
||||
for (auto &button : m_buttons) {
|
||||
button.second.setState(gpio_state & button.second.getGpioMask(), m_config.debounce_delay_ms);
|
||||
}
|
||||
|
||||
input_state.dpad.up = m_buttons.at(Id::UP).getState();
|
||||
input_state.dpad.down = m_buttons.at(Id::DOWN).getState();
|
||||
input_state.dpad.left = m_buttons.at(Id::LEFT).getState();
|
||||
input_state.dpad.right = m_buttons.at(Id::RIGHT).getState();
|
||||
input_state.buttons.north = m_buttons.at(Id::NORTH).getState();
|
||||
input_state.buttons.east = m_buttons.at(Id::EAST).getState();
|
||||
input_state.buttons.south = m_buttons.at(Id::SOUTH).getState();
|
||||
input_state.buttons.west = m_buttons.at(Id::WEST).getState();
|
||||
input_state.buttons.l = m_buttons.at(Id::L).getState();
|
||||
input_state.buttons.r = m_buttons.at(Id::R).getState();
|
||||
input_state.buttons.start = m_buttons.at(Id::START).getState();
|
||||
input_state.buttons.select = m_buttons.at(Id::SELECT).getState();
|
||||
input_state.buttons.home = m_buttons.at(Id::HOME).getState();
|
||||
input_state.buttons.share = m_buttons.at(Id::SHARE).getState();
|
||||
|
||||
socdClean(input_state);
|
||||
}
|
||||
} // namespace Doncon::Peripherals
|
@ -6,7 +6,8 @@
|
||||
namespace Doncon::Utils {
|
||||
|
||||
InputState::InputState()
|
||||
: drum({{false, 0}, {false, 0}, {false, 0}, {false, 0}}),
|
||||
: drum({{false, 0}, {false, 0}, {false, 0}, {false, 0}}), dpad({false, false, false, false}),
|
||||
buttons({false, false, false, false, false, false, false, false, false, false}),
|
||||
m_xinput_report({0x00, sizeof(xinput_report_t), 0, 0, 0, 0, 0, 0, 0, 0, {}}) {}
|
||||
|
||||
usb_report_t InputState::getReport(usb_mode_t mode) {
|
||||
@ -29,23 +30,23 @@ usb_report_t InputState::getReport(usb_mode_t mode) {
|
||||
|
||||
usb_report_t InputState::getXinputReport() {
|
||||
m_xinput_report.buttons1 = 0 //
|
||||
| (false ? (1 << 0) : 0) // Dpad Up
|
||||
| (drum.don_left.triggered ? (1 << 1) : 0) // Dpad Down
|
||||
| (drum.ka_left.triggered ? (1 << 2) : 0) // Dpad Left
|
||||
| (false ? (1 << 3) : 0) // Dpad Right
|
||||
| (false ? (1 << 4) : 0) // Start
|
||||
| (false ? (1 << 5) : 0) // Select
|
||||
| (dpad.up ? (1 << 0) : 0) // Dpad Up
|
||||
| ((dpad.down || drum.don_left.triggered) ? (1 << 1) : 0) // Dpad Down
|
||||
| ((dpad.left || drum.ka_left.triggered) ? (1 << 2) : 0) // Dpad Left
|
||||
| (dpad.right ? (1 << 3) : 0) // Dpad Right
|
||||
| (buttons.start ? (1 << 4) : 0) // Start
|
||||
| (buttons.select ? (1 << 5) : 0) // Select
|
||||
| (false ? (1 << 6) : 0) // L3
|
||||
| (false ? (1 << 7) : 0); // R3
|
||||
|
||||
m_xinput_report.buttons2 = 0 //
|
||||
| (false ? (1 << 0) : 0) // L1
|
||||
| (false ? (1 << 1) : 0) // R1
|
||||
| (false ? (1 << 2) : 0) // Guide
|
||||
| (drum.don_right.triggered ? (1 << 4) : 0) // A
|
||||
| (drum.ka_right.triggered ? (1 << 5) : 0) // B
|
||||
| (false ? (1 << 6) : 0) // X
|
||||
| (false ? (1 << 7) : 0); // Y
|
||||
| (buttons.l ? (1 << 0) : 0) // L1
|
||||
| (buttons.r ? (1 << 1) : 0) // R1
|
||||
| (buttons.home ? (1 << 2) : 0) // Guide
|
||||
| ((buttons.south || drum.don_right.triggered) ? (1 << 4) : 0) // A
|
||||
| ((buttons.east || drum.ka_right.triggered) ? (1 << 5) : 0) // B
|
||||
| (buttons.west ? (1 << 6) : 0) // X
|
||||
| (buttons.north ? (1 << 7) : 0); // Y
|
||||
|
||||
m_xinput_report.lt = 0;
|
||||
m_xinput_report.rt = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user