Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 299 lines (252 sloc) 9.001 kB
c5df392 Initial commit.
Florian authored
1 /*
2 * SNESDev - Simulates a virtual keyboard for two SNES controllers that are
3 * connected to the GPIO pins of the Raspberry Pi.
4 *
5 * (c) Copyright 2012 Florian Müller (petrockblog@flo-mueller.com)
6 *
7 * SNESDev homepage: https://github.com/petrockblog/SNESDev-RPi
8 *
9 * Permission to use, copy, modify and distribute SNESDev in both binary and
10 * source form, for non-commercial purposes, is hereby granted without fee,
11 * providing that this license information and copyright notice appear with
12 * all copies and any derived work.
13 *
14 * This software is provided 'as-is', without any express or implied
15 * warranty. In no event shall the authors be held liable for any damages
16 * arising from the use of this software.
17 *
18 * SNESDev is freeware for PERSONAL USE only. Commercial users should
19 * seek permission of the copyright holders first. Commercial use includes
20 * charging money for SNESDev or software derived from SNESDev.
21 *
22 * The copyright holders request that bug fixes and improvements to the code
23 * should be forwarded to them so everyone can benefit from the modifications
24 * in future versions.
25 *
26 * Raspberry Pi is a trademark of the Raspberry Pi Foundation.
27 */
28
29 #include <linux/input.h>
30 #include <linux/uinput.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stdio.h>
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
35 #include <stdlib.h>
c5df392 Initial commit.
Florian authored
36 #include <unistd.h>
37 #include <bcm2835.h>
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
38 #include <signal.h>
6da8309 Added recognition of short/long button press.
petrockblog authored
39 #include <time.h>
c5df392 Initial commit.
Florian authored
40
41 #include "SNESpad.h"
42
43 /* time to wait after each cycle */
44 #define FRAMEWAIT 20
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
45 #define FRAMEWAITLONG 200
c5df392 Initial commit.
Florian authored
46
47 /* set the GPIO pins of the button and the LEDs. */
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
48 #define BUTTONPIN RPI_GPIO_P1_11
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
49
50 int uinp_fd;
51 int doRun, pollButton, pollPads;
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
52 time_t timePressed;
53 uint8_t lastBtnState;
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
54
55 /* Signal callback function */
56 void sig_handler(int signo) {
57 if ((signo == SIGINT) | (signo == SIGKILL) | (signo == SIGQUIT) | (signo == SIGABRT)) {
58 printf("Releasing SNESDev-Rpi device.\n");
59 pollButton = 0;
60 pollPads = 0;
61 /* Destroy the input device */
62 ioctl(uinp_fd, UI_DEV_DESTROY);
63 /* Close the UINPUT device */
64 close(uinp_fd);
65 doRun = 0;
66 }
67 }
c5df392 Initial commit.
Florian authored
68
69 /* Setup the uinput device */
70 int setup_uinput_device() {
71 int uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
72 if (uinp_fd == 0) {
73 printf("Unable to open /dev/uinput\n");
74 return -1;
75 }
76
77 struct uinput_user_dev uinp;
78 memset(&uinp, 0, sizeof(uinp));
79 strncpy(uinp.name, "SNES-to-Keyboard Device", strlen("SNES-to-Keyboard Device"));
80 uinp.id.version = 4;
81 uinp.id.bustype = BUS_USB;
82 uinp.id.product = 1;
83 uinp.id.vendor = 1;
84
85 // Setup the uinput device
86 ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
87 ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
88 int i = 0;
89 for (i = 0; i < 256; i++) {
90 ioctl(uinp_fd, UI_SET_KEYBIT, i);
91 }
92
93 /* Create input device into input sub-system */
94 write(uinp_fd, &uinp, sizeof(uinp));
95 if (ioctl(uinp_fd, UI_DEV_CREATE)) {
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
96 printf("[SNESDev-Rpi] Unable to create UINPUT device.");
c5df392 Initial commit.
Florian authored
97 return -1;
98 }
99
100 return uinp_fd;
101 }
102
103 /* sends a key event to the virtual device */
104 void send_key_event(int fd, unsigned int keycode, int keyvalue) {
105 struct input_event event;
106 gettimeofday(&event.time, NULL);
107
108 event.type = EV_KEY;
109 event.code = keycode;
110 event.value = keyvalue;
111
112 if (write(fd, &event, sizeof(event)) < 0) {
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
113 printf("[SNESDev-Rpi] Simulate key error\n");
c5df392 Initial commit.
Florian authored
114 }
115
116 event.type = EV_SYN;
117 event.code = SYN_REPORT;
118 event.value = 0;
119 write(fd, &event, sizeof(event));
120 if (write(fd, &event, sizeof(event)) < 0) {
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
121 printf("[SNESDev-Rpi] Simulate key error\n");
c5df392 Initial commit.
Florian authored
122 }
123 }
124
6da8309 Added recognition of short/long button press.
petrockblog authored
125 /* checks the state of the button and decides for a short or long button press */
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
126 void checkButton(int uinh)
127 {
c5df392 Initial commit.
Florian authored
128
129 // read the state of the button into a local variable
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
130 uint8_t buttonState = bcm2835_gpio_lev(BUTTONPIN);
c5df392 Initial commit.
Florian authored
131
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
132 if (buttonState==HIGH && lastBtnState==LOW)
133 {
134 timePressed=time(NULL);
135 }
136
137 else if (buttonState==LOW && lastBtnState==HIGH)
138 {
139 time_t curTime = time(NULL);
140 double dif = difftime(curTime,timePressed);
141
142 // Sending ESC
143 send_key_event(uinh, KEY_ESC,1);
144 usleep(100000);
145 send_key_event(uinh, KEY_ESC,0);
146 usleep(500000);
147
148 send_key_event(uinh, KEY_F4,1);
149 usleep(100000);
150 send_key_event(uinh, KEY_F4,0);
151 usleep(2000000);
152
153 /*send_key_event(uinh, KEY_B,1);
154 usleep(100000);
155 send_key_event(uinh, KEY_B,0);
156 usleep(1000000);*/
157
158
159 system("sudo /home/pi/SNES-Pi/MCP23017_CartReader/cartCheckAndEmulate.sh f &");
160 usleep(1000000); //sleep for 1 seconds
161
162 //system("shutdown -t 3 -h now");
163 }
164 lastBtnState=buttonState;
165
c5df392 Initial commit.
Florian authored
166 }
167
168 /* checks, if a button on the pad is pressed and sends an event according the button state. */
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
169 void processPadBtn(uint16_t buttons, uint16_t mask, uint16_t key, int uinh) {
c5df392 Initial commit.
Florian authored
170 if ( (buttons & mask) == mask ) {
171 send_key_event(uinh, key, 1);
172 } else {
173 send_key_event(uinh, key, 0);
174 }
175 }
176
177
178 int main(int argc, char *argv[]) {
179
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
180 buttonstates padButtons;
181 snespad pads;
182 pollButton = 1;
183 pollPads = 1;
184 doRun = 1;
185
186 // check command line arguments
187 if (argc > 1) {
188 // argv[1]==1 poll controllers only
189 // argv[1]==2 poll button only
190 // argv[1]==3 poll controllers and button
191 switch ( atoi(argv[argc-1]) ) {
192 case 1:
193 printf("[SNESDev-Rpi] Polling only controllers.\n");
194 pollButton = 0;
195 pollPads = 1;
196 break;
197 case 2:
198 printf("[SNESDev-Rpi] Polling button only.\n");
199 pollButton = 1;
200 pollPads = 0;
201 break;
202 case 3:
203 printf("[SNESDev-Rpi] Polling controllers and button.\n");
204 pollButton = 1;
205 pollPads = 1;
206 break;
207 default:
208 return -1;
209 }
210 } else {
211 printf("[SNESDev-Rpi] Polling controllers and button.\n");
212 }
c5df392 Initial commit.
Florian authored
213
214 if (!bcm2835_init())
215 return 1;
216
217 // initialize button and LEDs
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
218 bcm2835_gpio_fsel(BUTTONPIN, BCM2835_GPIO_FSEL_INPT);
c5df392 Initial commit.
Florian authored
219
220 /* initialize controller structures with GPIO pin assignments */
221
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
222 // pin out used in SNESDev article on blog
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
223 pads.clock = RPI_GPIO_P1_18;
224 pads.strobe = RPI_GPIO_P1_16;
225 pads.data1 = RPI_GPIO_P1_22;
226 pads.data2 = RPI_GPIO_P1_15;
227
228 // pin out used pi gamecon GPIO driver
229 /* pads.clock = RPI_GPIO_P1_19;
230 pads.strobe = RPI_GPIO_P1_23;
231 pads.data1 = RPI_GPIO_P1_07;
232 pads.data2 = RPI_GPIO_P1_05;
233 */
c5df392 Initial commit.
Florian authored
234
235 /* set GPIO pins as input or output pins */
8b460e5 Enhanced polling of controllers
petrockblog authored
236 initializePads( &pads );
c5df392 Initial commit.
Florian authored
237
238 /* intialize virtual input device */
239 if ((uinp_fd = setup_uinput_device()) < 0) {
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
240 printf("[SNESDev-Rpi] Unable to find uinput device\n");
c5df392 Initial commit.
Florian authored
241 return -1;
242 }
243
7a24d81 @waterbury Changes for Super Nintendo Emulated System Project
authored
244 if (signal(SIGINT, sig_handler) == SIG_ERR)
245 printf("\n[SNESDev-Rpi] Cannot catch SIGINT\n");
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
246
c5df392 Initial commit.
Florian authored
247 /* enter the main loop */
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
248 while ( doRun ) {
249
250 if (pollButton) {
251 /* Check state of button. */
252 checkButton(uinp_fd);
253 }
254
255 if (pollPads) {
256 /* read states of the buttons */
257 updateButtons(&pads, &padButtons);
258
259 /* send an event (pressed or released) for each button */
260 /* key events for first controller */
261 processPadBtn(padButtons.buttons1, SNES_A, KEY_X, uinp_fd);
262 processPadBtn(padButtons.buttons1, SNES_B, KEY_Z, uinp_fd);
263 processPadBtn(padButtons.buttons1, SNES_X, KEY_S, uinp_fd);
264 processPadBtn(padButtons.buttons1, SNES_Y, KEY_A, uinp_fd);
265 processPadBtn(padButtons.buttons1, SNES_L, KEY_Q, uinp_fd);
266 processPadBtn(padButtons.buttons1, SNES_R, KEY_W, uinp_fd);
267 processPadBtn(padButtons.buttons1, SNES_SELECT,KEY_RIGHTSHIFT, uinp_fd);
268 processPadBtn(padButtons.buttons1, SNES_START, KEY_ENTER, uinp_fd);
269 processPadBtn(padButtons.buttons1, SNES_LEFT, KEY_LEFT, uinp_fd);
270 processPadBtn(padButtons.buttons1, SNES_RIGHT, KEY_RIGHT, uinp_fd);
271 processPadBtn(padButtons.buttons1, SNES_UP, KEY_UP, uinp_fd);
272 processPadBtn(padButtons.buttons1, SNES_DOWN, KEY_DOWN, uinp_fd);
273
274 // key events for second controller
275 processPadBtn(padButtons.buttons2, SNES_A, KEY_E, uinp_fd);
276 processPadBtn(padButtons.buttons2, SNES_B, KEY_R, uinp_fd);
277 processPadBtn(padButtons.buttons2, SNES_X, KEY_T, uinp_fd);
278 processPadBtn(padButtons.buttons2, SNES_Y, KEY_Y, uinp_fd);
279 processPadBtn(padButtons.buttons2, SNES_L, KEY_U, uinp_fd);
280 processPadBtn(padButtons.buttons2, SNES_R, KEY_I, uinp_fd);
281 processPadBtn(padButtons.buttons2, SNES_SELECT,KEY_O, uinp_fd);
282 processPadBtn(padButtons.buttons2, SNES_START, KEY_P, uinp_fd);
283 processPadBtn(padButtons.buttons2, SNES_LEFT, KEY_C, uinp_fd);
284 processPadBtn(padButtons.buttons2, SNES_RIGHT, KEY_B, uinp_fd);
285 processPadBtn(padButtons.buttons2, SNES_UP, KEY_F, uinp_fd);
286 processPadBtn(padButtons.buttons2, SNES_DOWN, KEY_V, uinp_fd);
287 }
c5df392 Initial commit.
Florian authored
288
289 /* wait for some time to keep the CPU load low */
bcd23e0 longer frame wait if only button is polled
petrockblog authored
290 if (pollButton && !pollPads) {
291 delay(FRAMEWAITLONG);
292 } else {
293 delay(FRAMEWAIT);
294 }
c5df392 Initial commit.
Florian authored
295 }
296
5d3d9f5 Extended code for use with RetroPie GPIO adapter, added signal handling
petrockblog authored
297 return 0;
c5df392 Initial commit.
Florian authored
298 }
Something went wrong with that request. Please try again.