Leonardo support

This commit is contained in:
CrazyRedMachine
2020-07-04 02:01:15 +02:00
parent 2ccc8a33e7
commit cd398a3468
5 changed files with 63 additions and 8 deletions
+2 -1
View File
@@ -1 +1,2 @@
\\?\HID#VID_2341&PID_003E&MI_02#7&3156e204&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
\\?\HID#VID_2341&PID_003E&MI_02#7&3156e204&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
\\?\HID#VID_2341&PID_8036&MI_02#7&63200bf&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
+13 -3
View File
@@ -1,11 +1,15 @@
# Ultimate Pop'n Controller
USB HID controller with 12 buttons, 18 lights, 12-key matrix numpad and nice programmable features.
USB HID controller with 12 buttons, 18 lights, 12-key matrix numpad, high polling rate and nice programmable features.
The goal was to replace the official IO Board from my pop'n cabinet with a DIY controller instead, for stability reasons (Konami IO boards are prone to failure, most Pop'n Music cabinets in the wild have broken lamps...) but also for QoL improvements (this allows me to use my panel system-wide and not only in-game, which means I can control a multiboot menu, play with emulators etc..).
In combination with the PN5180-cardio project, the whole IO from a Pop'n Music cabinet can be replaced pretty cheaply :)
# Leonardo version
Because I loved the ModeSwitch feature, I adapted the code so it could compile for Leonardo as well. Due to lack of gpio, in this case there's only 11 buttons and 9 lights, no keypad support, and reactive mode won't include AC light simulation (there's no side or top lamps, duh)
# Demo
https://www.instagram.com/p/CBWgSMklvvT/
@@ -22,7 +26,7 @@ The keypad code uses the Keypad library by Mark Stanley and Alexander Brevig.
# Supported devices and requirements
This code has been tested on Arduino Due. It should still compile for Leonardo provided you redefine the pinout.
This code was designed for Arduino Due. It will compile for Leonardo as well but some features are stripped due to lack of gpio (only 11 buttons and 9 lights, no keypad). The HID descriptor is updated accordingly depending on the selected target board.
The keypad code requires the Keypad library by Mark Stanley and Alexander Brevig. It can be installed from the Arduino IDE Library manager.
@@ -68,7 +72,7 @@ You can either press button 2 (left yellow button) while holding service to swit
I included pre-compiled binaries and sources in the "ModeSwitch" folder. Refer to readme.md inside that folder for more details.
# Pinout
# Pinout (DUE)
The Arduino DUE has 3.3v logic whereas the Pop'n Music cabinet lamps use 12V. Therefore I'm using mosfet transistors to do level shifting (the parts I used were three ULN2003APG chips). You can also buy pre-made level shifters such as this one https://www.tindie.com/products/ddebeer/12-channel-level-shifter-and-buffer/ (you'd need two of them since there are 18 lamps to control for a Pop'n cabinet).
@@ -84,3 +88,9 @@ Refer to ```pinout.png``` to see how it is all wired to a Pop'n Music cabinet.
connect button pin to ground to trigger button press
![pinout](https://github.com/CrazyRedMachine/UltimatePopnController/blob/master/pinout.png?raw=true)
# Pinout (Leonardo)
Arduino Leonardo has 5V logic therefore one can directly connect 5V leds to it.
![pinout](https://github.com/CrazyRedMachine/UltimatePopnController/blob/master/pinout_leonardo.png?raw=true)
Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

+27 -3
View File
@@ -24,13 +24,21 @@ static const byte PROGMEM _hidReportPOPN[] = {
0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
0x29, 0x0c, /* USAGE_MAXIMUM (Button 12)*/
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
#if defined(ARDUINO_ARCH_SAM)
0x95, 0x0c, /* REPORT_COUNT (12) */
#else
0x95, 0x0b, /* REPORT_COUNT (11) */
#endif
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
/* Reserved 4 bits */
/* Reserved bits */
0x95, 0x01, /* REPORT_COUNT (1) */
#if defined(ARDUINO_ARCH_SAM)
0x75, 0x04, /* REPORT_SIZE (4) */
#else
0x75, 0x05, /* REPORT_SIZE (5) */
#endif
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
/*Lights */
@@ -127,6 +135,7 @@ static const byte PROGMEM _hidReportPOPN[] = {
0x95, 0x01, /* REPORT_COUNT (1) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
0xc0, /* END_COLLECTION */
#if defined(ARDUINO_ARCH_SAM)
/*Led 10 */
0x05, 0x0a, /* USAGE_PAGE (Ordinals) */
0x09, 0x0a, /* USAGE (Instance 10) */
@@ -221,6 +230,12 @@ static const byte PROGMEM _hidReportPOPN[] = {
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x0E, /* REPORT_SIZE (14) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
#else
/* Reserved 23 bits */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x17, /* REPORT_SIZE (23) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
#endif
/*Footer */
0xc0 /* END_COLLECTION */
};
@@ -317,12 +332,21 @@ static const byte PROGMEM _hidReportPOPN[] = {
uint32_t leds = (*bitfield|buttonsState);
if (invert)
leds = ~leds;
for(int i = 0; i < 18; i++) {
for(int i = 0; i < 9; i++) {
if (leds>>i&1)
digitalWrite(LightPins[i],HIGH);
else
digitalWrite(LightPins[i],LOW);
}
#if defined(ARDUINO_ARCH_SAM)
for(int i = 9; i < 18; i++) {
if (leds>>i&1)
digitalWrite(LightPins[i],HIGH);
else
digitalWrite(LightPins[i],LOW);
}
#endif
}
int POPNHID_::sendState(uint32_t buttonsState){
+21 -1
View File
@@ -1,7 +1,9 @@
#define BOUNCE_WITH_PROMPT_DETECTION
#include <Bounce2.h>
#if defined(ARDUINO_ARCH_SAM)
#include <Keypad.h>
#include <Keyboard.h>
#endif
#include "POPNHID.h"
/* 125µs delay is 1 frame on highspeed USB spec */
#define REPORT_DELAY 125
@@ -9,12 +11,19 @@
POPNHID_ POPNHID;
/* Buttons + Lights declarations */
#if defined(ARDUINO_ARCH_SAM)
byte LightPins[] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 37, 39, 41, 43, 45, 47, 49, 51, 53};
byte ButtonPins[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 3, 2};
#else
uint8_t LightPins[] = {11,12,13,23,22,21,20,19,18};
uint8_t ButtonPins[] = {0,1,2,3,4,5,6,7,8,9,10};
#endif
const byte ButtonCount = sizeof(ButtonPins) / sizeof(ButtonPins[0]);
const byte LightCount = sizeof(LightPins) / sizeof(LightPins[0]);
Bounce buttons[ButtonCount];
#if defined(ARDUINO_ARCH_SAM)
/* Keypad declarations */
const byte ROWS = 4;
const byte COLS = 3;
@@ -47,6 +56,7 @@ byte colPins[COLS] = {A4, A6, A2}; //connect to the column pinouts of the keypad
*/
Keypad kpd = Keypad( makeKeymap(numpad), rowPins, colPins, ROWS, COLS );
#endif
/* SETUP */
void setup() {
@@ -61,15 +71,17 @@ void setup() {
pinMode(LightPins[i], OUTPUT);
}
#if defined(ARDUINO_ARCH_SAM)
kpd.setDebounceTime(30);
Keyboard.begin();
/* activate numlock if you are not using the toprow keys */
/* delay(2000);
Keyboard.press(136 + 83);
delay(500);
Keyboard.release(136+83);
*/
#endif
//boot animation
uint16_t anim[] = {1, 4, 16, 64, 256, 128, 32, 8, 2};
@@ -114,7 +126,9 @@ void loop() {
/* Reactive mode, locally determined lamp data */
case 0:
but_lights(buttonsState & 0x1ff);
#if defined(ARDUINO_ARCH_SAM)
reactive_neon(buttonsState & 0x1ff);
#endif
break;
/* HID mode, only based on received HID data */
case 1:
@@ -130,6 +144,7 @@ void loop() {
break;
}
#if defined(ARDUINO_ARCH_SAM)
/* KEYPAD */
if (kpd.getKeys())
{
@@ -154,6 +169,7 @@ void loop() {
}
}
}
#endif
/* MANUAL LIGHTMODE UPDATE */
if ( buttonsState & 1024 ) {
@@ -170,6 +186,7 @@ void loop() {
}
#if defined(ARDUINO_ARCH_SAM)
/* Manage pillars and top neons in reactive mode */
uint16_t neon_anim[] = {16, 24, 28, 30, 31, 30, 28, 24};
int neon_anim_index = 0;
@@ -256,6 +273,7 @@ if (pillar_lit)
*/
neon_lights(neons);
}
#endif
/* Light up button lights according to bitfield */
void but_lights(uint16_t lightDesc) {
@@ -283,7 +301,9 @@ void neon_lights(uint16_t lightDesc) {
void animate(uint16_t* tab, uint8_t n, int mswait) {
for (int i = 0; i < n; i++) {
but_lights(tab[i]);
#if defined(ARDUINO_ARCH_SAM)
neon_lights(tab[i]);
#endif
delay(mswait);
}
}