mirror of
https://github.com/qmk/qmk_firmware.git
synced 2026-10-25 02:12:40 +02:00
possibly all files needed to make things work
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/* Copyright 2019 Jack Humbert
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config_common.h"
|
||||
|
||||
/* USB Device descriptor parameter */
|
||||
#define VENDOR_ID 0x0e6f
|
||||
#define PRODUCT_ID 0x0185
|
||||
#define DEVICE_VER 0x0001
|
||||
#define MANUFACTURER QMK
|
||||
#define PRODUCT Proton C
|
||||
#define DESCRIPTION Handwired Gamepad
|
||||
|
||||
/* key matrix size */
|
||||
#define MATRIX_ROWS 1
|
||||
#define MATRIX_COLS 1
|
||||
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
||||
#define MATRIX_COL_PINS { A3 }
|
||||
#define MATRIX_ROW_PINS { A1 }
|
||||
|
||||
/* define if matrix has ghost */
|
||||
//#define MATRIX_HAS_GHOST
|
||||
|
||||
/* Set 0 if debouncing isn't needed */
|
||||
#define DEBOUNCE 5
|
||||
|
||||
/*
|
||||
* Feature disable options
|
||||
* These options are also useful to firmware size reduction.
|
||||
*/
|
||||
|
||||
/* disable debug print */
|
||||
//#define NO_DEBUG
|
||||
|
||||
/* disable print */
|
||||
//#define NO_PRINT
|
||||
|
||||
/* disable action features */
|
||||
//#define NO_ACTION_LAYER
|
||||
//#define NO_ACTION_TAPPING
|
||||
//#define NO_ACTION_ONESHOT
|
||||
//#define NO_ACTION_MACRO
|
||||
//#define NO_ACTION_FUNCTION
|
||||
|
||||
#define GAMECUBE_DATA_PIN A2
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "gc_controller.h"
|
||||
#include "gc_read.h"
|
||||
#include "gamepad.h"
|
||||
#include <string.h>
|
||||
|
||||
uint16_t gamecube_buttons = 0;
|
||||
uint8_t gamecube_joysticks[6] = {0};
|
||||
bool z_button = false;
|
||||
|
||||
report_gamepad_t report = {
|
||||
.Button = 0,
|
||||
.LX = STICK_CENTER,
|
||||
.LY = STICK_CENTER,
|
||||
.RX = STICK_CENTER,
|
||||
.RY = STICK_CENTER,
|
||||
.HAT = HAT_CENTER
|
||||
};
|
||||
|
||||
void board_init(void) {
|
||||
setPinOutput(C13);
|
||||
writePinLow(C13);
|
||||
gamecube_init();
|
||||
}
|
||||
|
||||
void matrix_init_user(void) {
|
||||
|
||||
}
|
||||
|
||||
void matrix_scan_user(void) {
|
||||
|
||||
gamecube_scan(&gamecube_buttons, gamecube_joysticks);
|
||||
|
||||
z_button = gamecube_buttons & GAMECUBE_Z;
|
||||
|
||||
// Home & Capture
|
||||
if (gamecube_buttons & GAMECUBE_START) {
|
||||
if (z_button && !(report.Button & SWITCH_HOME))
|
||||
report.Button |= SWITCH_CAPTURE;
|
||||
else
|
||||
report.Button |= SWITCH_HOME;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_HOME;
|
||||
report.Button &= ~SWITCH_CAPTURE;
|
||||
}
|
||||
// Y and L
|
||||
if (gamecube_buttons & GAMECUBE_Y) {
|
||||
if (z_button && !(report.Button & SWITCH_Y))
|
||||
report.Button |= SWITCH_L;
|
||||
else
|
||||
report.Button |= SWITCH_Y;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_Y;
|
||||
report.Button &= ~SWITCH_L;
|
||||
}
|
||||
// X and R
|
||||
if (gamecube_buttons & GAMECUBE_X) {
|
||||
if (z_button && !(report.Button & SWITCH_X))
|
||||
report.Button |= SWITCH_R;
|
||||
else
|
||||
report.Button |= SWITCH_X;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_X;
|
||||
report.Button &= ~SWITCH_R;
|
||||
}
|
||||
// B and -
|
||||
if (gamecube_buttons & GAMECUBE_B) {
|
||||
if (z_button && !(report.Button & SWITCH_B))
|
||||
report.Button |= SWITCH_MINUS;
|
||||
else
|
||||
report.Button |= SWITCH_B;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_B;
|
||||
report.Button &= ~SWITCH_MINUS;
|
||||
}
|
||||
// A and +
|
||||
if (gamecube_buttons & GAMECUBE_A) {
|
||||
if (z_button && !(report.Button & SWITCH_A))
|
||||
report.Button |= SWITCH_PLUS;
|
||||
else
|
||||
report.Button |= SWITCH_A;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_A;
|
||||
report.Button &= ~SWITCH_PLUS;
|
||||
}
|
||||
|
||||
if (gamecube_buttons & GAMECUBE_L) {
|
||||
report.Button |= SWITCH_ZL;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_ZL;
|
||||
}
|
||||
if (gamecube_buttons & GAMECUBE_R) {
|
||||
report.Button |= SWITCH_ZR;
|
||||
} else {
|
||||
report.Button &= ~SWITCH_ZR;
|
||||
}
|
||||
|
||||
if ((gamecube_buttons & GAMECUBE_UP) && (gamecube_buttons & GAMECUBE_RIGHT))
|
||||
report.HAT = HAT_TOP_RIGHT;
|
||||
else if ((gamecube_buttons & GAMECUBE_UP) && (gamecube_buttons & GAMECUBE_LEFT))
|
||||
report.HAT = HAT_TOP_LEFT;
|
||||
else if ((gamecube_buttons & GAMECUBE_DOWN) && (gamecube_buttons & GAMECUBE_RIGHT))
|
||||
report.HAT = HAT_BOTTOM_RIGHT;
|
||||
else if ((gamecube_buttons & GAMECUBE_DOWN) && (gamecube_buttons & GAMECUBE_LEFT))
|
||||
report.HAT = HAT_BOTTOM_LEFT;
|
||||
else if (gamecube_buttons & GAMECUBE_UP)
|
||||
report.HAT = HAT_TOP;
|
||||
else if (gamecube_buttons & GAMECUBE_DOWN)
|
||||
report.HAT = HAT_BOTTOM;
|
||||
else if (gamecube_buttons & GAMECUBE_RIGHT)
|
||||
report.HAT = HAT_RIGHT;
|
||||
else if (gamecube_buttons & GAMECUBE_LEFT)
|
||||
report.HAT = HAT_LEFT;
|
||||
else
|
||||
report.HAT = HAT_CENTER;
|
||||
|
||||
if (report.Button || report.HAT != HAT_CENTER)
|
||||
writePinHigh(C13);
|
||||
else
|
||||
writePinLow(C13);
|
||||
|
||||
// joystick calculations
|
||||
|
||||
report.LX = gamecube_joysticks[0];
|
||||
report.LY = 255 - gamecube_joysticks[1];
|
||||
report.RX = gamecube_joysticks[2];
|
||||
report.RY = 255 - gamecube_joysticks[3];
|
||||
|
||||
send_gamepad(&report);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "quantum.h"
|
||||
|
||||
typedef enum {
|
||||
SWITCH_Y = 0x01,
|
||||
SWITCH_B = 0x02,
|
||||
SWITCH_A = 0x04,
|
||||
SWITCH_X = 0x08,
|
||||
SWITCH_L = 0x10,
|
||||
SWITCH_R = 0x20,
|
||||
SWITCH_ZL = 0x40,
|
||||
SWITCH_ZR = 0x80,
|
||||
SWITCH_MINUS = 0x100,
|
||||
SWITCH_PLUS = 0x200,
|
||||
SWITCH_LCLICK = 0x400,
|
||||
SWITCH_RCLICK = 0x800,
|
||||
SWITCH_HOME = 0x1000,
|
||||
SWITCH_CAPTURE = 0x2000,
|
||||
} SwitchButtons_t;
|
||||
|
||||
typedef enum {
|
||||
GAMECUBE_A = 0b0000000000000001,
|
||||
GAMECUBE_B = 0b0000000000000010,
|
||||
GAMECUBE_X = 0b0000000000000100,
|
||||
GAMECUBE_Y = 0b0000000000001000,
|
||||
GAMECUBE_START = 0b0000000000010000,
|
||||
GAMECUBE_LEFT = 0b0000000100000000,
|
||||
GAMECUBE_RIGHT = 0b0000001000000000,
|
||||
GAMECUBE_DOWN = 0b0000010000000000,
|
||||
GAMECUBE_UP = 0b0000100000000000,
|
||||
GAMECUBE_Z = 0b0001000000000000,
|
||||
GAMECUBE_R = 0b0010000000000000,
|
||||
GAMECUBE_L = 0b0100000000000000,
|
||||
} GamecubeButtons_t;
|
||||
|
||||
#define HAT_TOP 0x00
|
||||
#define HAT_TOP_RIGHT 0x01
|
||||
#define HAT_RIGHT 0x02
|
||||
#define HAT_BOTTOM_RIGHT 0x03
|
||||
#define HAT_BOTTOM 0x04
|
||||
#define HAT_BOTTOM_LEFT 0x05
|
||||
#define HAT_LEFT 0x06
|
||||
#define HAT_TOP_LEFT 0x07
|
||||
#define HAT_CENTER 0x08
|
||||
|
||||
#define STICK_MIN 0
|
||||
#define STICK_CENTER 128
|
||||
#define STICK_MAX 255
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "gc_read.h"
|
||||
#include "gc_controller.h"
|
||||
|
||||
#define CONTROLLER_TIMEOUT 60
|
||||
|
||||
bool init_message[9] = {0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
bool request_message[25] = {
|
||||
0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1};
|
||||
|
||||
void start_message(void) {
|
||||
setPinOutput(GAMECUBE_DATA_PIN);
|
||||
writePinLow(GAMECUBE_DATA_PIN);
|
||||
}
|
||||
|
||||
void send_bit(bool b) {
|
||||
if (b) {
|
||||
writePinLow(GAMECUBE_DATA_PIN);
|
||||
wait_ns(900);
|
||||
writePinHigh(GAMECUBE_DATA_PIN);
|
||||
wait_ns(2900);
|
||||
} else {
|
||||
writePinLow(GAMECUBE_DATA_PIN);
|
||||
wait_ns(2900);
|
||||
writePinHigh(GAMECUBE_DATA_PIN);
|
||||
wait_ns(900);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_for_ready(void) {
|
||||
setPinInputHigh(GAMECUBE_DATA_PIN);
|
||||
|
||||
// wait for long high
|
||||
uint8_t ready = 0;
|
||||
while (ready < 5) {
|
||||
if (readPin(GAMECUBE_DATA_PIN))
|
||||
ready++;
|
||||
else
|
||||
ready = 0;
|
||||
wait_us(1);
|
||||
}
|
||||
}
|
||||
|
||||
void end_message(void) {
|
||||
setPinInputHigh(GAMECUBE_DATA_PIN);
|
||||
}
|
||||
|
||||
uint8_t buffer[9] = {0};
|
||||
uint16_t buttons_debounce = 0;
|
||||
bool initialised = false;
|
||||
bool calibrated = false;
|
||||
uint8_t mid_values[4] = {128, 128, 128, 128};
|
||||
uint8_t max_values[4] = {210, 210, 210, 210};
|
||||
uint8_t min_values[4] = {35, 35, 35, 35};
|
||||
|
||||
void gamecube_init(void) {
|
||||
setPinInputHigh(GAMECUBE_DATA_PIN);
|
||||
}
|
||||
|
||||
void gamecube_scan(uint16_t * buttons, uint8_t * joysticks) {
|
||||
bool exiting = false;
|
||||
uint16_t timeout_counter = 0;
|
||||
|
||||
// somehow we're missing the first bit, which can safely be ignored
|
||||
// i'm not sure if it's something with the timing or what
|
||||
uint8_t buffer_bit = 1;
|
||||
|
||||
chSysLock();
|
||||
|
||||
if (!initialised) {
|
||||
wait_for_ready();
|
||||
|
||||
start_message();
|
||||
for (uint8_t i = 0; i < 9; i++)
|
||||
send_bit(init_message[i]);
|
||||
end_message();
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
wait_for_ready();
|
||||
|
||||
start_message();
|
||||
for (uint8_t i = 0; i < 25; i++)
|
||||
send_bit(request_message[i]);
|
||||
end_message();
|
||||
|
||||
while (!exiting) {
|
||||
timeout_counter = 0;
|
||||
// wait for low or timeout
|
||||
while (readPin(GAMECUBE_DATA_PIN)) {
|
||||
wait_ns(100);
|
||||
timeout_counter++;
|
||||
if (timeout_counter > CONTROLLER_TIMEOUT) {
|
||||
exiting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exiting) {
|
||||
// wait for the data part
|
||||
wait_ns(1950);
|
||||
bool b = readPin(GAMECUBE_DATA_PIN);
|
||||
if (b)
|
||||
buffer[buffer_bit / 8] |= (1 << (7 - (buffer_bit % 8)));
|
||||
else
|
||||
buffer[buffer_bit / 8] &= ~(1 << (7 - (buffer_bit % 8)));
|
||||
buffer_bit++;
|
||||
|
||||
// wait for high
|
||||
while (!readPin(GAMECUBE_DATA_PIN));
|
||||
}
|
||||
}
|
||||
|
||||
chSysUnlock();
|
||||
|
||||
// basic debouncing for buttons
|
||||
uint16_t combined_buttons = buffer[0] | (buffer[1] << 8);
|
||||
*buttons |= buttons_debounce & combined_buttons;
|
||||
*buttons &= buttons_debounce | combined_buttons;
|
||||
buttons_debounce = combined_buttons;
|
||||
|
||||
if (!calibrated && mid_values[0] > 0) {
|
||||
mid_values[0] = buffer[2];
|
||||
mid_values[1] = buffer[3];
|
||||
mid_values[2] = buffer[4];
|
||||
mid_values[3] = buffer[5];
|
||||
calibrated = true;
|
||||
}
|
||||
|
||||
if (max_values[0] < buffer[2])
|
||||
max_values[0] = buffer[2];
|
||||
if (max_values[1] < buffer[3])
|
||||
max_values[1] = buffer[3];
|
||||
if (max_values[2] < buffer[4])
|
||||
max_values[2] = buffer[4];
|
||||
if (max_values[3] < buffer[5])
|
||||
max_values[3] = buffer[5];
|
||||
|
||||
if (min_values[0] > buffer[2])
|
||||
min_values[0] = buffer[2];
|
||||
if (min_values[1] > buffer[3])
|
||||
min_values[1] = buffer[3];
|
||||
if (min_values[2] > buffer[4])
|
||||
min_values[2] = buffer[4];
|
||||
if (min_values[3] > buffer[5])
|
||||
min_values[3] = buffer[5];
|
||||
|
||||
// values from my GC controller in Windows
|
||||
// 30 - 138 - 236
|
||||
// 20 - 124 - 225
|
||||
// 37 - 135 - 222
|
||||
// 34 - 126 - 216
|
||||
|
||||
// this should be 127? i don't understand what i'm doing wrong yet
|
||||
#define JOYSTICK_SCALER 180.0
|
||||
|
||||
int32_t lx_temp = (int16_t)buffer[2] - mid_values[0];
|
||||
if (lx_temp > 0)
|
||||
lx_temp *= JOYSTICK_SCALER / (max_values[0]-mid_values[0]);
|
||||
else
|
||||
lx_temp *= JOYSTICK_SCALER / (mid_values[0]-min_values[0]);
|
||||
lx_temp += STICK_CENTER;
|
||||
if (lx_temp > 255)
|
||||
lx_temp = 255;
|
||||
if (lx_temp < 0)
|
||||
lx_temp = 0;
|
||||
|
||||
int32_t ly_temp = (int16_t)buffer[3] - mid_values[1];
|
||||
if (ly_temp > 0)
|
||||
ly_temp *= JOYSTICK_SCALER / (max_values[1]-mid_values[1]);
|
||||
else
|
||||
ly_temp *= JOYSTICK_SCALER / (mid_values[1]-min_values[1]);
|
||||
ly_temp += STICK_CENTER;
|
||||
if (ly_temp > 255)
|
||||
ly_temp = 255;
|
||||
if (ly_temp < 0)
|
||||
ly_temp = 0;
|
||||
|
||||
int32_t rx_temp = (int16_t)buffer[4] - mid_values[2];
|
||||
if (rx_temp > 0)
|
||||
rx_temp *= JOYSTICK_SCALER / (max_values[2]-mid_values[2]);
|
||||
else
|
||||
rx_temp *= JOYSTICK_SCALER / (mid_values[2]-min_values[2]);
|
||||
rx_temp += STICK_CENTER;
|
||||
if (rx_temp > 255)
|
||||
rx_temp = 255;
|
||||
if (rx_temp < 0)
|
||||
rx_temp = 0;
|
||||
|
||||
int32_t ry_temp = (int16_t)buffer[5] - mid_values[3];
|
||||
if (ry_temp > 0)
|
||||
ry_temp *= JOYSTICK_SCALER / (max_values[3]-mid_values[3]);
|
||||
else
|
||||
ry_temp *= JOYSTICK_SCALER / (mid_values[3]-min_values[3]);
|
||||
ry_temp += STICK_CENTER;
|
||||
if (ry_temp > 255)
|
||||
ry_temp = 255;
|
||||
if (ry_temp < 0)
|
||||
ry_temp = 0;
|
||||
|
||||
// checks to avoid a data skip (0 values on input, which aren't possible, i think)
|
||||
if (buffer[2])
|
||||
joysticks[0] = lx_temp;
|
||||
if (buffer[3])
|
||||
joysticks[1] = ly_temp;
|
||||
if (buffer[4])
|
||||
joysticks[2] = rx_temp;
|
||||
if (buffer[5])
|
||||
joysticks[3] = ry_temp;
|
||||
if (buffer[6])
|
||||
joysticks[4] = buffer[6];
|
||||
if (buffer[7])
|
||||
joysticks[5] = buffer[7];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "quantum.h"
|
||||
|
||||
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
|
||||
|
||||
#ifndef NOP_FUDGE
|
||||
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX)
|
||||
# define NOP_FUDGE 0.4
|
||||
# else
|
||||
# error("NOP_FUDGE configuration required")
|
||||
# define NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define NUMBER_NOPS 6
|
||||
#define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE)
|
||||
#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
|
||||
#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
|
||||
#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
|
||||
|
||||
#define wait_ns(x) \
|
||||
do { \
|
||||
for (int i = 0; i < NS_TO_CYCLES(x); i++) { \
|
||||
__asm__ volatile("nop\n\t" \
|
||||
"nop\n\t" \
|
||||
"nop\n\t" \
|
||||
"nop\n\t" \
|
||||
"nop\n\t" \
|
||||
"nop\n\t"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
void gamecube_init(void);
|
||||
void gamecube_scan(uint16_t * buttons, uint8_t * joysticks);
|
||||
@@ -0,0 +1,3 @@
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { { { 0 } } };
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
J1 header
|
||||
---------
|
||||
|
||||
|#|Color |Proton C|Description|
|
||||
|-|-------|----|------------|
|
||||
|1|blue |3.3V| |
|
||||
|2|yellow |5V | |
|
||||
|3|red |A2 |Data (3.3V) |
|
||||
|4|green |GND | |
|
||||
|5|white |GND | |
|
||||
|6|black |NC | |
|
||||
@@ -0,0 +1,15 @@
|
||||
# MCU name
|
||||
MCU = STM32F303
|
||||
|
||||
BACKLIGHT_ENABLE = no
|
||||
MOUSEKEY_ENABLE = no
|
||||
EXTRAKEY_ENABLE = no
|
||||
CONSOLE_ENABLE = no
|
||||
NKRO_ENABLE = no
|
||||
RAW_ENABLE = no
|
||||
MIDI_ENABLE = no
|
||||
VIRTSER_ENABLE = no
|
||||
KEYBOARD_ENABLE = no
|
||||
SWITCH_CONTROLLER_ENABLE = yes
|
||||
|
||||
SRC += gc_read.c
|
||||
Reference in New Issue
Block a user