mirror of
https://github.com/ravinrabbid/DonCon2040.git
synced 2024-11-20 03:37:07 +01:00
Rework Drum to use ADC inputs
This commit is contained in:
parent
43aa53382c
commit
528172c2ca
@ -22,7 +22,7 @@ target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME} PUBLIC tinyusb_device tinyusb_board pico_stdlib
|
||||
${PROJECT_NAME} PUBLIC tinyusb_device tinyusb_board pico_stdlib hardware_adc
|
||||
pico_multicore pio_ws2812)
|
||||
|
||||
pico_enable_stdio_usb(${PROJECT_NAME} 1)
|
||||
|
@ -9,17 +9,14 @@ namespace Doncon::Config::Default {
|
||||
const Peripherals::Drum::Config drum_config = {
|
||||
// Pin config
|
||||
{
|
||||
4, // Don Left Weak
|
||||
3, // Ka Left Weak
|
||||
2, // Don Right Weak
|
||||
1, // Ka Right Weak
|
||||
|
||||
6, // Don Left Strong
|
||||
29, // Ka Left Strong
|
||||
7, // Don Right Strong
|
||||
0, // Ka Right Strong
|
||||
0, // Don Left
|
||||
1, // Ka Left
|
||||
2, // Don Right
|
||||
3, // Ka Right
|
||||
},
|
||||
10, // Debounce delay in milliseconds
|
||||
400, // Trigger threshold
|
||||
100, // Double hit threshold
|
||||
17, // Debounce delay in milliseconds
|
||||
};
|
||||
|
||||
const Peripherals::StatusLed::Config led_config = {
|
||||
|
@ -12,53 +12,46 @@ class Drum {
|
||||
public:
|
||||
struct Config {
|
||||
struct {
|
||||
uint8_t don_left_weak;
|
||||
uint8_t ka_left_weak;
|
||||
uint8_t don_right_weak;
|
||||
uint8_t ka_right_weak;
|
||||
|
||||
uint8_t don_left_strong;
|
||||
uint8_t ka_left_strong;
|
||||
uint8_t don_right_strong;
|
||||
uint8_t ka_right_strong;
|
||||
uint8_t don_left;
|
||||
uint8_t ka_left;
|
||||
uint8_t don_right;
|
||||
uint8_t ka_right;
|
||||
} pins;
|
||||
|
||||
uint8_t debounce_delay_ms;
|
||||
uint16_t trigger_threshold;
|
||||
uint16_t double_hit_threshold;
|
||||
|
||||
uint16_t debounce_delay_ms;
|
||||
};
|
||||
|
||||
private:
|
||||
enum class Id {
|
||||
DON_LEFT_WEAK,
|
||||
KA_LEFT_WEAK,
|
||||
DON_RIGHT_WEAK,
|
||||
KA_RIGHT_WEAK,
|
||||
DON_LEFT_STRONG,
|
||||
KA_LEFT_STRONG,
|
||||
DON_RIGHT_STRONG,
|
||||
KA_RIGHT_STRONG,
|
||||
DON_LEFT,
|
||||
KA_LEFT,
|
||||
DON_RIGHT,
|
||||
KA_RIGHT,
|
||||
};
|
||||
|
||||
class Pad {
|
||||
private:
|
||||
uint8_t gpio_pin;
|
||||
uint32_t gpio_mask;
|
||||
|
||||
uint8_t pin;
|
||||
uint32_t last_change;
|
||||
bool active;
|
||||
|
||||
public:
|
||||
Pad(uint8_t pin);
|
||||
|
||||
uint8_t getGpioPin() const { return gpio_pin; };
|
||||
uint32_t getGpioMask() const { return gpio_mask; };
|
||||
|
||||
uint8_t getPin() const { return pin; };
|
||||
bool getState() const { return active; };
|
||||
void setState(bool state, uint8_t debounce_delay);
|
||||
void setState(bool state, uint16_t debounce_delay);
|
||||
};
|
||||
|
||||
Config m_config;
|
||||
std::map<Id, Pad> m_pads;
|
||||
|
||||
private:
|
||||
std::map<Id, uint16_t> sampleInputs(uint8_t count, uint16_t delay_us);
|
||||
|
||||
public:
|
||||
Drum(const Config &config);
|
||||
|
||||
|
@ -12,7 +12,12 @@ namespace Doncon::Utils {
|
||||
struct InputState {
|
||||
public:
|
||||
struct Drum {
|
||||
bool don_left, ka_left, don_right, ka_right;
|
||||
struct Pad {
|
||||
bool triggered;
|
||||
uint16_t raw;
|
||||
};
|
||||
|
||||
Pad don_left, ka_left, don_right, ka_right;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -1,13 +1,15 @@
|
||||
#include "peripherals/Drum.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/adc.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Doncon::Peripherals {
|
||||
|
||||
Drum::Pad::Pad(uint8_t pin) : gpio_pin(pin), gpio_mask(1 << pin), last_change(0), active(false) {}
|
||||
Drum::Pad::Pad(uint8_t pin) : pin(pin), last_change(0), active(false) {}
|
||||
|
||||
void Drum::Pad::setState(bool state, uint8_t debounce_delay) {
|
||||
void Drum::Pad::setState(bool state, uint16_t debounce_delay) {
|
||||
if (active == state) {
|
||||
return;
|
||||
}
|
||||
@ -21,43 +23,111 @@ void Drum::Pad::setState(bool state, uint8_t debounce_delay) {
|
||||
}
|
||||
|
||||
Drum::Drum(const Config &config) : m_config(config) {
|
||||
m_pads.emplace(Id::DON_LEFT_WEAK, config.pins.don_left_weak);
|
||||
m_pads.emplace(Id::KA_LEFT_WEAK, config.pins.ka_left_weak);
|
||||
m_pads.emplace(Id::DON_RIGHT_WEAK, config.pins.don_right_weak);
|
||||
m_pads.emplace(Id::KA_RIGHT_WEAK, config.pins.ka_right_weak);
|
||||
m_pads.emplace(Id::DON_LEFT_STRONG, config.pins.don_left_strong);
|
||||
m_pads.emplace(Id::KA_LEFT_STRONG, config.pins.ka_left_strong);
|
||||
m_pads.emplace(Id::DON_RIGHT_STRONG, config.pins.don_right_strong);
|
||||
m_pads.emplace(Id::KA_RIGHT_STRONG, config.pins.ka_right_strong);
|
||||
m_pads.emplace(Id::DON_LEFT, config.pins.don_left);
|
||||
m_pads.emplace(Id::KA_LEFT, config.pins.ka_left);
|
||||
m_pads.emplace(Id::DON_RIGHT, config.pins.don_right);
|
||||
m_pads.emplace(Id::KA_RIGHT, config.pins.ka_right);
|
||||
|
||||
for (const auto &button : m_pads) {
|
||||
gpio_init(button.second.getGpioPin());
|
||||
gpio_set_dir(button.second.getGpioPin(), GPIO_IN);
|
||||
gpio_pull_up(button.second.getGpioPin());
|
||||
adc_init();
|
||||
|
||||
for (const auto &pad : m_pads) {
|
||||
adc_gpio_init(pad.second.getPin());
|
||||
}
|
||||
}
|
||||
|
||||
void Drum::updateInputState(Utils::InputState &input_state) {
|
||||
uint32_t gpio_state = ~gpio_get_all();
|
||||
const auto raw_values = sampleInputs(5, 100);
|
||||
|
||||
for (auto &button : m_pads) {
|
||||
button.second.setState(gpio_state & button.second.getGpioMask(), m_config.debounce_delay_ms);
|
||||
for (const auto &val : raw_values) {
|
||||
switch (val.first) {
|
||||
case Id::DON_LEFT:
|
||||
input_state.drum.don_left.raw = val.second;
|
||||
break;
|
||||
case Id::KA_LEFT:
|
||||
input_state.drum.ka_left.raw = val.second;
|
||||
break;
|
||||
case Id::DON_RIGHT:
|
||||
input_state.drum.don_right.raw = val.second;
|
||||
break;
|
||||
case Id::KA_RIGHT:
|
||||
input_state.drum.ka_right.raw = val.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
input_state.drum.don_left = m_pads.at(Id::DON_LEFT_WEAK).getState() || //
|
||||
m_pads.at(Id::DON_LEFT_STRONG).getState() || //
|
||||
m_pads.at(Id::DON_RIGHT_STRONG).getState();
|
||||
auto hardest_hit = *std::max_element(raw_values.begin(), raw_values.end(),
|
||||
[](const auto a, const auto b) { return a.second < b.second; });
|
||||
|
||||
input_state.drum.ka_left = m_pads.at(Id::KA_LEFT_WEAK).getState() || //
|
||||
m_pads.at(Id::KA_LEFT_STRONG).getState() || //
|
||||
m_pads.at(Id::KA_RIGHT_STRONG).getState();
|
||||
if (hardest_hit.second > m_config.trigger_threshold) {
|
||||
m_pads.at(hardest_hit.first).setState(true, m_config.debounce_delay_ms);
|
||||
|
||||
input_state.drum.don_right = m_pads.at(Id::DON_RIGHT_WEAK).getState() || //
|
||||
m_pads.at(Id::DON_LEFT_STRONG).getState() || //
|
||||
m_pads.at(Id::DON_RIGHT_STRONG).getState();
|
||||
auto set_twin = [&](const Id twin) {
|
||||
if ((raw_values.at(twin) > m_config.trigger_threshold) &&
|
||||
std::abs(static_cast<int32_t>(hardest_hit.second) - raw_values.at(twin)) <
|
||||
m_config.double_hit_threshold) {
|
||||
|
||||
input_state.drum.ka_right = m_pads.at(Id::KA_RIGHT_WEAK).getState() || //
|
||||
m_pads.at(Id::KA_LEFT_STRONG).getState() || //
|
||||
m_pads.at(Id::KA_RIGHT_STRONG).getState();
|
||||
m_pads.at(twin).setState(true, m_config.debounce_delay_ms);
|
||||
} else {
|
||||
m_pads.at(twin).setState(false, m_config.debounce_delay_ms);
|
||||
}
|
||||
};
|
||||
|
||||
switch (hardest_hit.first) {
|
||||
case Id::DON_LEFT:
|
||||
set_twin(Id::DON_RIGHT);
|
||||
m_pads.at(Id::KA_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::KA_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
break;
|
||||
case Id::KA_LEFT:
|
||||
set_twin(Id::KA_RIGHT);
|
||||
m_pads.at(Id::DON_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::DON_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
break;
|
||||
case Id::DON_RIGHT:
|
||||
set_twin(Id::DON_LEFT);
|
||||
m_pads.at(Id::KA_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::KA_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
break;
|
||||
case Id::KA_RIGHT:
|
||||
set_twin(Id::KA_LEFT);
|
||||
m_pads.at(Id::DON_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::DON_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
m_pads.at(Id::DON_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::DON_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::KA_LEFT).setState(false, m_config.debounce_delay_ms);
|
||||
m_pads.at(Id::KA_RIGHT).setState(false, m_config.debounce_delay_ms);
|
||||
}
|
||||
|
||||
input_state.drum.don_left.triggered = m_pads.at(Id::DON_LEFT).getState();
|
||||
input_state.drum.ka_left.triggered = m_pads.at(Id::KA_LEFT).getState();
|
||||
input_state.drum.don_right.triggered = m_pads.at(Id::DON_RIGHT).getState();
|
||||
input_state.drum.ka_right.triggered = m_pads.at(Id::KA_RIGHT).getState();
|
||||
}
|
||||
|
||||
std::map<Drum::Id, uint16_t> Drum::sampleInputs(uint8_t count, uint16_t delay_us) {
|
||||
std::map<Id, uint32_t> values;
|
||||
|
||||
delay_us = (delay_us - 8) > 0 ? (delay_us - 8) : 0; // Each sample takes 4 * 2µs
|
||||
|
||||
for (uint8_t sample_number = 0; sample_number < count; ++sample_number) {
|
||||
for (const auto &pad : m_pads) {
|
||||
adc_select_input(pad.second.getPin());
|
||||
values[pad.first] += adc_read();
|
||||
}
|
||||
|
||||
sleep_us(delay_us);
|
||||
}
|
||||
|
||||
// Take average of all samples
|
||||
std::map<Id, uint16_t> result;
|
||||
for (auto &value : values) {
|
||||
result[value.first] = value.second / count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Doncon::Peripherals
|
||||
|
@ -24,25 +24,25 @@ void StatusLed::update() {
|
||||
|
||||
uint8_t num_colors = 0;
|
||||
|
||||
if (m_input_state.drum.don_left) {
|
||||
if (m_input_state.drum.don_left.triggered) {
|
||||
mixed_red += m_config.don_left_color.r;
|
||||
mixed_green += m_config.don_left_color.g;
|
||||
mixed_blue += m_config.don_left_color.b;
|
||||
num_colors++;
|
||||
}
|
||||
if (m_input_state.drum.ka_left) {
|
||||
if (m_input_state.drum.ka_left.triggered) {
|
||||
mixed_red += m_config.ka_left_color.r;
|
||||
mixed_green += m_config.ka_left_color.g;
|
||||
mixed_blue += m_config.ka_left_color.b;
|
||||
num_colors++;
|
||||
}
|
||||
if (m_input_state.drum.don_right) {
|
||||
if (m_input_state.drum.don_right.triggered) {
|
||||
mixed_red += m_config.don_right_color.r;
|
||||
mixed_green += m_config.don_right_color.g;
|
||||
mixed_blue += m_config.don_right_color.b;
|
||||
num_colors++;
|
||||
}
|
||||
if (m_input_state.drum.ka_right) {
|
||||
if (m_input_state.drum.ka_right.triggered) {
|
||||
mixed_red += m_config.ka_right_color.r;
|
||||
mixed_green += m_config.ka_right_color.g;
|
||||
mixed_blue += m_config.ka_right_color.b;
|
||||
|
@ -1,12 +1,13 @@
|
||||
#include "utils/InputState.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace Doncon::Utils {
|
||||
|
||||
InputState::InputState()
|
||||
: drum({false, false, false, false}), m_xinput_report({0x00, sizeof(xinput_report_t), 0, 0, 0, 0, 0, 0, 0, 0, {}}) {
|
||||
}
|
||||
: drum({{false, 0}, {false, 0}, {false, 0}, {false, 0}}),
|
||||
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) {
|
||||
switch (mode) {
|
||||
@ -27,24 +28,24 @@ 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 ? (1 << 1) : 0) // Dpad Down
|
||||
| (drum.ka_left ? (1 << 2) : 0) // Dpad Left
|
||||
| (false ? (1 << 3) : 0) // Dpad Right
|
||||
| (false ? (1 << 4) : 0) // Start
|
||||
| (false ? (1 << 5) : 0) // Select
|
||||
| (false ? (1 << 6) : 0) // L3
|
||||
| (false ? (1 << 7) : 0); // R3
|
||||
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
|
||||
| (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 ? (1 << 4) : 0) // A
|
||||
| (drum.ka_right ? (1 << 5) : 0) // B
|
||||
| (false ? (1 << 6) : 0) // X
|
||||
| (false ? (1 << 7) : 0); // Y
|
||||
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
|
||||
|
||||
m_xinput_report.lt = 0;
|
||||
m_xinput_report.rt = 0;
|
||||
@ -60,11 +61,19 @@ usb_report_t InputState::getXinputReport() {
|
||||
usb_report_t InputState::getDebugReport() {
|
||||
std::stringstream out;
|
||||
|
||||
out << "Ka Left: " << drum.ka_left << " " //
|
||||
<< "Don Left: " << drum.don_left << " " //
|
||||
<< "Don Right: " << drum.don_right << " " //
|
||||
<< "Ka Right: " << drum.ka_right << " " //
|
||||
<< "\r";
|
||||
auto bar = [](uint16_t val) { return std::string(val / 512, '#'); };
|
||||
|
||||
if (drum.don_left.triggered || drum.ka_left.triggered || drum.don_right.triggered || drum.ka_right.triggered) {
|
||||
out << "(" << (drum.ka_left.triggered ? "*" : " ") << "( " //
|
||||
<< std::setw(4) << drum.ka_left.raw << "[" << std::setw(8) << bar(drum.ka_left.raw) << "]" //
|
||||
<< "(" << (drum.don_left.triggered ? "*" : " ") << "| " //
|
||||
<< std::setw(4) << drum.don_left.raw << "[" << std::setw(8) << bar(drum.don_left.raw) << "]" //
|
||||
<< "|" << (drum.don_right.triggered ? "*" : " ") << ") " //
|
||||
<< std::setw(4) << drum.don_right.raw << "[" << std::setw(8) << bar(drum.don_right.raw) << "]" //
|
||||
<< "(" << (drum.ka_right.triggered ? "*" : " ") << "( " << std::setw(4) << drum.ka_right.raw << "[" //
|
||||
<< std::setw(8) << bar(drum.ka_right.raw) << "]" //
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
m_debug_report = out.str();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user