3 Commits
Author SHA1 Message Date
CrazyRedMachine ba765f2cd9 keypad hotkey 2020-11-17 01:21:06 +01:00
CrazyRedMachine 9e6ff10523 Update README.md 2020-11-10 22:57:01 +01:00
CrazyRedMachine b3c44bdf5a working 2020-11-10 22:54:43 +01:00
3 changed files with 209 additions and 7 deletions
+17 -1
View File
@@ -28,6 +28,8 @@ The keypad code uses the Keypad library by Mark Stanley and Alexander Brevig.
Switch debouncing is done with Bounce2 library by Thomas O Fredericks.
PSX Controller code is based on busslave's PSX_RECEIVER.cpp
# Supported devices and requirements
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.
@@ -38,6 +40,18 @@ The keypad code requires the Keypad library by Mark Stanley and Alexander Brevig
# Features
## Playstation Controller (Leonardo only, Due coming soon)
This controller can be used as a playstation controller for Pop'n Music CS versions.
Note that this requires a couple hardware mods in order to work as we are using two extra pins (SS and ACK, on the RX and TX leds aka PB0 and PD5) which are not readily available on the pre-soldered headers.
Of course you'll need either a dualshock breakout board or a dualshock extension cable for it to work.
Refer to the pinout to know how to wire the controller plug to the arduino.
**Note:** This is PoC code, I'll try to port a more complete dualshock implementation soon and make it Due compatible as well
## I/O
This controller has 12 buttons (9 buttons + coin + service + test) and 18 lights (9 buttons + 5 top neon + 4 side pillar).
@@ -109,4 +123,6 @@ Refer to ```pinout.png``` to see how it is all wired to a Pop'n Music cabinet.
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)
![pinout](https://github.com/CrazyRedMachine/UltimatePopnController/blob/PSX/pinout_leonardo.png?raw=true)
For ACK (TXLED aka PD5) and SS (RXLED aka PB0) you have to solder new headers or cables directly on the leonardo PCB. For the PSX controller function to work properly you need to short SS to ground (leonardo doesn't work well as SPI slave otherwise, which is why we cannot use the "attention" line from the controller cable unfortunately).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 687 KiB

+192 -6
View File
@@ -2,9 +2,24 @@
#include <Bounce2.h>
#if defined(ARDUINO_ARCH_SAM)
#include <Keypad.h>
#include <Keyboard.h>
#else
#include <Keyboard.h>
#include <EEPROM.h>
/* PSX DEFINE */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define SPI_PORT PORTB
#define SPI_PINS PINB
#define SPI_DDR DDRB
#define SPI_PINS PINB
#define ACK_PIN 5 //PB1
#define ATT_PIN 0 //~SS
#define CMD_PIN 2 //MOSI
#define DATA_PIN 3 //MISO
#define CLK_PIN 1 //SCK
#define DATA_LEN 5
/* /PSX DEFINE */
#endif
#include "POPNHID.h"
/* 1 frame (as declared in POPNHID.cpp) on highspeed USB spec is 125µs */
@@ -58,6 +73,121 @@ byte colPins[COLS] = {A4, A6, A2}; //connect to the column pinouts of the keypad
*/
Keypad kpd = Keypad( makeKeymap(numpad), rowPins, colPins, ROWS, COLS );
#else
/* PSX globals */
volatile uint8_t data_buff[DATA_LEN]={0x41,0x5A,0xBF,0xFF,0xFF};//Reply.
volatile uint8_t command_buff[DATA_LEN]={0x01,0x42,0x00,0x00,0x00};
volatile uint8_t curr_byte=0;
volatile uint8_t next_byte=0;
byte b4;
byte b5;
void convertPopn(uint32_t buttons){
b4 = 0xFF;
b5 = 0xFF;
if (((buttons >> 9) & 1)) {
b4 &= ~((unsigned char) 0x01);
} else {
b4 |= ((unsigned char) 0x01);
}
if (((buttons >> 10) & 1)) {
b4 &= ~((unsigned char) 0x08);
} else {
b4 |= ((unsigned char) 0x08);
}
if (((buttons >> 0) & 1)) {
b5 &= ~((unsigned char) 0x10);
} else {
b5 |= ((unsigned char) 0x10);
}
if (((buttons >> 1) & 1)) {
b5 &= ~((unsigned char) 0x20);
} else {
b5 |= ((unsigned char) 0x20);
}
if (((buttons >> 2) & 1)) {
b5 &= ~((unsigned char) 0x08);
} else {
b5 |= ((unsigned char) 0x08);
}
if (((buttons >> 3) & 1)) {
b5 &= ~((unsigned char) 0x40);
} else {
b5 |= ((unsigned char) 0x40);
}
if (((buttons >> 4) & 1)) {
b5 &= ~((unsigned char) 0x04);
} else {
b5 |= ((unsigned char) 0x04);
}
if (((buttons >> 5) & 1)) {
b5 &= ~((unsigned char) 0x80);
} else {
b5 |= ((unsigned char) 0x80);
}
if (((buttons >> 6) & 1)) {
b5 &= ~((unsigned char) 0x02);
} else {
b5 |= ((unsigned char) 0x02);
}
if (((buttons >> 7) & 1)) {
b4 &= ~((unsigned char) 0x10);
} else {
b4 |= ((unsigned char) 0x10);
}
if (((buttons >> 8) & 1)) {
b5 &= ~((unsigned char) 0x01);
} else {
b5 |= ((unsigned char) 0x01);
}
// left down right always held with popn controller
b4 &= 0x1F;
data_buff[2] = b4;
data_buff[3] = b5;
}
ISR(SPI_STC_vect) {
uint8_t inbyte=SPDR;
if (inbyte==command_buff[curr_byte]) {
SPDR = data_buff[curr_byte];
curr_byte++;
if (curr_byte<DATA_LEN) {//ACK low.
//SPI_PORT &= ~(1<<ACK_PIN);
PORTD &= ~(1<<5);//set HIGH
// simulate open drain
// SPI_DDR |= (1<<ACK_PIN);//output
// SPI_PORT &= ~(1<<ACK_PIN);//set low (simulate open collector LOW)
_delay_us(5);
//SPI_PORT |= (1<<ACK_PIN);
PORTD |= (1<<5);//set HIGH
// simulate open drain
// SPI_DDR &= ~(1<<ACK_PIN);//input
// SPI_PORT |= (1<<ACK_PIN);//set high (simulate open collector Hi-Z)
} else {
SPDR = 0xFF;
curr_byte=0;
}
} else {
SPDR = 0xFF;
curr_byte=0;
}
SPI_DDR |= (1<<ATT_PIN);//out
SPI_PORT |= (1<<ATT_PIN);//set HIGH
_delay_us(5);
SPI_PORT &= ~(1<<ATT_PIN);//set HIGH
}
/* /PSX globals */
#endif
/* SETUP */
@@ -75,7 +205,6 @@ void setup() {
#if defined(ARDUINO_ARCH_SAM)
kpd.setDebounceTime(30);
Keyboard.begin();
/* activate numlock if you are not using the toprow keys */
/* delay(2000);
@@ -84,11 +213,42 @@ void setup() {
Keyboard.release(136+83);
*/
#else
uint8_t lightMode;
Keyboard.begin();
uint8_t lightMode = 2;
EEPROM.get(0, lightMode);
if (lightMode < 0 || lightMode > 3)
lightMode = 2;
POPNHID.setLightMode(lightMode);
/* PSX setup */
// use TXLED as ACK
// DDRD |= (1<<5);//output
PORTD |= (1<<5);//set HIGH
SPI_DDR |= (1<<DATA_PIN);//output
SPI_PORT |= (1<<DATA_PIN);//set HIGH
SPI_DDR |= (1<<ATT_PIN);//out
delay(500);
SPI_PORT |= (1<<ATT_PIN);//set HIGH
delay(5000);
SPI_PORT |= (1<<ATT_PIN);//set HIGH
//SPI setup.
// PRR &= ~(1<<PRSPI);//Set to 0 to ensure power to SPI module.
//SPSR|=(1<<SPI2X);//Fosc/32. @16MHz==500KHz.
SPCR|=(1<<SPR1);//Fosc/64. @16MHz==250KHz.
SPCR|=(1<<CPHA);//Setup @ leading edge, sample @ falling edge.
SPCR|=(1<<CPOL);//Leading edge is falling edge, trailing edge is rising edge.
SPCR &= ~(1<<MSTR);//MSTR bit is zero, SPI is slave.
SPCR|=(1<<DORD);//Byte is transmitted LSB first, MSB last.
SPCR|=(1<<SPE);//Enable SPI.
SPCR|=(1<<SPIE);//Enable Serial Transfer Complete (STC) interrupt.
SPDR=0xFF;
sei();//Enable global interrupts.
/* /PSX setup */
#endif
//boot animation
@@ -100,6 +260,7 @@ void setup() {
animate(anim2, 2, 500);
}
char kpdhotkeys[11] = {'1','2','3','4','5','6','7','8','9','x','0'};
/* LOOP */
unsigned long lastReport = 0;
uint32_t prevButtonsState = 0;
@@ -116,13 +277,16 @@ void loop() {
buttonsState &= ~((uint32_t)1 << i);
}
}
#if defined(ARDUINO_ARCH_AVR)
/* PSX convert */
convertPopn(buttonsState);
#endif
/* USB DATA */
if ( ( (micros() - lastReport) >= REPORT_DELAY) )
{
POPNHID.sendState(buttonsState);
lastReport = micros();
prevButtonsState = buttonsState;
//check for HID-requested lightmode change
POPNHID.updateLightMode();
@@ -188,7 +352,26 @@ void loop() {
}
}
#endif
/* KEYPAD HOTKEY */
if ( buttonsState & 512 ) {
if ( prevButtonsState != buttonsState )
{
for (int i=0; i<11; i++)
{
if (i==9) continue;
if ( ((buttonsState>>i) & 1) && !((prevButtonsState>>i) & 1) )
{
Keyboard.press(kpdhotkeys[i]);
}
else if ( !((buttonsState>>i) & 1) && ((prevButtonsState>>i) & 1) )
{
Keyboard.release(kpdhotkeys[i]);
}
}
}
}
/* MANUAL LIGHTMODE UPDATE */
if ( buttonsState & 1024 ) {
if ( (buttonsState & 2) && (modeChanged == false)) {
@@ -204,6 +387,9 @@ void loop() {
modeChanged = false;
}
}
prevButtonsState = buttonsState;
}
/* Light up button lights according to bitfield */
@@ -328,4 +514,4 @@ if (pillar_lit)
*/
neon_lights(neons);
}
#endif
#endif