Mercurial > repos > blastem
comparison io.c @ 803:236a184bf6f0
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 26 Jul 2015 16:51:03 -0700 |
parents | 41f73c76b978 |
children | 9f149f0e98b7 |
comparison
equal
deleted
inserted
replaced
802:6811f601008f | 803:236a184bf6f0 |
---|---|
1 /* | 1 /* |
2 Copyright 2013 Michael Pavone | 2 Copyright 2013 Michael Pavone |
3 This file is part of BlastEm. | 3 This file is part of BlastEm. |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. |
5 */ | 5 */ |
6 #ifndef _WIN32 | |
7 #include <unistd.h> | |
8 #include <fcntl.h> | |
9 #include <sys/socket.h> | |
10 #include <sys/un.h> | |
11 #include <sys/types.h> | |
12 #include <sys/stat.h> | |
13 #include <errno.h> | |
14 #endif | |
15 #include <string.h> | |
16 #include <stdlib.h> | |
17 | |
6 #include "io.h" | 18 #include "io.h" |
7 #include "blastem.h" | 19 #include "blastem.h" |
8 #include "render.h" | 20 #include "render.h" |
9 | 21 |
22 const char * device_type_names[] = { | |
23 "3-button gamepad", | |
24 "6-button gamepad", | |
25 "Mega Mouse", | |
26 "Menacer", | |
27 "Justifier", | |
28 "Sega multi-tap", | |
29 "EA 4-way Play cable A", | |
30 "EA 4-way Play cable B", | |
31 "Sega Parallel Transfer Board", | |
32 "Generic Device", | |
33 "None" | |
34 }; | |
35 | |
10 enum { | 36 enum { |
11 BIND_NONE, | 37 BIND_NONE, |
38 BIND_UI, | |
12 BIND_GAMEPAD1, | 39 BIND_GAMEPAD1, |
13 BIND_GAMEPAD2, | 40 BIND_GAMEPAD2, |
14 BIND_UI | 41 BIND_GAMEPAD3, |
42 BIND_GAMEPAD4, | |
43 BIND_GAMEPAD5, | |
44 BIND_GAMEPAD6, | |
45 BIND_GAMEPAD7, | |
46 BIND_GAMEPAD8 | |
15 }; | 47 }; |
16 | 48 |
17 typedef enum { | 49 typedef enum { |
18 UI_DEBUG_MODE_INC, | 50 UI_DEBUG_MODE_INC, |
19 UI_DEBUG_PAL_INC, | 51 UI_DEBUG_PAL_INC, |
24 UI_PREV_SPEED, | 56 UI_PREV_SPEED, |
25 UI_EXIT | 57 UI_EXIT |
26 } ui_action; | 58 } ui_action; |
27 | 59 |
28 typedef struct { | 60 typedef struct { |
61 io_port *port; | |
29 uint8_t bind_type; | 62 uint8_t bind_type; |
30 uint8_t subtype_a; | 63 uint8_t subtype_a; |
31 uint8_t subtype_b; | 64 uint8_t subtype_b; |
32 uint8_t value; | 65 uint8_t value; |
33 } keybinding; | 66 } keybinding; |
115 #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20) | 148 #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20) |
116 | 149 |
117 void bind_gamepad(int keycode, int gamepadnum, int button) | 150 void bind_gamepad(int keycode, int gamepadnum, int button) |
118 { | 151 { |
119 | 152 |
120 if (gamepadnum < 1 || gamepadnum > 2) { | 153 if (gamepadnum < 1 || gamepadnum > 8) { |
121 return; | 154 return; |
122 } | 155 } |
123 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 156 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
124 bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); | 157 bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); |
125 } | 158 } |
126 | 159 |
127 void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton) | 160 void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton) |
128 { | 161 { |
129 if (gamepadnum < 1 || gamepadnum > 2) { | 162 if (gamepadnum < 1 || gamepadnum > 8) { |
130 return; | 163 return; |
131 } | 164 } |
132 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 165 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
133 bind_button(joystick, joybutton, bind_type, padbutton >> 12, padbutton >> 8 & 0xF, padbutton & 0xFF); | 166 bind_button(joystick, joybutton, bind_type, padbutton >> 12, padbutton >> 8 & 0xF, padbutton & 0xFF); |
134 } | 167 } |
135 | 168 |
136 void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button) | 169 void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button) |
137 { | 170 { |
138 if (gamepadnum < 1 || gamepadnum > 2) { | 171 if (gamepadnum < 1 || gamepadnum > 8) { |
139 return; | 172 return; |
140 } | 173 } |
141 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 174 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
142 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); | 175 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); |
143 } | 176 } |
157 bind_dpad(joystick, dpad, direction, BIND_UI, action, 0, param); | 190 bind_dpad(joystick, dpad, direction, BIND_UI, action, 0, param); |
158 } | 191 } |
159 | 192 |
160 void handle_binding_down(keybinding * binding) | 193 void handle_binding_down(keybinding * binding) |
161 { | 194 { |
162 switch(binding->bind_type) | 195 if (binding->bind_type >= BIND_GAMEPAD1) |
163 { | 196 { |
164 case BIND_GAMEPAD1: | 197 if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { |
165 case BIND_GAMEPAD2: | 198 binding->port->input[binding->subtype_a] |= binding->value; |
166 if (binding->subtype_a <= GAMEPAD_EXTRA) { | 199 } |
167 genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] |= binding->value; | 200 if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { |
168 } | 201 binding->port->input[binding->subtype_b] |= binding->value; |
169 if (binding->subtype_b <= GAMEPAD_EXTRA) { | 202 } |
170 genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] |= binding->value; | |
171 } | |
172 break; | |
173 } | 203 } |
174 } | 204 } |
175 | 205 |
176 void handle_keydown(int keycode) | 206 void handle_keydown(int keycode) |
177 { | 207 { |
204 { | 234 { |
205 switch(binding->bind_type) | 235 switch(binding->bind_type) |
206 { | 236 { |
207 case BIND_GAMEPAD1: | 237 case BIND_GAMEPAD1: |
208 case BIND_GAMEPAD2: | 238 case BIND_GAMEPAD2: |
209 if (binding->subtype_a <= GAMEPAD_EXTRA) { | 239 if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { |
210 genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] &= ~binding->value; | 240 binding->port->input[binding->subtype_a] &= ~binding->value; |
211 } | 241 } |
212 if (binding->subtype_b <= GAMEPAD_EXTRA) { | 242 if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { |
213 genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] &= ~binding->value; | 243 binding->port->input[binding->subtype_b] &= ~binding->value; |
214 } | 244 } |
215 break; | 245 break; |
216 case BIND_UI: | 246 case BIND_UI: |
217 switch (binding->subtype_a) | 247 switch (binding->subtype_a) |
218 { | 248 { |
219 case UI_DEBUG_MODE_INC: | 249 case UI_DEBUG_MODE_INC: |
220 ui_debug_mode++; | 250 ui_debug_mode++; |
221 if (ui_debug_mode == 4) { | 251 if (ui_debug_mode == 7) { |
222 ui_debug_mode = 0; | 252 ui_debug_mode = 0; |
223 } | 253 } |
224 genesis->vdp->debug = ui_debug_mode; | 254 genesis->vdp->debug = ui_debug_mode; |
225 break; | 255 break; |
226 case UI_DEBUG_PAL_INC: | 256 case UI_DEBUG_PAL_INC: |
227 ui_debug_pal++; | 257 ui_debug_pal++; |
228 if (ui_debug_pal == 4) { | 258 if (ui_debug_pal == 4) { |
229 ui_debug_pal = 0; | 259 ui_debug_pal = 0; |
230 } | 260 } |
231 render_debug_pal(ui_debug_pal); | 261 genesis->vdp->debug_pal = ui_debug_pal; |
232 break; | 262 break; |
233 case UI_ENTER_DEBUGGER: | 263 case UI_ENTER_DEBUGGER: |
234 break_on_sync = 1; | 264 break_on_sync = 1; |
235 break; | 265 break; |
236 case UI_SAVE_STATE: | 266 case UI_SAVE_STATE: |
308 } | 338 } |
309 | 339 |
310 int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) | 340 int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) |
311 { | 341 { |
312 int gpadslen = strlen("gamepads."); | 342 int gpadslen = strlen("gamepads."); |
313 if (!memcmp(target, "gamepads.", gpadslen)) { | 343 if (!strncmp(target, "gamepads.", gpadslen)) { |
314 if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { | 344 if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { |
315 int padnum = target[gpadslen] - '0'; | 345 int padnum = target[gpadslen] - '0'; |
316 int button = tern_find_int(padbuttons, target + gpadslen + 1, 0); | 346 int button = tern_find_int(padbuttons, target + gpadslen + 1, 0); |
317 if (button) { | 347 if (button) { |
318 *padnum_out = padnum; | 348 *padnum_out = padnum; |
326 } | 356 } |
327 } | 357 } |
328 } else { | 358 } else { |
329 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); | 359 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); |
330 } | 360 } |
331 } else if(!memcmp(target, "ui.", strlen("ui."))) { | 361 } else if(!strncmp(target, "ui.", strlen("ui."))) { |
332 *padbutton_out = 0; | 362 *padbutton_out = 0; |
333 if (!strcmp(target + 3, "vdp_debug_mode")) { | 363 if (!strcmp(target + 3, "vdp_debug_mode")) { |
334 *ui_out = UI_DEBUG_MODE_INC; | 364 *ui_out = UI_DEBUG_MODE_INC; |
335 } else if(!strcmp(target + 3, "vdp_debug_pal")) { | 365 } else if(!strcmp(target + 3, "vdp_debug_pal")) { |
336 *ui_out = UI_DEBUG_PAL_INC; | 366 *ui_out = UI_DEBUG_PAL_INC; |
337 } else if(!strcmp(target + 3, "enter_debugger")) { | 367 } else if(!strcmp(target + 3, "enter_debugger")) { |
338 *ui_out = UI_ENTER_DEBUGGER; | 368 *ui_out = UI_ENTER_DEBUGGER; |
339 } else if(!strcmp(target + 3, "save_state")) { | 369 } else if(!strcmp(target + 3, "save_state")) { |
340 *ui_out = UI_SAVE_STATE; | 370 *ui_out = UI_SAVE_STATE; |
341 } else if(!memcmp(target + 3, "set_speed.", strlen("set_speed."))) { | 371 } else if(!strncmp(target + 3, "set_speed.", strlen("set_speed."))) { |
342 *ui_out = UI_SET_SPEED; | 372 *ui_out = UI_SET_SPEED; |
343 *padbutton_out = atoi(target + 3 + strlen("set_speed.")); | 373 *padbutton_out = atoi(target + 3 + strlen("set_speed.")); |
344 } else if(!strcmp(target + 3, "next_speed")) { | 374 } else if(!strcmp(target + 3, "next_speed")) { |
345 *ui_out = UI_NEXT_SPEED; | 375 *ui_out = UI_NEXT_SPEED; |
346 } else if(!strcmp(target + 3, "prev_speed")) { | 376 } else if(!strcmp(target + 3, "prev_speed")) { |
445 if (curstr && len) { | 475 if (curstr && len) { |
446 free(curstr); | 476 free(curstr); |
447 } | 477 } |
448 } | 478 } |
449 | 479 |
450 void set_keybindings() | 480 void process_device(char * device_type, io_port * port) |
481 { | |
482 port->device_type = IO_NONE; | |
483 if (!device_type) | |
484 { | |
485 return; | |
486 } | |
487 | |
488 const int gamepad_len = strlen("gamepad"); | |
489 if (!memcmp(device_type, "gamepad", gamepad_len)) | |
490 { | |
491 if ( | |
492 (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6') | |
493 || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1' | |
494 || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0 | |
495 ) | |
496 { | |
497 fprintf(stderr, "%s is not a valid gamepad type\n", device_type); | |
498 } else if (device_type[gamepad_len] == '3') | |
499 { | |
500 port->device_type = IO_GAMEPAD3; | |
501 } else { | |
502 port->device_type = IO_GAMEPAD6; | |
503 } | |
504 port->device.pad.gamepad_num = device_type[gamepad_len+2] - '1'; | |
505 } else if(!strcmp(device_type, "sega_parallel")) { | |
506 port->device_type = IO_SEGA_PARALLEL; | |
507 port->device.stream.data_fd = -1; | |
508 port->device.stream.listen_fd = -1; | |
509 } else if(!strcmp(device_type, "generic")) { | |
510 port->device_type = IO_GENERIC; | |
511 port->device.stream.data_fd = -1; | |
512 port->device.stream.listen_fd = -1; | |
513 } | |
514 } | |
515 | |
516 char * io_name(int i) | |
517 { | |
518 switch (i) | |
519 { | |
520 case 0: | |
521 return "1"; | |
522 case 1: | |
523 return "2"; | |
524 case 2: | |
525 return "EXT"; | |
526 default: | |
527 return "invalid"; | |
528 } | |
529 } | |
530 | |
531 static char * sockfile_name; | |
532 static void cleanup_sockfile() | |
533 { | |
534 unlink(sockfile_name); | |
535 } | |
536 | |
537 void setup_io_devices(tern_node * config, io_port * ports) | |
538 { | |
539 tern_node *io_nodes = tern_get_node(tern_find_path(config, "io\0devices\0")); | |
540 char * io_1 = tern_find_ptr(io_nodes, "1"); | |
541 char * io_2 = tern_find_ptr(io_nodes, "2"); | |
542 char * io_ext = tern_find_ptr(io_nodes, "ext"); | |
543 | |
544 process_device(io_1, ports); | |
545 process_device(io_2, ports+1); | |
546 process_device(io_ext, ports+2); | |
547 | |
548 for (int i = 0; i < 3; i++) | |
549 { | |
550 #ifndef _WIN32 | |
551 if (ports[i].device_type == IO_SEGA_PARALLEL) | |
552 { | |
553 char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval; | |
554 if (!pipe_name) | |
555 { | |
556 fprintf(stderr, "IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); | |
557 ports[i].device_type = IO_NONE; | |
558 } else { | |
559 printf("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name); | |
560 if (!strcmp("stdin", pipe_name)) | |
561 { | |
562 ports[i].device.stream.data_fd = STDIN_FILENO; | |
563 } else { | |
564 if (mkfifo(pipe_name, 0666) && errno != EEXIST) | |
565 { | |
566 fprintf(stderr, "Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); | |
567 ports[i].device_type = IO_NONE; | |
568 } else { | |
569 ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY); | |
570 if (ports[i].device.stream.data_fd == -1) | |
571 { | |
572 fprintf(stderr, "Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); | |
573 ports[i].device_type = IO_NONE; | |
574 } | |
575 } | |
576 } | |
577 } | |
578 } else if (ports[i].device_type == IO_GENERIC) { | |
579 char *sock_name = tern_find_path(config, "io\0socket\0").ptrval; | |
580 if (!sock_name) | |
581 { | |
582 fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); | |
583 ports[i].device_type = IO_NONE; | |
584 } else { | |
585 printf("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name); | |
586 ports[i].device.stream.data_fd = -1; | |
587 ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); | |
588 size_t pathlen = strlen(sock_name); | |
589 size_t addrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; | |
590 struct sockaddr_un *saddr = malloc(addrlen); | |
591 saddr->sun_family = AF_UNIX; | |
592 memcpy(saddr->sun_path, sock_name, pathlen+1); | |
593 if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen)) | |
594 { | |
595 fprintf(stderr, "Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno)); | |
596 goto cleanup_sock; | |
597 } | |
598 if (listen(ports[i].device.stream.listen_fd, 1)) | |
599 { | |
600 fprintf(stderr, "Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno)); | |
601 goto cleanup_sockfile; | |
602 } | |
603 sockfile_name = sock_name; | |
604 atexit(cleanup_sockfile); | |
605 continue; | |
606 cleanup_sockfile: | |
607 unlink(sock_name); | |
608 cleanup_sock: | |
609 close(ports[i].device.stream.listen_fd); | |
610 ports[i].device_type = IO_NONE; | |
611 } | |
612 } else | |
613 #endif | |
614 if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6) { | |
615 printf("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num + 1, device_type_names[ports[i].device_type]); | |
616 } else { | |
617 printf("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]); | |
618 } | |
619 } | |
620 } | |
621 | |
622 void map_bindings(io_port *ports, keybinding *bindings, int numbindings) | |
623 { | |
624 for (int i = 0; i < numbindings; i++) | |
625 { | |
626 if (bindings[i].bind_type >= BIND_GAMEPAD1) | |
627 { | |
628 int num = bindings[i].bind_type - BIND_GAMEPAD1; | |
629 for (int j = 0; j < 3; j++) | |
630 { | |
631 if ((ports[j].device_type == IO_GAMEPAD3 | |
632 || ports[j].device_type ==IO_GAMEPAD6) | |
633 && ports[j].device.pad.gamepad_num == num | |
634 ) | |
635 { | |
636 bindings[i].port = ports + j; | |
637 break; | |
638 } | |
639 } | |
640 } | |
641 } | |
642 } | |
643 | |
644 void set_keybindings(io_port *ports) | |
451 { | 645 { |
452 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); | 646 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); |
453 special = tern_insert_int(special, "down", RENDERKEY_DOWN); | 647 special = tern_insert_int(special, "down", RENDERKEY_DOWN); |
454 special = tern_insert_int(special, "left", RENDERKEY_LEFT); | 648 special = tern_insert_int(special, "left", RENDERKEY_LEFT); |
455 special = tern_insert_int(special, "right", RENDERKEY_RIGHT); | 649 special = tern_insert_int(special, "right", RENDERKEY_RIGHT); |
469 padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y); | 663 padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y); |
470 padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z); | 664 padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z); |
471 padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); | 665 padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); |
472 padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); | 666 padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); |
473 | 667 |
474 tern_node * keys = tern_find_prefix(config, "bindingskeys"); | 668 tern_node * keys = tern_get_node(tern_find_path(config, "bindings\0keys\0")); |
475 process_keys(keys, special, padbuttons, NULL); | 669 process_keys(keys, special, padbuttons, NULL); |
476 char prefix[] = "bindingspads00"; | 670 char numstr[] = "00"; |
477 for (int i = 0; i < 100 && i < render_num_joysticks(); i++) | 671 tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); |
478 { | 672 if (pads) { |
479 if (i < 10) { | 673 for (int i = 0; i < 100 && i < render_num_joysticks(); i++) |
480 prefix[strlen("bindingspads")] = i + '0'; | 674 { |
481 prefix[strlen("bindingspads")+1] = 0; | 675 |
482 } else { | 676 if (i < 10) { |
483 prefix[strlen("bindingspads")] = i/10 + '0'; | 677 numstr[0] = i + '0'; |
484 prefix[strlen("bindingspads")+1] = i%10 + '0'; | 678 numstr[1] = 0; |
485 } | 679 } else { |
486 tern_node * pad = tern_find_prefix(config, prefix); | 680 numstr[0] = i/10 + '0'; |
487 if (pad) { | 681 numstr[1] = i%10 + '0'; |
488 char dprefix[] = "dpads0"; | 682 } |
489 for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) | 683 tern_node * pad = tern_find_ptr(pads, numstr); |
490 { | 684 if (pad) { |
491 dprefix[strlen("dpads")] = dpad + '0'; | 685 tern_node * dpad_node = tern_find_ptr(pad, "dpads"); |
492 tern_node * pad_dpad = tern_find_prefix(pad, dprefix); | 686 if (dpad_node) { |
493 char * dirs[] = {"up", "down", "left", "right"}; | 687 for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) |
494 int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; | 688 { |
495 for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { | 689 numstr[0] = dpad + '0'; |
496 char * target = tern_find_ptr(pad_dpad, dirs[dir]); | 690 numstr[1] = 0; |
497 if (target) { | 691 tern_node * pad_dpad = tern_find_ptr(dpad_node, numstr); |
498 int ui_func, padnum, button; | 692 char * dirs[] = {"up", "down", "left", "right"}; |
499 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | 693 int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; |
500 if (bindtype == 1) { | 694 for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { |
501 bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); | 695 char * target = tern_find_ptr(pad_dpad, dirs[dir]); |
502 } else if (bindtype == 2) { | 696 if (target) { |
503 bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); | 697 int ui_func, padnum, button; |
698 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | |
699 if (bindtype == 1) { | |
700 bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); | |
701 } else if (bindtype == 2) { | |
702 bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); | |
703 } | |
704 } | |
504 } | 705 } |
505 } | 706 } |
506 } | 707 } |
507 } | 708 tern_node *button_node = tern_find_ptr(pad, "buttons"); |
508 char bprefix[] = "buttons00"; | 709 if (button_node) { |
509 for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) | 710 for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) |
510 { | 711 { |
511 if (but < 10) { | 712 if (but < 10) { |
512 bprefix[strlen("buttons")] = but + '0'; | 713 numstr[0] = but + '0'; |
513 bprefix[strlen("buttons")+1] = 0; | 714 numstr[1] = 0; |
514 } else { | 715 } else { |
515 bprefix[strlen("buttons")] = but/10 + '0'; | 716 numstr[0] = but/10 + '0'; |
516 bprefix[strlen("buttons")+1] = but%10 + '0'; | 717 numstr[1] = but%10 + '0'; |
517 } | 718 } |
518 char * target = tern_find_ptr(pad, bprefix); | 719 char * target = tern_find_ptr(button_node, numstr); |
519 if (target) { | 720 if (target) { |
520 int ui_func, padnum, button; | 721 int ui_func, padnum, button; |
521 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | 722 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); |
522 if (bindtype == 1) { | 723 if (bindtype == 1) { |
523 bind_button_gamepad(i, but, padnum, button); | 724 bind_button_gamepad(i, but, padnum, button); |
524 } else if (bindtype == 2) { | 725 } else if (bindtype == 2) { |
525 bind_button_ui(i, but, ui_func, button); | 726 bind_button_ui(i, but, ui_func, button); |
727 } | |
728 } | |
526 } | 729 } |
527 } | 730 } |
528 } | 731 } |
529 } | 732 } |
530 } | 733 } |
531 tern_node * speed_nodes = tern_find_prefix(config, "clocksspeeds"); | 734 tern_node * speed_nodes = tern_get_node(tern_find_path(config, "clocks\0speeds\0")); |
532 speeds = malloc(sizeof(uint32_t)); | 735 speeds = malloc(sizeof(uint32_t)); |
533 speeds[0] = 100; | 736 speeds[0] = 100; |
534 process_speeds(speed_nodes, NULL); | 737 process_speeds(speed_nodes, NULL); |
535 for (int i = 0; i < num_speeds; i++) { | 738 for (int i = 0; i < num_speeds; i++) |
739 { | |
536 if (!speeds[i]) { | 740 if (!speeds[i]) { |
537 fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); | 741 fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); |
538 speeds[i] = 100; | 742 speeds[i] = 100; |
539 } | 743 } |
540 } | 744 } |
745 for (int bucket = 0; bucket < 256; bucket++) | |
746 { | |
747 if (bindings[bucket]) | |
748 { | |
749 map_bindings(ports, bindings[bucket], 256); | |
750 } | |
751 } | |
752 for (int stick = 0; stick < MAX_JOYSTICKS; stick++) | |
753 { | |
754 if (joybindings[stick]) | |
755 { | |
756 int numbuttons = render_joystick_num_buttons(stick); | |
757 map_bindings(ports, joybindings[stick], render_joystick_num_buttons(stick)); | |
758 } | |
759 if (joydpads[stick]) | |
760 { | |
761 map_bindings(ports, joydpads[stick]->bindings, 4); | |
762 } | |
763 } | |
541 } | 764 } |
542 | 765 |
543 #define TH 0x40 | 766 #define TH 0x40 |
544 #define TH_TIMEOUT 8000 | 767 #define TH_TIMEOUT 56000 |
545 | 768 |
546 void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction) | 769 void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) |
547 { | 770 { |
548 /*uint8_t control = pad->control | 0x80; | 771 /*uint8_t control = pad->control | 0x80; |
549 uint8_t th = control & pad->output; | 772 uint8_t th = control & pad->output; |
550 if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { | 773 if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { |
551 printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle); | 774 printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle); |
552 }*/ | 775 }*/ |
553 if (current_cycle >= pad->timeout_cycle) { | 776 if (port->device_type == IO_GAMEPAD6) |
554 pad->th_counter = 0; | 777 { |
555 } else { | 778 if (current_cycle >= port->device.pad.timeout_cycle) |
556 pad->timeout_cycle -= deduction; | 779 { |
557 } | 780 port->device.pad.th_counter = 0; |
558 } | 781 } else { |
559 | 782 port->device.pad.timeout_cycle -= deduction; |
560 void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle) | 783 } |
561 { | 784 } |
562 if (pad->control & TH) { | 785 } |
563 //check if TH has changed | 786 |
564 if ((pad->output & TH) ^ (value & TH)) { | 787 #ifndef _WIN32 |
565 if (current_cycle >= pad->timeout_cycle) { | 788 static void wait_for_connection(io_port * port) |
566 pad->th_counter = 0; | 789 { |
567 } | 790 if (port->device.stream.data_fd == -1) |
568 if (!(value & TH)) { | 791 { |
569 pad->th_counter++; | 792 puts("Waiting for socket connection..."); |
570 } | 793 port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); |
571 pad->timeout_cycle = current_cycle + TH_TIMEOUT; | 794 fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); |
572 } | 795 } |
573 } | 796 } |
574 pad->output = value; | 797 |
575 } | 798 static void service_pipe(io_port * port) |
576 | 799 { |
577 uint8_t io_data_read(io_port * pad, uint32_t current_cycle) | 800 uint8_t value; |
578 { | 801 int numRead = read(port->device.stream.data_fd, &value, sizeof(value)); |
579 uint8_t control = pad->control | 0x80; | 802 if (numRead > 0) |
580 uint8_t th = control & pad->output; | 803 { |
804 port->input[IO_TH0] = (value & 0xF) | 0x10; | |
805 port->input[IO_TH1] = (value >> 4) | 0x10; | |
806 } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
807 fprintf(stderr, "Error reading pipe for IO port: %d %s\n", errno, strerror(errno)); | |
808 } | |
809 } | |
810 | |
811 static void service_socket(io_port *port) | |
812 { | |
813 uint8_t buf[32]; | |
814 uint8_t blocking = 0; | |
815 int numRead = 0; | |
816 while (numRead <= 0) | |
817 { | |
818 numRead = recv(port->device.stream.data_fd, buf, sizeof(buf), 0); | |
819 if (numRead > 0) | |
820 { | |
821 port->input[IO_TH0] = buf[numRead-1]; | |
822 if (port->input[IO_STATE] == IO_READ_PENDING) | |
823 { | |
824 port->input[IO_STATE] = IO_READ; | |
825 if (blocking) | |
826 { | |
827 //pending read satisfied, back to non-blocking mode | |
828 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); | |
829 } | |
830 } else if (port->input[IO_STATE] == IO_WRITTEN) { | |
831 port->input[IO_STATE] = IO_READ; | |
832 } | |
833 } else if (numRead == 0) { | |
834 port->device.stream.data_fd = -1; | |
835 wait_for_connection(port); | |
836 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { | |
837 fprintf(stderr, "Error reading from socket for IO port: %d %s\n", errno, strerror(errno)); | |
838 close(port->device.stream.data_fd); | |
839 wait_for_connection(port); | |
840 } else if (port->input[IO_STATE] == IO_READ_PENDING) { | |
841 //clear the nonblocking flag so the next read will block | |
842 if (!blocking) | |
843 { | |
844 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); | |
845 blocking = 1; | |
846 } | |
847 } else { | |
848 //no new data, but that's ok | |
849 break; | |
850 } | |
851 } | |
852 | |
853 if (port->input[IO_STATE] == IO_WRITE_PENDING) | |
854 { | |
855 uint8_t value = port->output & port->control; | |
856 int written = 0; | |
857 blocking = 0; | |
858 while (written <= 0) | |
859 { | |
860 send(port->device.stream.data_fd, &value, sizeof(value), 0); | |
861 if (written > 0) | |
862 { | |
863 port->input[IO_STATE] = IO_WRITTEN; | |
864 if (blocking) | |
865 { | |
866 //pending write satisfied, back to non-blocking mode | |
867 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); | |
868 } | |
869 } else if (written == 0) { | |
870 port->device.stream.data_fd = -1; | |
871 wait_for_connection(port); | |
872 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { | |
873 fprintf(stderr, "Error writing to socket for IO port: %d %s\n", errno, strerror(errno)); | |
874 close(port->device.stream.data_fd); | |
875 wait_for_connection(port); | |
876 } else { | |
877 //clear the nonblocking flag so the next write will block | |
878 if (!blocking) | |
879 { | |
880 fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); | |
881 blocking = 1; | |
882 } | |
883 } | |
884 } | |
885 } | |
886 } | |
887 #endif | |
888 | |
889 void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle) | |
890 { | |
891 switch (port->device_type) | |
892 { | |
893 case IO_GAMEPAD6: | |
894 if (port->control & TH) { | |
895 //check if TH has changed | |
896 if ((port->output & TH) ^ (value & TH)) { | |
897 if (current_cycle >= port->device.pad.timeout_cycle) { | |
898 port->device.pad.th_counter = 0; | |
899 } | |
900 if (!(value & TH)) { | |
901 port->device.pad.th_counter++; | |
902 } | |
903 port->device.pad.timeout_cycle = current_cycle + TH_TIMEOUT; | |
904 } | |
905 } | |
906 port->output = value; | |
907 break; | |
908 #ifndef _WIN32 | |
909 case IO_GENERIC: | |
910 wait_for_connection(port); | |
911 port->input[IO_STATE] = IO_WRITE_PENDING; | |
912 port->output = value; | |
913 service_socket(port); | |
914 break; | |
915 #endif | |
916 default: | |
917 port->output = value; | |
918 } | |
919 | |
920 } | |
921 | |
922 uint8_t io_data_read(io_port * port, uint32_t current_cycle) | |
923 { | |
924 uint8_t control = port->control | 0x80; | |
925 uint8_t th = control & port->output & 0x40; | |
581 uint8_t input; | 926 uint8_t input; |
582 if (current_cycle >= pad->timeout_cycle) { | 927 switch (port->device_type) |
583 pad->th_counter = 0; | 928 { |
584 } | 929 case IO_GAMEPAD3: |
585 /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { | 930 { |
586 printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, context->current_cycle); | 931 input = port->input[th ? GAMEPAD_TH1 : GAMEPAD_TH0]; |
587 }*/ | 932 break; |
588 if (th) { | 933 } |
589 if (pad->th_counter == 3) { | 934 case IO_GAMEPAD6: |
590 input = pad->input[GAMEPAD_EXTRA]; | 935 { |
936 if (current_cycle >= port->device.pad.timeout_cycle) { | |
937 port->device.pad.th_counter = 0; | |
938 } | |
939 /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { | |
940 printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, port->input[GAMEPAD_TH0], port->input[GAMEPAD_TH1], port->th_counter,port->timeout_cycle, context->current_cycle); | |
941 }*/ | |
942 if (th) { | |
943 if (port->device.pad.th_counter == 3) { | |
944 input = port->input[GAMEPAD_EXTRA]; | |
945 } else { | |
946 input = port->input[GAMEPAD_TH1]; | |
947 } | |
591 } else { | 948 } else { |
592 input = pad->input[GAMEPAD_TH1]; | 949 if (port->device.pad.th_counter == 3) { |
593 } | 950 input = port->input[GAMEPAD_TH0] | 0xF; |
594 } else { | 951 } else if(port->device.pad.th_counter == 4) { |
595 if (pad->th_counter == 3) { | 952 input = port->input[GAMEPAD_TH0] & 0x30; |
596 input = pad->input[GAMEPAD_TH0] | 0xF; | 953 } else { |
597 } else if(pad->th_counter == 4) { | 954 input = port->input[GAMEPAD_TH0] | 0xC; |
598 input = pad->input[GAMEPAD_TH0] & 0x30; | 955 } |
599 } else { | 956 } |
600 input = pad->input[GAMEPAD_TH0] | 0xC; | 957 break; |
601 } | 958 } |
602 } | 959 #ifndef _WIN32 |
603 uint8_t value = ((~input) & (~control)) | (pad->output & control); | 960 case IO_SEGA_PARALLEL: |
604 /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { | 961 if (!th) |
962 { | |
963 service_pipe(port); | |
964 } | |
965 input = ~port->input[th ? IO_TH1 : IO_TH0]; | |
966 break; | |
967 case IO_GENERIC: | |
968 if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN) | |
969 { | |
970 //device requested a blocking read after writes | |
971 port->input[IO_STATE] = IO_READ_PENDING; | |
972 } | |
973 service_socket(port); | |
974 input = ~port->input[IO_TH0]; | |
975 break; | |
976 #endif | |
977 default: | |
978 input = 0; | |
979 break; | |
980 } | |
981 uint8_t value = ((~input) & (~control)) | (port->output & control); | |
982 /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { | |
605 printf ("value: %X\n", value); | 983 printf ("value: %X\n", value); |
606 }*/ | 984 }*/ |
607 return value; | 985 return value; |
608 } | 986 } |
609 | 987 |