From 2405526f35ce057da9ecec7050af3d9c98d42c63 Mon Sep 17 00:00:00 2001 From: Tau Date: Fri, 3 May 2019 14:47:09 -0400 Subject: [PATCH] divaio: Break out Project Diva IO DLL --- divahook/jvs.c | 58 +++++++++---------- divahook/meson.build | 1 + divahook/slider-hook.c | 89 +++++++---------------------- divaio/divaio.c | 124 +++++++++++++++++++++++++++++++++++++++++ divaio/divaio.def | 10 ++++ divaio/divaio.h | 81 +++++++++++++++++++++++++++ divaio/meson.build | 12 ++++ meson.build | 1 + 8 files changed, 275 insertions(+), 101 deletions(-) create mode 100644 divaio/divaio.c create mode 100644 divaio/divaio.def create mode 100644 divaio/divaio.h create mode 100644 divaio/meson.build diff --git a/divahook/jvs.c b/divahook/jvs.c index d66f433..ca6df53 100644 --- a/divahook/jvs.c +++ b/divahook/jvs.c @@ -8,6 +8,8 @@ #include "board/io3.h" +#include "divaio/divaio.h" + #include "jvs/jvs-bus.h" #include "util/dprintf.h" @@ -21,8 +23,6 @@ static const struct io3_ops diva_jvs_io3_ops = { }; static struct io3 diva_jvs_io3; -static bool diva_jvs_coin; -static uint16_t diva_jvs_coins; void diva_jvs_init(void) { @@ -32,42 +32,44 @@ void diva_jvs_init(void) static void diva_jvs_read_switches(void *ctx, struct io3_switch_state *out) { + uint8_t opbtn; + uint8_t gamebtn; + assert(out != NULL); - /* Update gameplay buttons (P2 JVS input is not even polled) */ + opbtn = 0; + gamebtn = 0; - if (GetAsyncKeyState('S')) { - out->p1 |= 1 << 9; - } + diva_io_jvs_poll(&opbtn, &gamebtn); - if (GetAsyncKeyState('F')) { - out->p1 |= 1 << 8; - } - - if (GetAsyncKeyState('J')) { - out->p1 |= 1 << 7; - } - - if (GetAsyncKeyState('L')) { + if (gamebtn & 0x01) { out->p1 |= 1 << 6; } - /* Update start button */ + if (gamebtn & 0x02) { + out->p1 |= 1 << 7; + } - if (GetAsyncKeyState(VK_SPACE)) { + if (gamebtn & 0x04) { + out->p1 |= 1 << 8; + } + + if (gamebtn & 0x08) { + out->p1 |= 1 << 9; + } + + if (gamebtn & 0x10) { out->p1 |= 1 << 15; } - /* Update test/service buttons */ - - if (GetAsyncKeyState('1')) { + if (opbtn & 0x01) { out->system = 0x80; } else { out->system = 0; } - if (GetAsyncKeyState('2')) { - out->p1 |= 0x4000; + if (opbtn & 0x02) { + out->p1 |= 1 << 14; } } @@ -77,15 +79,5 @@ static uint16_t diva_jvs_read_coin_counter(void *ctx, uint8_t slot_no) return 0; } - if (GetAsyncKeyState('3')) { - if (!diva_jvs_coin) { - dprintf("Diva JVS: Coin drop\n"); - diva_jvs_coin = true; - diva_jvs_coins++; - } - } else { - diva_jvs_coin = false; - } - - return diva_jvs_coins; + return diva_io_jvs_read_coin_counter(); } diff --git a/divahook/meson.build b/divahook/meson.build index 0814908..a5bbc1b 100644 --- a/divahook/meson.build +++ b/divahook/meson.build @@ -13,6 +13,7 @@ shared_library( aimeio_dll, amex_lib, board_lib, + divaio_dll, jvs_lib, platform_lib, util_lib, diff --git a/divahook/slider-hook.c b/divahook/slider-hook.c index 2713715..703694c 100644 --- a/divahook/slider-hook.c +++ b/divahook/slider-hook.c @@ -1,7 +1,6 @@ #include #include -#include #include #include #include @@ -11,6 +10,8 @@ #include "divahook/slider-hook.h" +#include "divaio/divaio.h" + #include "hook/iobuf.h" #include "hook/iohook.h" @@ -29,16 +30,13 @@ static HRESULT slider_req_auto_scan_start(void); static HRESULT slider_req_auto_scan_stop(void); static HRESULT slider_req_set_led(const struct slider_req_set_led *req); -static unsigned int __stdcall slider_thread_proc(void *ctx); +static void slider_res_auto_scan(const uint8_t *pressure); static CRITICAL_SECTION slider_lock; static struct uart slider_uart; static uint8_t slider_written_bytes[520]; static uint8_t slider_readable_bytes[520]; -static HANDLE slider_thread; -static bool slider_stop; - void slider_hook_init(void) { InitializeCriticalSection(&slider_lock); @@ -175,24 +173,7 @@ static HRESULT slider_req_get_board_info(void) static HRESULT slider_req_auto_scan_start(void) { dprintf("Diva slider: Start slider thread\n"); - - if (slider_thread != NULL) { - dprintf("Thread is already running\n"); - - return S_OK; - } - - slider_thread = (HANDLE) _beginthreadex( - NULL, - 0, - slider_thread_proc, - NULL, - 0, - NULL); - - if (slider_thread == NULL) { - dprintf("Thread launch failed\n"); - } + diva_io_slider_start(slider_res_auto_scan); /* This message is not acknowledged */ @@ -205,19 +186,14 @@ static HRESULT slider_req_auto_scan_stop(void) dprintf("Diva slider: Stop slider thread\n"); - if (slider_thread != NULL) { - slider_stop = true; - LeaveCriticalSection(&slider_lock); + /* IO DLL worker thread might attempt to invoke the callback (which needs + to take slider_lock, which we are currently holding) before noticing that + it needs to shut down. Unlock here so that we don't deadlock in that + situation. */ - WaitForSingleObject(slider_thread, INFINITE); - CloseHandle(slider_thread); - slider_thread = NULL; - slider_stop = false; - - dprintf("Diva slider: Thread has terminated\n"); - - EnterCriticalSection(&slider_lock); - } + LeaveCriticalSection(&slider_lock); + diva_io_slider_stop(); + EnterCriticalSection(&slider_lock); resp.sync = SLIDER_FRAME_SYNC; resp.cmd = SLIDER_CMD_AUTO_SCAN_STOP; @@ -229,44 +205,21 @@ static HRESULT slider_req_auto_scan_stop(void) static HRESULT slider_req_set_led(const struct slider_req_set_led *req) { /* This message is not acknowledged */ + diva_io_slider_set_leds(req->payload.rgb); + return S_OK; } -static unsigned int WINAPI slider_thread_proc(void *ctx) +static void slider_res_auto_scan(const uint8_t *pressure) { - static const int keys[] = { - 'Q', 'W', 'E', 'R', 'U', 'I', 'O', 'P', - }; - struct slider_resp_auto_scan resp; - uint8_t pressure; - bool stop; - size_t i; - for (;;) { - resp.hdr.sync = SLIDER_FRAME_SYNC; - resp.hdr.cmd = SLIDER_CMD_AUTO_SCAN; - resp.hdr.nbytes = sizeof(resp.pressure); + resp.hdr.sync = SLIDER_FRAME_SYNC; + resp.hdr.cmd = SLIDER_CMD_AUTO_SCAN; + resp.hdr.nbytes = sizeof(resp.pressure); + memcpy(resp.pressure, pressure, sizeof(resp.pressure)); - for (i = 0 ; i < 8 ; i++) { - pressure = GetAsyncKeyState(keys[i]) ? 20 : 0; - memset(&resp.pressure[28 - 4 * i], pressure, 4); - } - - EnterCriticalSection(&slider_lock); - - stop = slider_stop; - - if (!stop) { - slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); - } - - LeaveCriticalSection(&slider_lock); - - if (stop) { - return 0; - } - - Sleep(1); - } + EnterCriticalSection(&slider_lock); + slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); + LeaveCriticalSection(&slider_lock); } diff --git a/divaio/divaio.c b/divaio/divaio.c new file mode 100644 index 0000000..701a983 --- /dev/null +++ b/divaio/divaio.c @@ -0,0 +1,124 @@ +#include + +#include +#include +#include +#include + +#include "divaio/divaio.h" + +static unsigned int __stdcall diva_io_slider_thread_proc(void *ctx); + +static bool diva_io_coin; +static uint16_t diva_io_coins; +static HANDLE diva_io_slider_thread; +static bool diva_io_slider_stop_flag; + +HRESULT diva_io_init(void) +{ + return S_OK; +} + +void diva_io_jvs_poll(uint8_t *opbtn_out, uint8_t *gamebtn_out) +{ + static const int opbtn_vk[] = { '1', '2' }; + static const int gamebtn_vk[] = { 'L', 'J', 'F', 'S', ' ' }; + + uint8_t opbtn; + uint8_t gamebtn; + size_t i; + + opbtn = 0; + gamebtn = 0; + + for (i = 0 ; i < _countof(opbtn_vk) ; i++) { + if (GetAsyncKeyState(opbtn_vk[i]) & 0x8000) { + opbtn |= 1 << i; + } + } + + for (i = 0 ; i < _countof(gamebtn_vk) ; i++) { + if (GetAsyncKeyState(gamebtn_vk[i]) & 0x8000) { + gamebtn |= 1 << i; + } + } + + *opbtn_out = opbtn; + *gamebtn_out = gamebtn; +} + +uint16_t diva_io_jvs_read_coin_counter(void) +{ + if (GetAsyncKeyState('3')) { + if (!diva_io_coin) { + diva_io_coin = true; + diva_io_coins++; + } + } else { + diva_io_coin = false; + } + + return diva_io_coins; +} + +void diva_io_jvs_set_coin_blocker(bool open) +{} + +void diva_io_slider_start(diva_io_slider_callback_t callback) +{ + if (diva_io_slider_thread != NULL) { + return; + } + + diva_io_slider_thread = (HANDLE) _beginthreadex( + NULL, + 0, + diva_io_slider_thread_proc, + callback, + 0, + NULL); +} + +void diva_io_slider_stop(void) +{ + diva_io_slider_stop_flag = true; + + WaitForSingleObject(diva_io_slider_thread, INFINITE); + CloseHandle(diva_io_slider_thread); + diva_io_slider_thread = NULL; + diva_io_slider_stop_flag = false; +} + +void diva_io_slider_set_leds(const uint8_t *rgb) +{} + +static unsigned int __stdcall diva_io_slider_thread_proc(void *ctx) +{ + static const int keys[] = { + 'Q', 'W', 'E', 'R', 'U', 'I', 'O', 'P', + }; + + diva_io_slider_callback_t callback; + uint8_t pressure_val; + uint8_t pressure[32]; + size_t i; + + callback = ctx; + + while (!diva_io_slider_stop_flag) { + for (i = 0 ; i < 8 ; i++) { + if(GetAsyncKeyState(keys[i]) & 0x8000) { + pressure_val = 20; + } else { + pressure_val = 0; + } + + memset(&pressure[28 - 4 * i], pressure_val, 4); + } + + callback(pressure); + Sleep(1); + } + + return 0; +} diff --git a/divaio/divaio.def b/divaio/divaio.def new file mode 100644 index 0000000..46b79c0 --- /dev/null +++ b/divaio/divaio.def @@ -0,0 +1,10 @@ +LIBRARY divaio + +EXPORTS + diva_io_init + diva_io_jvs_poll + diva_io_jvs_read_coin_counter + diva_io_jvs_set_coin_blocker + diva_io_slider_set_leds + diva_io_slider_start + diva_io_slider_stop diff --git a/divaio/divaio.h b/divaio/divaio.h new file mode 100644 index 0000000..8a78e4f --- /dev/null +++ b/divaio/divaio.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include +#include + +/* Initialize the Project Diva IO provider DLL. This is the first function to be + called on this DLL. Returning failure from this function will cause the main + application to immediately exit. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. */ + +HRESULT diva_io_init(void); + +/* Poll JVS input. + + opbtn returns the cabinet test/service state, where bit 0 is Test and Bit 1 + is Service. + + gamebtn bits, from least significant to most significant, are: + + Circle Cross Square Triangle Start UNUSED UNUSED UNUSED */ + +void diva_io_jvs_poll(uint8_t *opbtn, uint8_t *gamebtn); + +/* Read the current state of the coin counter. This value should be incremented + for every coin detected by the coin acceptor mechanism. This count does not + need to persist beyond the lifetime of the process. */ + +uint16_t diva_io_jvs_read_coin_counter(void); + +/* Set the state of the coin blocker. Parameter is true if the blocker is + disengaged (i.e. coins can be inserted) and false if the blocker is engaged + (i.e. the coin slot should be physically blocked). */ + +void diva_io_jvs_set_coin_blocker(bool open); + +/* Project Diva touch sliders consist of 32 pressure sensitive cells, where + cell 1 (array index 0) is the rightmost cell and cell 32 (array index 31) is + the leftmost cell. */ + +/* Callback function supplied to your IO DLL. This must be called with a + pointer to a 32-byte array of pressure values, one byte per slider cell. + Cells reporting a pressure value of at least 20 are considered to be pressed. + This threshold is not configurable. + + The callback will copy the pressure state data out of your buffer before + returning. The pointer will not be retained. */ + +typedef void (*diva_io_slider_callback_t)(const uint8_t *state); + +/* Start polling the slider. Your DLL must start a polling thread and call the + supplied function periodically from that thread with new input state. The + update interval is up to you, but if your input device doesn't have any + preferred interval then 1 kHz is a reasonable maximum frequency. + + Note that you do have to have to call the callback "occasionally" even if + nothing is changing, otherwise the game will raise a comm timeout error. */ + +void diva_io_slider_start(diva_io_slider_callback_t callback); + +/* Stop polling the slider. You must cease to invoke the input callback before + returning from this function. + + This *will* be called in the course of regular operation. For example, + every time you go into the operator menu the slider and all of the other I/O + on the cabinet gets restarted. + + Following on from the above, the slider polling loop *will* be restarted + after being stopped in the course of regular operation. Do not permanently + tear down your input driver in response to this function call. */ + +void diva_io_slider_stop(void); + +/* Update the RGB lighting on the slider. A pointer to an array of 32 * 3 = 96 + bytes is supplied. Layout is probably strictly linear but still TBD. */ + +void diva_io_slider_set_leds(const uint8_t *rgb); diff --git a/divaio/meson.build b/divaio/meson.build new file mode 100644 index 0000000..e8d498f --- /dev/null +++ b/divaio/meson.build @@ -0,0 +1,12 @@ +divaio_dll = shared_library( + 'divaio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'divaio.def', + c_pch : '../precompiled.h', + sources : [ + 'divaio.c', + 'divaio.h', + ], +) diff --git a/meson.build b/meson.build index 7fc08f3..66b2c0a 100644 --- a/meson.build +++ b/meson.build @@ -38,6 +38,7 @@ subdir('util') subdir('aimeio') subdir('chuniio') +subdir('divaio') subdir('cardhook') subdir('chunihook')