mirror of
https://github.com/whowechina/mai_pico.git
synced 2025-01-19 01:34:03 +01:00
Suppress nkro when button stuck
This commit is contained in:
parent
bbd2ff3472
commit
ed44780cb2
Binary file not shown.
@ -1,97 +1,107 @@
|
||||
/*
|
||||
* Mai Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "button.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/timer.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "board_defs.h"
|
||||
|
||||
static const uint8_t gpio_def[] = BUTTON_DEF;
|
||||
static uint8_t gpio_real[] = BUTTON_DEF;
|
||||
|
||||
#define BUTTON_NUM (sizeof(gpio_def))
|
||||
|
||||
static bool sw_val[BUTTON_NUM]; /* true if pressed */
|
||||
static uint64_t sw_freeze_time[BUTTON_NUM];
|
||||
|
||||
void button_init()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_NUM; i++)
|
||||
{
|
||||
sw_val[i] = false;
|
||||
sw_freeze_time[i] = 0;
|
||||
uint8_t gpio = mai_cfg->alt.buttons[i];
|
||||
if (gpio > 29) {
|
||||
gpio = gpio_def[i];
|
||||
}
|
||||
gpio_real[i] = gpio;
|
||||
gpio_init(gpio);
|
||||
gpio_set_function(gpio, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(gpio, GPIO_IN);
|
||||
gpio_pull_up(gpio);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t button_num()
|
||||
{
|
||||
return BUTTON_NUM;
|
||||
}
|
||||
|
||||
uint8_t button_real_gpio(int id)
|
||||
{
|
||||
if (id >= BUTTON_NUM) {
|
||||
return 0xff;
|
||||
}
|
||||
return gpio_real[id];
|
||||
}
|
||||
|
||||
uint8_t button_default_gpio(int id)
|
||||
{
|
||||
if (id >= BUTTON_NUM) {
|
||||
return 0xff;
|
||||
}
|
||||
return gpio_def[id];
|
||||
}
|
||||
|
||||
static uint16_t button_reading;
|
||||
|
||||
/* If a switch flips, it freezes for a while */
|
||||
#define DEBOUNCE_FREEZE_TIME_US 3000
|
||||
void button_update()
|
||||
{
|
||||
uint64_t now = time_us_64();
|
||||
uint16_t buttons = 0;
|
||||
|
||||
for (int i = BUTTON_NUM - 1; i >= 0; i--) {
|
||||
bool sw_pressed = !gpio_get(gpio_real[i]);
|
||||
|
||||
if (now >= sw_freeze_time[i]) {
|
||||
if (sw_pressed != sw_val[i]) {
|
||||
sw_val[i] = sw_pressed;
|
||||
sw_freeze_time[i] = now + DEBOUNCE_FREEZE_TIME_US;
|
||||
}
|
||||
}
|
||||
|
||||
buttons <<= 1;
|
||||
if (sw_val[i]) {
|
||||
buttons |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
button_reading = buttons;
|
||||
}
|
||||
|
||||
uint16_t button_read()
|
||||
{
|
||||
return button_reading;
|
||||
}
|
||||
/*
|
||||
* Mai Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "button.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/timer.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "board_defs.h"
|
||||
|
||||
static const uint8_t gpio_def[] = BUTTON_DEF;
|
||||
static uint8_t gpio_real[] = BUTTON_DEF;
|
||||
|
||||
#define BUTTON_NUM (sizeof(gpio_def))
|
||||
|
||||
static bool sw_val[BUTTON_NUM]; /* true if pressed */
|
||||
static uint64_t sw_freeze_time[BUTTON_NUM];
|
||||
|
||||
void button_init()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_NUM; i++)
|
||||
{
|
||||
sw_val[i] = false;
|
||||
sw_freeze_time[i] = 0;
|
||||
uint8_t gpio = mai_cfg->alt.buttons[i];
|
||||
if (gpio > 29) {
|
||||
gpio = gpio_def[i];
|
||||
}
|
||||
gpio_real[i] = gpio;
|
||||
gpio_init(gpio);
|
||||
gpio_set_function(gpio, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(gpio, GPIO_IN);
|
||||
gpio_pull_up(gpio);
|
||||
}
|
||||
}
|
||||
|
||||
bool button_is_stuck()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_NUM; i++) {
|
||||
if (!gpio_get(gpio_real[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t button_num()
|
||||
{
|
||||
return BUTTON_NUM;
|
||||
}
|
||||
|
||||
uint8_t button_real_gpio(int id)
|
||||
{
|
||||
if (id >= BUTTON_NUM) {
|
||||
return 0xff;
|
||||
}
|
||||
return gpio_real[id];
|
||||
}
|
||||
|
||||
uint8_t button_default_gpio(int id)
|
||||
{
|
||||
if (id >= BUTTON_NUM) {
|
||||
return 0xff;
|
||||
}
|
||||
return gpio_def[id];
|
||||
}
|
||||
|
||||
static uint16_t button_reading;
|
||||
|
||||
/* If a switch flips, it freezes for a while */
|
||||
#define DEBOUNCE_FREEZE_TIME_US 3000
|
||||
void button_update()
|
||||
{
|
||||
uint64_t now = time_us_64();
|
||||
uint16_t buttons = 0;
|
||||
|
||||
for (int i = BUTTON_NUM - 1; i >= 0; i--) {
|
||||
bool sw_pressed = !gpio_get(gpio_real[i]);
|
||||
|
||||
if (now >= sw_freeze_time[i]) {
|
||||
if (sw_pressed != sw_val[i]) {
|
||||
sw_val[i] = sw_pressed;
|
||||
sw_freeze_time[i] = now + DEBOUNCE_FREEZE_TIME_US;
|
||||
}
|
||||
}
|
||||
|
||||
buttons <<= 1;
|
||||
if (sw_val[i]) {
|
||||
buttons |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
button_reading = buttons;
|
||||
}
|
||||
|
||||
uint16_t button_read()
|
||||
{
|
||||
return button_reading;
|
||||
}
|
||||
|
@ -1,20 +1,24 @@
|
||||
/*
|
||||
* Mai Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef BUTTONS_H
|
||||
#define BUTTONS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "hardware/flash.h"
|
||||
|
||||
void button_init();
|
||||
uint8_t button_num();
|
||||
void button_update();
|
||||
uint16_t button_read();
|
||||
uint8_t button_real_gpio(int id);
|
||||
uint8_t button_default_gpio(int id);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Mai Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef BUTTONS_H
|
||||
#define BUTTONS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "hardware/flash.h"
|
||||
|
||||
void button_init();
|
||||
|
||||
/* if anykey is pressed, no debounce */
|
||||
bool button_is_stuck();
|
||||
|
||||
uint8_t button_num();
|
||||
void button_update();
|
||||
uint16_t button_read();
|
||||
uint8_t button_real_gpio(int id);
|
||||
uint8_t button_default_gpio(int id);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,120 +1,121 @@
|
||||
/*
|
||||
* Controller Config and Runtime Data
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* Config is a global data structure that stores all the configuration
|
||||
* Runtime is something to share between files.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "save.h"
|
||||
#include "touch.h"
|
||||
|
||||
mai_cfg_t *mai_cfg;
|
||||
|
||||
static mai_cfg_t default_cfg = {
|
||||
.color = {
|
||||
.key_on = 0xc0c0c0,
|
||||
.key_off = 0x080808,
|
||||
.level = 127,
|
||||
},
|
||||
.sense = {
|
||||
.filter = 0x10,
|
||||
.debounce_touch = 1,
|
||||
.debounce_release = 2,
|
||||
},
|
||||
.hid = {
|
||||
.joy = 0,
|
||||
.nkro = 1,
|
||||
},
|
||||
.rgb = {
|
||||
.per_button = 1,
|
||||
.per_aux = 1,
|
||||
},
|
||||
.alt = {
|
||||
.buttons = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
.touch = TOUCH_MAP,
|
||||
},
|
||||
.aime = {
|
||||
.mode = 0,
|
||||
.virtual_aic = 0,
|
||||
}
|
||||
};
|
||||
|
||||
mai_runtime_t *mai_runtime;
|
||||
static inline bool in_range(int val, int min, int max)
|
||||
{
|
||||
return (val >= min) && (val <= max);
|
||||
}
|
||||
|
||||
static bool touch_map_valid()
|
||||
{
|
||||
uint64_t mask = 0;
|
||||
for (int i = 0; i < sizeof(mai_cfg->alt.touch); i++) {
|
||||
if (mai_cfg->alt.touch[i] < 34) {
|
||||
mask |= 1ULL << mai_cfg->alt.touch[i];
|
||||
}
|
||||
}
|
||||
int keys = 0;
|
||||
for (int i = 0; i < 34; i++) {
|
||||
if (mask & (1ULL << i)) {
|
||||
keys++;
|
||||
}
|
||||
}
|
||||
return keys > 10; // bad data results in low touch key coverage
|
||||
}
|
||||
|
||||
static void config_loaded()
|
||||
{
|
||||
if ((mai_cfg->sense.filter & 0x0f) > 3 ||
|
||||
((mai_cfg->sense.filter >> 4) & 0x0f) > 3) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
if (!in_range(mai_cfg->sense.global, -9, 9)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
for (int i = 0; i < 34; i++) {
|
||||
if (!in_range(mai_cfg->sense.zones[i], -9, 9)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!in_range(mai_cfg->sense.debounce_touch, 0, 7) ||
|
||||
!in_range(mai_cfg->sense.debounce_release, 0, 7)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
|
||||
if (!in_range(mai_cfg->rgb.per_button, 1, 16) ||
|
||||
!in_range(mai_cfg->rgb.per_aux, 1, 16)) {
|
||||
mai_cfg->rgb = default_cfg.rgb;
|
||||
config_changed();
|
||||
}
|
||||
|
||||
if (!touch_map_valid()) {
|
||||
memcpy(mai_cfg->alt.touch, default_cfg.alt.touch,
|
||||
sizeof(mai_cfg->alt.touch));
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void config_changed()
|
||||
{
|
||||
save_request(false);
|
||||
}
|
||||
|
||||
void config_factory_reset()
|
||||
{
|
||||
*mai_cfg = default_cfg;
|
||||
save_request(true);
|
||||
}
|
||||
|
||||
void config_init()
|
||||
{
|
||||
mai_cfg = (mai_cfg_t *)save_alloc(sizeof(*mai_cfg), &default_cfg, config_loaded);
|
||||
}
|
||||
/*
|
||||
* Controller Config and Runtime Data
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* Config is a global data structure that stores all the configuration
|
||||
* Runtime is something to share between files.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "save.h"
|
||||
#include "touch.h"
|
||||
|
||||
mai_cfg_t *mai_cfg;
|
||||
|
||||
static mai_cfg_t default_cfg = {
|
||||
.color = {
|
||||
.key_on = 0xc0c0c0,
|
||||
.key_off = 0x080808,
|
||||
.level = 127,
|
||||
},
|
||||
.sense = {
|
||||
.filter = 0x10,
|
||||
.debounce_touch = 1,
|
||||
.debounce_release = 2,
|
||||
},
|
||||
.hid = {
|
||||
.joy = 0,
|
||||
.nkro = 1,
|
||||
},
|
||||
.rgb = {
|
||||
.per_button = 1,
|
||||
.per_aux = 1,
|
||||
},
|
||||
.alt = {
|
||||
.buttons = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
.touch = TOUCH_MAP,
|
||||
},
|
||||
.aime = {
|
||||
.mode = 0,
|
||||
.virtual_aic = 0,
|
||||
}
|
||||
};
|
||||
|
||||
mai_runtime_t mai_runtime;
|
||||
|
||||
static inline bool in_range(int val, int min, int max)
|
||||
{
|
||||
return (val >= min) && (val <= max);
|
||||
}
|
||||
|
||||
static bool touch_map_valid()
|
||||
{
|
||||
uint64_t mask = 0;
|
||||
for (int i = 0; i < sizeof(mai_cfg->alt.touch); i++) {
|
||||
if (mai_cfg->alt.touch[i] < 34) {
|
||||
mask |= 1ULL << mai_cfg->alt.touch[i];
|
||||
}
|
||||
}
|
||||
int keys = 0;
|
||||
for (int i = 0; i < 34; i++) {
|
||||
if (mask & (1ULL << i)) {
|
||||
keys++;
|
||||
}
|
||||
}
|
||||
return keys > 10; // bad data results in low touch key coverage
|
||||
}
|
||||
|
||||
static void config_loaded()
|
||||
{
|
||||
if ((mai_cfg->sense.filter & 0x0f) > 3 ||
|
||||
((mai_cfg->sense.filter >> 4) & 0x0f) > 3) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
if (!in_range(mai_cfg->sense.global, -9, 9)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
for (int i = 0; i < 34; i++) {
|
||||
if (!in_range(mai_cfg->sense.zones[i], -9, 9)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!in_range(mai_cfg->sense.debounce_touch, 0, 7) ||
|
||||
!in_range(mai_cfg->sense.debounce_release, 0, 7)) {
|
||||
mai_cfg->sense = default_cfg.sense;
|
||||
config_changed();
|
||||
}
|
||||
|
||||
if (!in_range(mai_cfg->rgb.per_button, 1, 16) ||
|
||||
!in_range(mai_cfg->rgb.per_aux, 1, 16)) {
|
||||
mai_cfg->rgb = default_cfg.rgb;
|
||||
config_changed();
|
||||
}
|
||||
|
||||
if (!touch_map_valid()) {
|
||||
memcpy(mai_cfg->alt.touch, default_cfg.alt.touch,
|
||||
sizeof(mai_cfg->alt.touch));
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void config_changed()
|
||||
{
|
||||
save_request(false);
|
||||
}
|
||||
|
||||
void config_factory_reset()
|
||||
{
|
||||
*mai_cfg = default_cfg;
|
||||
save_request(true);
|
||||
}
|
||||
|
||||
void config_init()
|
||||
{
|
||||
mai_cfg = (mai_cfg_t *)save_alloc(sizeof(*mai_cfg), &default_cfg, config_loaded);
|
||||
}
|
||||
|
@ -1,56 +1,57 @@
|
||||
/*
|
||||
* Controller Config
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
struct {
|
||||
uint32_t key_on;
|
||||
uint32_t key_off;
|
||||
uint8_t level;
|
||||
} color;
|
||||
struct {
|
||||
int8_t filter;
|
||||
int8_t global;
|
||||
uint8_t debounce_touch;
|
||||
uint8_t debounce_release;
|
||||
int8_t zones[34];
|
||||
} sense;
|
||||
struct {
|
||||
uint8_t joy : 4;
|
||||
uint8_t nkro : 4;
|
||||
} hid;
|
||||
struct {
|
||||
uint8_t per_button;
|
||||
uint8_t per_aux;
|
||||
} rgb;
|
||||
struct {
|
||||
uint8_t buttons[12];
|
||||
uint8_t touch[36];
|
||||
} alt;
|
||||
struct {
|
||||
uint8_t mode : 4;
|
||||
uint8_t virtual_aic : 4;
|
||||
} aime;
|
||||
} mai_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t fps[2];
|
||||
} mai_runtime_t;
|
||||
|
||||
extern mai_cfg_t *mai_cfg;
|
||||
extern mai_runtime_t *mai_runtime;
|
||||
|
||||
void config_init();
|
||||
void config_changed(); // Notify the config has changed
|
||||
void config_factory_reset(); // Reset the config to factory default
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Controller Config
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
struct {
|
||||
uint32_t key_on;
|
||||
uint32_t key_off;
|
||||
uint8_t level;
|
||||
} color;
|
||||
struct {
|
||||
int8_t filter;
|
||||
int8_t global;
|
||||
uint8_t debounce_touch;
|
||||
uint8_t debounce_release;
|
||||
int8_t zones[34];
|
||||
} sense;
|
||||
struct {
|
||||
uint8_t joy : 4;
|
||||
uint8_t nkro : 4;
|
||||
} hid;
|
||||
struct {
|
||||
uint8_t per_button;
|
||||
uint8_t per_aux;
|
||||
} rgb;
|
||||
struct {
|
||||
uint8_t buttons[12];
|
||||
uint8_t touch[36];
|
||||
} alt;
|
||||
struct {
|
||||
uint8_t mode : 4;
|
||||
uint8_t virtual_aic : 4;
|
||||
} aime;
|
||||
} mai_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t fps[2];
|
||||
bool key_stuck;
|
||||
} mai_runtime_t;
|
||||
|
||||
extern mai_cfg_t *mai_cfg;
|
||||
extern mai_runtime_t mai_runtime;
|
||||
|
||||
void config_init();
|
||||
void config_changed(); // Notify the config has changed
|
||||
void config_factory_reset(); // Reset the config to factory default
|
||||
|
||||
#endif
|
||||
|
@ -1,122 +1,122 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "hid.h"
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t adcs[8];
|
||||
uint16_t spinners[4];
|
||||
uint16_t chutes[2];
|
||||
uint16_t buttons[2];
|
||||
uint8_t system_status;
|
||||
uint8_t usb_status;
|
||||
uint8_t padding[29];
|
||||
} hid_joy;
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t modifier;
|
||||
uint8_t keymap[15];
|
||||
} hid_nkro;
|
||||
|
||||
static uint16_t native_to_io4(uint16_t button)
|
||||
{
|
||||
static const int target_pos[] = { 2, 3, 0, 15, 14, 13, 12, 11, 1, 9, 6 };
|
||||
uint16_t io4btn = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool pressed = button & (1 << i);
|
||||
io4btn |= pressed ? 0 : (1 << target_pos[i]);
|
||||
}
|
||||
for (int i = 8; i < 11; i++) {
|
||||
bool pressed = button & (1 << i);
|
||||
io4btn |= pressed ? (1 << target_pos[i]) : 0;
|
||||
}
|
||||
return io4btn;
|
||||
}
|
||||
|
||||
static void report_usb_hid()
|
||||
{
|
||||
if (tud_hid_ready()) {
|
||||
if (mai_cfg->hid.joy) {
|
||||
static uint16_t last_buttons = 0;
|
||||
uint16_t buttons = button_read();
|
||||
hid_joy.buttons[0] = native_to_io4(buttons);
|
||||
hid_joy.buttons[1] = native_to_io4(0);
|
||||
if (last_buttons ^ buttons & (1 << 11)) {
|
||||
if (buttons & (1 << 11)) {
|
||||
// just pressed coin button
|
||||
hid_joy.chutes[0] += 0x100;
|
||||
}
|
||||
}
|
||||
tud_hid_n_report(0, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy));
|
||||
last_buttons = buttons;
|
||||
}
|
||||
if (mai_cfg->hid.nkro) {
|
||||
tud_hid_n_report(1, 0, &hid_nkro, sizeof(hid_nkro));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char keymap_p1[] = BUTTON_NKRO_MAP_P1;
|
||||
const char keymap_p2[] = BUTTON_NKRO_MAP_P2;
|
||||
|
||||
static void gen_nkro_report()
|
||||
{
|
||||
if (!mai_cfg->hid.nkro) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t buttons = button_read();
|
||||
const char *keymap = (mai_cfg->hid.nkro == 2) ? keymap_p2 : keymap_p1;
|
||||
for (int i = 0; i < button_num(); i++) {
|
||||
uint8_t code = keymap[i];
|
||||
uint8_t byte = code / 8;
|
||||
uint8_t bit = code % 8;
|
||||
if (buttons & (1 << i)) {
|
||||
hid_nkro.keymap[byte] |= (1 << bit);
|
||||
} else {
|
||||
hid_nkro.keymap[byte] &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hid_update()
|
||||
{
|
||||
gen_nkro_report();
|
||||
report_usb_hid();
|
||||
}
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t report_id;
|
||||
uint8_t cmd;
|
||||
uint8_t payload[62];
|
||||
} hid_output_t;
|
||||
|
||||
void hid_proc(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
hid_output_t *output = (hid_output_t *)data;
|
||||
if (output->report_id == REPORT_ID_OUTPUT) {
|
||||
switch (output->cmd) {
|
||||
case 0x01: // Set Timeout
|
||||
case 0x02: // Set Sampling Count
|
||||
hid_joy.system_status = 0x30;
|
||||
break;
|
||||
case 0x03: // Clear Board Status
|
||||
hid_joy.chutes[0] = 0;
|
||||
hid_joy.chutes[1] = 0;
|
||||
hid_joy.system_status = 0x00;
|
||||
break;
|
||||
case 0x04: // Set General Output
|
||||
case 0x41: // I don't know what this is
|
||||
break;
|
||||
default:
|
||||
printf("USB unknown cmd: %d\n", output->cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "hid.h"
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t adcs[8];
|
||||
uint16_t spinners[4];
|
||||
uint16_t chutes[2];
|
||||
uint16_t buttons[2];
|
||||
uint8_t system_status;
|
||||
uint8_t usb_status;
|
||||
uint8_t padding[29];
|
||||
} hid_joy;
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t modifier;
|
||||
uint8_t keymap[15];
|
||||
} hid_nkro;
|
||||
|
||||
static uint16_t native_to_io4(uint16_t button)
|
||||
{
|
||||
static const int target_pos[] = { 2, 3, 0, 15, 14, 13, 12, 11, 1, 9, 6 };
|
||||
uint16_t io4btn = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool pressed = button & (1 << i);
|
||||
io4btn |= pressed ? 0 : (1 << target_pos[i]);
|
||||
}
|
||||
for (int i = 8; i < 11; i++) {
|
||||
bool pressed = button & (1 << i);
|
||||
io4btn |= pressed ? (1 << target_pos[i]) : 0;
|
||||
}
|
||||
return io4btn;
|
||||
}
|
||||
|
||||
static void report_usb_hid()
|
||||
{
|
||||
if (tud_hid_ready()) {
|
||||
if (mai_cfg->hid.joy || mai_runtime.key_stuck) {
|
||||
static uint16_t last_buttons = 0;
|
||||
uint16_t buttons = button_read();
|
||||
hid_joy.buttons[0] = native_to_io4(buttons);
|
||||
hid_joy.buttons[1] = native_to_io4(0);
|
||||
if (last_buttons ^ buttons & (1 << 11)) {
|
||||
if (buttons & (1 << 11)) {
|
||||
// just pressed coin button
|
||||
hid_joy.chutes[0] += 0x100;
|
||||
}
|
||||
}
|
||||
tud_hid_n_report(0, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy));
|
||||
last_buttons = buttons;
|
||||
}
|
||||
if (mai_cfg->hid.nkro && !mai_runtime.key_stuck) {
|
||||
tud_hid_n_report(1, 0, &hid_nkro, sizeof(hid_nkro));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char keymap_p1[] = BUTTON_NKRO_MAP_P1;
|
||||
const char keymap_p2[] = BUTTON_NKRO_MAP_P2;
|
||||
|
||||
static void gen_nkro_report()
|
||||
{
|
||||
if (!mai_cfg->hid.nkro) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t buttons = button_read();
|
||||
const char *keymap = (mai_cfg->hid.nkro == 2) ? keymap_p2 : keymap_p1;
|
||||
for (int i = 0; i < button_num(); i++) {
|
||||
uint8_t code = keymap[i];
|
||||
uint8_t byte = code / 8;
|
||||
uint8_t bit = code % 8;
|
||||
if (buttons & (1 << i)) {
|
||||
hid_nkro.keymap[byte] |= (1 << bit);
|
||||
} else {
|
||||
hid_nkro.keymap[byte] &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hid_update()
|
||||
{
|
||||
gen_nkro_report();
|
||||
report_usb_hid();
|
||||
}
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t report_id;
|
||||
uint8_t cmd;
|
||||
uint8_t payload[62];
|
||||
} hid_output_t;
|
||||
|
||||
void hid_proc(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
hid_output_t *output = (hid_output_t *)data;
|
||||
if (output->report_id == REPORT_ID_OUTPUT) {
|
||||
switch (output->cmd) {
|
||||
case 0x01: // Set Timeout
|
||||
case 0x02: // Set Sampling Count
|
||||
hid_joy.system_status = 0x30;
|
||||
break;
|
||||
case 0x03: // Clear Board Status
|
||||
hid_joy.chutes[0] = 0;
|
||||
hid_joy.chutes[1] = 0;
|
||||
hid_joy.system_status = 0x00;
|
||||
break;
|
||||
case 0x04: // Set General Output
|
||||
case 0x41: // I don't know what this is
|
||||
break;
|
||||
default:
|
||||
printf("USB unknown cmd: %d\n", output->cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,8 @@ void init()
|
||||
cli_init("mai_pico>", "\n << Mai Pico Controller >>\n"
|
||||
" https://github.com/whowechina\n\n");
|
||||
commands_init();
|
||||
|
||||
mai_runtime.key_stuck = button_is_stuck();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
Loading…
x
Reference in New Issue
Block a user