diff --git a/arcade_station_v1.0.6.c b/arcade_station_v1.0.6.c new file mode 100644 index 0000000..62536e3 --- /dev/null +++ b/arcade_station_v1.0.6.c @@ -0,0 +1,567 @@ +/* +ADAFRUIT RETROGAME UTILITY: remaps buttons on Raspberry Pi GPIO header +to virtual USB keyboard presses. Great for classic game emulators! +Retrogame is interrupt-driven and efficient (usually under 0.3% CPU use) +and debounces inputs for glitch-free gaming. + +Connect one side of button(s) to GND pin (there are several on the GPIO +header, but see later notes) and the other side to GPIO pin of interest. +Internal pullups are used; no resistors required. Avoid pins 8 and 10; +these are configured as a serial port by default on most systems (this +can be disabled but takes some doing). Pin configuration is currently +set in global table; no config file yet. See later comments. + +Must be run as root, i.e. 'sudo ./retrogame &' or configure init scripts +to launch automatically at system startup. + +Requires uinput kernel module. This is typically present on popular +Raspberry Pi Linux distributions but not enabled on some older varieties. +To enable, either type: + + sudo modprobe uinput + +Or, to make this persistent between reboots, add a line to /etc/modules: + + uinput + +To use with the Picade project (w/Adafruit PiTFT and menu util), retrogame +must be recompiled with PICADE #defined, i.e.: + + make clean; make CFLAGS=-DPICADE + +Written by Phil Burgess for Adafruit Industries, distributed under BSD +License. Adafruit invests time and resources providing this open source +code, please support Adafruit and open-source hardware by purchasing +products from Adafruit! + + +Copyright (c) 2013 Adafruit Industries. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// ----------------------------------------------------------------------- +// MCP23017 (I2c) Config ------------------------------------------------- + +#define I2C000_ADDRESS 0x20 // MCP "000" address +#define IODIRA 0x00 // bank A GPIO pin address direction +#define IODIRB 0x01 // bank B GPIO pin address direction +#define GPINTENA 0x04 // enable interrupt on change of GPIOA register +#define GPINTENB 0x05 // enable interrupt on change of GPIOB register +#define GPPUA 0x0C // bank A pull-up register address +#define GPPUB 0x0D // bank B pull-up register address +#define INTCAPA 0x10 // store GPIOA register values on interrupt +#define INTCAPB 0x11 // store GPIOB register values on interrupt +#define GPIOA 0x12 // bank A GPIO pin address +#define GPIOB 0x13 // bank B GPIO pin address + +char i2c000_path[] = "/dev/i2c-1"; + +struct regBank { + bool p_state[8]; + uint8_t key_code[8]; +}; + +// Define player 1 controls +struct regBank bankA = { + {1,1,1,1,1,1,1,1}, + { KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + KEY_UP, + KEY_LEFTCTRL, + KEY_LEFTALT, + KEY_SPACE, + KEY_LEFTSHIFT + } +}; + +// Define player 2 controls +struct regBank bankB = { + {1,1,1,1,1,1,1,1}, + { KEY_D, + KEY_V, + KEY_G, + KEY_R, + KEY_A, + KEY_S, + KEY_Q, + KEY_W + } +}; + + +// START HERE ------------------------------------------------------------ +// This table remaps GPIO inputs to keyboard values. In this initial +// implementation there's a 1:1 relationship (can't attach multiple keys +// to a button) and the list is fixed in code; there is no configuration +// file. Buttons physically connect between GPIO pins and ground. There +// are only a few GND pins on the GPIO header, so a breakout board is +// often needed. If you require just a couple extra ground connections +// and have unused GPIO pins, set the corresponding key value to GND to +// create a spare ground point. + +#define GND -1 +struct { + int pin; + int key; +} io[] = { + { 23, -2 }, // I2C000 INTA + { 18, -3 }, // I2C000 INTB + { 8, KEY_ESC }, // quit game + { 17, KEY_1 }, // start player 1 + { 27, KEY_2 }, // start player 2 + { 7, KEY_5 }, // insert coin - Select 1 + { 22, KEY_6 }, // insert coin - Select 20 + { 10, KEY_P } // game pause +}; +#define IOLEN (sizeof(io) / sizeof(io[0])) // io[] table size + +// A "Vulcan nerve pinch" (holding down a specific button combination +// for a few seconds) issues an 'esc' keypress to MAME (which brings up +// an exit menu or quits the current game). The button combo is +// configured with a bitmask corresponding to elements in the above io[] +// array. The default value here uses elements 6 and 7 (credit and start +// in the Picade pinout). If you change this, make certain it's a combo +// that's not likely to occur during actual gameplay (i.e. avoid using +// joystick directions or hold-for-rapid-fire buttons). +// const unsigned long vulcanMask = (1L << 6) | (1L << 7); +//const int vulcanKey = KEY_ESC, // Keycode to send +// vulcanTime = 1500; // Pinch time in milliseconds + + +// A few globals --------------------------------------------------------- + +char + *progName, // Program name (for error reporting) + sysfs_root[] = "/sys/class/gpio", // Location of Sysfs GPIO files + running = 1; // Signal handler will set to 0 (exit) +volatile unsigned int + *gpio; // GPIO register table +const int + debounceTime = 20; // 20 ms for button de-bouncing + + +// Some utility functions ------------------------------------------------ + +// Set one GPIO pin attribute through the Sysfs interface. +int pinConfig(int pin, char *attr, char *value) { + char filename[50]; + int fd, w, len = strlen(value); + sprintf(filename, "%s/gpio%d/%s", sysfs_root, pin, attr); + if((fd = open(filename, O_WRONLY)) < 0) return -1; + w = write(fd, value, len); + close(fd); + return (w != len); // 0 = success +} + +// Un-export any Sysfs pins used; don't leave filesystem cruft. Also +// restores any GND pins to inputs. Write errors are ignored as pins +// may be in a partially-initialized state. +void cleanup() { + char buf[50]; + int fd, i; + sprintf(buf, "%s/unexport", sysfs_root); + if((fd = open(buf, O_WRONLY)) >= 0) { + for(i=0; i 0) { // If IRQ... + for(i=0; i= 0; i--) { // Press, release + keyEv.value = i; + write(fd, &keyEv, sizeof(keyEv)); + usleep(10000); // Be slow, else MAME flakes + write(fd, &synEv, sizeof(synEv)); + usleep(10000); + } + timeout = -1; // Return to normal processing +#endif + } */ + } + + // ---------------------------------------------------------------- + // Clean up + + ioctl(fd, UI_DEV_DESTROY); // Destroy and + close(fd); // close uinput + close(fd_i2c000); // close fd_i2c000 + cleanup(); // Un-export pins + + puts("Done."); + return 0; +} diff --git a/circuit_schematic.txt b/circuit_schematic.txt new file mode 100644 index 0000000..29d6076 --- /dev/null +++ b/circuit_schematic.txt @@ -0,0 +1,21 @@ + MCP23017 chip (MCP) Raspberry GPIO (RASPY) + ____________ ______ + | | | | + (Button LEFT P2)-| GPB0 GPA7 |-(Button 4 P1) (MCP VDD,RESET)-| O O | + (Button DOWN P2)-| GPB1 GPA6 |-(Button 3 P1) (MCP SDA)-| O O | +(Button RIGHT P2)-| GPB2 GPA5 |-(Button 2 P1) (MCP SCL)-| O O | + (Button UP P2)-| GPB3 GPA4 |-(Button 1 P1) | O O | + (Button 1 P2)-| GPB4 GPA3 |-(Button UP P1) | O O | + (Button 2 P2)-| GPB5 GPA2 |-(Button RIGHT P1) (BUTTON 1)-| O O | + (Button 3 P2)-| GPB6 GPA1 |-(Button DOWN P1) (BUTTON 2)-| O O | + (Button 4 P2)-| GPB7 GPA0 |-(Button LEFT P1) (BUTTON 6)-| O O |-(MCP INTA) + (RASPY +3.3V)-| VDD INTA |-(RASPY GPIO23) | O O |-(MCP INTB) + (RASPY GROUND)-| VSS INTB |-(RASPY GPIO18) (BUTTON P=PAUSE)-| O O | + -| NC RESET |-(RASPY +3.3V) | O O | + (RASPY SCL)-| SCL A2 |-(RASPY GROUND) | O O |-(BUTTON ESC) + (RASPY SDA)-| SDA A1 |-(RASPY GROUND) (MCP VSS,A2,A1,A0)-| O O |-(BUTTON 5) + -| NC A0 |-(RASPY GROUND) |______| + |____________| + + +