From 05e762d3ce809bb4943cc364a169ebdce906c111 Mon Sep 17 00:00:00 2001 From: Zsolt Zitting Date: Sat, 18 Feb 2023 22:58:00 -0700 Subject: [PATCH 001/204] fix Makefile failing on strip --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f39d291..c9b1b14 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +SHELL = /bin/bash + V ?= @ .DEFAULT_GOAL := help From 301a0e0ce753d65289e1698695d0f211f495b8fc Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Sun, 19 Mar 2023 13:29:08 -0400 Subject: [PATCH 002/204] update build system --- Makefile | 15 --------------- docker-build.bat | 1 - meson.build | 1 + 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Makefile b/Makefile index c9b1b14..a05bb64 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ -SHELL = /bin/bash - V ?= @ .DEFAULT_GOAL := help @@ -7,16 +5,12 @@ V ?= @ BUILD_DIR := build BUILD_DIR_32 := $(BUILD_DIR)/build32 BUILD_DIR_64 := $(BUILD_DIR)/build64 -BUILD_DIR_DOCKER := $(BUILD_DIR)/docker BUILD_DIR_ZIP := $(BUILD_DIR)/zip DOC_DIR := doc DIST_DIR := dist -DOCKER_CONTAINER_NAME := "segatools-build" -DOCKER_IMAGE_NAME := "segatools:build" - # ----------------------------------------------------------------------------- # Targets # ----------------------------------------------------------------------------- @@ -44,15 +38,6 @@ zip: $(BUILD_DIR_ZIP)/segatools.zip clean: $(V)rm -rf $(BUILD_DIR) subprojects/capnhook -.PHONY: build-docker # Build the project in a docker container -build-docker: - $(V)docker rm -f $(DOCKER_CONTAINER_NAME) 2> /dev/null || true - $(V)docker build -t $(DOCKER_IMAGE_NAME) -f Dockerfile . - $(V)docker create --name $(DOCKER_CONTAINER_NAME) $(DOCKER_IMAGE_NAME) - $(V)rm -rf $(BUILD_DIR_DOCKER) - $(V)mkdir -p $(BUILD_DIR_DOCKER) - $(V)docker cp $(DOCKER_CONTAINER_NAME):/segatools/$(BUILD_DIR_ZIP) $(BUILD_DIR_DOCKER) - # ----------------------------------------------------------------------------- # Utility, combo and alias targets # ----------------------------------------------------------------------------- diff --git a/docker-build.bat b/docker-build.bat index 1b0ce12..969e032 100644 --- a/docker-build.bat +++ b/docker-build.bat @@ -2,7 +2,6 @@ setlocal enabledelayedexpansion :: Static Environment Variables -set BUILD_OUTPUT_PATH=build\docker set IMAGE_NAME=djhackers/segatools-build:latest set CONTAINER_NAME=segatools-build diff --git a/meson.build b/meson.build index 2c6b673..b5a3d5f 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,7 @@ add_project_arguments( '-DWIN32_LEAN_AND_MEAN', '-D_WIN32_WINNT=_WIN32_WINNT_WIN7', '-DMINGW_HAS_SECURE_API=1', + '-Wno-unused', language: 'c', ) From 8c97dc09c038a04e628f983e8d157a285f7d7310 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Thu, 30 Mar 2023 03:55:40 -0400 Subject: [PATCH 003/204] carol: fix control board request struct --- carolhook/controlbd.c | 116 +++++++++++++++++++++++++++++------------- carolhook/controlbd.h | 19 ++++--- carolhook/touch.c | 4 +- 3 files changed, 95 insertions(+), 44 deletions(-) diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index 44fa5a6..793b0f8 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -21,7 +21,9 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp); static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf); static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest); -static HRESULT controlbd_req_nop(uint8_t cmd); +static HRESULT controlbd_req_noop(uint8_t cmd); +static HRESULT controlbd_req_unk7c(uint8_t cmd); +static HRESULT controlbd_req_unkF0(uint8_t cmd); static CRITICAL_SECTION controlbd_lock; static struct uart controlbd_uart; @@ -76,7 +78,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) hr = carol_dll.controlbd_init(); if (FAILED(hr)) { - dprintf("Control Board: Backend DLL error: %x\n", (int) hr); + dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr); return hr; } @@ -96,14 +98,14 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) hr = controlbd_frame_decode(&req, &controlbd_uart.written); if (FAILED(hr)) { - dprintf("Control Board: Deframe Error: %x\n", (int) hr); + dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); return hr; } hr = controlbd_frame_dispatch(&req); if (FAILED(hr)) { - dprintf("Control Board: Dispatch Error: %x\n", (int) hr); + dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); return hr; } @@ -115,62 +117,104 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) static HRESULT controlbd_frame_dispatch(struct controlbd_req *req) { switch (req->cmd) { - case CONTROLBD_CMD_UNK_11: - return controlbd_req_nop(req->cmd); + case CONTROLBD_CMD_UNK_10: + return controlbd_req_noop(req->cmd); + case CONTROLBD_CMD_UNK_7C: + return controlbd_req_unk7c(req->cmd); + case CONTROLBD_CMD_UNK_F0: + return controlbd_req_unkF0(req->cmd); + case CONTROLBD_CMD_UNK_30: + return controlbd_req_noop(req->cmd); default: - dprintf("Unhandled command %#02x\n", req->cmd); - - return S_OK; + dprintf("Unhandled command 0x%02X\n", req->cmd); + return controlbd_req_noop(req->cmd); } } -static HRESULT controlbd_req_nop(uint8_t cmd) +static HRESULT controlbd_req_noop(uint8_t cmd) { - dprintf("Control Board: No-op cmd %#02x\n", cmd); - - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0xE0; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x11; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x03; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x10; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01; - controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x27; + dprintf("Control Board: Noop cmd 0x%02X\n", cmd); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 }; + resp[5] = cmd; + resp[7] = 0x17 + cmd; + iobuf_write(&controlbd_uart.readable, resp, 8); return S_OK; } -/* Decodes the response into a struct that's easier to work with. */ +static HRESULT controlbd_req_unk7c(uint8_t cmd) +{ + dprintf("Control Board: Cmd 0x7C\n"); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B }; + iobuf_write(&controlbd_uart.readable, resp, 9); + + return S_OK; +} + +static HRESULT controlbd_req_unkF0(uint8_t cmd) +{ + dprintf("Control Board: Cmd 0xF0\n"); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E }; + iobuf_write(&controlbd_uart.readable, resp, 16); + + return S_OK; +} + +/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf) { int initial_pos = iobuf->pos; - uint8_t check = 0; + int processed_pos = 0; + uint8_t check = 0; + bool escape = false; + dump_iobuf(iobuf); dest->sync = iobuf->bytes[0]; - iobuf->pos--; - dest->cmd = iobuf->bytes[1]; - iobuf->pos--; + dest->dest = iobuf->bytes[1]; + check += dest->dest; + + dest->src = iobuf->bytes[2]; + check += dest->src; + + dest->data_len = iobuf->bytes[3]; + check += dest->data_len; + + dest->cmd = iobuf->bytes[4]; check += dest->cmd; - dest->checksum = iobuf->bytes[initial_pos - 1]; - iobuf->pos--; - - dest->data_length = initial_pos - 3; // sync, cmd, checksum - if (dest->data_length > 0) { - for (int i = 0; i < dest->data_length; i++) { - dest->data[i] = iobuf->bytes[i+2]; + if (dest->data_len > 1) { + for (int i = 0; i < iobuf->pos - 6; i++) { + if (iobuf->bytes[i+6] == 0xD0) { + escape = true; + } + + dest->data[i] = iobuf->bytes[i+6]; + + if (escape) { + dest->data[i]++; + escape = false; + } + check += dest->data[i]; } + } - iobuf->pos -= dest->data_length; + dest->checksum = iobuf->bytes[iobuf->pos - 1]; + if (escape) { + dest->checksum++; + escape = false; + } + + iobuf->pos = 0; if (dest->sync != 0xe0) { - dprintf("Control Board: Sync error, expected 0xe0, got %x\n", dest->sync); + dprintf("Control Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); return E_FAIL; } - if (dest->checksum != check) { - dprintf("Control Board: Checksum error, expected %x, got %x\n", check, dest->checksum); + + if (dest->checksum != (check & 0xFF)) { + dprintf("Control Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); return E_FAIL; } diff --git a/carolhook/controlbd.h b/carolhook/controlbd.h index 500efd7..16c3280 100644 --- a/carolhook/controlbd.h +++ b/carolhook/controlbd.h @@ -7,15 +7,22 @@ struct controlbd_config { bool enable; }; + enum controlbd_cmd { - CONTROLBD_CMD_UNK_11 = 0x11 + CONTROLBD_CMD_UNK_10 = 0x10, + CONTROLBD_CMD_UNK_7C = 0x7C, + CONTROLBD_CMD_UNK_30 = 0x30, + CONTROLBD_CMD_UNK_F0 = 0xF0, }; + struct controlbd_req { - uint8_t sync; // First byte is the sync - uint8_t cmd; // Command byte - uint8_t data[256]; // Request body goes here - uint8_t checksum; // Final byte is all bytes added, except the sync - uint8_t data_length; // Size of the data including command byte + uint8_t sync; // Sync byte, always 0xE0 + uint8_t dest; // command destination id? + uint8_t src; // command source id? + uint8_t data_len; // length of the proceeding data bytes + uint8_t cmd; // might be the command byte? + uint8_t data[255]; // rest of the data, len = data_len - 1 + uint8_t checksum; // final byte is all bytes (excluding sync) added }; HRESULT controlbd_hook_init(const struct controlbd_config *cfg); \ No newline at end of file diff --git a/carolhook/touch.c b/carolhook/touch.c index 8cbb8ca..83d184d 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -71,7 +71,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) hr = carol_dll.touch_init(); if (FAILED(hr)) { - dprintf("Touchscreen: Backend DLL error: %x\n", (int) hr); + dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr); return hr; } @@ -91,7 +91,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) hr = touch_frame_decode(&req, &touch_uart.written); if (FAILED(hr)) { - dprintf("Touchscreen: Deframe Error: %x\n", (int) hr); + dprintf("Touchscreen: Deframe Error: %X\n", (int) hr); return hr; } From ef00932c649c6f556bd6ce12ac2496934524ae99 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Tue, 11 Apr 2023 00:20:51 -0400 Subject: [PATCH 004/204] carol: fix ports --- carolhook/carol-dll.c | 3 + carolhook/carol-dll.h | 1 + carolhook/carolhook.def | 1 + carolhook/config.c | 15 +++ carolhook/config.h | 2 + carolhook/controlbd.c | 132 +++--------------------- carolhook/controlbd.h | 17 --- carolhook/dllmain.c | 19 ++-- carolhook/ledbd.c | 223 ++++++++++++++++++++++++++++++++++++++++ carolhook/ledbd.h | 28 +++++ carolhook/meson.build | 2 + carolhook/touch.c | 1 + carolio/carolio.c | 5 + carolio/carolio.h | 2 + 14 files changed, 308 insertions(+), 143 deletions(-) create mode 100644 carolhook/ledbd.c create mode 100644 carolhook/ledbd.h diff --git a/carolhook/carol-dll.c b/carolhook/carol-dll.c index 5cc8e98..9aa1484 100644 --- a/carolhook/carol-dll.c +++ b/carolhook/carol-dll.c @@ -21,6 +21,9 @@ const struct dll_bind_sym carol_dll_syms[] = { }, { .sym = "carol_io_touch_init", .off = offsetof(struct carol_dll, touch_init), + }, { + .sym = "carol_io_ledbd_init", + .off = offsetof(struct carol_dll, ledbd_init), }, { .sym = "carol_io_controlbd_init", .off = offsetof(struct carol_dll, controlbd_init), diff --git a/carolhook/carol-dll.h b/carolhook/carol-dll.h index 095a1fd..d56df64 100644 --- a/carolhook/carol-dll.h +++ b/carolhook/carol-dll.h @@ -10,6 +10,7 @@ struct carol_dll { void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams); void (*jvs_read_coin_counter)(uint16_t *total); HRESULT (*touch_init)(); + HRESULT (*ledbd_init)(); HRESULT (*controlbd_init)(); }; diff --git a/carolhook/carolhook.def b/carolhook/carolhook.def index 3c324c4..260058e 100644 --- a/carolhook/carolhook.def +++ b/carolhook/carolhook.def @@ -16,4 +16,5 @@ EXPORTS carol_io_jvs_poll carol_io_jvs_read_coin_counter carol_io_touch_init + carol_io_ledbd_init carol_io_controlbd_init diff --git a/carolhook/config.c b/carolhook/config.c index 740a162..9f2ef2d 100644 --- a/carolhook/config.c +++ b/carolhook/config.c @@ -58,6 +58,20 @@ void controlbd_config_load( filename); } +void ledbd_config_load( + struct ledbd_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW( + L"ledbd", + L"enable", + 1, + filename); +} + void carol_hook_config_load( struct carol_hook_config *cfg, @@ -73,4 +87,5 @@ void carol_hook_config_load( gfx_config_load(&cfg->gfx, filename); touch_config_load(&cfg->touch, filename); controlbd_config_load(&cfg->controlbd, filename); + ledbd_config_load(&cfg->ledbd, filename); } diff --git a/carolhook/config.h b/carolhook/config.h index 50b7f0b..31f4525 100644 --- a/carolhook/config.h +++ b/carolhook/config.h @@ -13,6 +13,7 @@ #include "gfxhook/gfx.h" #include "carolhook/touch.h" +#include "carolhook/ledbd.h" #include "carolhook/controlbd.h" struct carol_hook_config { @@ -22,6 +23,7 @@ struct carol_hook_config { struct carol_dll_config dll; struct gfx_config gfx; struct touch_config touch; + struct ledbd_config ledbd; struct controlbd_config controlbd; }; diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index 793b0f8..810d17b 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -18,8 +18,8 @@ static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp_locked(struct irp *irp); -static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf); -static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest); +//static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf); +//static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest); static HRESULT controlbd_req_noop(uint8_t cmd); static HRESULT controlbd_req_unk7c(uint8_t cmd); @@ -38,7 +38,7 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) InitializeCriticalSection(&controlbd_lock); - uart_init(&controlbd_uart, 11); + uart_init(&controlbd_uart, 12); controlbd_uart.written.bytes = controlbd_written_bytes; controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes); controlbd_uart.readable.bytes = controlbd_readable_bytes; @@ -49,6 +49,7 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) return iohook_push_handler(controlbd_handle_irp); } + static HRESULT controlbd_handle_irp(struct irp *irp) { HRESULT hr; @@ -68,17 +69,16 @@ static HRESULT controlbd_handle_irp(struct irp *irp) static HRESULT controlbd_handle_irp_locked(struct irp *irp) { - struct controlbd_req req; HRESULT hr; assert(carol_dll.controlbd_init != NULL); if (irp->op == IRP_OP_OPEN) { - dprintf("Control Board: Starting backend DLL\n"); + dprintf("LED Board: Starting backend DLL\n"); hr = carol_dll.controlbd_init(); if (FAILED(hr)) { - dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr); + dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr); return hr; } @@ -91,132 +91,26 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 - dprintf("Control Board: TX Buffer:\n"); +#if 1 + dprintf("LED Board: TX Buffer:\n"); dump_iobuf(&controlbd_uart.written); #endif - hr = controlbd_frame_decode(&req, &controlbd_uart.written); + //hr = controlbd_frame_decode(&req, &controlbd_uart.written); if (FAILED(hr)) { - dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); + dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr); return hr; } - hr = controlbd_frame_dispatch(&req); + //hr = controlbd_frame_dispatch(&req); if (FAILED(hr)) { - dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); + dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr); return hr; } + controlbd_uart.written.pos = 0; return hr; } -} - -static HRESULT controlbd_frame_dispatch(struct controlbd_req *req) -{ - switch (req->cmd) { - case CONTROLBD_CMD_UNK_10: - return controlbd_req_noop(req->cmd); - case CONTROLBD_CMD_UNK_7C: - return controlbd_req_unk7c(req->cmd); - case CONTROLBD_CMD_UNK_F0: - return controlbd_req_unkF0(req->cmd); - case CONTROLBD_CMD_UNK_30: - return controlbd_req_noop(req->cmd); - default: - dprintf("Unhandled command 0x%02X\n", req->cmd); - return controlbd_req_noop(req->cmd); - } -} - -static HRESULT controlbd_req_noop(uint8_t cmd) -{ - dprintf("Control Board: Noop cmd 0x%02X\n", cmd); - uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 }; - resp[5] = cmd; - resp[7] = 0x17 + cmd; - iobuf_write(&controlbd_uart.readable, resp, 8); - - return S_OK; -} - -static HRESULT controlbd_req_unk7c(uint8_t cmd) -{ - dprintf("Control Board: Cmd 0x7C\n"); - uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B }; - iobuf_write(&controlbd_uart.readable, resp, 9); - - return S_OK; -} - -static HRESULT controlbd_req_unkF0(uint8_t cmd) -{ - dprintf("Control Board: Cmd 0xF0\n"); - uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E }; - iobuf_write(&controlbd_uart.readable, resp, 16); - - return S_OK; -} - -/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ -static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf) -{ - int initial_pos = iobuf->pos; - int processed_pos = 0; - uint8_t check = 0; - bool escape = false; - dump_iobuf(iobuf); - - dest->sync = iobuf->bytes[0]; - - dest->dest = iobuf->bytes[1]; - check += dest->dest; - - dest->src = iobuf->bytes[2]; - check += dest->src; - - dest->data_len = iobuf->bytes[3]; - check += dest->data_len; - - dest->cmd = iobuf->bytes[4]; - check += dest->cmd; - - if (dest->data_len > 1) { - for (int i = 0; i < iobuf->pos - 6; i++) { - if (iobuf->bytes[i+6] == 0xD0) { - escape = true; - } - - dest->data[i] = iobuf->bytes[i+6]; - - if (escape) { - dest->data[i]++; - escape = false; - } - - check += dest->data[i]; - } - - } - dest->checksum = iobuf->bytes[iobuf->pos - 1]; - if (escape) { - dest->checksum++; - escape = false; - } - - iobuf->pos = 0; - - if (dest->sync != 0xe0) { - dprintf("Control Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); - return E_FAIL; - } - - if (dest->checksum != (check & 0xFF)) { - dprintf("Control Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); - return E_FAIL; - } - - return S_OK; } \ No newline at end of file diff --git a/carolhook/controlbd.h b/carolhook/controlbd.h index 16c3280..15f04ac 100644 --- a/carolhook/controlbd.h +++ b/carolhook/controlbd.h @@ -8,21 +8,4 @@ struct controlbd_config { bool enable; }; -enum controlbd_cmd { - CONTROLBD_CMD_UNK_10 = 0x10, - CONTROLBD_CMD_UNK_7C = 0x7C, - CONTROLBD_CMD_UNK_30 = 0x30, - CONTROLBD_CMD_UNK_F0 = 0xF0, -}; - -struct controlbd_req { - uint8_t sync; // Sync byte, always 0xE0 - uint8_t dest; // command destination id? - uint8_t src; // command source id? - uint8_t data_len; // length of the proceeding data bytes - uint8_t cmd; // might be the command byte? - uint8_t data[255]; // rest of the data, len = data_len - 1 - uint8_t checksum; // final byte is all bytes (excluding sync) added -}; - HRESULT controlbd_hook_init(const struct controlbd_config *cfg); \ No newline at end of file diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index bb664d1..608ca49 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -12,8 +12,9 @@ #include "carolhook/carol-dll.h" #include "carolhook/jvs.h" #include "carolhook/touch.h" -#include "carolhook/controlbd.h" +#include "carolhook/ledbd.h" #include "carolhook/serial.h" +#include "carolhook/controlbd.h" #include "hook/process.h" @@ -30,10 +31,10 @@ static struct carol_hook_config carol_hook_cfg; /* COM Layout -01:(?) Touchscreen +01: Touchscreen 10: Aime reader -11: Control board -12(?): LED Board +11: LED board +12: LED Board */ static DWORD CALLBACK carol_pre_startup(void) @@ -81,9 +82,7 @@ static DWORD CALLBACK carol_pre_startup(void) } gfx_hook_init(&carol_hook_cfg.gfx); - gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod); - //serial_init(); - + gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod); hr = touch_hook_init(&carol_hook_cfg.touch); @@ -91,6 +90,12 @@ static DWORD CALLBACK carol_pre_startup(void) goto fail; } + hr = ledbd_hook_init(&carol_hook_cfg.ledbd); + + if (FAILED(hr)) { + goto fail; + } + hr = controlbd_hook_init(&carol_hook_cfg.controlbd); if (FAILED(hr)) { diff --git a/carolhook/ledbd.c b/carolhook/ledbd.c new file mode 100644 index 0000000..18b9aab --- /dev/null +++ b/carolhook/ledbd.c @@ -0,0 +1,223 @@ +#include + +#include +#include +#include +#include + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "carolhook/carol-dll.h" +#include "carolhook/ledbd.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT ledbd_handle_irp(struct irp *irp); +static HRESULT ledbd_handle_irp_locked(struct irp *irp); +static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf); +static HRESULT ledbd_frame_dispatch(struct ledbd_req *dest); + +static HRESULT ledbd_req_noop(uint8_t cmd); +static HRESULT ledbd_req_unk7c(uint8_t cmd); +static HRESULT ledbd_req_unkF0(uint8_t cmd); + +static CRITICAL_SECTION ledbd_lock; +static struct uart ledbd_uart; +static uint8_t ledbd_written_bytes[520]; +static uint8_t ledbd_readable_bytes[520]; + +HRESULT ledbd_hook_init(const struct ledbd_config *cfg) +{ + if (!cfg->enable) { + return S_OK; + } + + InitializeCriticalSection(&ledbd_lock); + + uart_init(&ledbd_uart, 11); + ledbd_uart.written.bytes = ledbd_written_bytes; + ledbd_uart.written.nbytes = sizeof(ledbd_written_bytes); + ledbd_uart.readable.bytes = ledbd_readable_bytes; + ledbd_uart.readable.nbytes = sizeof(ledbd_readable_bytes); + + dprintf("LED Board: Init\n"); + + return iohook_push_handler(ledbd_handle_irp); +} + +static HRESULT ledbd_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + if (!uart_match_irp(&ledbd_uart, irp)) { + return iohook_invoke_next(irp); + } + + EnterCriticalSection(&ledbd_lock); + hr = ledbd_handle_irp_locked(irp); + LeaveCriticalSection(&ledbd_lock); + + return hr; +} + +static HRESULT ledbd_handle_irp_locked(struct irp *irp) +{ + struct ledbd_req req; + HRESULT hr; + + assert(carol_dll.ledbd_init != NULL); + + if (irp->op == IRP_OP_OPEN) { + dprintf("LED Board: Starting backend DLL\n"); + hr = carol_dll.ledbd_init(); + + if (FAILED(hr)) { + dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr); + + return hr; + } + } + + hr = uart_handle_irp(&ledbd_uart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("LED Board: TX Buffer:\n"); + dump_iobuf(&ledbd_uart.written); +#endif + hr = ledbd_frame_decode(&req, &ledbd_uart.written); + + if (FAILED(hr)) { + dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr); + + return hr; + } + + hr = ledbd_frame_dispatch(&req); + if (FAILED(hr)) { + dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr); + + return hr; + } + + return hr; + } +} + +static HRESULT ledbd_frame_dispatch(struct ledbd_req *req) +{ + switch (req->cmd) { + case LEDBD_CMD_UNK_10: + return ledbd_req_noop(req->cmd); + case LEDBD_CMD_UNK_7C: + return ledbd_req_unk7c(req->cmd); + case LEDBD_CMD_UNK_F0: + return ledbd_req_unkF0(req->cmd); + case LEDBD_CMD_UNK_30: + return ledbd_req_noop(req->cmd); + default: + dprintf("Unhandled command 0x%02X\n", req->cmd); + return ledbd_req_noop(req->cmd); + } +} + +static HRESULT ledbd_req_noop(uint8_t cmd) +{ + dprintf("LED Board: Noop cmd 0x%02X\n", cmd); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 }; + resp[5] = cmd; + resp[7] = 0x17 + cmd; + iobuf_write(&ledbd_uart.readable, resp, 8); + + return S_OK; +} + +static HRESULT ledbd_req_unk7c(uint8_t cmd) +{ + dprintf("LED Board: Cmd 0x7C\n"); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B }; + iobuf_write(&ledbd_uart.readable, resp, 9); + + return S_OK; +} + +static HRESULT ledbd_req_unkF0(uint8_t cmd) +{ + dprintf("LED Board: Cmd 0xF0\n"); + uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E }; + iobuf_write(&ledbd_uart.readable, resp, 16); + + return S_OK; +} + +/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ +static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf) +{ + int initial_pos = iobuf->pos; + int processed_pos = 0; + uint8_t check = 0; + bool escape = false; + + dest->sync = iobuf->bytes[0]; + + dest->dest = iobuf->bytes[1]; + check += dest->dest; + + dest->src = iobuf->bytes[2]; + check += dest->src; + + dest->data_len = iobuf->bytes[3]; + check += dest->data_len; + + dest->cmd = iobuf->bytes[4]; + check += dest->cmd; + + for (int i = 0; i < dest->data_len - 1; i++) { + if (iobuf->bytes[i+5] == 0xD0) { + escape = true; + check += 0xD0; + continue; + } + + dest->data[i] = iobuf->bytes[i+5]; + + if (escape) { + dest->data[i]++; + escape = false; + } + + check += iobuf->bytes[i+5]; + } + + dest->checksum = iobuf->bytes[iobuf->pos - 1]; + if (escape) { + dest->checksum++; + escape = false; + } + + iobuf->pos = 0; + + if (dest->sync != 0xe0) { + dprintf("LED Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); + dump_iobuf(iobuf); + return E_FAIL; + } + + if (dest->checksum != (check & 0xFF)) { + dprintf("LED Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); + dump_iobuf(iobuf); + return E_FAIL; + } + + return S_OK; +} \ No newline at end of file diff --git a/carolhook/ledbd.h b/carolhook/ledbd.h new file mode 100644 index 0000000..bbabf4c --- /dev/null +++ b/carolhook/ledbd.h @@ -0,0 +1,28 @@ +#pragma once +#include + +#include +#include + +struct ledbd_config { + bool enable; +}; + +enum ledbd_cmd { + LEDBD_CMD_UNK_10 = 0x10, + LEDBD_CMD_UNK_7C = 0x7C, + LEDBD_CMD_UNK_30 = 0x30, + LEDBD_CMD_UNK_F0 = 0xF0, +}; + +struct ledbd_req { + uint8_t sync; // Sync byte, always 0xE0 + uint8_t dest; // command destination id? + uint8_t src; // command source id? + uint8_t data_len; // length of the proceeding data bytes + uint8_t cmd; // might be the command byte? + uint8_t data[255]; // rest of the data, len = data_len - 1 + uint8_t checksum; // final byte is all bytes (excluding sync) added +}; + +HRESULT ledbd_hook_init(const struct ledbd_config *cfg); \ No newline at end of file diff --git a/carolhook/meson.build b/carolhook/meson.build index ac4c3cd..d62c897 100644 --- a/carolhook/meson.build +++ b/carolhook/meson.build @@ -32,6 +32,8 @@ shared_library( 'touch.h', 'controlbd.c', 'controlbd.h', + 'ledbd.c', + 'ledbd.h', 'serial.c', 'serial.h', ], diff --git a/carolhook/touch.c b/carolhook/touch.c index 83d184d..9a5ab03 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -96,6 +96,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) return hr; } + touch_uart.written.pos = 0; return hr; } } diff --git a/carolio/carolio.c b/carolio/carolio.c index 1ae4817..67339c9 100644 --- a/carolio/carolio.c +++ b/carolio/carolio.c @@ -73,6 +73,11 @@ HRESULT carol_io_touch_init() return S_OK; } +HRESULT carol_io_ledbd_init() +{ + return S_OK; +} + HRESULT carol_io_controlbd_init() { return S_OK; diff --git a/carolio/carolio.h b/carolio/carolio.h index dbe1091..7310f54 100644 --- a/carolio/carolio.h +++ b/carolio/carolio.h @@ -49,4 +49,6 @@ void carol_io_jvs_read_coin_counter(uint16_t *out); HRESULT carol_io_touch_init(); +HRESULT carol_io_ledbd_init(); + HRESULT carol_io_controlbd_init(); \ No newline at end of file From 74c8b312c57ab118c2677e0c1c6dc8fc45555404 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Tue, 11 Apr 2023 00:22:41 -0400 Subject: [PATCH 005/204] carol: fix prints --- carolhook/controlbd.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index 810d17b..c39eb83 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -18,8 +18,6 @@ static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp_locked(struct irp *irp); -//static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf); -//static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest); static HRESULT controlbd_req_noop(uint8_t cmd); static HRESULT controlbd_req_unk7c(uint8_t cmd); @@ -74,11 +72,11 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) assert(carol_dll.controlbd_init != NULL); if (irp->op == IRP_OP_OPEN) { - dprintf("LED Board: Starting backend DLL\n"); + dprintf("Control Board: Starting backend DLL\n"); hr = carol_dll.controlbd_init(); if (FAILED(hr)) { - dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr); + dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr); return hr; } @@ -92,20 +90,18 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) for (;;) { #if 1 - dprintf("LED Board: TX Buffer:\n"); + dprintf("Control Board: TX Buffer:\n"); dump_iobuf(&controlbd_uart.written); #endif - //hr = controlbd_frame_decode(&req, &controlbd_uart.written); if (FAILED(hr)) { - dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr); + dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); return hr; } - //hr = controlbd_frame_dispatch(&req); if (FAILED(hr)) { - dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr); + dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); return hr; } From 555784258a82013ea7d22a4cf135d9fa401f78e3 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 23 Apr 2023 16:13:51 +0200 Subject: [PATCH 006/204] idac: test --- Package.mk | 16 ++ dist/idac/segatools.ini | 116 ++++++++ dist/idac/start.bat | 10 + docker-build.bat | 2 +- idachook/config.c | 59 +++++ idachook/config.h | 36 +++ idachook/dllmain.c | 139 ++++++++++ idachook/idac-dll.c | 112 ++++++++ idachook/idac-dll.h | 22 ++ idachook/idachook copy.def | 24 ++ idachook/idachook.def | 19 ++ idachook/jvs.c | 177 +++++++++++++ idachook/jvs.h | 7 + idachook/meson.build | 36 +++ idachook/zinput.c | 186 +++++++++++++ idachook/zinput.h | 11 + idacio/backend.h | 11 + idacio/config.c | 121 +++++++++ idacio/config.h | 45 ++++ idacio/di-dev.c | 163 ++++++++++++ idacio/di-dev.h | 19 ++ idacio/di.c | 523 +++++++++++++++++++++++++++++++++++++ idacio/di.h | 9 + idacio/dllmain.c | 125 +++++++++ idacio/idacio.h | 106 ++++++++ idacio/idzio.def | 8 + idacio/meson.build | 32 +++ idacio/shifter.c | 32 +++ idacio/shifter.h | 8 + idacio/wnd.c | 86 ++++++ idacio/wnd.h | 5 + idacio/xi.c | 165 ++++++++++++ idacio/xi.h | 10 + meson.build | 2 + segatools.md | 456 ++++++++++++++++++++++++++++++++ 35 files changed, 2897 insertions(+), 1 deletion(-) create mode 100644 dist/idac/segatools.ini create mode 100644 dist/idac/start.bat create mode 100644 idachook/config.c create mode 100644 idachook/config.h create mode 100644 idachook/dllmain.c create mode 100644 idachook/idac-dll.c create mode 100644 idachook/idac-dll.h create mode 100644 idachook/idachook copy.def create mode 100644 idachook/idachook.def create mode 100644 idachook/jvs.c create mode 100644 idachook/jvs.h create mode 100644 idachook/meson.build create mode 100644 idachook/zinput.c create mode 100644 idachook/zinput.h create mode 100644 idacio/backend.h create mode 100644 idacio/config.c create mode 100644 idacio/config.h create mode 100644 idacio/di-dev.c create mode 100644 idacio/di-dev.h create mode 100644 idacio/di.c create mode 100644 idacio/di.h create mode 100644 idacio/dllmain.c create mode 100644 idacio/idacio.h create mode 100644 idacio/idzio.def create mode 100644 idacio/meson.build create mode 100644 idacio/shifter.c create mode 100644 idacio/shifter.h create mode 100644 idacio/wnd.c create mode 100644 idacio/wnd.h create mode 100644 idacio/xi.c create mode 100644 idacio/xi.h create mode 100644 segatools.md diff --git a/Package.mk b/Package.mk index 850f9ee..3e6a887 100644 --- a/Package.mk +++ b/Package.mk @@ -73,6 +73,21 @@ $(BUILD_DIR_ZIP)/idz.zip: $(V)strip $(BUILD_DIR_ZIP)/idz/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/idz ; zip -r ../idz.zip * +$(BUILD_DIR_ZIP)/idac.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/idac + $(V)mkdir -p $(BUILD_DIR_ZIP)/idac/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/idachook/idachook.dll \ + $(DIST_DIR)/idac/segatools.ini \ + $(DIST_DIR)/idac/start.bat \ + $(BUILD_DIR_ZIP)/idac + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/idac/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/idac/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/idac ; zip -r ../idac.zip * + $(BUILD_DIR_ZIP)/mercury.zip: $(V)echo ... $@ $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury @@ -119,6 +134,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/diva.zip \ $(BUILD_DIR_ZIP)/doc.zip \ $(BUILD_DIR_ZIP)/idz.zip \ + $(BUILD_DIR_ZIP)/idac.zip \ $(BUILD_DIR_ZIP)/mercury.zip \ $(BUILD_DIR_ZIP)/mu3.zip \ CHANGELOG.md \ diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini new file mode 100644 index 0000000..367d27e --- /dev/null +++ b/dist/idac/segatools.ini @@ -0,0 +1,116 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains OPxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[ds] +; Region code on the emulated AMEX board DS EEPROM. +; 1: Japan +; 4: Export (some UI elements in English) +; +; NOTE: Changing this setting causes a factory reset. +region=1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.100.0 + +[gpio] +; Emulated Nu DIP switch for Distribution Server setting. +; +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. +dipsw1=1 + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[idzio] +; To use a custom Initial D Zero IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in gamepad/wheel input. +path= + +[io3] +; Input API selection for JVS input emulator. +; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. +mode=xinput +; Automatically reset the simulated shifter to Neutral when XInput Start is +; pressed (e.g. when navigating menus between races). +autoNeutral=1 +; Use the left thumbstick for steering instead of both on XInput Controllers. +; Not recommended as it will not give you the precision needed for this game +singleStickSteering=0 +; Adjust scaling for steering wheel input. +; +; This setting scales the steering wheel input so that the maximum positive +; and minimum negative steering inputs reported in the operator menu's input +; test screen do not exceed the value below. The maximum possible value is 128, +; and the value that matches the input range of a real cabinet is 97. +; +; NOTE: This is not the same thing as DirectInput steering wheel movement +; range! Segatools cannot control the maximum angle of your physical steering +; wheel controller, this setting is vendor-specific and can only be adjusted +; in the Control Panel. +restrict=97 + +[dinput] +; Name of the DirectInput wheel to use (or any text that occurs in its name) +; Example: TMX +; +; If this is left blank then the first DirectInput device will be used. +deviceName= +; Name of the positional shifter to use (or any subset thereof). +; Leave blank if you do not have a positional shifter; a positional shifter +; will be simulated using the configured Shift Down and Shift Up buttons +; in this case. +; +; Can be the same device as the wheel. +; +; Example: T500 +shifterName= +; Pedal mappings. Valid axis names are: +; +; X, Y, Z, RX, RY, RZ, U, V +; +; (U and V are old names for Slider 1 and Slider 2). +; The examples below are valid for a Thrustmaster TMX. +brakeAxis=RZ +accelAxis=Y +; DirectInput button numbers to map to menu inputs. Note that buttons are +; numbered from 1; some software numbers buttons from 0. +start=3 +viewChg=10 +; Button mappings for the simulated six-speed shifter. +shiftDn=1 +shiftUp=2 +; Button mappings for the positional shifter, if present. +gear1=1 +gear2=2 +gear3=3 +gear4=4 +gear5=5 +gear6=6 +; Invert the accelerator and or brake axis +; (Needed when using DirectInput for the Dualshock 4 for example) +reverseAccelAxis=0 +reverseBrakeAxis=0 diff --git a/dist/idac/start.bat b/dist/idac/start.bat new file mode 100644 index 0000000..61ed927 --- /dev/null +++ b/dist/idac/start.bat @@ -0,0 +1,10 @@ +@echo off + +pushd %~dp0 + +start inject.exe -d -k idachook.dll amdaemon.exe -c config_common.json config_jp.json config_seat_1_jp.json config_seat_2_jp.json config_ex.json config_seat_1_ex.json config_seat_2_ex.json +inject -d -k idachook.dll ../WindowsNoEditor/GameProject/Binaries/Win64/GameProject-Win64-Shipping.exe + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/docker-build.bat b/docker-build.bat index 969e032..822dc9b 100644 --- a/docker-build.bat +++ b/docker-build.bat @@ -18,7 +18,7 @@ if ERRORLEVEL 1 ( goto failure ) -docker image rm -f %IMAGE_NAME% +:: docker image rm -f %IMAGE_NAME% goto success diff --git a/idachook/config.c b/idachook/config.c new file mode 100644 index 0000000..7e648bf --- /dev/null +++ b/idachook/config.c @@ -0,0 +1,59 @@ +#include +#include + +#include "amex/amex.h" +#include "amex/config.h" + +#include "board/config.h" +#include "board/sg-reader.h" + +#include "gfxhook/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "idachook/config.h" +#include "idachook/idac-dll.h" + +#include "platform/config.h" +#include "platform/platform.h" + +void idac_dll_config_load( + struct idac_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"idzio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void idac_hook_config_load( + struct idac_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + amex_config_load(&cfg->amex, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + // gfx_config_load(&cfg->gfx, filename); + idac_dll_config_load(&cfg->dll, filename); + zinput_config_load(&cfg->zinput, filename); +} + +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename); +} diff --git a/idachook/config.h b/idachook/config.h new file mode 100644 index 0000000..674797e --- /dev/null +++ b/idachook/config.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "amex/amex.h" + +#include "board/sg-reader.h" + +#include "gfxhook/gfx.h" + +#include "hooklib/dvd.h" + +#include "idachook/idac-dll.h" +#include "idachook/zinput.h" + +#include "platform/platform.h" + +struct idac_hook_config { + struct platform_config platform; + struct amex_config amex; + struct aime_config aime; + struct dvd_config dvd; + struct idac_dll_config dll; + struct zinput_config zinput; +}; + +void idac_dll_config_load( + struct idac_dll_config *cfg, + const wchar_t *filename); + +void idac_hook_config_load( + struct idac_hook_config *cfg, + const wchar_t *filename); + +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename); diff --git a/idachook/dllmain.c b/idachook/dllmain.c new file mode 100644 index 0000000..fcf44d9 --- /dev/null +++ b/idachook/dllmain.c @@ -0,0 +1,139 @@ +#include +#include + +#include +#include +#include + +#include "amex/amex.h" + +#include "board/sg-reader.h" + +// #include "gfxhook/d3d11.h" +// #include "gfxhook/dxgi.h" +// #include "gfxhook/gfx.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "idachook/config.h" +#include "idachook/idac-dll.h" +#include "idachook/jvs.h" +#include "idachook/zinput.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" +#include "util/lib.h" + +static HMODULE idac_hook_mod; +static process_entry_t idac_startup; +static struct idac_hook_config idac_hook_cfg; + +static DWORD CALLBACK idac_pre_startup(void) +{ + wchar_t *module_path; + wchar_t *file_name; + HRESULT hr; + + dprintf("--- Begin idac_pre_startup ---\n"); + + /* Config load */ + + idac_hook_config_load(&idac_hook_cfg, L".\\segatools.ini"); + + /* + module_path = module_file_name(NULL); + + if (module_path != NULL) { + file_name = PathFindFileNameW(module_path); + + _wcslwr(file_name); + + if (wcsstr(file_name, L"serverbox") != NULL) { + dprintf("Executable filename contains 'ServerBox', disabling full-screen mode\n"); + + idac_hook_cfg.gfx.windowed = true; + idac_hook_cfg.gfx.framed = true; + } + + free(module_path); + + module_path = NULL; + } + */ + + /* Hook Win32 APIs */ + + serial_hook_init(); + // gfx_hook_init(&idac_hook_cfg.gfx); + // gfx_d3d11_hook_init(&idac_hook_cfg.gfx, idac_hook_mod); + // gfx_dxgi_hook_init(&idac_hook_cfg.gfx, idac_hook_mod); + zinput_hook_init(&idac_hook_cfg.zinput); + dvd_hook_init(&idac_hook_cfg.dvd, idac_hook_mod); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &idac_hook_cfg.platform, + "SDGT", + "ACA2", + idac_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = amex_hook_init(&idac_hook_cfg.amex, idac_jvs_init); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&idac_hook_cfg.aime, 10, idac_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End idac_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return idac_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + idac_hook_mod = mod; + + hr = process_hijack_startup(idac_pre_startup, &idac_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c new file mode 100644 index 0000000..6346089 --- /dev/null +++ b/idachook/idac-dll.c @@ -0,0 +1,112 @@ +#include + +#include +#include + +#include "idachook/idac-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym idac_dll_syms[] = { + { + .sym = "idac_io_jvs_init", + .off = offsetof(struct idac_dll, jvs_init), + }, { + .sym = "idac_io_jvs_read_analogs", + .off = offsetof(struct idac_dll, jvs_read_analogs), + }, { + .sym = "idac_io_jvs_read_buttons", + .off = offsetof(struct idac_dll, jvs_read_buttons), + }, { + .sym = "idac_io_jvs_read_shifter", + .off = offsetof(struct idac_dll, jvs_read_shifter), + }, { + .sym = "idac_io_jvs_read_coin_counter", + .off = offsetof(struct idac_dll, jvs_read_coin_counter), + } +}; + +struct idac_dll idac_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT idac_dll_init(const struct idac_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("IDZ IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("IDZ IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "idac_io_get_api_version"); + + if (get_api_version != NULL) { + idac_dll.api_version = get_api_version(); + } else { + idac_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose idac_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (idac_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("IDZ IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + idac_dll.api_version); + + goto end; + } + + sym = idac_dll_syms; + hr = dll_bind(&idac_dll, src, &sym, _countof(idac_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("IDZ IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h new file mode 100644 index 0000000..88902ed --- /dev/null +++ b/idachook/idac-dll.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "idacio/idacio.h" + +struct idac_dll { + uint16_t api_version; + HRESULT (*jvs_init)(void); + void (*jvs_read_analogs)(struct idac_io_analog_state *out); + void (*jvs_read_buttons)(uint8_t *opbtn, uint8_t *gamebtn); + void (*jvs_read_shifter)(uint8_t *gear); + void (*jvs_read_coin_counter)(uint16_t *total); +}; + +struct idac_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct idac_dll idac_dll; + +HRESULT idac_dll_init(const struct idac_dll_config *cfg, HINSTANCE self); diff --git a/idachook/idachook copy.def b/idachook/idachook copy.def new file mode 100644 index 0000000..a46fa06 --- /dev/null +++ b/idachook/idachook copy.def @@ -0,0 +1,24 @@ +LIBRARY idachook + +EXPORTS + CreateDXGIFactory + CreateDXGIFactory1 + CreateDXGIFactory2 + D3D11CreateDevice + D3D11CreateDeviceAndSwapChain + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + idac_io_get_api_version + idac_io_jvs_init + idac_io_jvs_read_analogs + idac_io_jvs_read_buttons + idac_io_jvs_read_coin_counter + idac_io_jvs_read_shifter diff --git a/idachook/idachook.def b/idachook/idachook.def new file mode 100644 index 0000000..68ed1d0 --- /dev/null +++ b/idachook/idachook.def @@ -0,0 +1,19 @@ +LIBRARY idachook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + idac_io_get_api_version + idac_io_jvs_init + idac_io_jvs_read_analogs + idac_io_jvs_read_buttons + idac_io_jvs_read_coin_counter + idac_io_jvs_read_shifter diff --git a/idachook/jvs.c b/idachook/jvs.c new file mode 100644 index 0000000..2192c24 --- /dev/null +++ b/idachook/jvs.c @@ -0,0 +1,177 @@ +#include + +#include +#include +#include + +#include "amex/jvs.h" + +#include "board/io3.h" + +#include "idachook/idac-dll.h" +#include "idachook/jvs.h" + +#include "jvs/jvs-bus.h" + +#include "util/dprintf.h" + +static void idac_jvs_read_analogs( + void *ctx, + uint16_t *analogs, + uint8_t nanalogs); +static void idac_jvs_read_switches(void *ctx, struct io3_switch_state *out); +static void idac_jvs_read_coin_counter( + void *ctx, + uint8_t slot_no, + uint16_t *out); + +static const struct io3_ops idac_jvs_io3_ops = { + .read_switches = idac_jvs_read_switches, + .read_analogs = idac_jvs_read_analogs, + .read_coin_counter = idac_jvs_read_coin_counter, +}; + +static const uint16_t idac_jvs_gear_signals[] = { + /* Neutral */ + 0x0000, + /* 1: Left|Up */ + 0x2800, + /* 2: Left|Down */ + 0x1800, + /* 3: Up */ + 0x2000, + /* 4: Down */ + 0x1000, + /* 5: Right|Up */ + 0x2400, + /* 6: Right|Down */ + 0x1400, +}; + +static struct io3 idac_jvs_io3; + +HRESULT idac_jvs_init(struct jvs_node **out) +{ + HRESULT hr; + + assert(out != NULL); + assert(idac_dll.jvs_init != NULL); + + dprintf("JVS I/O: Starting Initial D Zero backend DLL\n"); + hr = idac_dll.jvs_init(); + + if (FAILED(hr)) { + dprintf("JVS I/O: Backend error, I/O disconnected; %x\n", (int) hr); + + return hr; + } + + io3_init(&idac_jvs_io3, NULL, &idac_jvs_io3_ops, NULL); + *out = io3_to_jvs_node(&idac_jvs_io3); + + return S_OK; +} + +static void idac_jvs_read_switches(void *ctx, struct io3_switch_state *out) +{ + uint8_t opbtn; + uint8_t gamebtn; + uint8_t gear; + + assert(out != NULL); + assert(idac_dll.jvs_read_buttons != NULL); + assert(idac_dll.jvs_read_shifter != NULL); + + opbtn = 0; + gamebtn = 0; + gear = 0; + + idac_dll.jvs_read_buttons(&opbtn, &gamebtn); + idac_dll.jvs_read_shifter(&gear); + + /* Update gameplay buttons */ + + if (gamebtn & IDAC_IO_GAMEBTN_UP) { + out->p1 |= 1 << 13; + } + + if (gamebtn & IDAC_IO_GAMEBTN_DOWN) { + out->p1 |= 1 << 12; + } + + if (gamebtn & IDAC_IO_GAMEBTN_LEFT) { + out->p1 |= 1 << 11; + } + + if (gamebtn & IDAC_IO_GAMEBTN_RIGHT) { + out->p1 |= 1 << 10; + } + + if (gamebtn & IDAC_IO_GAMEBTN_START) { + out->p1 |= 1 << 15; + } + + if (gamebtn & IDAC_IO_GAMEBTN_VIEW_CHANGE) { + out->p1 |= 1 << 9; + } + + /* Update simulated six-speed shifter */ + + if (gear > 6) { + gear = 6; + } + + out->p2 = idac_jvs_gear_signals[gear]; + + /* Update test/service buttons */ + + if (opbtn & IDAC_IO_OPBTN_TEST) { + out->system = 0x80; + } else { + out->system = 0; + } + + if (opbtn & IDAC_IO_OPBTN_SERVICE) { + out->p1 |= 1 << 14; + } +} + +static void idac_jvs_read_analogs( + void *ctx, + uint16_t *analogs, + uint8_t nanalogs) +{ + struct idac_io_analog_state state; + + assert(analogs != NULL); + assert(idac_dll.jvs_read_analogs != NULL); + + memset(&state, 0, sizeof(state)); + idac_dll.jvs_read_analogs(&state); + + if (nanalogs > 0) { + analogs[0] = 0x8000 + state.wheel; + } + + if (nanalogs > 1) { + analogs[1] = state.accel; + } + + if (nanalogs > 2) { + analogs[2] = state.brake; + } +} + +static void idac_jvs_read_coin_counter( + void *ctx, + uint8_t slot_no, + uint16_t *out) +{ + assert(idac_dll.jvs_read_coin_counter != NULL); + + if (slot_no > 0) { + return; + } + + idac_dll.jvs_read_coin_counter(out); +} diff --git a/idachook/jvs.h b/idachook/jvs.h new file mode 100644 index 0000000..f0781a4 --- /dev/null +++ b/idachook/jvs.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "jvs/jvs-bus.h" + +HRESULT idac_jvs_init(struct jvs_node **root); diff --git a/idachook/meson.build b/idachook/meson.build new file mode 100644 index 0000000..3a3369d --- /dev/null +++ b/idachook/meson.build @@ -0,0 +1,36 @@ +shared_library( + 'idachook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'idachook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + shlwapi_lib, + xinput_lib, + ], + link_with : [ + aimeio_lib, + amex_lib, + board_lib, + # gfxhook_lib, + hooklib_lib, + idacio_lib, + jvs_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'idac-dll.c', + 'idac-dll.h', + 'jvs.c', + 'jvs.h', + 'zinput.c', + 'zinput.h', + ], +) diff --git a/idachook/zinput.c b/idachook/zinput.c new file mode 100644 index 0000000..59c77b5 --- /dev/null +++ b/idachook/zinput.c @@ -0,0 +1,186 @@ +#include +#include + +#include +#include +#include + +#include "idachook/config.h" +#include "idachook/zinput.h" + +#include "hook/table.h" + +#include "util/dprintf.h" + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter); + +static unsigned long WINAPI hook_AddRef(IUnknown *self); + +static unsigned long WINAPI hook_Release(IUnknown *self); + +static HRESULT WINAPI hook_CreateDevice( + IDirectInput8W *self, + REFGUID rguid, + LPDIRECTINPUTDEVICE8W * lplpDirectInputDevice, + LPUNKNOWN pUnkOuter); + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags); + +static HRESULT WINAPI hook_SetDataFormat( + IDirectInputDevice8W *self, + LPCDIDATAFORMAT lpdf); + +static HRESULT WINAPI hook_SetCooperativeLevel( + IDirectInputDevice8W *self, + HWND hwnd, + DWORD flags); + +static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self); + +static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self); + +static HRESULT WINAPI hook_GetDeviceState( + IDirectInputDevice8W *self, + DWORD cbData, + LPVOID lpvData); + +static const IDirectInput8WVtbl api_vtbl = { + .AddRef = (void *) hook_AddRef, + .Release = (void *) hook_Release, + .CreateDevice = hook_CreateDevice, + .EnumDevices = hook_EnumDevices, +}; + +static const IDirectInput8W api = { (void *) &api_vtbl }; + +static const IDirectInputDevice8WVtbl dev_vtbl = { + .AddRef = (void *) hook_AddRef, + .Release = (void *) hook_Release, + .SetDataFormat = hook_SetDataFormat, + .SetCooperativeLevel= hook_SetCooperativeLevel, + .Acquire = hook_Acquire, + .Unacquire = hook_Unacquire, + .GetDeviceState = hook_GetDeviceState, +}; + +static const IDirectInputDevice8W dev = { (void *) &dev_vtbl }; + +static const struct hook_symbol zinput_hook_syms[] = { + { + .name = "DirectInput8Create", + .patch = hook_DirectInput8Create, + } +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + hook_table_apply( + NULL, + "dinput8.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + return S_OK; +} + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter) +{ + dprintf("ZInput: Blocking built-in DirectInput support\n"); + *ppvOut = (void *) &api; + + return S_OK; +} + +static unsigned long WINAPI hook_AddRef(IUnknown *self) +{ + return 1; +} + +static unsigned long WINAPI hook_Release(IUnknown *self) +{ + return 1; +} + +static HRESULT WINAPI hook_CreateDevice( + IDirectInput8W *self, + REFGUID rguid, + LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, + LPUNKNOWN pUnkOuter) +{ + dprintf("ZInput: %s\n", __func__); + *lplpDirectInputDevice = (void *) &dev; + + return S_OK; +} + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_SetDataFormat( + IDirectInputDevice8W *self, + LPCDIDATAFORMAT lpdf) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_SetCooperativeLevel( + IDirectInputDevice8W *self, + HWND hwnd, + DWORD flags) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self) +{ + return S_OK; +} + +static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self) +{ + return S_OK; +} + +static HRESULT WINAPI hook_GetDeviceState( + IDirectInputDevice8W *self, + DWORD cbData, + LPVOID lpvData) +{ + memset(lpvData, 0, cbData); + + return S_OK; +} diff --git a/idachook/zinput.h b/idachook/zinput.h new file mode 100644 index 0000000..13a46cd --- /dev/null +++ b/idachook/zinput.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +struct zinput_config { + bool enable; +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg); diff --git a/idacio/backend.h b/idacio/backend.h new file mode 100644 index 0000000..46daa0b --- /dev/null +++ b/idacio/backend.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "idacio/idacio.h" + +struct idac_io_backend { + void (*jvs_read_buttons)(uint8_t *gamebtn); + void (*jvs_read_shifter)(uint8_t *gear); + void (*jvs_read_analogs)(struct idac_io_analog_state *state); +}; diff --git a/idacio/config.c b/idacio/config.c new file mode 100644 index 0000000..5df7971 --- /dev/null +++ b/idacio/config.c @@ -0,0 +1,121 @@ +#include + +#include +#include +#include +#include +#include + +#include "idacio/config.h" + +void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename) +{ + wchar_t key[8]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"dinput", + L"deviceName", + L"", + cfg->device_name, + _countof(cfg->device_name), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"shifterName", + L"", + cfg->shifter_name, + _countof(cfg->shifter_name), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"brakeAxis", + L"RZ", + cfg->brake_axis, + _countof(cfg->brake_axis), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"accelAxis", + L"Y", + cfg->accel_axis, + _countof(cfg->accel_axis), + filename); + + cfg->start = GetPrivateProfileIntW(L"dinput", L"start", 0, filename); + cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename); + cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename); + cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename); + + cfg->reverse_brake_axis = GetPrivateProfileIntW( + L"dinput", + L"reverseBrakeAxis", + 0, + filename); + cfg->reverse_accel_axis = GetPrivateProfileIntW( + L"dinput", + L"reverseAccelAxis", + 0, + filename); + + for (i = 0 ; i < 6 ; i++) { + swprintf_s(key, _countof(key), L"gear%i", i + 1); + cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename); + } + +} + +void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->single_stick_steering = GetPrivateProfileIntW( + L"io3", + L"singleStickSteering", + 0, + filename); +} + +void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + cfg->restrict_ = GetPrivateProfileIntW(L"io3", L"restrict", 97, filename); + + GetPrivateProfileStringW( + L"io3", + L"mode", + L"xinput", + cfg->mode, + _countof(cfg->mode), + filename); + + idac_shifter_config_load(&cfg->shifter, filename); + idac_di_config_load(&cfg->di, filename); + idac_xi_config_load(&cfg->xi, filename); +} + +void idac_shifter_config_load( + struct idac_shifter_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->auto_neutral = GetPrivateProfileIntW( + L"io3", + L"autoNeutral", + 0, + filename); +} diff --git a/idacio/config.h b/idacio/config.h new file mode 100644 index 0000000..6e5563d --- /dev/null +++ b/idacio/config.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +struct idac_shifter_config { + bool auto_neutral; +}; + +struct idac_di_config { + wchar_t device_name[64]; + wchar_t shifter_name[64]; + wchar_t brake_axis[16]; + wchar_t accel_axis[16]; + uint8_t start; + uint8_t view_chg; + uint8_t shift_dn; + uint8_t shift_up; + uint8_t gear[6]; + bool reverse_brake_axis; + bool reverse_accel_axis; +}; + +struct idac_xi_config { + bool single_stick_steering; +}; + +struct idac_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + wchar_t mode[8]; + int restrict_; + struct idac_shifter_config shifter; + struct idac_di_config di; + struct idac_xi_config xi; +}; + +void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename); +void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename); +void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename); +void idac_shifter_config_load( + struct idac_shifter_config *cfg, + const wchar_t *filename); diff --git a/idacio/di-dev.c b/idacio/di-dev.c new file mode 100644 index 0000000..c77584b --- /dev/null +++ b/idacio/di-dev.c @@ -0,0 +1,163 @@ +#include +#include + +#include + +#include "idacio/di-dev.h" + +#include "util/dprintf.h" + +HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +{ + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +{ + /* Set up force-feedback on devices that support it. This is just a stub + for the time being, since we don't yet know how the serial port force + feedback protocol works. + + I'm currently developing with an Xbox One Thrustmaster TMX wheel, if + we don't perform at least some perfunctory FFB initialization of this + nature (or indeed if no DirectInput application is running) then the + wheel exhibits considerable resistance, similar to that of a stationary + car. Changing cf.lMagnitude to a nonzero value does cause the wheel to + continuously turn in the given direction with the given force as one + would expect (max magnitude per DirectInput docs is +/- 10000). + + Failure here is non-fatal, we log any errors and move on. + + https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) + */ + + IDirectInputEffect *obj; + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + assert(dev != NULL); + assert(out != NULL); + + *out = NULL; + + dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + + axis = DIJOFS_X; + direction = 0; + + memset(&cf, 0, sizeof(cf)); + cf.lMagnitude = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + hr = IDirectInputDevice8_CreateEffect( + dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + (int) hr); + + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + + if (FAILED(hr)) { + IDirectInputEffect_Release(obj); + dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + (int) hr); + + return; + } + + *out = obj; + + dprintf("DirectInput: Force feedback initialized and set to zero\n"); +} + +HRESULT idac_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union idac_di_state *out) +{ + HRESULT hr; + MSG msg; + + assert(dev != NULL); + assert(wnd != NULL); + assert(out != NULL); + + memset(out, 0, sizeof(*out)); + + /* Pump our dummy window's message queue just in case DirectInput or an + IHV DirectInput driver somehow relies on it */ + + while (PeekMessageW(&msg, wnd, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (FAILED(hr)) { + dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + } + + /* JVS lacks a protocol for reporting hardware errors from poll command + responses, so this ends up returning zeroed input state instead. */ + + return hr; +} diff --git a/idacio/di-dev.h b/idacio/di-dev.h new file mode 100644 index 0000000..efbe39e --- /dev/null +++ b/idacio/di-dev.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +union idac_di_state { + DIJOYSTATE st; + uint8_t bytes[sizeof(DIJOYSTATE)]; +}; + +HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); +void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +HRESULT idac_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union idac_di_state *out); + diff --git a/idacio/di.c b/idacio/di.c new file mode 100644 index 0000000..b2d0d3d --- /dev/null +++ b/idacio/di.c @@ -0,0 +1,523 @@ +#include +#include + +#include +#include +#include + +#include "idacio/backend.h" +#include "idacio/config.h" +#include "idacio/di.h" +#include "idacio/di-dev.h" +#include "idacio/idacio.h" +#include "idacio/shifter.h" +#include "idacio/wnd.h" + +#include "util/dprintf.h" +#include "util/str.h" + +struct idac_di_axis { + wchar_t name[4]; + size_t off; +}; + +static HRESULT idac_di_config_apply(const struct idac_di_config *cfg); +static const struct idac_di_axis *idac_di_get_axis(const wchar_t *name); +static BOOL CALLBACK idac_di_enum_callback( + const DIDEVICEINSTANCEW *dev, + void *ctx); +static BOOL CALLBACK idac_di_enum_callback_shifter( + const DIDEVICEINSTANCEW *dev, + void *ctx); +static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out); +static uint8_t idac_di_decode_pov(DWORD pov); +static void idac_di_jvs_read_shifter(uint8_t *gear); +static void idac_di_jvs_read_shifter_pos(uint8_t *gear); +static void idac_di_jvs_read_shifter_virt(uint8_t *gear); +static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out); + +static const struct idac_di_axis idac_di_axes[] = { + /* Just map DIJOYSTATE for now, we can map DIJOYSTATE2 later if needed */ + { .name = L"X", .off = DIJOFS_X }, + { .name = L"Y", .off = DIJOFS_Y }, + { .name = L"Z", .off = DIJOFS_Z }, + { .name = L"RX", .off = DIJOFS_RX }, + { .name = L"RY", .off = DIJOFS_RY }, + { .name = L"RZ", .off = DIJOFS_RZ }, + { .name = L"U", .off = DIJOFS_SLIDER(0) }, + { .name = L"V", .off = DIJOFS_SLIDER(1) }, +}; + +static const struct idac_io_backend idac_di_backend = { + .jvs_read_buttons = idac_di_jvs_read_buttons, + .jvs_read_shifter = idac_di_jvs_read_shifter, + .jvs_read_analogs = idac_di_jvs_read_analogs, +}; + +static HWND idac_di_wnd; +static IDirectInput8W *idac_di_api; +static IDirectInputDevice8W *idac_di_dev; +static IDirectInputDevice8W *idac_di_shifter; +static IDirectInputEffect *idac_di_fx; +static size_t idac_di_off_brake; +static size_t idac_di_off_accel; +static uint8_t idac_di_shift_dn; +static uint8_t idac_di_shift_up; +static uint8_t idac_di_view_chg; +static uint8_t idac_di_start; +static uint8_t idac_di_gear[6]; +static bool idac_di_reverse_brake_axis; +static bool idac_di_reverse_accel_axis; + +HRESULT idac_di_init( + const struct idac_di_config *cfg, + HINSTANCE inst, + const struct idac_io_backend **backend) +{ + HRESULT hr; + HMODULE dinput8; + HRESULT (WINAPI *api_entry)(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); + wchar_t dll_path[MAX_PATH]; + UINT path_pos; + + assert(cfg != NULL); + assert(backend != NULL); + + *backend = NULL; + + hr = idac_di_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + hr = idac_io_wnd_create(inst, &idac_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + /* Initial D Zero has some built-in DirectInput support that is not + particularly useful. idzhook shorts this out by redirecting dinput8.dll + to a no-op implementation of DirectInput. However, idzio does need to + talk to the real operating system implementation of DirectInput without + the stub DLL interfering, so build a path to + C:\Windows\System32\dinput.dll here. */ + + dll_path[0] = L'\0'; + path_pos = GetSystemDirectoryW(dll_path, _countof(dll_path)); + wcscat_s( + dll_path + path_pos, + _countof(dll_path) - path_pos, + L"\\dinput8.dll"); + + dinput8 = LoadLibraryW(dll_path); + + if (dinput8 == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("DirectInput: LoadLibrary failed: %08x\n", (int) hr); + + return hr; + } + + api_entry = (void *) GetProcAddress(dinput8, "DirectInput8Create"); + + if (api_entry == NULL) { + dprintf("DirectInput: GetProcAddress failed\n"); + + return E_FAIL; + } + + hr = api_entry( + inst, + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void **) &idac_di_api, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: API create failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInput8_EnumDevices( + idac_di_api, + DI8DEVCLASS_GAMECTRL, + idac_di_enum_callback, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (idac_di_dev == NULL) { + dprintf("Wheel: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = idac_di_dev_start(idac_di_dev, idac_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + idac_di_dev_start_fx(idac_di_dev, &idac_di_fx); + + if (cfg->shifter_name[0] != L'\0') { + hr = IDirectInput8_EnumDevices( + idac_di_api, + DI8DEVCLASS_GAMECTRL, + idac_di_enum_callback_shifter, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (idac_di_dev == NULL) { + dprintf("Shifter: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = idac_di_dev_start(idac_di_shifter, idac_di_wnd); + + if (FAILED(hr)) { + return hr; + } + } + + dprintf("DirectInput: Controller initialized\n"); + + *backend = &idac_di_backend; + + return S_OK; +} + +static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) +{ + const struct idac_di_axis *brake_axis; + const struct idac_di_axis *accel_axis; + int i; + + brake_axis = idac_di_get_axis(cfg->brake_axis); + accel_axis = idac_di_get_axis(cfg->accel_axis); + + if (brake_axis == NULL) { + dprintf("Wheel: Invalid brake axis: %S\n", cfg->brake_axis); + + return E_INVALIDARG; + } + + if (accel_axis == NULL) { + dprintf("Wheel: Invalid accel axis: %S\n", cfg->accel_axis); + + return E_INVALIDARG; + } + + if (cfg->start > 32) { + dprintf("Wheel: Invalid start button: %i\n", cfg->start); + + return E_INVALIDARG; + } + + if (cfg->view_chg > 32) { + dprintf("Wheel: Invalid view change button: %i\n", cfg->view_chg); + + return E_INVALIDARG; + } + + if (cfg->shift_dn > 32) { + dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn); + + return E_INVALIDARG; + } + + if (cfg->shift_up > 32) { + dprintf("Wheel: Invalid shift up button: %i\n", cfg->shift_up); + + return E_INVALIDARG; + } + + for (i = 0 ; i < 6 ; i++) { + if (cfg->gear[i] > 32) { + dprintf("Shifter: Invalid gear %i button: %i\n", + i + 1, + cfg->gear[i]); + + return E_INVALIDARG; + } + } + + /* Print some debug output to make sure config works... */ + + dprintf("Wheel: --- Begin configuration ---\n"); + dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", + cfg->device_name); + dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name); + dprintf("Wheel: Accelerator axis . : %S\n", brake_axis->name); + dprintf("Wheel: Start button . . . : %i\n", cfg->start); + dprintf("Wheel: View Change button : %i\n", cfg->view_chg); + dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); + dprintf("Wheel: Shift Up button . . : %i\n", cfg->shift_up); + dprintf("Wheel: Reverse Brake Axis : %i\n", cfg->reverse_brake_axis); + dprintf("Wheel: Reverse Accel Axis : %i\n", cfg->reverse_accel_axis); + dprintf("Wheel: --- End configuration ---\n"); + + if (cfg->shifter_name[0] != L'\0') { + dprintf("Shifter: --- Begin configuration ---\n"); + dprintf("Shifter: Device name . . . : Contains \"%S\"\n", + cfg->shifter_name); + dprintf("Shifter: Gear buttons . . : %i %i %i %i %i %i\n", + cfg->gear[0], + cfg->gear[1], + cfg->gear[2], + cfg->gear[3], + cfg->gear[4], + cfg->gear[5]); + dprintf("Shifter: --- End configuration ---\n"); + } + + idac_di_off_brake = accel_axis->off; + idac_di_off_accel = brake_axis->off; + idac_di_start = cfg->start; + idac_di_view_chg = cfg->view_chg; + idac_di_shift_dn = cfg->shift_dn; + idac_di_shift_up = cfg->shift_up; + idac_di_reverse_brake_axis = cfg->reverse_brake_axis; + idac_di_reverse_accel_axis = cfg->reverse_accel_axis; + + for (i = 0 ; i < 6 ; i++) { + idac_di_gear[i] = cfg->gear[i]; + } + + return S_OK; +} + +static const struct idac_di_axis *idac_di_get_axis(const wchar_t *name) +{ + const struct idac_di_axis *axis; + size_t i; + + for (i = 0 ; i < _countof(idac_di_axes) ; i++) { + axis = &idac_di_axes[i]; + + if (wstr_ieq(name, axis->name)) { + return axis; + } + } + + return NULL; +} + +static BOOL CALLBACK idac_di_enum_callback( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct idac_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->device_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Wheel: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + idac_di_api, + &dev->guidInstance, + &idac_di_dev, + NULL); + + if (FAILED(hr)) { + dprintf("Wheel: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + +static BOOL CALLBACK idac_di_enum_callback_shifter( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct idac_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->shifter_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Shifter: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + idac_di_api, + &dev->guidInstance, + &idac_di_shifter, + NULL); + + if (FAILED(hr)) { + dprintf("Shifter: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + +static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out) +{ + union idac_di_state state; + uint8_t gamebtn; + HRESULT hr; + + assert(gamebtn_out != NULL); + + hr = idac_di_dev_poll(idac_di_dev, idac_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + gamebtn = idac_di_decode_pov(state.st.rgdwPOV[0]); + + if (idac_di_start && state.st.rgbButtons[idac_di_start - 1]) { + gamebtn |= IDAC_IO_GAMEBTN_START; + } + + if (idac_di_view_chg && state.st.rgbButtons[idac_di_view_chg - 1]) { + gamebtn |= IDAC_IO_GAMEBTN_VIEW_CHANGE; + } + + *gamebtn_out = gamebtn; +} + +static uint8_t idac_di_decode_pov(DWORD pov) +{ + switch (pov) { + case 0: return IDAC_IO_GAMEBTN_UP; + case 4500: return IDAC_IO_GAMEBTN_UP | IDAC_IO_GAMEBTN_RIGHT; + case 9000: return IDAC_IO_GAMEBTN_RIGHT; + case 13500: return IDAC_IO_GAMEBTN_RIGHT | IDAC_IO_GAMEBTN_DOWN; + case 18000: return IDAC_IO_GAMEBTN_DOWN; + case 22500: return IDAC_IO_GAMEBTN_DOWN | IDAC_IO_GAMEBTN_RIGHT; + case 27000: return IDAC_IO_GAMEBTN_LEFT; + case 31500: return IDAC_IO_GAMEBTN_LEFT | IDAC_IO_GAMEBTN_UP; + default: return 0; + } +} + +static void idac_di_jvs_read_shifter(uint8_t *gear) +{ + assert(gear != NULL); + + if (idac_di_shifter != NULL) { + idac_di_jvs_read_shifter_pos(gear); + } else { + idac_di_jvs_read_shifter_virt(gear); + } +} + +static void idac_di_jvs_read_shifter_pos(uint8_t *out) +{ + union idac_di_state state; + uint8_t btn_no; + uint8_t gear; + uint8_t i; + HRESULT hr; + + assert(out != NULL); + assert(idac_di_shifter != NULL); + + hr = idac_di_dev_poll(idac_di_shifter, idac_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + gear = 0; + + for (i = 0 ; i < 6 ; i++) { + btn_no = idac_di_gear[i]; + + if (btn_no && state.st.rgbButtons[btn_no - 1]) { + gear = i + 1; + } + } + + *out = gear; +} + +static void idac_di_jvs_read_shifter_virt(uint8_t *gear) +{ + union idac_di_state state; + bool shift_dn; + bool shift_up; + HRESULT hr; + + assert(gear != NULL); + + hr = idac_di_dev_poll(idac_di_dev, idac_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + if (idac_di_shift_dn) { + shift_dn = state.st.rgbButtons[idac_di_shift_dn - 1]; + } else { + shift_dn = false; + } + + if (idac_di_shift_up) { + shift_up = state.st.rgbButtons[idac_di_shift_up - 1]; + } else { + shift_up = false; + } + + idac_shifter_update(shift_dn, shift_up); + + *gear = idac_shifter_current_gear(); +} + +static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out) +{ + union idac_di_state state; + const LONG *brake; + const LONG *accel; + HRESULT hr; + + assert(out != NULL); + + hr = idac_di_dev_poll(idac_di_dev, idac_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + brake = (LONG *) &state.bytes[idac_di_off_brake]; + accel = (LONG *) &state.bytes[idac_di_off_accel]; + + out->wheel = state.st.lX - 32768; + + if (idac_di_reverse_brake_axis) { + out->brake = *brake; + } else { + out->brake = 65535 - *brake; + } + + if (idac_di_reverse_accel_axis) { + out->accel = *accel; + } else { + out->accel = 65535 - *accel; + } +} diff --git a/idacio/di.h b/idacio/di.h new file mode 100644 index 0000000..fc03e21 --- /dev/null +++ b/idacio/di.h @@ -0,0 +1,9 @@ +#pragma once + +#include "idacio/backend.h" +#include "idacio/config.h" + +HRESULT idac_di_init( + const struct idac_di_config *cfg, + HINSTANCE inst, + const struct idac_io_backend **backend); diff --git a/idacio/dllmain.c b/idacio/dllmain.c new file mode 100644 index 0000000..fdf1004 --- /dev/null +++ b/idacio/dllmain.c @@ -0,0 +1,125 @@ +#include + +#include +#include +#include + +#include "idacio/backend.h" +#include "idacio/config.h" +#include "idacio/di.h" +#include "idacio/idacio.h" +#include "idacio/xi.h" + +#include "util/dprintf.h" +#include "util/str.h" + +static struct idac_io_config idac_io_cfg; +static const struct idac_io_backend *idac_io_backend; +static bool idac_io_coin; +static uint16_t idac_io_coins; + +uint16_t idac_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT idac_io_jvs_init(void) +{ + HINSTANCE inst; + HRESULT hr; + + assert(idac_io_backend == NULL); + + inst = GetModuleHandleW(NULL); + + if (inst == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("GetModuleHandleW failed: %lx\n", hr); + + return hr; + } + + idac_io_config_load(&idac_io_cfg, L".\\segatools.ini"); + + if (wstr_ieq(idac_io_cfg.mode, L"dinput")) { + hr = idac_di_init(&idac_io_cfg.di, inst, &idac_io_backend); + } else if (wstr_ieq(idac_io_cfg.mode, L"xinput")) { + hr = idac_xi_init(&idac_io_cfg.xi, &idac_io_backend); + } else { + hr = E_INVALIDARG; + dprintf("IDZ IO: Invalid IO mode \"%S\", use dinput or xinput\n", + idac_io_cfg.mode); + } + + return hr; +} + +void idac_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) +{ + uint8_t opbtn; + + assert(idac_io_backend != NULL); + assert(opbtn_out != NULL); + assert(gamebtn_out != NULL); + + opbtn = 0; + + if (GetAsyncKeyState(idac_io_cfg.vk_test) & 0x8000) { + opbtn |= IDAC_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(idac_io_cfg.vk_service) & 0x8000) { + opbtn |= IDAC_IO_OPBTN_SERVICE; + } + + *opbtn_out = opbtn; + + idac_io_backend->jvs_read_buttons(gamebtn_out); +} + +void idac_io_jvs_read_shifter(uint8_t *gear) +{ + assert(gear != NULL); + assert(idac_io_backend != NULL); + + idac_io_backend->jvs_read_shifter(gear); +} + +void idac_io_jvs_read_analogs(struct idac_io_analog_state *out) +{ + struct idac_io_analog_state tmp; + + assert(out != NULL); + assert(idac_io_backend != NULL); + + idac_io_backend->jvs_read_analogs(&tmp); + + /* Apply steering wheel restriction. Real cabs only report about 77% of + the IO-3's max ADC output value when the wheel is turned to either of + its maximum positions. To match this behavior we set the default value + for the wheel restriction config parameter to 97 (out of 128). This + scaling factor is applied using fixed-point arithmetic below. */ + + out->wheel = (tmp.wheel * idac_io_cfg.restrict_) / 128; + out->accel = tmp.accel; + out->brake = tmp.brake; +} + +void idac_io_jvs_read_coin_counter(uint16_t *out) +{ + assert(out != NULL); + + /* Coin counter is not backend-specific */ + + if (idac_io_cfg.vk_coin && + (GetAsyncKeyState(idac_io_cfg.vk_coin) & 0x8000)) { + if (!idac_io_coin) { + idac_io_coin = true; + idac_io_coins++; + } + } else { + idac_io_coin = false; + } + + *out = idac_io_coins; +} diff --git a/idacio/idacio.h b/idacio/idacio.h new file mode 100644 index 0000000..10fff60 --- /dev/null +++ b/idacio/idacio.h @@ -0,0 +1,106 @@ +#pragma once + +/* INITIAL D THE ARCADE CUSTOM IO API + + This API definition allows custom driver DLLs to be defined for the + emulation of Initial D The Arcade cabinets. To be honest, there is very + little reason to want to do this, since driving game controllers are a + mostly-standardized PC peripheral which can be adequately controlled by the + built-in DirectInput and XInput support in idzhook. However, previous + versions of Segatools broke this functionality out into a separate DLL just + like all of the other supported games, so in the interests of maintaining + backwards compatibility we provide the option to load custom IDZIO + implementations as well. */ + +#include + +#include + +enum { + IDAC_IO_OPBTN_TEST = 0x01, + IDAC_IO_OPBTN_SERVICE = 0x02, +}; + +enum { + IDAC_IO_GAMEBTN_UP = 0x01, + IDAC_IO_GAMEBTN_DOWN = 0x02, + IDAC_IO_GAMEBTN_LEFT = 0x04, + IDAC_IO_GAMEBTN_RIGHT = 0x08, + IDAC_IO_GAMEBTN_START = 0x10, + IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20, +}; + +struct idac_io_analog_state { + /* Current steering wheel position, where zero is the centered position. + + The game will accept any signed 16-bit position value, however a real + cabinet will report a value of approximately +/- 25230 when the wheel + is at full lock. Steering wheel positions of a magnitude greater than + this value are not possible on a real cabinet. */ + + int16_t wheel; + + /* Current position of the accelerator pedal, where 0 is released. */ + + uint16_t accel; + + /* Current position of the brake pedal, where 0 is released. */ + + uint16_t brake; +}; + +/* Get the version of the IDZ IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t idac_io_get_api_version(void); + +/* Initialize JVS-based input. This function will be called before any other + idac_io_jvs_*() function calls. Errors returned from this function will + manifest as a disconnected JVS bus. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0100 */ + +HRESULT idac_io_jvs_init(void); + +/* Poll the current state of the cabinet's JVS analog inputs. See structure + definition above for details. + + Minimum API version: 0x0100 */ + +void idac_io_jvs_read_analogs(struct idac_io_analog_state *out); + +/* Poll the current state of the cabinet's JVS input buttons and return them + through the opbtn and gamebtn out parameters. See enum definitions at the + top of this file for a list of bit masks to be used with these out + parameters. + + Minimum API version: 0x0100 */ + +void idac_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn); + +/* Poll the current position of the six-speed shifter and return it via the + gear out parameter. Valid values are 0 for neutral and 1-6 for gears 1-6. + + idzhook internally translates this gear position value into the correct + combination of Gear Left, Gear Right, Gear Up, Gear Down buttons that the + game will then interpret as the current position of the gear lever. + + Minimum API version: 0x0100 */ + +void idac_io_jvs_read_shifter(uint8_t *gear); + +/* 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. + + Minimum API version: 0x0100 */ + +void idac_io_jvs_read_coin_counter(uint16_t *total); diff --git a/idacio/idzio.def b/idacio/idzio.def new file mode 100644 index 0000000..b495482 --- /dev/null +++ b/idacio/idzio.def @@ -0,0 +1,8 @@ +LIBRARY idacio + +EXPORTS + idac_io_jvs_init + idac_io_jvs_read_analogs + idac_io_jvs_read_buttons + idac_io_jvs_read_coin_counter + idac_io_jvs_read_shifter diff --git a/idacio/meson.build b/idacio/meson.build new file mode 100644 index 0000000..7c7eddd --- /dev/null +++ b/idacio/meson.build @@ -0,0 +1,32 @@ +idacio_lib = static_library( + 'idacio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + dependencies : [ + dinput8_lib, + dxguid_lib, + xinput_lib, + ], + link_with : [ + util_lib, + ], + sources : [ + 'backend.h', + 'config.c', + 'config.h', + 'di.c', + 'di.h', + 'di-dev.c', + 'di-dev.h', + 'dllmain.c', + 'idacio.h', + 'shifter.c', + 'shifter.h', + 'wnd.c', + 'wnd.h', + 'xi.c', + 'xi.h', + ], +) diff --git a/idacio/shifter.c b/idacio/shifter.c new file mode 100644 index 0000000..02d8a54 --- /dev/null +++ b/idacio/shifter.c @@ -0,0 +1,32 @@ +#include +#include + +#include "idzio/shifter.h" + +static bool idac_shifter_shifting; +static uint8_t idac_shifter_gear; + +void idac_shifter_reset(void) +{ + idac_shifter_gear = 0; +} + +void idac_shifter_update(bool shift_dn, bool shift_up) +{ + if (!idac_shifter_shifting) { + if (shift_dn && idac_shifter_gear > 0) { + idac_shifter_gear--; + } + + if (shift_up && idac_shifter_gear < 6) { + idac_shifter_gear++; + } + } + + idac_shifter_shifting = shift_dn || shift_up; +} + +uint8_t idac_shifter_current_gear(void) +{ + return idac_shifter_gear; +} diff --git a/idacio/shifter.h b/idacio/shifter.h new file mode 100644 index 0000000..523a9a6 --- /dev/null +++ b/idacio/shifter.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +void idac_shifter_reset(void); +void idac_shifter_update(bool shift_dn, bool shift_up); +uint8_t idac_shifter_current_gear(void); diff --git a/idacio/wnd.c b/idacio/wnd.c new file mode 100644 index 0000000..7353273 --- /dev/null +++ b/idacio/wnd.c @@ -0,0 +1,86 @@ +#include + +#include +#include + +#include "util/dprintf.h" + +/* DirectInput requires a window for correct initialization (and also force + feedback), so this source file provides some utilities for creating a + generic message-only window. */ + +static LRESULT WINAPI idac_io_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wparam, + LPARAM lparam); + +HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out) +{ + HRESULT hr; + WNDCLASSEXW wcx; + ATOM atom; + HWND hwnd; + + assert(inst != NULL); /* We are not an EXE */ + assert(out != NULL); + + *out = NULL; + + memset(&wcx, 0, sizeof(wcx)); + wcx.cbSize = sizeof(wcx); + wcx.lpfnWndProc = idac_io_wnd_proc; + wcx.hInstance = inst; + wcx.lpszClassName = L"IDZIO"; + + atom = RegisterClassExW(&wcx); + + if (atom == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("IDZIO: RegisterClassExW failed: %08x\n", (int) hr); + + goto fail; + } + + hwnd = CreateWindowExW( + 0, + (wchar_t *) (intptr_t) atom, + L"", + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_MESSAGE, + NULL, + inst, + NULL); + + if (hwnd == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("IDZIO: CreateWindowExW failed: %08x\n", (int) hr); + + goto fail; + } + + *out = hwnd; + + return S_OK; + +fail: + UnregisterClassW((wchar_t *) (intptr_t) atom, inst); + + return hr; +} + +static LRESULT WINAPI idac_io_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wparam, + LPARAM lparam) +{ + switch (msg) { + default: + return DefWindowProcW(hwnd, msg, wparam, lparam); + } +} diff --git a/idacio/wnd.h b/idacio/wnd.h new file mode 100644 index 0000000..21a5a8b --- /dev/null +++ b/idacio/wnd.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out); diff --git a/idacio/xi.c b/idacio/xi.c new file mode 100644 index 0000000..63e4242 --- /dev/null +++ b/idacio/xi.c @@ -0,0 +1,165 @@ +#include +#include + +#include +#include +#include + +#include "idacio/backend.h" +#include "idacio/config.h" +#include "idacio/idacio.h" +#include "idacio/shifter.h" +#include "idacio/xi.h" + +#include "util/dprintf.h" + +static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out); +static void idac_xi_jvs_read_shifter(uint8_t *gear); +static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out); + +static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg); + +static const struct idac_io_backend idac_xi_backend = { + .jvs_read_buttons = idac_xi_jvs_read_buttons, + .jvs_read_shifter = idac_xi_jvs_read_shifter, + .jvs_read_analogs = idac_xi_jvs_read_analogs, +}; + +static bool idac_xi_single_stick_steering; + +HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) +{ + HRESULT hr; + assert(cfg != NULL); + assert(backend != NULL); + + hr = idac_xi_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + dprintf("XInput: Using XInput controller\n"); + *backend = &idac_xi_backend; + + return S_OK; +} + +static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) +{ + dprintf("XInput: --- Begin configuration ---\n"); + dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); + dprintf("XInput: --- End configuration ---\n"); + + idac_xi_single_stick_steering = cfg->single_stick_steering; + + return S_OK; +} + +static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out) +{ + uint8_t gamebtn; + XINPUT_STATE xi; + WORD xb; + + assert(gamebtn_out != NULL); + + gamebtn = 0; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xb & XINPUT_GAMEPAD_DPAD_UP) { + gamebtn |= IDAC_IO_GAMEBTN_UP; + } + + if (xb & XINPUT_GAMEPAD_DPAD_DOWN) { + gamebtn |= IDAC_IO_GAMEBTN_DOWN; + } + + if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + gamebtn |= IDAC_IO_GAMEBTN_LEFT; + } + + if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + gamebtn |= IDAC_IO_GAMEBTN_RIGHT; + } + + if (xb & (XINPUT_GAMEPAD_START | XINPUT_GAMEPAD_A)) { + gamebtn |= IDAC_IO_GAMEBTN_START; + } + + if (xb & (XINPUT_GAMEPAD_BACK | XINPUT_GAMEPAD_B)) { + gamebtn |= IDAC_IO_GAMEBTN_VIEW_CHANGE; + } + + *gamebtn_out = gamebtn; +} + +static void idac_xi_jvs_read_shifter(uint8_t *gear) +{ + bool shift_dn; + bool shift_up; + XINPUT_STATE xi; + WORD xb; + + assert(gear != NULL); + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xb & XINPUT_GAMEPAD_START) { + /* Reset to Neutral when start is pressed */ + idac_shifter_reset(); + } + + shift_dn = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER); + shift_up = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER); + + idac_shifter_update(shift_dn, shift_up); + + *gear = idac_shifter_current_gear(); +} + +static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out) +{ + XINPUT_STATE xi; + int left; + int right; + + assert(out != NULL); + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + left = xi.Gamepad.sThumbLX; + + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + right = xi.Gamepad.sThumbRX; + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } + + if(idac_xi_single_stick_steering) { + out->wheel = left; + } else { + out->wheel = (left + right) / 2; + } + + out->accel = xi.Gamepad.bRightTrigger << 8; + out->brake = xi.Gamepad.bLeftTrigger << 8; +} diff --git a/idacio/xi.h b/idacio/xi.h new file mode 100644 index 0000000..16cdea5 --- /dev/null +++ b/idacio/xi.h @@ -0,0 +1,10 @@ +#pragma once + +/* Can't call this xinput.h or it will conflict with */ + +#include + +#include "idacio/backend.h" +#include "idacio/config.h" + +HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend); diff --git a/meson.build b/meson.build index b5a3d5f..abbc4a6 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,7 @@ subdir('chuniio') subdir('divaio') subdir('carolio') subdir('idzio') +subdir('idacio') subdir('mu3io') subdir('mercuryio') subdir('cxbio') @@ -66,6 +67,7 @@ subdir('chunihook') subdir('divahook') subdir('carolhook') subdir('idzhook') +subdir('idachook') subdir('minihook') subdir('mu3hook') subdir('mercuryhook') diff --git a/segatools.md b/segatools.md new file mode 100644 index 0000000..4dcaf43 --- /dev/null +++ b/segatools.md @@ -0,0 +1,456 @@ +# Segatools common configuration settings + +This file describes configuration settings for Segatools that are common to +all games. + +Keyboard binding settings use +[Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). + +## `[aimeio]` + +Controls the card reader driver. + +### `path` + +Specify a path for a third-party card reader driver DLL. Default is empty +(use built-in emulation based on text files and keyboard input). + +In previous versions of Segatools this was accomplished by replacing the +AIMEIO.DLL file that came with Segatools. Segatools no longer ships with a +separate AIMEIO.DLL file (its functionality is now built into the various hook +DLLs). + +## `[aime]` + +Controls emulation of the Aime card reader assembly. + +### `enable` + +Default: `1` + +Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +reader (COM port number varies by game). + +### `aimePath` + +Default: `DEVICE\aime.txt` + +Path to a text file containing a classic Aime IC card ID. **This does not +currently work**. + +### `felicaPath` + +Default: `DEVICE\felica.txt` + +Path to a text file containing a FeliCa e-cash card IDm serial number. + +### `felicaGen` + +Default: `1` + +Whether to generate a random FeliCa ID if the file at `felicaPath` does not +exist. + +### `scan` + +Default: `0x0D` (`VK_RETURN`) + +Virtual-key code. If this button is **held** then the emulated IC card reader +emulates an IC card in its proximity. A variety of different IC cards can be +emulated; the exact choice of card that is emulated depends on the presence or +absence of the configured card ID files. + +## `[amvideo]` + +Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is +normally present on the SEGA operating system image which is responsible for +changing screen resolution and orientation. + +### `enable` + +Default: `1` + +Enable stub `amvideo.dll`. Disable to use a real `amvideo.dll` build. Note that +you must have the correct registry settings installed and you must use the +version of `amvideo.dll` that matches your GPU vendor (since these DLLs make +use of vendor-specific APIs). + +## `[clock]` + +Controls hooks for Windows time-of-day APIs. + +### `timezone` + +Default: `1` + +Make the system time zone appear to be JST. SEGA games malfunction in strange +ways if the system time zone is not JST. There should not be any reason to +disable this hook other than possible implementation bugs, but the option is +provided if you need it. + +### `timewarp` + +Default: `0` + +Experimental time-of-day warping hook that skips over the hardcoded server +maintenance period. Causes an incorrect in-game time-of-day to be reported. +Better solutions for this problem exist and this feature will probably be +removed soon. + +### `writeable` + +Default: `0` + +Allow game to adjust system clock and time zone settings. This should normally +be left at `0`, but the option is provided if you need it. + +## `[dns]` + +Controls redirection of network server hostname lookups + +### `default` + +Default: `localhost` + +Controls hostname of all of the common network services servers, unless +overriden by a specific setting below. Most users will only need to change this +setting. Also, loopback addresses are specifically checked for and rejected by +the games themselves; this needs to be a LAN or WAN IP (or a hostname that +resolves to one). + +### `router` + +Default: Empty string (i.e. use value from `default` setting) + +Overrides the target of the `tenporouter.loc` and `bbrouter.loc` hostname +lookups. + +### `startup` + +Default: Empty string (i.e. use value from `default` setting) + +Overrides the target of the `naominet.jp` host lookup. + +### `billing` + +Default: Empty string (i.e. use value from `default` setting) + +Overrides the target of the `ib.naominet.jp` host lookup. + +### `aimedb` + +Default: Empty string (i.e. use value from `default` setting) + +Overrides the target of the `aime.naominet.jp` host lookup. + +## `[ds]` + +Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX +PCIe board. This is a small (32 byte) EEPROM that contains serial number and +region code information. It is not normally written to outside of inital +factory provisioning of a Sega Nu. + +### `enable` + +Default: `1` + +Enable DS EEPROM emulation. Disable to use the DS EEPROM chip on a real AMEX. + +### `region` + +Default: `1` + +AMEX Board region code. This appears to be a bit mask? + +- `1`: Japan +- `2`: USA? (Dead code, not used) +- `4`: Export +- `8`: China + +### `serialNo` + +Default `AAVE-01A99999999` + +"MAIN ID" serial number. First three characters are hardware series: + +- `AAV`: Nu-series +- `AAW`: NuSX-series +- `ACA`: ALLS-series + +## `[eeprom]` + +Controls emulation of the bulk EEPROM on the AMEX PCIe board. This chip stores +status and configuration information. + +### `enable` + +Default: `1` + +Enable bulk EEPROM emulation. Disable to use the bulk EEPROM chip on a real +AMEX. + +### `path` + +Default: `DEVICE\eeprom.bin` + +Path to the storage file for EEPROM emulation. This file is automatically +created and initialized with a suitable number of zero bytes if it does not +already exist. + +## `[gpio]` + +Configure emulation of the AMEX PCIe GPIO (General Purpose Input Output) +controller. + +### `enable` + +Default: `1` + +Enable GPIO emulation. Disable to use the GPIO controller on a real AMEX. + +### `sw1` + +Default `0x70` (`VK_F1`) + +Keyboard binding for Nu chassis SW1 button (alternative Test) + +### `sw2` + +Default `0x71` (`VK_F2`) + +Keyboard binding for Nu chassis SW2 button (alternative Service) + +### `dipsw1` .. `dipsw8` + +Defaults: `1`, `0`, `0`, `0`, `0`, `0`, `0`, `0` + +Nu chassis DIP switch settings: + +- Switch 1: Game-specific, but usually controls the "distribution server" + setting. Exactly one arcade machine on a cabinet router must be set to the + Server setting. + - `0`: Client + - `1`: Server +- Switch 2,3: Game-specific. + - Used by Mario&Sonic to configure cabinet ID, possibly other games. +- Switch 4: Screen orientation. Only used by the Nu system startup program. + - `0`: YOKO/Horizontal + - `1`: TATE/Vertical +- Switch 5,6,7: Screen resolution. Only used by the Nu system startup program. + - `000`: No change + - `100`: 640x480 + - `010`: 1024x600 + - `110`: 1024x768 + - `001`: 1280x720 + - `101`: 1280x1024 + - `110`: 1360x768 + - `111`: 1920x1080 +- Switch 8: Game-specific. Not used in any shipping game. + +## `[hwmon]` + +Configure stub implementation of the platform hardware monitor driver. The +real implementation of this driver monitors CPU temperatures by reading from +Intel Model Specific Registers, which is an action that is only permitted from +kernel mode. + +### `enable` + +Default `1` + +Enable hwmon emulation. Disable to use the real hwmon driver. + +## `[jvs]` + +Configure emulation of the AMEX PCIe JVS *controller* (not IO board!) + +### `enable` + +Default `1` + +Enable JVS port emulation. Disable to use the JVS port on a real AMEX. + +## `[keychip]` + +Configure keychip emulation. + +### `enable` + +Enable keychip emulation. Disable to use a real keychip. + +### `id` + +Default: `A69E-01A88888888` + +Keychip serial number. Keychip serials observed in the wild follow this +pattern: `A6xE-01Ayyyyyyyy`. + +### `gameId` + +Default: (Varies depending on game) + +Override the game's four-character model code. Changing this from the game's +expected value will probably just cause a system error. + +### `platformId` + +Default: (Varies depending on game) + +Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This +is actually supposed to be a separate three-character `platformId` and +integer `modelType` setting, but they are combined here for convenience. Valid +values include: + +- `AAV0`: Nu 1 (Project DIVA) +- `AAV1`: Nu 1.1 (Chunithm) +- `AAV2`: Nu 2 (Initial D Zero) +- `AAW0`: NuSX 1 +- `AAW1`: NuSX 1.1 +- `ACA0`: ALLS UX +- `ACA1`: ALLS HX +- `ACA2`: ALLS UX (without dedicated GPU) +- `ACA4`: ALLS MX + +### `region` + +Default: `1` + +Override the keychip's region code. Most games seem to pay attention to the +DS EEPROM region code and not the keychip region code, and this seems to be +a bit mask that controls which Nu PCB region codes this keychip is authorized +for. So it probably only affects the system software and not the game software. +Bit values are: + +- 1: JPN: Japan +- 2: USA (unused) +- 3: EXP: Export (for Asian markets) +- 4: CHS: China (Simplified Chinese?) + +### `systemFlag` + +Default: `0x64` + +An 8-bit bitfield of unclear meaning. The least significant bit indicates a +developer dongle, I think? Changing this doesn't seem to have any effect on +anything other than Project DIVA. + +Other values observed in the wild: + +- `0x04`: SDCH, SDCA +- `0x20`: SDCA + +### `subnet` + +Default `192.168.100.0` + +The LAN IP range that the game will expect. The prefix length is hardcoded into +the game program: for some games this is `/24`, for others it is `/20`. + +## `[netenv]` + +Configure network environment virtualization. This module helps bypass various +restrictions placed upon the game's LAN environment. + +### `enable` + +Default `1` + +Enable network environment virtualization. You may need to disable this if +you want to do any head-to-head play on your LAN. + +Note: The virtualized LAN IP range is taken from the emulated keychip's +`subnet` setting. + +### `addrSuffix` + +Default: `11` + +The final octet of the local host's IP address on the virtualized subnet (so, +if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +local host's virtualized LAN IP is `192.168.32.11`). + +### `routerSuffix` + +Default: `1` + +The final octet of the default gateway's IP address on the virtualized subnet. + +### `macAddr` + +Default: `01:02:03:04:05:06` + +The MAC address of the virtualized Ethernet adapter. The exact value shouldn't +ever matter. + +## `[pcbid]` + +Configure Windows host name virtualization. The ALLS-series platform no longer +has an AMEX board, so the MAIN ID serial number is stored in the Windows +hostname. + +### `enable` + +Default: `1` + +Enable Windows host name virtualization. This is only needed for ALLS-platform +games (since the ALLS lacks an AMEX and therefore has no DS EEPROM, so it needs +another way to store the PCB serial), but it does no harm on games that run on +earlier hardware. + +### `serialNo` + +Default: `ACAE01A99999999` + +Set the Windows host name. This should be an ALLS MAIN ID, without the +hyphen (which is not a valid character in a Windows host name). + +## `[sram]` + +Configure emulation of the AMEX PCIe battery-backed SRAM. This stores +bookkeeping state and settings. This file is automatically created and +initialized with a suitable number of zero bytes if it does not already exist. + +### `enable` + +Default `1` + +Enable SRAM emulation. Disable to use the SRAM on a real AMEX. + +### `path` + +Default `DEVICE\sram.bin` + +Path to the storage file for SRAM emulation. + +## `[vfs]` + +Configure Windows path redirection hooks. + +### `enable` + +Default: `1` + +Enable path redirection. + +### `amfs` + +Default: Empty string (causes a startup error) + +Configure the location of the SEGA AMFS volume. Stored on the `E` partition on +real hardware. + +### `appdata` + +Default: Empty string (causes a startup error) + +Configure the location of the SEGA "APPDATA" volume (nothing to do with the +Windows user's `%APPDATA%` directory). Stored on the `Y` partition on real +hardware. + +### `option` + +Default: Empty string + +Configure the location of the "Option" data mount point. This mount point is +optional (hence the name, probably) and contains directories which contain +minor over-the-air content updates. From 6fc2482c19f7c921fb0b550f4719c0b81053f66b Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 28 Apr 2023 04:25:47 -0400 Subject: [PATCH 007/204] carol: add control board emulation, document touch board more --- carolhook/controlbd.c | 341 ++++++++++++++++++++++++++++++++++++++++-- carolhook/controlbd.h | 137 +++++++++++++++++ carolhook/dllmain.c | 25 +++- carolhook/ledbd.c | 99 +++--------- carolhook/meson.build | 2 - carolhook/serial.c | 39 ----- carolhook/serial.h | 5 - carolhook/touch.c | 82 ++++++++-- carolhook/touch.h | 8 +- 9 files changed, 587 insertions(+), 151 deletions(-) delete mode 100644 carolhook/serial.c delete mode 100644 carolhook/serial.h diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index c39eb83..a59fe65 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -8,6 +8,8 @@ #include "hook/iobuf.h" #include "hook/iohook.h" +#include "hook/table.h" + #include "carolhook/carol-dll.h" #include "carolhook/controlbd.h" @@ -18,16 +20,57 @@ static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp_locked(struct irp *irp); +static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src); +static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len); +static uint8_t calc_checksum(void *data, size_t len); -static HRESULT controlbd_req_noop(uint8_t cmd); -static HRESULT controlbd_req_unk7c(uint8_t cmd); -static HRESULT controlbd_req_unkF0(uint8_t cmd); +static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req); +static HRESULT controlbd_req_ack_any(uint8_t cmd); +static HRESULT controlbd_req_reset(void); +static HRESULT controlbd_req_get_board_info(void); +static HRESULT controlbd_req_firmware_checksum(void); +static HRESULT controlbd_req_polling(const struct controlbd_req_any *req); + +const uint8_t CONTROLBD_SYNC_BYTE = 0xE0; static CRITICAL_SECTION controlbd_lock; static struct uart controlbd_uart; static uint8_t controlbd_written_bytes[520]; static uint8_t controlbd_readable_bytes[520]; +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); +static BOOL (WINAPI *next_CreateProcessA)( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); + +static const struct hook_symbol win32_hooks[] = { + { + .name = "CreateProcessA", + .patch = my_CreateProcessA, + .link = (void **) &next_CreateProcessA + } +}; + HRESULT controlbd_hook_init(const struct controlbd_config *cfg) { if (!cfg->enable) { @@ -42,12 +85,17 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) controlbd_uart.readable.bytes = controlbd_readable_bytes; controlbd_uart.readable.nbytes = sizeof(controlbd_readable_bytes); + hook_table_apply( + NULL, + "kernel32.dll", + win32_hooks, + _countof(win32_hooks)); + dprintf("Control Board: Init\n"); return iohook_push_handler(controlbd_handle_irp); } - static HRESULT controlbd_handle_irp(struct irp *irp) { HRESULT hr; @@ -65,9 +113,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp) return hr; } +static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobuf *src) +{ + uint8_t data_len = 0; + uint8_t checksum_pos = src->pos - 1; + uint8_t calculated_checksum = 0; + uint8_t checksum = 0; + + if (src->pos < 6) { + dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos); + return SEC_E_BUFFER_TOO_SMALL; + } + + req->hdr.sync = src->bytes[0]; + req->hdr.dest = src->bytes[1]; + req->hdr.src = src->bytes[2]; + req->hdr.len = src->bytes[3]; + req->hdr.cmd = src->bytes[4]; + data_len = req->hdr.len; + src->pos -= 5; + + for (int i = 0; i < data_len; i++) { + if (src->pos == 0) { + break; + } + req->bytes[i] = src->bytes[i + 5]; + src->pos --; + } + + checksum = src->bytes[checksum_pos]; + calculated_checksum = calc_checksum(req, checksum_pos); + + if (checksum != calculated_checksum) { + dprintf("Control Board: Decode Error, checksum failure (expected 0x%02X, got 0x%02X)\n", calculated_checksum, checksum); + return HRESULT_FROM_WIN32(ERROR_CRC); + } + + return S_OK; +} + static HRESULT controlbd_handle_irp_locked(struct irp *irp) { HRESULT hr; + struct controlbd_req_any req; assert(carol_dll.controlbd_init != NULL); @@ -89,24 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 - dprintf("Control Board: TX Buffer:\n"); - dump_iobuf(&controlbd_uart.written); + if (controlbd_uart.written.bytes[0] == 0xE0) { +#if 0 + dprintf("Control Board: TX Buffer:\n"); + dump_iobuf(&controlbd_uart.written); #endif + hr = controlbd_frame_decode(&req, &controlbd_uart.written); + if (FAILED(hr)) { + dprintf("Control Board: Deframe error: %x\n", (int) hr); + return hr; + } - if (FAILED(hr)) { - dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); - + hr = controlbd_req_dispatch(&req); + if (FAILED(hr)) { + dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); + return hr; + } +#if 0 + dprintf("Control Board: RX Buffer:\n"); + dump_iobuf(&controlbd_uart.readable); +#endif + controlbd_uart.written.pos = 0; return hr; } - if (FAILED(hr)) { - dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); + // The board has a LPC111x bootloader that gets ran over every boot + // this is to account for that. + char cmd[255]; + strcpy_s(cmd, 255, (char *)controlbd_uart.written.bytes); + cmd[controlbd_uart.written.pos] = '\0'; - return hr; + if (!strcmp(cmd, "?")) { + dprintf("Control Board: Bootloader Hello\n"); + } + else if (!strcmp(cmd, "Synchronized\r\n")) { + iobuf_write(&controlbd_uart.readable, "Synchronized\r\nNG\r\n", 19); + // Set this to OK instead of NG to do an update + } + else if (!strcmp(cmd, "12000\r\n")) { + iobuf_write(&controlbd_uart.readable, "12000\r\nOK\r\n", 12); + } + else { + // Everything other then the two commands above just want 0\r\n + // appended to the request as the response. Given that it only checks sometimes, + // it's safe to just run over the readable buffer every response. + controlbd_uart.readable.pos = 0; + cmd[controlbd_uart.written.pos] = '0'; + cmd[controlbd_uart.written.pos + 1] = '\r'; + cmd[controlbd_uart.written.pos + 2] = '\n'; + cmd[controlbd_uart.written.pos + 3] = '\0'; + // dprintf("Control Board: Return %s\n", cmd); + iobuf_write(&controlbd_uart.readable, cmd, controlbd_uart.written.pos + 3); } controlbd_uart.written.pos = 0; return hr; } +} + +static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req) +{ + switch (req->hdr.cmd) { + case CONTROLBD_CMD_RESET: + return controlbd_req_reset(); + + case CONTROLBD_CMD_BDINFO: + return controlbd_req_get_board_info(); + + case CONTROLBD_CMD_FIRM_SUM: + return controlbd_req_firmware_checksum(); + + case CONTROLBD_CMD_TIMEOUT: + dprintf("Control Board: Acknowledge Timeout\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_PORT_SETTING: + dprintf("Control Board: Acknowledge Port Setting\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_INITIALIZE: + dprintf("Control Board: Acknowledge Initialize\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_POLLING: + return controlbd_req_polling(req); + + default: + dprintf("Unhandled command 0x%02x\n", req->hdr.cmd); + return controlbd_req_ack_any(req->hdr.cmd); + } +} + +static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len) +{ + resp->sync = CONTROLBD_SYNC_BYTE; + resp->dest = 0x01; + resp->src = 0x02; + resp->len = len; + resp->report = 0x01; + resp->cmd = cmd; + return S_OK; +} + +static uint8_t calc_checksum(void *data, size_t len) +{ + uint8_t *stuff; + stuff = data; + uint8_t checksum = 0; + uint16_t tmp = 0; + + for (int i = 1; i < len; i++) { + tmp = checksum + stuff[i]; + checksum = tmp & 0xFF; + } + + return checksum; +} + +static HRESULT controlbd_req_reset(void) +{ + struct controlbd_resp_reset resp; + + dprintf("Control Board: Reset\n"); + + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_RESET, 2); + resp.checksum = 0; + + // No data, just ack + resp.checksum = calc_checksum(&resp, sizeof(resp)); + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); + +} + +static HRESULT controlbd_req_get_board_info(void) +{ + struct controlbd_resp_bdinfo resp; + memset(&resp, 0, sizeof(resp)); + dprintf("Control Board: Get Board Info\n"); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_BDINFO, 21); + + resp.rev = 0x90; + resp.bfr_size = 0x0001; + resp.ack = 1; + + strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 "); + strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 "); + resp.chip_no[5] = 0xFF; + resp.bd_no[8] = 0x0A; + + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_firmware_checksum(void) +{ + struct controlbd_resp_fw_checksum resp; + memset(&resp, 0, sizeof(resp)); + dprintf("Control Board: Get Firmware Checksum\n"); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_FIRM_SUM, 5); + + resp.ack = 1; + resp.fw_checksum = 0x1b36; // This could change with an update... oh well + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_polling(const struct controlbd_req_any *req) +{ + struct controlbd_req_polling req_struct; + memset(&req_struct, 0, sizeof(req_struct)); + memcpy_s(&req_struct, sizeof(req_struct), req, sizeof(req_struct)); + struct controlbd_resp_polling resp; + memset(&resp, 0, sizeof(resp)); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_POLLING, 16); + // TODO: Figure out output (pen vibration, etc) + + resp.ack = 1; + resp.unk7 = 3; + resp.unk8 = 1; + resp.unk9 = 1; + + resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge + resp.coord_x = 0x0; + resp.coord_y = 0x0; + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_ack_any(uint8_t cmd) +{ + struct controlbd_resp_any_ack resp; + memset(&resp, 0, sizeof(resp)); + controlbd_set_header(&resp.hdr, cmd, 3); + + resp.ack = 1; + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +) +{ + dprintf("Control Board: my_CreateProcessA Hit! %s\n", lpCommandLine); + if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) { + return next_CreateProcessA( + lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); + } + + dprintf("Control Board: Hooking child process\n"); + char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll "; + strcat_s(new_cmd, MAX_PATH, lpCommandLine); + + return next_CreateProcessA( + lpApplicationName, + new_cmd, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); } \ No newline at end of file diff --git a/carolhook/controlbd.h b/carolhook/controlbd.h index 15f04ac..5f160d3 100644 --- a/carolhook/controlbd.h +++ b/carolhook/controlbd.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include #include @@ -8,4 +10,139 @@ struct controlbd_config { bool enable; }; +#pragma pack(push, 1) +struct controlbd_req_hdr { + uint8_t sync; + uint8_t dest; // unsure + uint8_t src; // unsure + uint8_t len; // length of the rest of the request minus checksum + uint8_t cmd; +}; + +struct controlbd_req_any { + struct controlbd_req_hdr hdr; + uint8_t bytes[255]; +}; + +struct controlbd_req_reset { + struct controlbd_req_hdr hdr; + uint8_t payload; + uint8_t checksum; +}; + +struct controlbd_req_bdinfo { + struct controlbd_req_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_req_fw_checksum { + struct controlbd_req_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_req_timeout { + struct controlbd_req_hdr hdr; + uint8_t unknown; + uint8_t checksum; +}; + +struct controlbd_req_polling { + struct controlbd_req_hdr hdr; + uint8_t unknown[20]; + uint8_t checksum; +}; + +struct controlbd_resp_hdr { + uint8_t sync; + uint8_t dest; // unsure + uint8_t src; // unsure + uint8_t len; // length of the rest of the request minus checksum + uint8_t report; // 0x01 for success, anything else for failure + uint8_t cmd; +}; + +struct controlbd_resp_any { + struct controlbd_resp_hdr hdr; + uint8_t bytes[255]; +}; + +struct controlbd_resp_any_ack { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint8_t checksum; +}; + +struct controlbd_resp_reset { + struct controlbd_resp_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_resp_bdinfo { + struct controlbd_resp_hdr hdr; + uint8_t ack; + char bd_no[9]; + char chip_no[6]; + uint8_t rev; + uint16_t bfr_size; + uint8_t checksum; +}; + +struct controlbd_resp_fw_checksum { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint16_t fw_checksum; + uint8_t checksum; +}; + +struct controlbd_resp_polling { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint8_t unk7; + uint8_t unk8; + uint8_t unk9; + uint8_t btns_pressed; + uint8_t blob[7]; + int8_t coord_x; + int8_t coord_y; + uint8_t checksum; +}; + +enum { + PEN_BTN_PRESSED_BIT = 1, + DODGE_BTN_PRESSED_BIT = 2 +}; + +enum { + CONTROLBD_CMD_RESET = 0x10, + CONTROLBD_CMD_TIMEOUT = 0x11, + CONTROLBD_CMD_RETRY = 0x12, + + CONTROLBD_CMD_GETIN = 0x20, + CONTROLBD_CMD_GETADI = 0x21, + + CONTROLBD_CMD_SETOUTPUT = 0x30, + + CONTROLBD_CMD_INITIALIZE = 0x80, + CONTROLBD_CMD_POLLING = 0x81, + CONTROLBD_CMD_CUSTOM_PATTERN = 0x82, + CONTROLBD_CMD_DEBUG_CAROL = 0x83, + CONTROLBD_CMD_POLLING_GENERAL = 0x84, + + CONTROLBD_CMD_CMD_STATUS = 0x90, + CONTROLBD_CMD_PORT_SETTING = 0x91, + CONTROLBD_CMD_PWM_DUTY = 0x92, + CONTROLBD_CMD_LED_SET = 0x93, + CONTROLBD_CMD_LED_REFRESH = 0x94, + + CONTROLBD_CMD_DEBUG_UART = 0xB0, + CONTROLBD_CMD_DEBUG_I2C = 0xB1, + + CONTROLBD_CMD_DEBUG_STATUS = 0xC0, + + CONTROLBD_CMD_BDINFO = 0xF0, + CONTROLBD_CMD_FIRM_SUM = 0xF2, + CONTROLBD_CMD_PROTOCOL = 0xF3, + CONTROLBD_CMD_UPDATE = 0xFE, +}; +#pragma pack(pop) HRESULT controlbd_hook_init(const struct controlbd_config *cfg); \ No newline at end of file diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 608ca49..55608c7 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -13,7 +13,6 @@ #include "carolhook/jvs.h" #include "carolhook/touch.h" #include "carolhook/ledbd.h" -#include "carolhook/serial.h" #include "carolhook/controlbd.h" #include "hook/process.h" @@ -34,14 +33,36 @@ COM Layout 01: Touchscreen 10: Aime reader 11: LED board -12: LED Board +12: Control Board */ static DWORD CALLBACK carol_pre_startup(void) { HRESULT hr; + HMODULE d3dc; + HMODULE dbghelp; dprintf("--- Begin carol_pre_startup ---\n"); + + /* Pin the D3D shader compiler. This makes startup much faster. */ + + d3dc = LoadLibraryW(L"D3DCompiler_43.dll"); + + if (d3dc != NULL) { + dprintf("Pinned shader compiler, hMod=%p\n", d3dc); + } else { + dprintf("Failed to load shader compiler!\n"); + } + + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } else { + dprintf("Failed to load debug helper library!\n"); + } /* Config load */ diff --git a/carolhook/ledbd.c b/carolhook/ledbd.c index 18b9aab..1513359 100644 --- a/carolhook/ledbd.c +++ b/carolhook/ledbd.c @@ -16,10 +16,12 @@ #include "util/dprintf.h" #include "util/dump.h" +#include "board/slider-frame.h" +#include "board/slider-cmd.h" + static HRESULT ledbd_handle_irp(struct irp *irp); static HRESULT ledbd_handle_irp_locked(struct irp *irp); -static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf); -static HRESULT ledbd_frame_dispatch(struct ledbd_req *dest); +static HRESULT ledbd_frame_dispatch(const union slider_req_any *dest); static HRESULT ledbd_req_noop(uint8_t cmd); static HRESULT ledbd_req_unk7c(uint8_t cmd); @@ -68,7 +70,8 @@ static HRESULT ledbd_handle_irp(struct irp *irp) static HRESULT ledbd_handle_irp_locked(struct irp *irp) { - struct ledbd_req req; + union slider_req_any req; + struct iobuf req_iobuf; HRESULT hr; assert(carol_dll.ledbd_init != NULL); @@ -95,7 +98,11 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) dprintf("LED Board: TX Buffer:\n"); dump_iobuf(&ledbd_uart.written); #endif - hr = ledbd_frame_decode(&req, &ledbd_uart.written); + req_iobuf.bytes = req.bytes; + req_iobuf.nbytes = sizeof(req.bytes); + req_iobuf.pos = 0; + + hr = slider_frame_decode(&req_iobuf, &ledbd_uart.written); if (FAILED(hr)) { dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr); @@ -114,26 +121,26 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) } } -static HRESULT ledbd_frame_dispatch(struct ledbd_req *req) +static HRESULT ledbd_frame_dispatch(const union slider_req_any *req) { - switch (req->cmd) { + switch (req->hdr.cmd) { case LEDBD_CMD_UNK_10: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); case LEDBD_CMD_UNK_7C: - return ledbd_req_unk7c(req->cmd); + return ledbd_req_unk7c(req->hdr.cmd); case LEDBD_CMD_UNK_F0: - return ledbd_req_unkF0(req->cmd); + return ledbd_req_unkF0(req->hdr.cmd); case LEDBD_CMD_UNK_30: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); default: - dprintf("Unhandled command 0x%02X\n", req->cmd); - return ledbd_req_noop(req->cmd); + //dprintf("Unhandled command 0x%02X\n", req->cmd); + return ledbd_req_noop(req->hdr.cmd); } } static HRESULT ledbd_req_noop(uint8_t cmd) { - dprintf("LED Board: Noop cmd 0x%02X\n", cmd); + //dprintf("LED Board: Noop cmd 0x%02X\n", cmd); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 }; resp[5] = cmd; resp[7] = 0x17 + cmd; @@ -144,7 +151,7 @@ static HRESULT ledbd_req_noop(uint8_t cmd) static HRESULT ledbd_req_unk7c(uint8_t cmd) { - dprintf("LED Board: Cmd 0x7C\n"); + //dprintf("LED Board: Cmd 0x7C\n"); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B }; iobuf_write(&ledbd_uart.readable, resp, 9); @@ -153,71 +160,9 @@ static HRESULT ledbd_req_unk7c(uint8_t cmd) static HRESULT ledbd_req_unkF0(uint8_t cmd) { - dprintf("LED Board: Cmd 0xF0\n"); + //dprintf("LED Board: Cmd 0xF0\n"); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E }; iobuf_write(&ledbd_uart.readable, resp, 16); - return S_OK; -} - -/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ -static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf) -{ - int initial_pos = iobuf->pos; - int processed_pos = 0; - uint8_t check = 0; - bool escape = false; - - dest->sync = iobuf->bytes[0]; - - dest->dest = iobuf->bytes[1]; - check += dest->dest; - - dest->src = iobuf->bytes[2]; - check += dest->src; - - dest->data_len = iobuf->bytes[3]; - check += dest->data_len; - - dest->cmd = iobuf->bytes[4]; - check += dest->cmd; - - for (int i = 0; i < dest->data_len - 1; i++) { - if (iobuf->bytes[i+5] == 0xD0) { - escape = true; - check += 0xD0; - continue; - } - - dest->data[i] = iobuf->bytes[i+5]; - - if (escape) { - dest->data[i]++; - escape = false; - } - - check += iobuf->bytes[i+5]; - } - - dest->checksum = iobuf->bytes[iobuf->pos - 1]; - if (escape) { - dest->checksum++; - escape = false; - } - - iobuf->pos = 0; - - if (dest->sync != 0xe0) { - dprintf("LED Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); - dump_iobuf(iobuf); - return E_FAIL; - } - - if (dest->checksum != (check & 0xFF)) { - dprintf("LED Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); - dump_iobuf(iobuf); - return E_FAIL; - } - return S_OK; } \ No newline at end of file diff --git a/carolhook/meson.build b/carolhook/meson.build index d62c897..cba763c 100644 --- a/carolhook/meson.build +++ b/carolhook/meson.build @@ -34,7 +34,5 @@ shared_library( 'controlbd.h', 'ledbd.c', 'ledbd.h', - 'serial.c', - 'serial.h', ], ) diff --git a/carolhook/serial.c b/carolhook/serial.c deleted file mode 100644 index 3a50907..0000000 --- a/carolhook/serial.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#include "hook/table.h" - -#include "util/dprintf.h" - -static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB); -static BOOL (WINAPI *next_SetCommState)(HANDLE hFile, LPDCB lpDCB); -static void com_hook_insert_hooks(HMODULE target); - -static const struct hook_symbol win32_hooks[] = { - { - .name = "SetCommState", - .patch = my_SetCommState, - .link = (void **) &next_SetCommState - } -}; - -void serial_init() -{ - com_hook_insert_hooks(NULL); - dprintf("Serial: Spy init\n"); -} - -static void com_hook_insert_hooks(HMODULE target) -{ - hook_table_apply( - target, - "kernel32.dll", - win32_hooks, - _countof(win32_hooks)); -} - -static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB) -{ - dprintf("Serial: my_SetCommState with baudrate %ld\n", lpDCB->BaudRate); - return next_SetCommState(hFile, lpDCB); -} \ No newline at end of file diff --git a/carolhook/serial.h b/carolhook/serial.h deleted file mode 100644 index 8a682ac..0000000 --- a/carolhook/serial.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -#include - -void serial_init(); \ No newline at end of file diff --git a/carolhook/touch.c b/carolhook/touch.c index 9a5ab03..c062e90 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -13,14 +13,31 @@ #include "util/dprintf.h" #include "util/dump.h" +/** + * CMDS for M3 EX series + * CX -> Calibrate Extend, preform callibration + * MS -> Mode Stream, enters stream mode + * R -> Reset, resets the device + * RD -> Reset Default, Resets the device to factory + * Z -> Null, keepalive command + * NM -> Name, return the name of the device (not documented?) + * OI -> Output Identity, output unique device identity, SC followed by 4 characters + * UT -> Unit Type, returns controller unit type + status + */ + static HRESULT touch_handle_irp(struct irp *irp); static HRESULT touch_handle_irp_locked(struct irp *irp); static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf); +static HRESULT handle_touch_ack_cmd(const struct touch_req *req); +static HRESULT handle_touch_name_cmd(const struct touch_req *req); +static HRESULT handle_touch_id_cmd(const struct touch_req *req); + static CRITICAL_SECTION touch_lock; static struct uart touch_uart; static uint8_t touch_written_bytes[520]; static uint8_t touch_readable_bytes[520]; +static bool should_stream = false; HRESULT touch_hook_init(const struct touch_config *cfg) { @@ -84,7 +101,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 +#if 0 dprintf("Touchscreen: TX Buffer:\n"); dump_iobuf(&touch_uart.written); #endif @@ -96,24 +113,69 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) return hr; } - touch_uart.written.pos = 0; + if (!strcmp("Z", (char *)req.cmd)) { + hr = handle_touch_ack_cmd(&req); + } + else if (!strcmp("OI", (char *)req.cmd)) { + hr = handle_touch_id_cmd(&req); + should_stream = true; // possibly send stuff after we get this? + } + else if (!strcmp("NM", (char *)req.cmd)) { + hr = handle_touch_name_cmd(&req); + } + else if (!strcmp("R", (char *)req.cmd)) { + should_stream = false; + dprintf("Touch: Reset\n"); + hr = handle_touch_ack_cmd(&req); + } + else { + dprintf("Touchscreen: Unhandled cmd %s\n", (char *)req.cmd); + hr = handle_touch_ack_cmd(&req); + } + return hr; } } +static HRESULT handle_touch_ack_cmd(const struct touch_req *req) +{ + return iobuf_write(&touch_uart.readable, "\0010\015", 3); +} + +static HRESULT handle_touch_name_cmd(const struct touch_req *req) +{ + dprintf("Touch: Get Name\n"); + return iobuf_write(&touch_uart.readable, "\001EX1234 EX1234\015", 15); +} + +static HRESULT handle_touch_id_cmd(const struct touch_req *req) +{ + dprintf("Touch: Get ID\n"); + return iobuf_write(&touch_uart.readable, "\001EX1234\015", 8); +} + /* Decodes the response into a struct that's easier to work with. */ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) { - dest->cmd = iobuf->bytes[0]; - iobuf->pos--; - dest->data_length = iobuf->pos; + dest->sync = iobuf->bytes[0]; + memset(dest->cmd, 0, sizeof(dest->cmd)); + size_t data_len = 0; - if (dest->data_length > 0) { - for (int i = 1; i < dest->data_length; i++) { - dest->data[i-1] = iobuf->bytes[i]; - } + for (int i = 1; i < 255; i++) { + if (iobuf->bytes[i] == 0x0D) { break; } + dest->cmd[i - 1] = iobuf->bytes[i]; + data_len++; + } + + dest->tail = iobuf->bytes[data_len + 1]; + dest->data_len = data_len; + + iobuf->pos = 0; + + if (dest->sync != 1 || dest->tail != 0x0D) { + dprintf("Touch: Data recieve error, sync: 0x%02X (expected 0x01) tail: 0x%02X (expected 0x0D)", dest->sync, dest->tail); + return E_FAIL; } - iobuf->pos -= dest->data_length; return S_OK; } \ No newline at end of file diff --git a/carolhook/touch.h b/carolhook/touch.h index 6881b8f..2ae3031 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -8,10 +8,12 @@ struct touch_config { bool enable; }; +// Always starts with 0x01, always ends with 0x0D struct touch_req { - uint8_t cmd; // First byte is the command byte - uint8_t data[256]; // rest of the data goes here - uint8_t data_length; // Size of the data including command byte + uint8_t sync; // Always 0x01 + uint8_t cmd[256]; // rest of the data goes here + uint8_t tail; // Always 0x0D + size_t data_len; // length of data }; HRESULT touch_hook_init(const struct touch_config *cfg); \ No newline at end of file From 9113766c224db11cfb348800bf9d0ddf49969e30 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 24 May 2023 01:07:56 -0400 Subject: [PATCH 008/204] vfs: add D drive hooks --- platform/vfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/vfs.c b/platform/vfs.c index d356d7f..7bd2953 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -273,6 +273,8 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) } switch (src[0]) { + case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it + case L'd': case L'e': case L'E': redir = vfs_config.amfs; @@ -404,7 +406,7 @@ static HRESULT vfs_path_hook_option( static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) { - return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); + return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); // seems to be busted? } static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) From 02201dfba5a37122ed93888b0bdca09f963cc5f8 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 24 May 2023 01:08:08 -0400 Subject: [PATCH 009/204] path: add hooks for PathFileExistsA/W --- hooklib/path.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/hooklib/path.c b/hooklib/path.c index 0c6fe42..1d1d4d2 100644 --- a/hooklib/path.c +++ b/hooklib/path.c @@ -97,6 +97,10 @@ static BOOL WINAPI hook_RemoveDirectoryA(const char *lpFileName); static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName); +static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath); + +static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath); + /* Link pointers */ static BOOL (WINAPI *next_CreateDirectoryA)( @@ -177,6 +181,10 @@ static BOOL (WINAPI *next_RemoveDirectoryA)(const char *lpFileName); static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName); +static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath); + +static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath); + /* Hook table */ static const struct hook_symbol path_hook_syms[] = { @@ -244,6 +252,14 @@ static const struct hook_symbol path_hook_syms[] = { .name = "RemoveDirectoryW", .patch = hook_RemoveDirectoryW, .link = (void **) &next_RemoveDirectoryW, + }, { + .name = "PathFileExistsA", + .patch = hook_PathFileExistsA, + .link = (void **) &next_PathFileExistsA, + }, { + .name = "PathFileExistsW", + .patch = hook_PathFileExistsW, + .link = (void **) &next_PathFileExistsW, } }; @@ -854,3 +870,39 @@ static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName) return ok; } + +static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath) +{ + char *trans; + BOOL ok; + + ok = path_transform_a(&trans, pszPath); + + if (!ok) { + return FALSE; + } + + ok = next_PathFileExistsA(trans ? trans : pszPath); + + free(trans); + + return ok; +} + +static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath) +{ + wchar_t *trans; + BOOL ok; + + ok = path_transform_w(&trans, pszPath); + + if (!ok) { + return FALSE; + } + + ok = next_PathFileExistsW(trans ? trans : pszPath); + + free(trans); + + return ok; +} From 4c67843f086933e5a34778ebe2ec4201a2781a63 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 31 May 2023 04:54:38 -0400 Subject: [PATCH 010/204] carol: add touch dll functions --- carolhook/carol-dll.c | 6 ++++ carolhook/carol-dll.h | 2 ++ carolhook/carolhook.def | 2 ++ carolhook/touch.c | 65 ++++++++++++++++++++++++++++++++++++++--- carolhook/touch.h | 19 ++++++++++++ carolio/carolio.c | 55 ++++++++++++++++++++++++++++++++++ carolio/carolio.h | 8 ++++- 7 files changed, 152 insertions(+), 5 deletions(-) diff --git a/carolhook/carol-dll.c b/carolhook/carol-dll.c index 9aa1484..ce3adf9 100644 --- a/carolhook/carol-dll.c +++ b/carolhook/carol-dll.c @@ -27,6 +27,12 @@ const struct dll_bind_sym carol_dll_syms[] = { }, { .sym = "carol_io_controlbd_init", .off = offsetof(struct carol_dll, controlbd_init), + }, { + .sym = "carol_io_touch_start", + .off = offsetof(struct carol_dll, touch_start), + }, { + .sym = "carol_io_touch_stop", + .off = offsetof(struct carol_dll, touch_stop), } }; diff --git a/carolhook/carol-dll.h b/carolhook/carol-dll.h index d56df64..9f8c7ff 100644 --- a/carolhook/carol-dll.h +++ b/carolhook/carol-dll.h @@ -12,6 +12,8 @@ struct carol_dll { HRESULT (*touch_init)(); HRESULT (*ledbd_init)(); HRESULT (*controlbd_init)(); + void (*touch_start)(carol_io_touch_callback_t callback); + void (*touch_stop)(); }; struct carol_dll_config { diff --git a/carolhook/carolhook.def b/carolhook/carolhook.def index 260058e..5102937 100644 --- a/carolhook/carolhook.def +++ b/carolhook/carolhook.def @@ -18,3 +18,5 @@ EXPORTS carol_io_touch_init carol_io_ledbd_init carol_io_controlbd_init + carol_io_touch_start + carol_io_touch_stop diff --git a/carolhook/touch.c b/carolhook/touch.c index c062e90..46527b8 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -32,12 +32,17 @@ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf); static HRESULT handle_touch_ack_cmd(const struct touch_req *req); static HRESULT handle_touch_name_cmd(const struct touch_req *req); static HRESULT handle_touch_id_cmd(const struct touch_req *req); +static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y); static CRITICAL_SECTION touch_lock; static struct uart touch_uart; -static uint8_t touch_written_bytes[520]; -static uint8_t touch_readable_bytes[520]; +static uint8_t touch_written_bytes[528]; +static uint8_t touch_readable_bytes[528]; static bool should_stream = false; +static bool last_pressed; +static uint16_t last_x; +static uint16_t last_y; + HRESULT touch_hook_init(const struct touch_config *cfg) { @@ -118,13 +123,13 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } else if (!strcmp("OI", (char *)req.cmd)) { hr = handle_touch_id_cmd(&req); - should_stream = true; // possibly send stuff after we get this? + //carol_dll.touch_start(touch_scan_auto); } else if (!strcmp("NM", (char *)req.cmd)) { hr = handle_touch_name_cmd(&req); } else if (!strcmp("R", (char *)req.cmd)) { - should_stream = false; + carol_dll.touch_stop(); dprintf("Touch: Reset\n"); hr = handle_touch_ack_cmd(&req); } @@ -154,6 +159,58 @@ static HRESULT handle_touch_id_cmd(const struct touch_req *req) return iobuf_write(&touch_uart.readable, "\001EX1234\015", 8); } +static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y) +{ + struct touch_auto_resp resp; + uint16_t tmp_x; + uint16_t tmp_y; + bool flg = false; + + memset(&resp, 0, sizeof(resp)); + resp.rep_id = 0x17; + resp.touches[0].status = 0x04; + resp.count = 1; + + if (is_pressed) { + resp.touches[0].status = 0x07; + resp.touches[0].touch_id = 1; + tmp_x = mouse_x & 0x7FFF; + tmp_y = mouse_y & 0x7FFF; + + // flip + resp.touches[0].x = (tmp_x << 8) | (tmp_x >> 8); + resp.touches[0].y = (tmp_y << 8) | (tmp_y >> 8); + + flg = resp.touches[0].x != last_x || resp.touches[0].y != last_y; + +#if 1 + if (flg) + dprintf("Touch: Mouse down! x %04X y: %04X\n", resp.touches[0].x, resp.touches[0].y); +#endif + + + last_x = resp.touches[0].x; + last_y = resp.touches[0].y; + + } else if (last_pressed) { + resp.touches[0].x = last_x; + resp.touches[0].y = last_y; + } + + last_pressed = is_pressed; + + EnterCriticalSection(&touch_lock); + iobuf_write(&touch_uart.readable, &resp, sizeof(resp)); + LeaveCriticalSection(&touch_lock); + +#if 1 + //if (flg) { + dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos); + dump_iobuf(&touch_uart.readable); + //} +#endif +} + /* Decodes the response into a struct that's easier to work with. */ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) { diff --git a/carolhook/touch.h b/carolhook/touch.h index 2ae3031..a815cd1 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -4,6 +4,8 @@ #include #include +#pragma pack(push, 1) + struct touch_config { bool enable; }; @@ -16,4 +18,21 @@ struct touch_req { size_t data_len; // length of data }; +struct touch_report { + uint8_t status; + uint8_t touch_id; + uint16_t x; + uint16_t y; +}; + +struct touch_auto_resp { + uint8_t rep_id; + struct touch_report touches[10]; + uint8_t count; + uint16_t scan_time; + //uint8_t padding[456]; +}; + +#pragma pack(pop) + HRESULT touch_hook_init(const struct touch_config *cfg); \ No newline at end of file diff --git a/carolio/carolio.c b/carolio/carolio.c index 67339c9..3f4339b 100644 --- a/carolio/carolio.c +++ b/carolio/carolio.c @@ -8,9 +8,13 @@ #include "carolio/carolio.h" #include "carolio/config.h" +static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx); + static bool carol_io_coin; static uint16_t carol_io_coins; static struct carol_io_config carol_io_cfg; +static bool carol_io_touch_stop_flag; +static HANDLE carol_io_touch_thread; uint16_t carol_io_get_api_version(void) { @@ -81,4 +85,55 @@ HRESULT carol_io_ledbd_init() HRESULT carol_io_controlbd_init() { return S_OK; +} + +void carol_io_touch_start(carol_io_touch_callback_t callback) +{ + if (carol_io_touch_thread != NULL) { + return; + } + + carol_io_touch_stop_flag = false; + + carol_io_touch_thread = (HANDLE) _beginthreadex( + NULL, + 0, + carol_io_touch_thread_proc, + callback, + 0, + NULL + ); +} + +void carol_io_touch_stop() +{ + carol_io_touch_stop_flag = true; +} + +static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx) +{ + carol_io_touch_callback_t callback; + bool mouse_is_down = false; + uint32_t mX = 0; + uint32_t mY = 0; + POINT lpPoint; + + callback = ctx; + + while (!carol_io_touch_stop_flag) { + if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) { + mouse_is_down = true; + if (GetCursorPos(&lpPoint)) { + mX = lpPoint.x; + mY = lpPoint.y; + } + } else { + mouse_is_down = false; + } + + callback(mouse_is_down, mX, mY); + Sleep(1); + } + + return 0; } \ No newline at end of file diff --git a/carolio/carolio.h b/carolio/carolio.h index 7310f54..6c85e3d 100644 --- a/carolio/carolio.h +++ b/carolio/carolio.h @@ -5,6 +5,8 @@ #include #include +typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y); + /* Get the version of the Project carol IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the @@ -51,4 +53,8 @@ HRESULT carol_io_touch_init(); HRESULT carol_io_ledbd_init(); -HRESULT carol_io_controlbd_init(); \ No newline at end of file +HRESULT carol_io_controlbd_init(); + +void carol_io_touch_start(carol_io_touch_callback_t callback); + +void carol_io_touch_stop(); \ No newline at end of file From da97d23b51877b70890d2c737d3902835a5fbd75 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 29 Jun 2023 11:24:34 +0200 Subject: [PATCH 011/204] idac: first segatools support --- dist/idac/segatools.ini | 31 +++---- dist/idac/start.bat | 6 +- idachook/config.c | 12 +-- idachook/config.h | 8 +- idachook/dllmain.c | 64 ++++---------- idachook/idac-dll.c | 31 ++++--- idachook/idac-dll.h | 11 +-- idachook/idachook copy.def | 24 ----- idachook/idachook.def | 11 +-- idachook/io4.c | 138 +++++++++++++++++++++++++++++ idachook/io4.h | 7 ++ idachook/jvs.c | 177 ------------------------------------- idachook/jvs.h | 7 -- idachook/meson.build | 7 +- idacio/backend.h | 7 +- idacio/config.c | 14 +-- idacio/di.c | 34 +++---- idacio/dllmain.c | 55 ++++++------ idacio/idacio.def | 9 ++ idacio/idacio.h | 74 ++++++++-------- idacio/idzio.def | 8 -- idacio/shifter.c | 6 +- idacio/shifter.h | 2 +- idacio/wnd.c | 6 +- idacio/xi.c | 43 ++++++--- 25 files changed, 351 insertions(+), 441 deletions(-) delete mode 100644 idachook/idachook copy.def create mode 100644 idachook/io4.c create mode 100644 idachook/io4.h delete mode 100644 idachook/jvs.c delete mode 100644 idachook/jvs.h create mode 100644 idacio/idacio.def delete mode 100644 idacio/idzio.def diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 367d27e..aa408c5 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -13,14 +13,6 @@ appdata= ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 -[ds] -; Region code on the emulated AMEX board DS EEPROM. -; 1: Japan -; 4: Export (some UI elements in English) -; -; NOTE: Changing this setting causes a factory reset. -region=1 - [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. ; SEGA games are somewhat picky about their LAN environment, so leaving this @@ -33,25 +25,24 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.100.0 -[gpio] -; Emulated Nu DIP switch for Distribution Server setting. -; -; If multiple machines are present on the same LAN then set this to 1 on -; exactly one machine and set this to 0 on all others. -dipsw1=1 - [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. path= -[idzio] -; To use a custom Initial D Zero IO DLL enter its path here. +[idacio] +; To use a custom Initial D The Arcade IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= -[io3] -; Input API selection for JVS input emulator. +[io4] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 +; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput ; Automatically reset the simulated shifter to Neutral when XInput Start is @@ -59,7 +50,7 @@ mode=xinput autoNeutral=1 ; Use the left thumbstick for steering instead of both on XInput Controllers. ; Not recommended as it will not give you the precision needed for this game -singleStickSteering=0 +singleStickSteering=1 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive diff --git a/dist/idac/start.bat b/dist/idac/start.bat index 61ed927..022d5ec 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -2,8 +2,10 @@ pushd %~dp0 -start inject.exe -d -k idachook.dll amdaemon.exe -c config_common.json config_jp.json config_seat_1_jp.json config_seat_2_jp.json config_ex.json config_seat_1_ex.json config_seat_2_ex.json -inject -d -k idachook.dll ../WindowsNoEditor/GameProject/Binaries/Win64/GameProject-Win64-Shipping.exe +REM start /min inject.exe -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json +start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_normal_jp.json config_common.json config_jp.json config_laninstall_server_jp.json config_seat_1_jp.json +inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +taskkill /f /im amdaemon.exe > nul 2>&1 echo. echo Game processes have terminated diff --git a/idachook/config.c b/idachook/config.c index 7e648bf..5452bf6 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -1,14 +1,9 @@ #include #include -#include "amex/amex.h" -#include "amex/config.h" - #include "board/config.h" #include "board/sg-reader.h" -#include "gfxhook/config.h" - #include "hooklib/config.h" #include "hooklib/dvd.h" @@ -26,7 +21,7 @@ void idac_dll_config_load( assert(filename != NULL); GetPrivateProfileStringW( - L"idzio", + L"idacio", L"path", L"", cfg->path, @@ -42,12 +37,11 @@ void idac_hook_config_load( assert(filename != NULL); platform_config_load(&cfg->platform, filename); - amex_config_load(&cfg->amex, filename); aime_config_load(&cfg->aime, filename); - dvd_config_load(&cfg->dvd, filename); - // gfx_config_load(&cfg->gfx, filename); idac_dll_config_load(&cfg->dll, filename); zinput_config_load(&cfg->zinput, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/idachook/config.h b/idachook/config.h index 674797e..9c7dfd7 100644 --- a/idachook/config.h +++ b/idachook/config.h @@ -3,11 +3,7 @@ #include #include -#include "amex/amex.h" - -#include "board/sg-reader.h" - -#include "gfxhook/gfx.h" +#include "board/config.h" #include "hooklib/dvd.h" @@ -18,9 +14,9 @@ struct idac_hook_config { struct platform_config platform; - struct amex_config amex; struct aime_config aime; struct dvd_config dvd; + struct io4_config io4; struct idac_dll_config dll; struct zinput_config zinput; }; diff --git a/idachook/dllmain.c b/idachook/dllmain.c index fcf44d9..ed64515 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -1,17 +1,11 @@ #include #include -#include #include -#include - -#include "amex/amex.h" #include "board/sg-reader.h" - -// #include "gfxhook/d3d11.h" -// #include "gfxhook/dxgi.h" -// #include "gfxhook/gfx.h" +#include "board/io4.h" +#include "board/vfd.h" #include "hook/process.h" @@ -21,13 +15,12 @@ #include "idachook/config.h" #include "idachook/idac-dll.h" -#include "idachook/jvs.h" +#include "idachook/io4.h" #include "idachook/zinput.h" #include "platform/platform.h" #include "util/dprintf.h" -#include "util/lib.h" static HMODULE idac_hook_mod; static process_entry_t idac_startup; @@ -35,8 +28,6 @@ static struct idac_hook_config idac_hook_cfg; static DWORD CALLBACK idac_pre_startup(void) { - wchar_t *module_path; - wchar_t *file_name; HRESULT hr; dprintf("--- Begin idac_pre_startup ---\n"); @@ -44,34 +35,10 @@ static DWORD CALLBACK idac_pre_startup(void) /* Config load */ idac_hook_config_load(&idac_hook_cfg, L".\\segatools.ini"); - - /* - module_path = module_file_name(NULL); - - if (module_path != NULL) { - file_name = PathFindFileNameW(module_path); - - _wcslwr(file_name); - - if (wcsstr(file_name, L"serverbox") != NULL) { - dprintf("Executable filename contains 'ServerBox', disabling full-screen mode\n"); - - idac_hook_cfg.gfx.windowed = true; - idac_hook_cfg.gfx.framed = true; - } - - free(module_path); - - module_path = NULL; - } - */ /* Hook Win32 APIs */ serial_hook_init(); - // gfx_hook_init(&idac_hook_cfg.gfx); - // gfx_d3d11_hook_init(&idac_hook_cfg.gfx, idac_hook_mod); - // gfx_dxgi_hook_init(&idac_hook_cfg.gfx, idac_hook_mod); zinput_hook_init(&idac_hook_cfg.zinput); dvd_hook_init(&idac_hook_cfg.dvd, idac_hook_mod); @@ -80,26 +47,33 @@ static DWORD CALLBACK idac_pre_startup(void) hr = platform_hook_init( &idac_hook_cfg.platform, "SDGT", - "ACA2", + "ACA4", idac_hook_mod); if (FAILED(hr)) { goto fail; } + hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, idac_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + // Not needed? + hr = vfd_hook_init(4); + + if (FAILED(hr)) { + return hr; + } + hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); if (FAILED(hr)) { goto fail; } - hr = amex_hook_init(&idac_hook_cfg.amex, idac_jvs_init); - - if (FAILED(hr)) { - goto fail; - } - - hr = sg_reader_hook_init(&idac_hook_cfg.aime, 10, idac_hook_mod); + hr = idac_io4_hook_init(&idac_hook_cfg.io4); if (FAILED(hr)) { goto fail; @@ -109,7 +83,7 @@ static DWORD CALLBACK idac_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End idac_pre_startup ---\n"); + dprintf("--- End idac_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c index 6346089..03a6a3e 100644 --- a/idachook/idac-dll.c +++ b/idachook/idac-dll.c @@ -10,20 +10,23 @@ const struct dll_bind_sym idac_dll_syms[] = { { - .sym = "idac_io_jvs_init", - .off = offsetof(struct idac_dll, jvs_init), + .sym = "idac_io_init", + .off = offsetof(struct idac_dll, init), }, { - .sym = "idac_io_jvs_read_analogs", - .off = offsetof(struct idac_dll, jvs_read_analogs), + .sym = "idac_io_poll", + .off = offsetof(struct idac_dll, poll), }, { - .sym = "idac_io_jvs_read_buttons", - .off = offsetof(struct idac_dll, jvs_read_buttons), + .sym = "idac_io_get_opbtns", + .off = offsetof(struct idac_dll, get_opbtns), }, { - .sym = "idac_io_jvs_read_shifter", - .off = offsetof(struct idac_dll, jvs_read_shifter), + .sym = "idac_io_get_gamebtns", + .off = offsetof(struct idac_dll, get_gamebtns), }, { - .sym = "idac_io_jvs_read_coin_counter", - .off = offsetof(struct idac_dll, jvs_read_coin_counter), + .sym = "idac_io_get_shifter", + .off = offsetof(struct idac_dll, get_shifter), + }, { + .sym = "idac_io_get_analogs", + .off = offsetof(struct idac_dll, get_analogs), } }; @@ -51,14 +54,14 @@ HRESULT idac_dll_init(const struct idac_dll_config *cfg, HINSTANCE self) if (owned == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); - dprintf("IDZ IO: Failed to load IO DLL: %lx: %S\n", + dprintf("IDAC IO: Failed to load IO DLL: %lx: %S\n", hr, cfg->path); goto end; } - dprintf("IDZ IO: Using custom IO DLL: %S\n", cfg->path); + dprintf("IDAC IO: Using custom IO DLL: %S\n", cfg->path); src = owned; } else { owned = NULL; @@ -78,7 +81,7 @@ HRESULT idac_dll_init(const struct idac_dll_config *cfg, HINSTANCE self) if (idac_dll.api_version >= 0x0200) { hr = E_NOTIMPL; - dprintf("IDZ IO: Custom IO DLL implements an unsupported " + dprintf("IDAC IO: Custom IO DLL implements an unsupported " "API version (%#04x). Please update Segatools.\n", idac_dll.api_version); @@ -90,7 +93,7 @@ HRESULT idac_dll_init(const struct idac_dll_config *cfg, HINSTANCE self) if (FAILED(hr)) { if (src != self) { - dprintf("IDZ IO: Custom IO DLL does not provide function " + dprintf("IDAC IO: Custom IO DLL does not provide function " "\"%s\". Please contact your IO DLL's developer for " "further assistance.\n", sym->sym); diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h index 88902ed..7db5639 100644 --- a/idachook/idac-dll.h +++ b/idachook/idac-dll.h @@ -6,11 +6,12 @@ struct idac_dll { uint16_t api_version; - HRESULT (*jvs_init)(void); - void (*jvs_read_analogs)(struct idac_io_analog_state *out); - void (*jvs_read_buttons)(uint8_t *opbtn, uint8_t *gamebtn); - void (*jvs_read_shifter)(uint8_t *gear); - void (*jvs_read_coin_counter)(uint16_t *total); + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_shifter)(uint8_t *gear); + void (*get_analogs)(struct idac_io_analog_state *out); }; struct idac_dll_config { diff --git a/idachook/idachook copy.def b/idachook/idachook copy.def deleted file mode 100644 index a46fa06..0000000 --- a/idachook/idachook copy.def +++ /dev/null @@ -1,24 +0,0 @@ -LIBRARY idachook - -EXPORTS - CreateDXGIFactory - CreateDXGIFactory1 - CreateDXGIFactory2 - D3D11CreateDevice - D3D11CreateDeviceAndSwapChain - aime_io_get_api_version - aime_io_init - aime_io_led_set_color - aime_io_nfc_get_aime_id - aime_io_nfc_get_felica_id - aime_io_nfc_poll - amDllVideoClose @2 - amDllVideoGetVBiosVersion @4 - amDllVideoOpen @1 - amDllVideoSetResolution @3 - idac_io_get_api_version - idac_io_jvs_init - idac_io_jvs_read_analogs - idac_io_jvs_read_buttons - idac_io_jvs_read_coin_counter - idac_io_jvs_read_shifter diff --git a/idachook/idachook.def b/idachook/idachook.def index 68ed1d0..4c944fd 100644 --- a/idachook/idachook.def +++ b/idachook/idachook.def @@ -12,8 +12,9 @@ EXPORTS amDllVideoOpen @1 amDllVideoSetResolution @3 idac_io_get_api_version - idac_io_jvs_init - idac_io_jvs_read_analogs - idac_io_jvs_read_buttons - idac_io_jvs_read_coin_counter - idac_io_jvs_read_shifter + idac_io_init + idac_io_poll + idac_io_get_opbtns + idac_io_get_gamebtns + idac_io_get_shifter + idac_io_get_analogs diff --git a/idachook/io4.c b/idachook/io4.c new file mode 100644 index 0000000..3d2eec5 --- /dev/null +++ b/idachook/io4.c @@ -0,0 +1,138 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "idachook/idac-dll.h" + +#include "util/dprintf.h" + +static HRESULT idac_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops idac_io4_ops = { + .poll = idac_io4_poll, +}; + +static const uint16_t idac_gear_signals[] = { + /* Neutral */ + 0x0000, + /* 1: Left|Up */ + 0x0028, + /* 2: Left|Down */ + 0x0018, + /* 3: Up */ + 0x0020, + /* 4: Down */ + 0x0010, + /* 5: Right|Up */ + 0x0024, + /* 6: Right|Down */ + 0x0014, +}; + +HRESULT idac_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(idac_dll.init != NULL); + + hr = io4_hook_init(cfg, &idac_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return idac_dll.init(); +} + +static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + uint8_t gamebtn; + uint8_t gear; + struct idac_io_analog_state analog_state; + HRESULT hr; + + assert(idac_dll.poll != NULL); + assert(idac_dll.get_opbtns != NULL); + assert(idac_dll.get_gamebtns != NULL); + assert(idac_dll.get_analogs != NULL); + assert(idac_dll.get_shifter != NULL); + + memset(state, 0, sizeof(*state)); + memset(&analog_state, 0, sizeof(analog_state)); + + hr = idac_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + gamebtn = 0; + gear = 0; + + idac_dll.get_opbtns(&opbtn); + idac_dll.get_gamebtns(&gamebtn); + idac_dll.get_shifter(&gear); + idac_dll.get_analogs(&analog_state); + + if (opbtn & IDAC_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & IDAC_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & IDAC_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + if (gamebtn & IDAC_IO_GAMEBTN_START) { + state->buttons[0] |= 1 << 7; + } + + if (gamebtn & IDAC_IO_GAMEBTN_VIEW_CHANGE) { + state->buttons[0] |= 1 << 1; + } + + if (gamebtn & IDAC_IO_GAMEBTN_UP) { + state->buttons[0] |= 1 << 5; + } + + if (gamebtn & IDAC_IO_GAMEBTN_DOWN) { + state->buttons[0] |= 1 << 4; + } + + if (gamebtn & IDAC_IO_GAMEBTN_LEFT) { + state->buttons[0] |= 1 << 3; + } + + if (gamebtn & IDAC_IO_GAMEBTN_RIGHT) { + state->buttons[0] |= 1 << 2; + } + + /* Update simulated six-speed shifter */ + + if (gear > 6) { + gear = 6; + } + + state->buttons[1] = idac_gear_signals[gear]; + + /* Steering wheel increases left-to-right. + + Use 0x8000 as the center point. */ + + state->adcs[0] = 0x8000 + analog_state.wheel; + state->adcs[1] = analog_state.accel; + state->adcs[2] = analog_state.brake; + + return S_OK; +} diff --git a/idachook/io4.h b/idachook/io4.h new file mode 100644 index 0000000..af2ded1 --- /dev/null +++ b/idachook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT idac_io4_hook_init(const struct io4_config *cfg); diff --git a/idachook/jvs.c b/idachook/jvs.c deleted file mode 100644 index 2192c24..0000000 --- a/idachook/jvs.c +++ /dev/null @@ -1,177 +0,0 @@ -#include - -#include -#include -#include - -#include "amex/jvs.h" - -#include "board/io3.h" - -#include "idachook/idac-dll.h" -#include "idachook/jvs.h" - -#include "jvs/jvs-bus.h" - -#include "util/dprintf.h" - -static void idac_jvs_read_analogs( - void *ctx, - uint16_t *analogs, - uint8_t nanalogs); -static void idac_jvs_read_switches(void *ctx, struct io3_switch_state *out); -static void idac_jvs_read_coin_counter( - void *ctx, - uint8_t slot_no, - uint16_t *out); - -static const struct io3_ops idac_jvs_io3_ops = { - .read_switches = idac_jvs_read_switches, - .read_analogs = idac_jvs_read_analogs, - .read_coin_counter = idac_jvs_read_coin_counter, -}; - -static const uint16_t idac_jvs_gear_signals[] = { - /* Neutral */ - 0x0000, - /* 1: Left|Up */ - 0x2800, - /* 2: Left|Down */ - 0x1800, - /* 3: Up */ - 0x2000, - /* 4: Down */ - 0x1000, - /* 5: Right|Up */ - 0x2400, - /* 6: Right|Down */ - 0x1400, -}; - -static struct io3 idac_jvs_io3; - -HRESULT idac_jvs_init(struct jvs_node **out) -{ - HRESULT hr; - - assert(out != NULL); - assert(idac_dll.jvs_init != NULL); - - dprintf("JVS I/O: Starting Initial D Zero backend DLL\n"); - hr = idac_dll.jvs_init(); - - if (FAILED(hr)) { - dprintf("JVS I/O: Backend error, I/O disconnected; %x\n", (int) hr); - - return hr; - } - - io3_init(&idac_jvs_io3, NULL, &idac_jvs_io3_ops, NULL); - *out = io3_to_jvs_node(&idac_jvs_io3); - - return S_OK; -} - -static void idac_jvs_read_switches(void *ctx, struct io3_switch_state *out) -{ - uint8_t opbtn; - uint8_t gamebtn; - uint8_t gear; - - assert(out != NULL); - assert(idac_dll.jvs_read_buttons != NULL); - assert(idac_dll.jvs_read_shifter != NULL); - - opbtn = 0; - gamebtn = 0; - gear = 0; - - idac_dll.jvs_read_buttons(&opbtn, &gamebtn); - idac_dll.jvs_read_shifter(&gear); - - /* Update gameplay buttons */ - - if (gamebtn & IDAC_IO_GAMEBTN_UP) { - out->p1 |= 1 << 13; - } - - if (gamebtn & IDAC_IO_GAMEBTN_DOWN) { - out->p1 |= 1 << 12; - } - - if (gamebtn & IDAC_IO_GAMEBTN_LEFT) { - out->p1 |= 1 << 11; - } - - if (gamebtn & IDAC_IO_GAMEBTN_RIGHT) { - out->p1 |= 1 << 10; - } - - if (gamebtn & IDAC_IO_GAMEBTN_START) { - out->p1 |= 1 << 15; - } - - if (gamebtn & IDAC_IO_GAMEBTN_VIEW_CHANGE) { - out->p1 |= 1 << 9; - } - - /* Update simulated six-speed shifter */ - - if (gear > 6) { - gear = 6; - } - - out->p2 = idac_jvs_gear_signals[gear]; - - /* Update test/service buttons */ - - if (opbtn & IDAC_IO_OPBTN_TEST) { - out->system = 0x80; - } else { - out->system = 0; - } - - if (opbtn & IDAC_IO_OPBTN_SERVICE) { - out->p1 |= 1 << 14; - } -} - -static void idac_jvs_read_analogs( - void *ctx, - uint16_t *analogs, - uint8_t nanalogs) -{ - struct idac_io_analog_state state; - - assert(analogs != NULL); - assert(idac_dll.jvs_read_analogs != NULL); - - memset(&state, 0, sizeof(state)); - idac_dll.jvs_read_analogs(&state); - - if (nanalogs > 0) { - analogs[0] = 0x8000 + state.wheel; - } - - if (nanalogs > 1) { - analogs[1] = state.accel; - } - - if (nanalogs > 2) { - analogs[2] = state.brake; - } -} - -static void idac_jvs_read_coin_counter( - void *ctx, - uint8_t slot_no, - uint16_t *out) -{ - assert(idac_dll.jvs_read_coin_counter != NULL); - - if (slot_no > 0) { - return; - } - - idac_dll.jvs_read_coin_counter(out); -} diff --git a/idachook/jvs.h b/idachook/jvs.h deleted file mode 100644 index f0781a4..0000000 --- a/idachook/jvs.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -#include "jvs/jvs-bus.h" - -HRESULT idac_jvs_init(struct jvs_node **root); diff --git a/idachook/meson.build b/idachook/meson.build index 3a3369d..81c2c7b 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -13,12 +13,9 @@ shared_library( ], link_with : [ aimeio_lib, - amex_lib, board_lib, - # gfxhook_lib, hooklib_lib, idacio_lib, - jvs_lib, platform_lib, util_lib, ], @@ -28,8 +25,8 @@ shared_library( 'dllmain.c', 'idac-dll.c', 'idac-dll.h', - 'jvs.c', - 'jvs.h', + 'io4.c', + 'io4.h', 'zinput.c', 'zinput.h', ], diff --git a/idacio/backend.h b/idacio/backend.h index 46daa0b..b9833a1 100644 --- a/idacio/backend.h +++ b/idacio/backend.h @@ -5,7 +5,8 @@ #include "idacio/idacio.h" struct idac_io_backend { - void (*jvs_read_buttons)(uint8_t *gamebtn); - void (*jvs_read_shifter)(uint8_t *gear); - void (*jvs_read_analogs)(struct idac_io_analog_state *state); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_shifter)(uint8_t *gear); + void (*get_analogs)(struct idac_io_analog_state *state); }; diff --git a/idacio/config.c b/idacio/config.c index 5df7971..700f18b 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -77,7 +77,7 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->single_stick_steering = GetPrivateProfileIntW( - L"io3", + L"io4", L"singleStickSteering", 0, filename); @@ -88,13 +88,13 @@ void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); - cfg->restrict_ = GetPrivateProfileIntW(L"io3", L"restrict", 97, filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 97, filename); GetPrivateProfileStringW( - L"io3", + L"io4", L"mode", L"xinput", cfg->mode, @@ -114,7 +114,7 @@ void idac_shifter_config_load( assert(filename != NULL); cfg->auto_neutral = GetPrivateProfileIntW( - L"io3", + L"io4", L"autoNeutral", 0, filename); diff --git a/idacio/di.c b/idacio/di.c index b2d0d3d..110a2ed 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -29,12 +29,12 @@ static BOOL CALLBACK idac_di_enum_callback( static BOOL CALLBACK idac_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx); -static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out); +static void idac_di_get_buttons(uint8_t *gamebtn_out); static uint8_t idac_di_decode_pov(DWORD pov); -static void idac_di_jvs_read_shifter(uint8_t *gear); -static void idac_di_jvs_read_shifter_pos(uint8_t *gear); -static void idac_di_jvs_read_shifter_virt(uint8_t *gear); -static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out); +static void idac_di_get_shifter(uint8_t *gear); +static void idac_di_get_shifter_pos(uint8_t *gear); +static void idac_di_get_shifter_virt(uint8_t *gear); +static void idac_di_get_analogs(struct idac_io_analog_state *out); static const struct idac_di_axis idac_di_axes[] = { /* Just map DIJOYSTATE for now, we can map DIJOYSTATE2 later if needed */ @@ -49,9 +49,9 @@ static const struct idac_di_axis idac_di_axes[] = { }; static const struct idac_io_backend idac_di_backend = { - .jvs_read_buttons = idac_di_jvs_read_buttons, - .jvs_read_shifter = idac_di_jvs_read_shifter, - .jvs_read_analogs = idac_di_jvs_read_analogs, + .get_gamebtns = idac_di_get_buttons, + .get_shifter = idac_di_get_shifter, + .get_analogs = idac_di_get_analogs, }; static HWND idac_di_wnd; @@ -98,8 +98,8 @@ HRESULT idac_di_init( } /* Initial D Zero has some built-in DirectInput support that is not - particularly useful. idzhook shorts this out by redirecting dinput8.dll - to a no-op implementation of DirectInput. However, idzio does need to + particularly useful. idachook shorts this out by redirecting dinput8.dll + to a no-op implementation of DirectInput. However, idacio does need to talk to the real operating system implementation of DirectInput without the stub DLL interfering, so build a path to C:\Windows\System32\dinput.dll here. */ @@ -374,7 +374,7 @@ static BOOL CALLBACK idac_di_enum_callback_shifter( return DIENUM_STOP; } -static void idac_di_jvs_read_buttons(uint8_t *gamebtn_out) +static void idac_di_get_buttons(uint8_t *gamebtn_out) { union idac_di_state state; uint8_t gamebtn; @@ -416,18 +416,18 @@ static uint8_t idac_di_decode_pov(DWORD pov) } } -static void idac_di_jvs_read_shifter(uint8_t *gear) +static void idac_di_get_shifter(uint8_t *gear) { assert(gear != NULL); if (idac_di_shifter != NULL) { - idac_di_jvs_read_shifter_pos(gear); + idac_di_get_shifter_pos(gear); } else { - idac_di_jvs_read_shifter_virt(gear); + idac_di_get_shifter_virt(gear); } } -static void idac_di_jvs_read_shifter_pos(uint8_t *out) +static void idac_di_get_shifter_pos(uint8_t *out) { union idac_di_state state; uint8_t btn_no; @@ -457,7 +457,7 @@ static void idac_di_jvs_read_shifter_pos(uint8_t *out) *out = gear; } -static void idac_di_jvs_read_shifter_virt(uint8_t *gear) +static void idac_di_get_shifter_virt(uint8_t *gear) { union idac_di_state state; bool shift_dn; @@ -489,7 +489,7 @@ static void idac_di_jvs_read_shifter_virt(uint8_t *gear) *gear = idac_shifter_current_gear(); } -static void idac_di_jvs_read_analogs(struct idac_io_analog_state *out) +static void idac_di_get_analogs(struct idac_io_analog_state *out) { union idac_di_state state; const LONG *brake; diff --git a/idacio/dllmain.c b/idacio/dllmain.c index fdf1004..f524139 100644 --- a/idacio/dllmain.c +++ b/idacio/dllmain.c @@ -16,14 +16,13 @@ static struct idac_io_config idac_io_cfg; static const struct idac_io_backend *idac_io_backend; static bool idac_io_coin; -static uint16_t idac_io_coins; uint16_t idac_io_get_api_version(void) { return 0x0100; } -HRESULT idac_io_jvs_init(void) +HRESULT idac_io_init(void) { HINSTANCE inst; HRESULT hr; @@ -47,20 +46,19 @@ HRESULT idac_io_jvs_init(void) hr = idac_xi_init(&idac_io_cfg.xi, &idac_io_backend); } else { hr = E_INVALIDARG; - dprintf("IDZ IO: Invalid IO mode \"%S\", use dinput or xinput\n", + dprintf("IDAC IO: Invalid IO mode \"%S\", use dinput or xinput\n", idac_io_cfg.mode); } return hr; } -void idac_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) +void idac_io_get_opbtns(uint8_t *opbtn_out) { uint8_t opbtn; assert(idac_io_backend != NULL); assert(opbtn_out != NULL); - assert(gamebtn_out != NULL); opbtn = 0; @@ -72,27 +70,43 @@ void idac_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) opbtn |= IDAC_IO_OPBTN_SERVICE; } - *opbtn_out = opbtn; + if (GetAsyncKeyState(idac_io_cfg.vk_coin) & 0x8000) { + if (!idac_io_coin) { + idac_io_coin = true; + opbtn |= IDAC_IO_OPBTN_COIN; + } + } else { + idac_io_coin = false; + } - idac_io_backend->jvs_read_buttons(gamebtn_out); + *opbtn_out = opbtn; } -void idac_io_jvs_read_shifter(uint8_t *gear) + +void idac_io_get_gamebtns(uint8_t *gamebtn_out) +{ + assert(idac_io_backend != NULL); + assert(gamebtn_out != NULL); + + idac_io_backend->get_gamebtns(gamebtn_out); +} + +void idac_io_get_shifter(uint8_t *gear) { assert(gear != NULL); assert(idac_io_backend != NULL); - idac_io_backend->jvs_read_shifter(gear); + idac_io_backend->get_shifter(gear); } -void idac_io_jvs_read_analogs(struct idac_io_analog_state *out) +void idac_io_get_analogs(struct idac_io_analog_state *out) { struct idac_io_analog_state tmp; assert(out != NULL); assert(idac_io_backend != NULL); - idac_io_backend->jvs_read_analogs(&tmp); + idac_io_backend->get_analogs(&tmp); /* Apply steering wheel restriction. Real cabs only report about 77% of the IO-3's max ADC output value when the wheel is turned to either of @@ -104,22 +118,3 @@ void idac_io_jvs_read_analogs(struct idac_io_analog_state *out) out->accel = tmp.accel; out->brake = tmp.brake; } - -void idac_io_jvs_read_coin_counter(uint16_t *out) -{ - assert(out != NULL); - - /* Coin counter is not backend-specific */ - - if (idac_io_cfg.vk_coin && - (GetAsyncKeyState(idac_io_cfg.vk_coin) & 0x8000)) { - if (!idac_io_coin) { - idac_io_coin = true; - idac_io_coins++; - } - } else { - idac_io_coin = false; - } - - *out = idac_io_coins; -} diff --git a/idacio/idacio.def b/idacio/idacio.def new file mode 100644 index 0000000..18839b2 --- /dev/null +++ b/idacio/idacio.def @@ -0,0 +1,9 @@ +LIBRARY idacio + +EXPORTS + idac_io_init + idac_io_poll + idac_io_get_opbtns + idac_io_get_gamebtns + idac_io_get_shifter + idac_io_get_analogs diff --git a/idacio/idacio.h b/idacio/idacio.h index 10fff60..035c5c4 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -1,17 +1,5 @@ #pragma once -/* INITIAL D THE ARCADE CUSTOM IO API - - This API definition allows custom driver DLLs to be defined for the - emulation of Initial D The Arcade cabinets. To be honest, there is very - little reason to want to do this, since driving game controllers are a - mostly-standardized PC peripheral which can be adequately controlled by the - built-in DirectInput and XInput support in idzhook. However, previous - versions of Segatools broke this functionality out into a separate DLL just - like all of the other supported games, so in the interests of maintaining - backwards compatibility we provide the option to load custom IDZIO - implementations as well. */ - #include #include @@ -19,6 +7,7 @@ enum { IDAC_IO_OPBTN_TEST = 0x01, IDAC_IO_OPBTN_SERVICE = 0x02, + IDAC_IO_OPBTN_COIN = 0x04, }; enum { @@ -49,7 +38,7 @@ struct idac_io_analog_state { uint16_t brake; }; -/* Get the version of the IDZ IO API that this DLL supports. This +/* Get the version of the IDAC IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the Semantic Versioning standard). @@ -58,33 +47,48 @@ struct idac_io_analog_state { uint16_t idac_io_get_api_version(void); -/* Initialize JVS-based input. This function will be called before any other - idac_io_jvs_*() function calls. Errors returned from this function will - manifest as a disconnected JVS bus. +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after mu3_io_get_api_version. - All subsequent calls may originate from arbitrary threads and some may - overlap with each other. Ensuring synchronization inside your IO DLL is - your responsibility. + All subsequent calls to this API may originate from arbitrary threads. Minimum API version: 0x0100 */ -HRESULT idac_io_jvs_init(void); +HRESULT idac_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT idac_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + MU3_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void idac_io_get_opbtns(uint8_t *opbtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + MU3_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + a left hand side set of inputs and a right hand side set of inputs: the bit + mappings are the same in both cases. + + All buttons are active-high, even though some buttons' electrical signals + on a real cabinet are active-low. + + Minimum API version: 0x0100 */ + +void idac_io_get_gamebtns(uint8_t *gamebtn); /* Poll the current state of the cabinet's JVS analog inputs. See structure definition above for details. Minimum API version: 0x0100 */ -void idac_io_jvs_read_analogs(struct idac_io_analog_state *out); - -/* Poll the current state of the cabinet's JVS input buttons and return them - through the opbtn and gamebtn out parameters. See enum definitions at the - top of this file for a list of bit masks to be used with these out - parameters. - - Minimum API version: 0x0100 */ - -void idac_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn); +void idac_io_get_analogs(struct idac_io_analog_state *out); /* Poll the current position of the six-speed shifter and return it via the gear out parameter. Valid values are 0 for neutral and 1-6 for gears 1-6. @@ -95,12 +99,4 @@ void idac_io_jvs_read_buttons(uint8_t *opbtn, uint8_t *gamebtn); Minimum API version: 0x0100 */ -void idac_io_jvs_read_shifter(uint8_t *gear); - -/* 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. - - Minimum API version: 0x0100 */ - -void idac_io_jvs_read_coin_counter(uint16_t *total); +void idac_io_get_shifter(uint8_t *gear); \ No newline at end of file diff --git a/idacio/idzio.def b/idacio/idzio.def deleted file mode 100644 index b495482..0000000 --- a/idacio/idzio.def +++ /dev/null @@ -1,8 +0,0 @@ -LIBRARY idacio - -EXPORTS - idac_io_jvs_init - idac_io_jvs_read_analogs - idac_io_jvs_read_buttons - idac_io_jvs_read_coin_counter - idac_io_jvs_read_shifter diff --git a/idacio/shifter.c b/idacio/shifter.c index 02d8a54..55de837 100644 --- a/idacio/shifter.c +++ b/idacio/shifter.c @@ -1,14 +1,14 @@ #include #include -#include "idzio/shifter.h" +#include "idacio/shifter.h" static bool idac_shifter_shifting; static uint8_t idac_shifter_gear; -void idac_shifter_reset(void) +void idac_shifter_set(uint8_t gear) { - idac_shifter_gear = 0; + idac_shifter_gear = gear; } void idac_shifter_update(bool shift_dn, bool shift_up) diff --git a/idacio/shifter.h b/idacio/shifter.h index 523a9a6..c32dcf1 100644 --- a/idacio/shifter.h +++ b/idacio/shifter.h @@ -3,6 +3,6 @@ #include #include -void idac_shifter_reset(void); +void idac_shifter_set(uint8_t gear); void idac_shifter_update(bool shift_dn, bool shift_up); uint8_t idac_shifter_current_gear(void); diff --git a/idacio/wnd.c b/idacio/wnd.c index 7353273..68720b4 100644 --- a/idacio/wnd.c +++ b/idacio/wnd.c @@ -31,13 +31,13 @@ HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out) wcx.cbSize = sizeof(wcx); wcx.lpfnWndProc = idac_io_wnd_proc; wcx.hInstance = inst; - wcx.lpszClassName = L"IDZIO"; + wcx.lpszClassName = L"IDACIO"; atom = RegisterClassExW(&wcx); if (atom == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); - dprintf("IDZIO: RegisterClassExW failed: %08x\n", (int) hr); + dprintf("IDACIO: RegisterClassExW failed: %08x\n", (int) hr); goto fail; } @@ -58,7 +58,7 @@ HRESULT idac_io_wnd_create(HINSTANCE inst, HWND *out) if (hwnd == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); - dprintf("IDZIO: CreateWindowExW failed: %08x\n", (int) hr); + dprintf("IDACIO: CreateWindowExW failed: %08x\n", (int) hr); goto fail; } diff --git a/idacio/xi.c b/idacio/xi.c index 63e4242..87f3fbd 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -13,16 +13,16 @@ #include "util/dprintf.h" -static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out); -static void idac_xi_jvs_read_shifter(uint8_t *gear); -static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out); +static void idac_xi_get_gamebtns(uint8_t *gamebtn_out); +static void idac_xi_get_shifter(uint8_t *gear); +static void idac_xi_get_analogs(struct idac_io_analog_state *out); static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg); static const struct idac_io_backend idac_xi_backend = { - .jvs_read_buttons = idac_xi_jvs_read_buttons, - .jvs_read_shifter = idac_xi_jvs_read_shifter, - .jvs_read_analogs = idac_xi_jvs_read_analogs, + .get_gamebtns = idac_xi_get_gamebtns, + .get_shifter = idac_xi_get_shifter, + .get_analogs = idac_xi_get_analogs, }; static bool idac_xi_single_stick_steering; @@ -45,6 +45,11 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back return S_OK; } +HRESULT idac_io_poll(void) +{ + return S_OK; +} + static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) { dprintf("XInput: --- Begin configuration ---\n"); @@ -56,7 +61,7 @@ static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) return S_OK; } -static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out) +static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) { uint8_t gamebtn; XINPUT_STATE xi; @@ -97,7 +102,7 @@ static void idac_xi_jvs_read_buttons(uint8_t *gamebtn_out) *gamebtn_out = gamebtn; } -static void idac_xi_jvs_read_shifter(uint8_t *gear) +static void idac_xi_get_shifter(uint8_t *gear) { bool shift_dn; bool shift_up; @@ -112,9 +117,25 @@ static void idac_xi_jvs_read_shifter(uint8_t *gear) if (xb & XINPUT_GAMEPAD_START) { /* Reset to Neutral when start is pressed */ - idac_shifter_reset(); + idac_shifter_set(0); } + /* + // Alternative shifting mode + if (xb & XINPUT_GAMEPAD_X) { + // Set to Gear 2 when X is pressed + idac_shifter_set(2); + } + + if (xb & XINPUT_GAMEPAD_Y) { + // Set to Gear 3 when Y is pressed + idac_shifter_set(3); + } + + shift_dn = xb & XINPUT_GAMEPAD_LEFT_SHOULDER; + shift_up = xb & XINPUT_GAMEPAD_RIGHT_SHOULDER; + */ + shift_dn = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER); shift_up = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER); @@ -123,7 +144,7 @@ static void idac_xi_jvs_read_shifter(uint8_t *gear) *gear = idac_shifter_current_gear(); } -static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out) +static void idac_xi_get_analogs(struct idac_io_analog_state *out) { XINPUT_STATE xi; int left; @@ -154,7 +175,7 @@ static void idac_xi_jvs_read_analogs(struct idac_io_analog_state *out) right = 0; } - if(idac_xi_single_stick_steering) { + if (idac_xi_single_stick_steering) { out->wheel = left; } else { out->wheel = (left + right) / 2; From c27ef9674d2f15f92b9bc3cd0d4f0e094daf55a0 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:41:23 +0200 Subject: [PATCH 012/204] idac: added dipswitch support (beta) --- dist/idac/segatools.ini | 31 +++++++- dist/idac/start.bat | 22 +++++- idachook/dllmain.c | 8 --- idachook/meson.build | 1 - platform/config.c | 20 ++++++ platform/config.h | 2 + platform/dipsw.c | 153 ++++++++++++++++++++++++++++++++++++++++ platform/dipsw.h | 15 ++++ platform/dns.c | 8 +++ platform/meson.build | 2 + platform/platform.c | 7 ++ platform/platform.h | 2 + platform/vfs.c | 8 ++- 13 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 platform/dipsw.c create mode 100644 platform/dipsw.h diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index aa408c5..c6660ca 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -8,6 +8,12 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt +felicaGen=0 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -22,9 +28,32 @@ enable=1 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and -; that subnet must start with 192.168. +; that subnet must start with 192.168. Set it to your LAN's subnet if you +; want to play head-to-head using netenv=1. subnet=192.168.100.0 +; Override the keychip's region code. Most games seem to pay attention to the +; DS EEPROM region code and not the keychip region code, and this seems to be +; a bit mask that controls which Nu PCB region codes this keychip is authorized +; for. So it probably only affects the system software and not the game software. +; 1: JPN: Japan, 4: EXP: Export (for Asian markets) +region=4 + +[gpio] +; ALLS DIP switches. + +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. +dipsw1=1 +; 0 is the DZero CVT cab and 1 is the SWDC CVT cab. +dipsw2=0 +; Enable the Single Seat mode, always requires dipsw1=1. +dipsw3=0 +; The next two dip switches are the seat settings in bits, where +; 00 = Seat 1, 10 = Seat 2, 01 = Seat 3 and 11 = Seat 4 +dipsw4=0 +dipsw5=0 + [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. diff --git a/dist/idac/start.bat b/dist/idac/start.bat index 022d5ec..4b2d8e9 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -2,11 +2,27 @@ pushd %~dp0 -REM start /min inject.exe -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json -start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_normal_jp.json config_common.json config_jp.json config_laninstall_server_jp.json config_seat_1_jp.json -inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +REM set the APP_DIR to the Y drive +set APP_DIR=Y:\SDGT + +REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder +if not exist "%APP_DIR%" ( + subst Y: %TEMP% + REM timeout /t 1 + if not exist "%APP_DIR%" ( + mkdir "%APP_DIR%" + ) +) + +echo Mounted the Y:\ drive to the %TEMP%\SDGT folder + +start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json +inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 +REM unmount the APP_DIR +subst Y: /d > nul 2>&1 + echo. echo Game processes have terminated pause \ No newline at end of file diff --git a/idachook/dllmain.c b/idachook/dllmain.c index ed64515..5d6f695 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -5,7 +5,6 @@ #include "board/sg-reader.h" #include "board/io4.h" -#include "board/vfd.h" #include "hook/process.h" @@ -60,13 +59,6 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } - // Not needed? - hr = vfd_hook_init(4); - - if (FAILED(hr)) { - return hr; - } - hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); if (FAILED(hr)) { diff --git a/idachook/meson.build b/idachook/meson.build index 81c2c7b..72214ac 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -8,7 +8,6 @@ shared_library( dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), - shlwapi_lib, xinput_lib, ], link_with : [ diff --git a/platform/config.c b/platform/config.c index 1c6be62..62f2707 100644 --- a/platform/config.c +++ b/platform/config.c @@ -21,6 +21,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -37,6 +38,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) netenv_config_load(&cfg->netenv, filename); nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); + dipsw_config_load(&cfg->dipsw, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -317,3 +319,21 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) filename); } +void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) +{ + wchar_t name[7]; + size_t i; + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 1, filename); + + wcscpy_s(name, _countof(name), L"dipsw0"); + + for (i = 0 ; i < 8 ; i++) { + name[5] = L'1' + i; + cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename); + } +} + diff --git a/platform/config.h b/platform/config.h index 7ece41d..1e56d43 100644 --- a/platform/config.h +++ b/platform/config.h @@ -17,6 +17,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" void platform_config_load( struct platform_config *cfg, @@ -32,3 +33,4 @@ void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename); void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); +void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename); diff --git a/platform/dipsw.c b/platform/dipsw.c new file mode 100644 index 0000000..e6af610 --- /dev/null +++ b/platform/dipsw.c @@ -0,0 +1,153 @@ +#include +#include + +#include +#include +// #include + +#include "platform/dipsw.h" +#include "platform/vfs.h" + +#include "util/dprintf.h" +#include "util/str.h" +#include "util/crc.h" + +#define DATA_SIZE 503 +#define BLOCK_SIZE (sizeof(uint32_t) + 4 + 1 + DATA_SIZE) + +#pragma pack(push, 1) + +typedef struct +{ + uint32_t checksum; + char padding_1[4]; + uint8_t dip_switches; + char data[DATA_SIZE]; +} DipSwitchBlock; + +typedef struct +{ + DipSwitchBlock dip_switch_block; + char *data; +} DipSwitches; + +#pragma pack(pop) + +static DipSwitches dip_switches; + +static struct dipsw_config dipsw_config; +static struct vfs_config vfs_config; + +static void dipsw_read_sysfile(const wchar_t *sys_file); +static void dipsw_save_sysfile(const wchar_t *sys_file); + +HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg) +{ + HRESULT hr; + wchar_t sys_file_path[MAX_PATH]; + + assert(cfg != NULL); + assert(vfs_cfg != NULL); + + if (!cfg->enable) + { + return S_FALSE; + } + + memcpy(&dipsw_config, cfg, sizeof(*cfg)); + + sys_file_path[0] = L'\0'; + // concatenate vfs_config.amfs with L"sysfile.dat" + wcsncpy(sys_file_path, vfs_cfg->amfs, MAX_PATH); + wcsncat(sys_file_path, L"\\sysfile.dat", MAX_PATH); + + dipsw_read_sysfile(sys_file_path); + + // now write the dipsw_config.dipsw to the dip_switch_block + dipsw_save_sysfile(sys_file_path); + + return S_OK; +} + +static void dipsw_read_sysfile(const wchar_t *sys_file) +{ + FILE *f = _wfopen(sys_file, L"r"); + + if (f == NULL) + { + dprintf("First run detected, DipSw settings can only be applied AFTER the first run\n"); + return; + } + + fseek(f, 0, SEEK_END); + long file_size = ftell(f); + fseek(f, 0, SEEK_SET); + + if (file_size != 0x6000) + { + dprintf("Invalid sysfile.dat file size\n"); + fclose(f); + + return; + } + + dip_switches.data = malloc(file_size); + fread(dip_switches.data, 1, file_size, f); + fclose(f); + + // memcpy(dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); + memcpy(&dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); +} + +static void dipsw_save_sysfile(const wchar_t *sys_file) +{ + uint8_t dipsw = 0; + // open the sysfile.dat for writing in bytes mode + FILE *f = _wfopen(sys_file, L"rb+"); + + if (f == NULL) + { + return; + } + + // write the dipsw_config.dipsw to the dip_switch_block + for (int i = 0; i < 8; i++) + { + if (dipsw_config.dipsw[i]) + { + // print which dipsw is enabled + dprintf("DipSw: DipSw%d=1 set\n", i + 1); + dipsw |= (1 << i); + } + } + + dip_switches.dip_switch_block.dip_switches = dipsw; + + // calculate the new checksum, skip the old crc32 value + // which is at the beginning of the block, thats's why the +4 + // conver the struct to chars in order for the crc32 calculation to work + dip_switches.dip_switch_block.checksum = crc32( + (char *)&dip_switches.dip_switch_block + 4, BLOCK_SIZE - 4, 0); + + // build the new dip switch block + char block[BLOCK_SIZE]; + memcpy(block, (char *)&dip_switches.dip_switch_block, BLOCK_SIZE); + + // replace the old block with the new one + memcpy(dip_switches.data + 0x2800, block, BLOCK_SIZE); + memcpy(dip_switches.data + 0x5800, block, BLOCK_SIZE); + + // print the dip_switch_block in hex + /* + dprintf("DipSw Block: "); + for (size_t i = 0; i < BLOCK_SIZE; i++) + { + dprintf("%02X ", ((uint8_t *)&dip_switches.dip_switch_block)[i]); + } + dprintf("\n"); + */ + + fwrite(dip_switches.data, 1, 0x6000, f); + + fclose(f); +} diff --git a/platform/dipsw.h b/platform/dipsw.h new file mode 100644 index 0000000..a4bfdb2 --- /dev/null +++ b/platform/dipsw.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include +#include + +#include "platform/vfs.h" + +struct dipsw_config { + bool enable; + bool dipsw[8]; +}; + +HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg); diff --git a/platform/dns.c b/platform/dns.c index 5486d42..e2c5905 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -79,5 +79,13 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + // Disable api/polling to the original servers + + hr = dns_hook_push(L"amlog.sys-all.net", NULL); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/platform/meson.build b/platform/meson.build index 4f0fbc9..0de228c 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -32,5 +32,7 @@ platform_lib = static_library( 'platform.h', 'vfs.c', 'vfs.h', + 'dipsw.c', + 'dipsw.h', ], ) diff --git a/platform/platform.c b/platform/platform.c index 218204c..35d2ba7 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -12,6 +12,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -80,5 +81,11 @@ HRESULT platform_hook_init( return hr; } + hr = dipsw_init(&cfg->dipsw, &cfg->vfs); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/platform/platform.h b/platform/platform.h index 69c65e2..ba06567 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -12,6 +12,7 @@ #include "platform/nusec.h" #include "platform/pcbid.h" #include "platform/vfs.h" +#include "platform/dipsw.h" struct platform_config { struct amvideo_config amvideo; @@ -24,6 +25,7 @@ struct platform_config { struct netenv_config netenv; struct nusec_config nusec; struct vfs_config vfs; + struct dipsw_config dipsw; }; HRESULT platform_hook_init( diff --git a/platform/vfs.c b/platform/vfs.c index 7bd2953..9f620d8 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -28,7 +28,9 @@ static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); static wchar_t vfs_nthome_real[MAX_PATH]; -static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; +// new home for ALLS +static const wchar_t vfs_nthome[] = L"C:\\Users\\AppUser"; +// static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; static const wchar_t vfs_option[] = L"C:\\Mount\\Option"; @@ -273,8 +275,8 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) } switch (src[0]) { - case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it - case L'd': + // case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it + // case L'd': case L'e': case L'E': redir = vfs_config.amfs; From ec072667b3e8eee702871fcc87519a90331ba5d2 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:52:50 +0200 Subject: [PATCH 013/204] swdc: first segatools added --- Package.mk | 16 ++ README.md | 5 +- dist/swdc/segatools.ini | 99 ++++++++++ dist/swdc/start.bat | 29 +++ meson.build | 2 + swdchook/config.c | 53 +++++ swdchook/config.h | 32 +++ swdchook/dllmain.c | 112 +++++++++++ swdchook/io4.c | 137 +++++++++++++ swdchook/io4.h | 7 + swdchook/meson.build | 32 +++ swdchook/swdc-dll.c | 112 +++++++++++ swdchook/swdc-dll.h | 22 +++ swdchook/swdchook.def | 19 ++ swdchook/zinput.c | 186 ++++++++++++++++++ swdchook/zinput.h | 11 ++ swdcio/backend.h | 11 ++ swdcio/config.c | 111 +++++++++++ swdcio/config.h | 47 +++++ swdcio/di-dev.c | 163 ++++++++++++++++ swdcio/di-dev.h | 19 ++ swdcio/di.c | 420 ++++++++++++++++++++++++++++++++++++++++ swdcio/di.h | 9 + swdcio/dllmain.c | 112 +++++++++++ swdcio/meson.build | 30 +++ swdcio/swdcio.def | 8 + swdcio/swdcio.h | 98 ++++++++++ swdcio/wnd.c | 86 ++++++++ swdcio/wnd.h | 5 + swdcio/xi.c | 165 ++++++++++++++++ swdcio/xi.h | 10 + 31 files changed, 2167 insertions(+), 1 deletion(-) create mode 100644 dist/swdc/segatools.ini create mode 100644 dist/swdc/start.bat create mode 100644 swdchook/config.c create mode 100644 swdchook/config.h create mode 100644 swdchook/dllmain.c create mode 100644 swdchook/io4.c create mode 100644 swdchook/io4.h create mode 100644 swdchook/meson.build create mode 100644 swdchook/swdc-dll.c create mode 100644 swdchook/swdc-dll.h create mode 100644 swdchook/swdchook.def create mode 100644 swdchook/zinput.c create mode 100644 swdchook/zinput.h create mode 100644 swdcio/backend.h create mode 100644 swdcio/config.c create mode 100644 swdcio/config.h create mode 100644 swdcio/di-dev.c create mode 100644 swdcio/di-dev.h create mode 100644 swdcio/di.c create mode 100644 swdcio/di.h create mode 100644 swdcio/dllmain.c create mode 100644 swdcio/meson.build create mode 100644 swdcio/swdcio.def create mode 100644 swdcio/swdcio.h create mode 100644 swdcio/wnd.c create mode 100644 swdcio/wnd.h create mode 100644 swdcio/xi.c create mode 100644 swdcio/xi.h diff --git a/Package.mk b/Package.mk index 3e6a887..4562bf1 100644 --- a/Package.mk +++ b/Package.mk @@ -88,6 +88,21 @@ $(BUILD_DIR_ZIP)/idac.zip: $(V)strip $(BUILD_DIR_ZIP)/idac/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/idac ; zip -r ../idac.zip * +$(BUILD_DIR_ZIP)/swdc.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc + $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/swdchook/swdchook.dll \ + $(DIST_DIR)/swdc/segatools.ini \ + $(DIST_DIR)/swdc/start.bat \ + $(BUILD_DIR_ZIP)/swdc + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/swdc/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/swdc/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/swdc ; zip -r ../swdc.zip * + $(BUILD_DIR_ZIP)/mercury.zip: $(V)echo ... $@ $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury @@ -135,6 +150,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/doc.zip \ $(BUILD_DIR_ZIP)/idz.zip \ $(BUILD_DIR_ZIP)/idac.zip \ + $(BUILD_DIR_ZIP)/swdc.zip \ $(BUILD_DIR_ZIP)/mercury.zip \ $(BUILD_DIR_ZIP)/mu3.zip \ CHANGELOG.md \ diff --git a/README.md b/README.md index a9c53d7..4f48d8d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Segatools -Version: `v005` +Version: `2023-07-14` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. @@ -14,6 +14,9 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo * [Chunithm Crystal (Plus)](doc/chunihook.md) * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) + * Initial D The Arcade +* SEGA World Drivers Championship + * SEGA World Drivers Championship 2019 * Wacca * Wacca Lilly R (WIP) diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini new file mode 100644 index 0000000..dc0c003 --- /dev/null +++ b/dist/swdc/segatools.ini @@ -0,0 +1,99 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains OPxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt +felicaGen=0 + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; You must set this to your LAN's IP subnet, and that subnet must start with 192.168. +subnet=192.168.100.0 + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[swdcio] +; To use a custom SEGA World Drivers Championship DLL enter its path here. +; Leave empty if you want to use Segatools built-in gamepad/wheel input. +path= + +[io4] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 +; Input API selection for IO4 input emulator. +; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. +mode=xinput +; Use the left thumbstick for steering instead of both on XInput Controllers. +; Not recommended as it will not give you the precision needed for this game +singleStickSteering=1 +; Adjust scaling for steering wheel input. +; +; This setting scales the steering wheel input so that the maximum positive +; and minimum negative steering inputs reported in the operator menu's input +; test screen do not exceed the value below. The maximum possible value is 128, +; and the value that matches the input range of a real cabinet is 97. +; +; NOTE: This is not the same thing as DirectInput steering wheel movement +; range! Segatools cannot control the maximum angle of your physical steering +; wheel controller, this setting is vendor-specific and can only be adjusted +; in the Control Panel. +restrict=97 + +[dinput] +; Name of the DirectInput wheel to use (or any text that occurs in its name) +; Example: TMX +; +; If this is left blank then the first DirectInput device will be used. +deviceName= +; Pedal mappings. Valid axis names are: +; +; X, Y, Z, RX, RY, RZ, U, V +; +; (U and V are old names for Slider 1 and Slider 2). +; The examples below are valid for a Thrustmaster TMX. +brakeAxis=RZ +accelAxis=Y +; DirectInput button numbers to map to menu inputs. Note that buttons are +; numbered from 1; some software numbers buttons from 0. +start=3 +viewChg=10 +; Button mappings for the steering wheel paddles. Note shiftDn is the +; left paddle and shiftUp is the right paddle. +shiftDn=1 +shiftUp=2 +; Button mappings for the steering wheel buttons. +wheelGreen=4 +wheelRed=5 +wheelBlue=6 +wheelYellow=7 +; Invert the accelerator and or brake axis +; (Needed when using DirectInput for the Dualshock 4 for example) +reverseAccelAxis=0 +reverseBrakeAxis=0 diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat new file mode 100644 index 0000000..ae33ae9 --- /dev/null +++ b/dist/swdc/start.bat @@ -0,0 +1,29 @@ +@echo off + +pushd %~dp0 + +REM set the APP_DIR to the Y drive +set APP_DIR=Y:\SWDC + +REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder +if not exist "%APP_DIR%" ( + subst Y: %TEMP% + REM timeout /t 1 + if not exist "%APP_DIR%" ( + mkdir "%APP_DIR%" + ) +) + +echo Mounted the Y:\ drive to the %TEMP%\SWDC folder + +REM start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanClient.json config_MiniCabinet.json +start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanServer.json config_MiniCabinet.json +inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +taskkill /f /im amdaemon.exe > nul 2>&1 + +REM unmount the APP_DIR +subst Y: /d > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/meson.build b/meson.build index abbc4a6..e346cea 100644 --- a/meson.build +++ b/meson.build @@ -59,6 +59,7 @@ subdir('divaio') subdir('carolio') subdir('idzio') subdir('idacio') +subdir('swdcio') subdir('mu3io') subdir('mercuryio') subdir('cxbio') @@ -68,6 +69,7 @@ subdir('divahook') subdir('carolhook') subdir('idzhook') subdir('idachook') +subdir('swdchook') subdir('minihook') subdir('mu3hook') subdir('mercuryhook') diff --git a/swdchook/config.c b/swdchook/config.c new file mode 100644 index 0000000..ba4d34a --- /dev/null +++ b/swdchook/config.c @@ -0,0 +1,53 @@ +#include +#include + +#include "board/config.h" +#include "board/sg-reader.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "swdchook/config.h" +#include "swdchook/swdc-dll.h" + +#include "platform/config.h" +#include "platform/platform.h" + +void swdc_dll_config_load( + struct swdc_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"swdcio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void swdc_hook_config_load( + struct swdc_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + swdc_dll_config_load(&cfg->dll, filename); + zinput_config_load(&cfg->zinput, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); +} + +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename); +} diff --git a/swdchook/config.h b/swdchook/config.h new file mode 100644 index 0000000..5237b9f --- /dev/null +++ b/swdchook/config.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" + +#include "swdchook/swdc-dll.h" +#include "swdchook/zinput.h" + +#include "platform/platform.h" + +struct swdc_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct swdc_dll_config dll; + struct zinput_config zinput; +}; + +void swdc_dll_config_load( + struct swdc_dll_config *cfg, + const wchar_t *filename); + +void swdc_hook_config_load( + struct swdc_hook_config *cfg, + const wchar_t *filename); + +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename); diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c new file mode 100644 index 0000000..a37c3b0 --- /dev/null +++ b/swdchook/dllmain.c @@ -0,0 +1,112 @@ +#include +#include + +#include + +#include "board/sg-reader.h" +#include "board/io4.h" +#include "board/vfd.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "swdchook/config.h" +#include "swdchook/swdc-dll.h" +#include "swdchook/io4.h" +#include "swdchook/zinput.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE swdc_hook_mod; +static process_entry_t swdc_startup; +static struct swdc_hook_config swdc_hook_cfg; + +static DWORD CALLBACK swdc_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin swdc_pre_startup ---\n"); + + /* Config load */ + + swdc_hook_config_load(&swdc_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + serial_hook_init(); + zinput_hook_init(&swdc_hook_cfg.zinput); + dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &swdc_hook_cfg.platform, + "SDDS", + "ACA4", + swdc_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, swdc_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = vfd_hook_init(4); + + if (FAILED(hr)) { + return hr; + } + + hr = swdc_dll_init(&swdc_hook_cfg.dll, swdc_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = swdc_io4_hook_init(&swdc_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End swdc_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return swdc_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + swdc_hook_mod = mod; + + hr = process_hijack_startup(swdc_pre_startup, &swdc_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/swdchook/io4.c b/swdchook/io4.c new file mode 100644 index 0000000..10736ef --- /dev/null +++ b/swdchook/io4.c @@ -0,0 +1,137 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "swdchook/swdc-dll.h" + +#include "util/dprintf.h" + +static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops swdc_io4_ops = { + .poll = swdc_io4_poll, +}; + +HRESULT swdc_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(swdc_dll.init != NULL); + + hr = io4_hook_init(cfg, &swdc_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return swdc_dll.init(); +} + +static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + uint16_t gamebtn; + struct swdc_io_analog_state analog_state; + HRESULT hr; + + assert(swdc_dll.poll != NULL); + assert(swdc_dll.get_opbtns != NULL); + assert(swdc_dll.get_gamebtns != NULL); + assert(swdc_dll.get_analogs != NULL); + + memset(state, 0, sizeof(*state)); + memset(&analog_state, 0, sizeof(analog_state)); + + hr = swdc_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + gamebtn = 0; + + swdc_dll.get_opbtns(&opbtn); + swdc_dll.get_gamebtns(&gamebtn); + swdc_dll.get_analogs(&analog_state); + + if (opbtn & SWDC_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & SWDC_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & SWDC_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + /* Update Cabinet buttons */ + + if (gamebtn & SWDC_IO_GAMEBTN_START) { + state->buttons[0] |= 1 << 7; + } + + if (gamebtn & SWDC_IO_GAMEBTN_VIEW_CHANGE) { + state->buttons[0] |= 1 << 1; + } + + if (gamebtn & SWDC_IO_GAMEBTN_UP) { + state->buttons[0] |= 1 << 5; + } + + if (gamebtn & SWDC_IO_GAMEBTN_DOWN) { + state->buttons[0] |= 1 << 4; + } + + if (gamebtn & SWDC_IO_GAMEBTN_LEFT) { + state->buttons[0] |= 1 << 3; + } + + if (gamebtn & SWDC_IO_GAMEBTN_RIGHT) { + state->buttons[0] |= 1 << 2; + } + + /* Update steering wheel buttons */ + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) { + state->buttons[1] |= 1 << 15; + } + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_GREEN) { + state->buttons[1] |= 1 << 14; + } + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_RED) { + state->buttons[1] |= 1 << 13; + } + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_YELLOW) { + state->buttons[1] |= 1 << 12; + } + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT) { + state->buttons[1] |= 1 << 1; + } + + if (gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT) { + state->buttons[1] |= 1 << 0; + } + + /* Steering wheel increases left-to-right. + + Use 0x8000 as the center point. */ + + state->adcs[0] = 0x8000 + analog_state.wheel; + state->adcs[1] = analog_state.accel; + state->adcs[2] = analog_state.brake; + + return S_OK; +} diff --git a/swdchook/io4.h b/swdchook/io4.h new file mode 100644 index 0000000..69580d1 --- /dev/null +++ b/swdchook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT swdc_io4_hook_init(const struct io4_config *cfg); diff --git a/swdchook/meson.build b/swdchook/meson.build new file mode 100644 index 0000000..c312ed4 --- /dev/null +++ b/swdchook/meson.build @@ -0,0 +1,32 @@ +shared_library( + 'swdchook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'swdchook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + swdcio_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'swdc-dll.c', + 'swdc-dll.h', + 'io4.c', + 'io4.h', + 'zinput.c', + 'zinput.h', + ], +) diff --git a/swdchook/swdc-dll.c b/swdchook/swdc-dll.c new file mode 100644 index 0000000..47120ee --- /dev/null +++ b/swdchook/swdc-dll.c @@ -0,0 +1,112 @@ +#include + +#include +#include + +#include "swdchook/swdc-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym swdc_dll_syms[] = { + { + .sym = "swdc_io_init", + .off = offsetof(struct swdc_dll, init), + }, { + .sym = "swdc_io_poll", + .off = offsetof(struct swdc_dll, poll), + }, { + .sym = "swdc_io_get_opbtns", + .off = offsetof(struct swdc_dll, get_opbtns), + }, { + .sym = "swdc_io_get_gamebtns", + .off = offsetof(struct swdc_dll, get_gamebtns), + }, { + .sym = "swdc_io_get_analogs", + .off = offsetof(struct swdc_dll, get_analogs), + } +}; + +struct swdc_dll swdc_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT swdc_dll_init(const struct swdc_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("SWDC IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("SWDC IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "swdc_io_get_api_version"); + + if (get_api_version != NULL) { + swdc_dll.api_version = get_api_version(); + } else { + swdc_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose swdc_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (swdc_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("SWDC IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + swdc_dll.api_version); + + goto end; + } + + sym = swdc_dll_syms; + hr = dll_bind(&swdc_dll, src, &sym, _countof(swdc_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("SWDC IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/swdchook/swdc-dll.h b/swdchook/swdc-dll.h new file mode 100644 index 0000000..8e13a2c --- /dev/null +++ b/swdchook/swdc-dll.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "swdcio/swdcio.h" + +struct swdc_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint16_t *gamebtn); + void (*get_analogs)(struct swdc_io_analog_state *out); +}; + +struct swdc_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct swdc_dll swdc_dll; + +HRESULT swdc_dll_init(const struct swdc_dll_config *cfg, HINSTANCE self); diff --git a/swdchook/swdchook.def b/swdchook/swdchook.def new file mode 100644 index 0000000..37b47bd --- /dev/null +++ b/swdchook/swdchook.def @@ -0,0 +1,19 @@ +LIBRARY swdchook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + swdc_io_get_api_version + swdc_io_init + swdc_io_poll + swdc_io_get_opbtns + swdc_io_get_gamebtns + swdc_io_get_analogs diff --git a/swdchook/zinput.c b/swdchook/zinput.c new file mode 100644 index 0000000..bd18392 --- /dev/null +++ b/swdchook/zinput.c @@ -0,0 +1,186 @@ +#include +#include + +#include +#include +#include + +#include "swdchook/config.h" +#include "swdchook/zinput.h" + +#include "hook/table.h" + +#include "util/dprintf.h" + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter); + +static unsigned long WINAPI hook_AddRef(IUnknown *self); + +static unsigned long WINAPI hook_Release(IUnknown *self); + +static HRESULT WINAPI hook_CreateDevice( + IDirectInput8W *self, + REFGUID rguid, + LPDIRECTINPUTDEVICE8W * lplpDirectInputDevice, + LPUNKNOWN pUnkOuter); + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags); + +static HRESULT WINAPI hook_SetDataFormat( + IDirectInputDevice8W *self, + LPCDIDATAFORMAT lpdf); + +static HRESULT WINAPI hook_SetCooperativeLevel( + IDirectInputDevice8W *self, + HWND hwnd, + DWORD flags); + +static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self); + +static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self); + +static HRESULT WINAPI hook_GetDeviceState( + IDirectInputDevice8W *self, + DWORD cbData, + LPVOID lpvData); + +static const IDirectInput8WVtbl api_vtbl = { + .AddRef = (void *) hook_AddRef, + .Release = (void *) hook_Release, + .CreateDevice = hook_CreateDevice, + .EnumDevices = hook_EnumDevices, +}; + +static const IDirectInput8W api = { (void *) &api_vtbl }; + +static const IDirectInputDevice8WVtbl dev_vtbl = { + .AddRef = (void *) hook_AddRef, + .Release = (void *) hook_Release, + .SetDataFormat = hook_SetDataFormat, + .SetCooperativeLevel= hook_SetCooperativeLevel, + .Acquire = hook_Acquire, + .Unacquire = hook_Unacquire, + .GetDeviceState = hook_GetDeviceState, +}; + +static const IDirectInputDevice8W dev = { (void *) &dev_vtbl }; + +static const struct hook_symbol zinput_hook_syms[] = { + { + .name = "DirectInput8Create", + .patch = hook_DirectInput8Create, + } +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + hook_table_apply( + NULL, + "dinput8.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + return S_OK; +} + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter) +{ + dprintf("ZInput: Blocking built-in DirectInput support\n"); + *ppvOut = (void *) &api; + + return S_OK; +} + +static unsigned long WINAPI hook_AddRef(IUnknown *self) +{ + return 1; +} + +static unsigned long WINAPI hook_Release(IUnknown *self) +{ + return 1; +} + +static HRESULT WINAPI hook_CreateDevice( + IDirectInput8W *self, + REFGUID rguid, + LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, + LPUNKNOWN pUnkOuter) +{ + dprintf("ZInput: %s\n", __func__); + *lplpDirectInputDevice = (void *) &dev; + + return S_OK; +} + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_SetDataFormat( + IDirectInputDevice8W *self, + LPCDIDATAFORMAT lpdf) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_SetCooperativeLevel( + IDirectInputDevice8W *self, + HWND hwnd, + DWORD flags) +{ + dprintf("ZInput: %s\n", __func__); + + return S_OK; +} + +static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self) +{ + return S_OK; +} + +static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self) +{ + return S_OK; +} + +static HRESULT WINAPI hook_GetDeviceState( + IDirectInputDevice8W *self, + DWORD cbData, + LPVOID lpvData) +{ + memset(lpvData, 0, cbData); + + return S_OK; +} diff --git a/swdchook/zinput.h b/swdchook/zinput.h new file mode 100644 index 0000000..13a46cd --- /dev/null +++ b/swdchook/zinput.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +struct zinput_config { + bool enable; +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg); diff --git a/swdcio/backend.h b/swdcio/backend.h new file mode 100644 index 0000000..d30645b --- /dev/null +++ b/swdcio/backend.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "swdcio/swdcio.h" + +struct swdc_io_backend { + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint16_t *gamebtn); + void (*get_analogs)(struct swdc_io_analog_state *state); +}; diff --git a/swdcio/config.c b/swdcio/config.c new file mode 100644 index 0000000..7396338 --- /dev/null +++ b/swdcio/config.c @@ -0,0 +1,111 @@ +#include + +#include +#include +#include +#include +#include + +#include "swdcio/config.h" + +void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename) +{ + wchar_t key[8]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"dinput", + L"deviceName", + L"", + cfg->device_name, + _countof(cfg->device_name), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"brakeAxis", + L"RZ", + cfg->brake_axis, + _countof(cfg->brake_axis), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"accelAxis", + L"Y", + cfg->accel_axis, + _countof(cfg->accel_axis), + filename); + + cfg->start = GetPrivateProfileIntW(L"dinput", L"start", 0, filename); + cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename); + cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename); + cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename); + cfg->wheel_green = GetPrivateProfileIntW(L"dinput", L"wheelGreen", 0, filename); + cfg->wheel_red = GetPrivateProfileIntW(L"dinput", L"wheelRed", 0, filename); + cfg->wheel_blue = GetPrivateProfileIntW(L"dinput", L"wheelBlue", 0, filename); + cfg->wheel_yellow = GetPrivateProfileIntW(L"dinput", L"wheelYellow", 0, filename); + + cfg->reverse_brake_axis = GetPrivateProfileIntW( + L"dinput", + L"reverseBrakeAxis", + 0, + filename); + cfg->reverse_accel_axis = GetPrivateProfileIntW( + L"dinput", + L"reverseAccelAxis", + 0, + filename); +} + +void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->single_stick_steering = GetPrivateProfileIntW( + L"io4", + L"singleStickSteering", + 0, + filename); +} + +void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 97, filename); + + GetPrivateProfileStringW( + L"io4", + L"mode", + L"xinput", + cfg->mode, + _countof(cfg->mode), + filename); + + swdc_shifter_config_load(&cfg->shifter, filename); + swdc_di_config_load(&cfg->di, filename); + swdc_xi_config_load(&cfg->xi, filename); +} + +void swdc_shifter_config_load( + struct swdc_shifter_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->auto_neutral = GetPrivateProfileIntW( + L"io4", + L"autoNeutral", + 0, + filename); +} diff --git a/swdcio/config.h b/swdcio/config.h new file mode 100644 index 0000000..4fa482f --- /dev/null +++ b/swdcio/config.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +struct swdc_shifter_config { + bool auto_neutral; +}; + +struct swdc_di_config { + wchar_t device_name[64]; + wchar_t brake_axis[16]; + wchar_t accel_axis[16]; + uint8_t start; + uint8_t view_chg; + uint8_t shift_dn; + uint8_t shift_up; + uint8_t wheel_green; + uint8_t wheel_red; + uint8_t wheel_blue; + uint8_t wheel_yellow; + bool reverse_brake_axis; + bool reverse_accel_axis; +}; + +struct swdc_xi_config { + bool single_stick_steering; +}; + +struct swdc_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + wchar_t mode[8]; + int restrict_; + struct swdc_shifter_config shifter; + struct swdc_di_config di; + struct swdc_xi_config xi; +}; + +void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename); +void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename); +void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename); +void swdc_shifter_config_load( + struct swdc_shifter_config *cfg, + const wchar_t *filename); diff --git a/swdcio/di-dev.c b/swdcio/di-dev.c new file mode 100644 index 0000000..116e529 --- /dev/null +++ b/swdcio/di-dev.c @@ -0,0 +1,163 @@ +#include +#include + +#include + +#include "swdcio/di-dev.h" + +#include "util/dprintf.h" + +HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +{ + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +{ + /* Set up force-feedback on devices that support it. This is just a stub + for the time being, since we don't yet know how the serial port force + feedback protocol works. + + I'm currently developing with an Xbox One Thrustmaster TMX wheel, if + we don't perform at least some perfunctory FFB initialization of this + nature (or indeed if no DirectInput application is running) then the + wheel exhibits considerable resistance, similar to that of a stationary + car. Changing cf.lMagnitude to a nonzero value does cause the wheel to + continuously turn in the given direction with the given force as one + would expect (max magnitude per DirectInput docs is +/- 10000). + + Failure here is non-fatal, we log any errors and move on. + + https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) + */ + + IDirectInputEffect *obj; + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + assert(dev != NULL); + assert(out != NULL); + + *out = NULL; + + dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + + axis = DIJOFS_X; + direction = 0; + + memset(&cf, 0, sizeof(cf)); + cf.lMagnitude = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + hr = IDirectInputDevice8_CreateEffect( + dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + (int) hr); + + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + + if (FAILED(hr)) { + IDirectInputEffect_Release(obj); + dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + (int) hr); + + return; + } + + *out = obj; + + dprintf("DirectInput: Force feedback initialized and set to zero\n"); +} + +HRESULT swdc_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union swdc_di_state *out) +{ + HRESULT hr; + MSG msg; + + assert(dev != NULL); + assert(wnd != NULL); + assert(out != NULL); + + memset(out, 0, sizeof(*out)); + + /* Pump our dummy window's message queue just in case DirectInput or an + IHV DirectInput driver somehow relies on it */ + + while (PeekMessageW(&msg, wnd, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (FAILED(hr)) { + dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + } + + /* JVS lacks a protocol for reporting hardware errors from poll command + responses, so this ends up returning zeroed input state instead. */ + + return hr; +} diff --git a/swdcio/di-dev.h b/swdcio/di-dev.h new file mode 100644 index 0000000..82ceef0 --- /dev/null +++ b/swdcio/di-dev.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +union swdc_di_state { + DIJOYSTATE st; + uint8_t bytes[sizeof(DIJOYSTATE)]; +}; + +HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); +void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +HRESULT swdc_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union swdc_di_state *out); + diff --git a/swdcio/di.c b/swdcio/di.c new file mode 100644 index 0000000..f75aa6b --- /dev/null +++ b/swdcio/di.c @@ -0,0 +1,420 @@ +#include +#include + +#include +#include +#include + +#include "swdcio/backend.h" +#include "swdcio/config.h" +#include "swdcio/di.h" +#include "swdcio/di-dev.h" +#include "swdcio/swdcio.h" +#include "swdcio/wnd.h" + +#include "util/dprintf.h" +#include "util/str.h" + +struct swdc_di_axis { + wchar_t name[4]; + size_t off; +}; + +static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg); +static const struct swdc_di_axis *swdc_di_get_axis(const wchar_t *name); +static BOOL CALLBACK swdc_di_enum_callback( + const DIDEVICEINSTANCEW *dev, + void *ctx); +static BOOL CALLBACK swdc_di_enum_callback_shifter( + const DIDEVICEINSTANCEW *dev, + void *ctx); +static void swdc_di_get_buttons(uint16_t *gamebtn_out); +static uint8_t swdc_di_decode_pov(DWORD pov); +static void swdc_di_get_analogs(struct swdc_io_analog_state *out); + +static const struct swdc_di_axis swdc_di_axes[] = { + /* Just map DIJOYSTATE for now, we can map DIJOYSTATE2 later if needed */ + { .name = L"X", .off = DIJOFS_X }, + { .name = L"Y", .off = DIJOFS_Y }, + { .name = L"Z", .off = DIJOFS_Z }, + { .name = L"RX", .off = DIJOFS_RX }, + { .name = L"RY", .off = DIJOFS_RY }, + { .name = L"RZ", .off = DIJOFS_RZ }, + { .name = L"U", .off = DIJOFS_SLIDER(0) }, + { .name = L"V", .off = DIJOFS_SLIDER(1) }, +}; + +static const struct swdc_io_backend swdc_di_backend = { + .get_gamebtns = swdc_di_get_buttons, + .get_analogs = swdc_di_get_analogs, +}; + +static HWND swdc_di_wnd; +static IDirectInput8W *swdc_di_api; +static IDirectInputDevice8W *swdc_di_dev; +static IDirectInputEffect *swdc_di_fx; +static size_t swdc_di_off_brake; +static size_t swdc_di_off_accel; +static uint8_t swdc_di_shift_dn; +static uint8_t swdc_di_shift_up; +static uint8_t swdc_di_view_chg; +static uint8_t swdc_di_start; +static uint8_t swdc_di_wheel_green; +static uint8_t swdc_di_wheel_red; +static uint8_t swdc_di_wheel_blue; +static uint8_t swdc_di_wheel_yellow; +static bool swdc_di_reverse_brake_axis; +static bool swdc_di_reverse_accel_axis; + +HRESULT swdc_di_init( + const struct swdc_di_config *cfg, + HINSTANCE inst, + const struct swdc_io_backend **backend) +{ + HRESULT hr; + HMODULE dinput8; + HRESULT (WINAPI *api_entry)(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN); + wchar_t dll_path[MAX_PATH]; + UINT path_pos; + + assert(cfg != NULL); + assert(backend != NULL); + + *backend = NULL; + + hr = swdc_di_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + hr = swdc_io_wnd_create(inst, &swdc_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + /* SWDC has some built-in DirectInput support that is not + particularly useful. swdchook shorts this out by redirecting dinput8.dll + to a no-op implementation of DirectInput. However, swdcio does need to + talk to the real operating system implementation of DirectInput without + the stub DLL interfering, so build a path to + C:\Windows\System32\dinput.dll here. */ + + dll_path[0] = L'\0'; + path_pos = GetSystemDirectoryW(dll_path, _countof(dll_path)); + wcscat_s( + dll_path + path_pos, + _countof(dll_path) - path_pos, + L"\\dinput8.dll"); + + dinput8 = LoadLibraryW(dll_path); + + if (dinput8 == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("DirectInput: LoadLibrary failed: %08x\n", (int) hr); + + return hr; + } + + api_entry = (void *) GetProcAddress(dinput8, "DirectInput8Create"); + + if (api_entry == NULL) { + dprintf("DirectInput: GetProcAddress failed\n"); + + return E_FAIL; + } + + hr = api_entry( + inst, + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void **) &swdc_di_api, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: API create failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInput8_EnumDevices( + swdc_di_api, + DI8DEVCLASS_GAMECTRL, + swdc_di_enum_callback, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (swdc_di_dev == NULL) { + dprintf("Wheel: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = swdc_di_dev_start(swdc_di_dev, swdc_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx); + + dprintf("DirectInput: Controller initialized\n"); + + *backend = &swdc_di_backend; + + return S_OK; +} + +static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) +{ + const struct swdc_di_axis *brake_axis; + const struct swdc_di_axis *accel_axis; + int i; + + brake_axis = swdc_di_get_axis(cfg->brake_axis); + accel_axis = swdc_di_get_axis(cfg->accel_axis); + + if (brake_axis == NULL) { + dprintf("Wheel: Invalid brake axis: %S\n", cfg->brake_axis); + + return E_INVALIDARG; + } + + if (accel_axis == NULL) { + dprintf("Wheel: Invalid accel axis: %S\n", cfg->accel_axis); + + return E_INVALIDARG; + } + + if (cfg->start > 32) { + dprintf("Wheel: Invalid start button: %i\n", cfg->start); + + return E_INVALIDARG; + } + + if (cfg->view_chg > 32) { + dprintf("Wheel: Invalid view change button: %i\n", cfg->view_chg); + + return E_INVALIDARG; + } + + if (cfg->shift_dn > 32) { + dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn); + + return E_INVALIDARG; + } + + if (cfg->shift_up > 32) { + dprintf("Wheel: Invalid shift up button: %i\n", cfg->shift_up); + + return E_INVALIDARG; + } + + if (cfg->wheel_green > 32) { + dprintf("Wheel: Invalid steering wheel green button: %i\n", cfg->wheel_green); + + return E_INVALIDARG; + } + + if (cfg->wheel_red > 32) { + dprintf("Wheel: Invalid steering wheel red button: %i\n", cfg->wheel_red); + + return E_INVALIDARG; + } + + if (cfg->wheel_blue > 32) { + dprintf("Wheel: Invalid steering wheel blue button: %i\n", cfg->wheel_blue); + + return E_INVALIDARG; + } + + if (cfg->wheel_yellow > 32) { + dprintf("Wheel: Invalid steering wheel yellow button: %i\n", cfg->wheel_yellow); + + return E_INVALIDARG; + } + + /* Print some debug output to make sure config works... */ + + dprintf("Wheel: --- Begin configuration ---\n"); + dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", + cfg->device_name); + dprintf("Wheel: Brake axis . . . . . . : %S\n", accel_axis->name); + dprintf("Wheel: Accelerator axis . . . : %S\n", brake_axis->name); + dprintf("Wheel: Start button . . . . . : %i\n", cfg->start); + dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg); + dprintf("Wheel: Shift Down button . . : %i\n", cfg->shift_dn); + dprintf("Wheel: Shift Up button . . . : %i\n", cfg->shift_up); + dprintf("Wheel: Steering Green button : %i\n", cfg->wheel_green); + dprintf("Wheel: Steering Red button . : %i\n", cfg->wheel_red); + dprintf("Wheel: Steering Blue button . : %i\n", cfg->wheel_blue); + dprintf("Wheel: Steering Yellow button : %i\n", cfg->wheel_yellow); + dprintf("Wheel: Reverse Brake Axis . . : %i\n", cfg->reverse_brake_axis); + dprintf("Wheel: Reverse Accel Axis . . : %i\n", cfg->reverse_accel_axis); + dprintf("Wheel: --- End configuration ---\n"); + + swdc_di_off_brake = accel_axis->off; + swdc_di_off_accel = brake_axis->off; + swdc_di_start = cfg->start; + swdc_di_view_chg = cfg->view_chg; + swdc_di_shift_dn = cfg->shift_dn; + swdc_di_shift_up = cfg->shift_up; + swdc_di_wheel_green = cfg->wheel_green; + swdc_di_wheel_red = cfg->wheel_red; + swdc_di_wheel_blue = cfg->wheel_blue; + swdc_di_wheel_yellow = cfg->wheel_yellow; + swdc_di_reverse_brake_axis = cfg->reverse_brake_axis; + swdc_di_reverse_accel_axis = cfg->reverse_accel_axis; + + return S_OK; +} + +static const struct swdc_di_axis *swdc_di_get_axis(const wchar_t *name) +{ + const struct swdc_di_axis *axis; + size_t i; + + for (i = 0 ; i < _countof(swdc_di_axes) ; i++) { + axis = &swdc_di_axes[i]; + + if (wstr_ieq(name, axis->name)) { + return axis; + } + } + + return NULL; +} + +static BOOL CALLBACK swdc_di_enum_callback( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct swdc_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->device_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Wheel: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + swdc_di_api, + &dev->guidInstance, + &swdc_di_dev, + NULL); + + if (FAILED(hr)) { + dprintf("Wheel: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + +static void swdc_di_get_buttons(uint16_t *gamebtn_out) +{ + union swdc_di_state state; + uint8_t gamebtn; + HRESULT hr; + + assert(gamebtn_out != NULL); + + hr = swdc_di_dev_poll(swdc_di_dev, swdc_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + gamebtn = swdc_di_decode_pov(state.st.rgdwPOV[0]); + + if (swdc_di_start && state.st.rgbButtons[swdc_di_start - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_START; + } + + if (swdc_di_view_chg && state.st.rgbButtons[swdc_di_view_chg - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_VIEW_CHANGE; + } + + if (swdc_di_shift_dn && state.st.rgbButtons[swdc_di_shift_dn - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT; + } + + if (swdc_di_shift_up && state.st.rgbButtons[swdc_di_shift_up - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT; + } + + if (swdc_di_wheel_green && state.st.rgbButtons[swdc_di_wheel_green - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_GREEN; + } + + if (swdc_di_wheel_red && state.st.rgbButtons[swdc_di_wheel_red - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_RED; + } + + if (swdc_di_wheel_blue && state.st.rgbButtons[swdc_di_wheel_blue - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_BLUE; + } + + if (swdc_di_wheel_yellow && state.st.rgbButtons[swdc_di_wheel_yellow - 1]) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_YELLOW; + } + + *gamebtn_out = gamebtn; +} + +static uint8_t swdc_di_decode_pov(DWORD pov) +{ + switch (pov) { + case 0: return SWDC_IO_GAMEBTN_UP; + case 4500: return SWDC_IO_GAMEBTN_UP | SWDC_IO_GAMEBTN_RIGHT; + case 9000: return SWDC_IO_GAMEBTN_RIGHT; + case 13500: return SWDC_IO_GAMEBTN_RIGHT | SWDC_IO_GAMEBTN_DOWN; + case 18000: return SWDC_IO_GAMEBTN_DOWN; + case 22500: return SWDC_IO_GAMEBTN_DOWN | SWDC_IO_GAMEBTN_RIGHT; + case 27000: return SWDC_IO_GAMEBTN_LEFT; + case 31500: return SWDC_IO_GAMEBTN_LEFT | SWDC_IO_GAMEBTN_UP; + default: return 0; + } +} + +static void swdc_di_get_analogs(struct swdc_io_analog_state *out) +{ + union swdc_di_state state; + const LONG *brake; + const LONG *accel; + HRESULT hr; + + assert(out != NULL); + + hr = swdc_di_dev_poll(swdc_di_dev, swdc_di_wnd, &state); + + if (FAILED(hr)) { + return; + } + + brake = (LONG *) &state.bytes[swdc_di_off_brake]; + accel = (LONG *) &state.bytes[swdc_di_off_accel]; + + out->wheel = state.st.lX - 32768; + + if (swdc_di_reverse_brake_axis) { + out->brake = *brake; + } else { + out->brake = 65535 - *brake; + } + + if (swdc_di_reverse_accel_axis) { + out->accel = *accel; + } else { + out->accel = 65535 - *accel; + } +} diff --git a/swdcio/di.h b/swdcio/di.h new file mode 100644 index 0000000..6e4b32c --- /dev/null +++ b/swdcio/di.h @@ -0,0 +1,9 @@ +#pragma once + +#include "swdcio/backend.h" +#include "swdcio/config.h" + +HRESULT swdc_di_init( + const struct swdc_di_config *cfg, + HINSTANCE inst, + const struct swdc_io_backend **backend); diff --git a/swdcio/dllmain.c b/swdcio/dllmain.c new file mode 100644 index 0000000..ead174c --- /dev/null +++ b/swdcio/dllmain.c @@ -0,0 +1,112 @@ +#include + +#include +#include +#include + +#include "swdcio/backend.h" +#include "swdcio/config.h" +#include "swdcio/di.h" +#include "swdcio/swdcio.h" +#include "swdcio/xi.h" + +#include "util/dprintf.h" +#include "util/str.h" + +static struct swdc_io_config swdc_io_cfg; +static const struct swdc_io_backend *swdc_io_backend; +static bool swdc_io_coin; + +uint16_t swdc_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT swdc_io_init(void) +{ + HINSTANCE inst; + HRESULT hr; + + assert(swdc_io_backend == NULL); + + inst = GetModuleHandleW(NULL); + + if (inst == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("GetModuleHandleW failed: %lx\n", hr); + + return hr; + } + + swdc_io_config_load(&swdc_io_cfg, L".\\segatools.ini"); + + if (wstr_ieq(swdc_io_cfg.mode, L"dinput")) { + hr = swdc_di_init(&swdc_io_cfg.di, inst, &swdc_io_backend); + } else if (wstr_ieq(swdc_io_cfg.mode, L"xinput")) { + hr = swdc_xi_init(&swdc_io_cfg.xi, &swdc_io_backend); + } else { + hr = E_INVALIDARG; + dprintf("swdc IO: Invalid IO mode \"%S\", use dinput or xinput\n", + swdc_io_cfg.mode); + } + + return hr; +} + +void swdc_io_get_opbtns(uint8_t *opbtn_out) +{ + uint8_t opbtn; + + assert(swdc_io_backend != NULL); + assert(opbtn_out != NULL); + + opbtn = 0; + + if (GetAsyncKeyState(swdc_io_cfg.vk_test) & 0x8000) { + opbtn |= SWDC_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(swdc_io_cfg.vk_service) & 0x8000) { + opbtn |= SWDC_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(swdc_io_cfg.vk_coin) & 0x8000) { + if (!swdc_io_coin) { + swdc_io_coin = true; + opbtn |= SWDC_IO_OPBTN_COIN; + } + } else { + swdc_io_coin = false; + } + + *opbtn_out = opbtn; +} + + +void swdc_io_get_gamebtns(uint16_t *gamebtn_out) +{ + assert(swdc_io_backend != NULL); + assert(gamebtn_out != NULL); + + swdc_io_backend->get_gamebtns(gamebtn_out); +} + +void swdc_io_get_analogs(struct swdc_io_analog_state *out) +{ + struct swdc_io_analog_state tmp; + + assert(out != NULL); + assert(swdc_io_backend != NULL); + + swdc_io_backend->get_analogs(&tmp); + + /* Apply steering wheel restriction. Real cabs only report about 77% of + the IO-3's max ADC output value when the wheel is turned to either of + its maximum positions. To match this behavior we set the default value + for the wheel restriction config parameter to 97 (out of 128). This + scaling factor is applied using fixed-point arithmetic below. */ + + out->wheel = (tmp.wheel * swdc_io_cfg.restrict_) / 128; + out->accel = tmp.accel; + out->brake = tmp.brake; +} diff --git a/swdcio/meson.build b/swdcio/meson.build new file mode 100644 index 0000000..71e018a --- /dev/null +++ b/swdcio/meson.build @@ -0,0 +1,30 @@ +swdcio_lib = static_library( + 'swdccio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + dependencies : [ + dinput8_lib, + dxguid_lib, + xinput_lib, + ], + link_with : [ + util_lib, + ], + sources : [ + 'backend.h', + 'config.c', + 'config.h', + 'di.c', + 'di.h', + 'di-dev.c', + 'di-dev.h', + 'dllmain.c', + 'swdcio.h', + 'wnd.c', + 'wnd.h', + 'xi.c', + 'xi.h', + ], +) diff --git a/swdcio/swdcio.def b/swdcio/swdcio.def new file mode 100644 index 0000000..c2cb0ce --- /dev/null +++ b/swdcio/swdcio.def @@ -0,0 +1,8 @@ +LIBRARY swdcio + +EXPORTS + swdc_io_init + swdc_io_poll + swdc_io_get_opbtns + swdc_io_get_gamebtns + swdc_io_get_analogs diff --git a/swdcio/swdcio.h b/swdcio/swdcio.h new file mode 100644 index 0000000..5ce593c --- /dev/null +++ b/swdcio/swdcio.h @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include + +enum { + SWDC_IO_OPBTN_TEST = 0x01, + SWDC_IO_OPBTN_SERVICE = 0x02, + SWDC_IO_OPBTN_COIN = 0x04, +}; + +enum { + SWDC_IO_GAMEBTN_UP = 0x01, + SWDC_IO_GAMEBTN_DOWN = 0x02, + SWDC_IO_GAMEBTN_LEFT = 0x04, + SWDC_IO_GAMEBTN_RIGHT = 0x08, + SWDC_IO_GAMEBTN_START = 0x10, + SWDC_IO_GAMEBTN_VIEW_CHANGE = 0x20, + + SWDC_IO_GAMEBTN_STEERING_BLUE = 0x40, + SWDC_IO_GAMEBTN_STEERING_GREEN = 0x80, + SWDC_IO_GAMEBTN_STEERING_RED = 0x100, + SWDC_IO_GAMEBTN_STEERING_YELLOW = 0x200, + SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT = 0x400, + SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT = 0x800, +}; + +struct swdc_io_analog_state { + /* Current steering wheel position, where zero is the centered position. + + The game will accept any signed 16-bit position value, however a real + cabinet will report a value of approximately +/- 25230 when the wheel + is at full lock. Steering wheel positions of a magnitude greater than + this value are not possible on a real cabinet. */ + + int16_t wheel; + + /* Current position of the accelerator pedal, where 0 is released. */ + + uint16_t accel; + + /* Current position of the brake pedal, where 0 is released. */ + + uint16_t brake; +}; + +/* Get the version of the IDAC IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t swdc_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after mu3_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT swdc_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT swdc_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + MU3_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void swdc_io_get_opbtns(uint8_t *opbtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + MU3_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + a left hand side set of inputs and a right hand side set of inputs: the bit + mappings are the same in both cases. + + All buttons are active-high, even though some buttons' electrical signals + on a real cabinet are active-low. + + Minimum API version: 0x0100 */ + +void swdc_io_get_gamebtns(uint16_t *gamebtn); + +/* Poll the current state of the cabinet's JVS analog inputs. See structure + definition above for details. + + Minimum API version: 0x0100 */ + +void swdc_io_get_analogs(struct swdc_io_analog_state *out); diff --git a/swdcio/wnd.c b/swdcio/wnd.c new file mode 100644 index 0000000..66699ee --- /dev/null +++ b/swdcio/wnd.c @@ -0,0 +1,86 @@ +#include + +#include +#include + +#include "util/dprintf.h" + +/* DirectInput requires a window for correct initialization (and also force + feedback), so this source file provides some utilities for creating a + generic message-only window. */ + +static LRESULT WINAPI swdc_io_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wparam, + LPARAM lparam); + +HRESULT swdc_io_wnd_create(HINSTANCE inst, HWND *out) +{ + HRESULT hr; + WNDCLASSEXW wcx; + ATOM atom; + HWND hwnd; + + assert(inst != NULL); /* We are not an EXE */ + assert(out != NULL); + + *out = NULL; + + memset(&wcx, 0, sizeof(wcx)); + wcx.cbSize = sizeof(wcx); + wcx.lpfnWndProc = swdc_io_wnd_proc; + wcx.hInstance = inst; + wcx.lpszClassName = L"SWDCIO"; + + atom = RegisterClassExW(&wcx); + + if (atom == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("SWDCIO: RegisterClassExW failed: %08x\n", (int) hr); + + goto fail; + } + + hwnd = CreateWindowExW( + 0, + (wchar_t *) (intptr_t) atom, + L"", + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_MESSAGE, + NULL, + inst, + NULL); + + if (hwnd == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("SWDCIO: CreateWindowExW failed: %08x\n", (int) hr); + + goto fail; + } + + *out = hwnd; + + return S_OK; + +fail: + UnregisterClassW((wchar_t *) (intptr_t) atom, inst); + + return hr; +} + +static LRESULT WINAPI swdc_io_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wparam, + LPARAM lparam) +{ + switch (msg) { + default: + return DefWindowProcW(hwnd, msg, wparam, lparam); + } +} diff --git a/swdcio/wnd.h b/swdcio/wnd.h new file mode 100644 index 0000000..5ab4188 --- /dev/null +++ b/swdcio/wnd.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +HRESULT swdc_io_wnd_create(HINSTANCE inst, HWND *out); diff --git a/swdcio/xi.c b/swdcio/xi.c new file mode 100644 index 0000000..9be56a2 --- /dev/null +++ b/swdcio/xi.c @@ -0,0 +1,165 @@ +#include +#include + +#include +#include +#include + +#include "swdcio/backend.h" +#include "swdcio/config.h" +#include "swdcio/swdcio.h" +#include "swdcio/xi.h" + +#include "util/dprintf.h" + +static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out); +static void swdc_xi_get_analogs(struct swdc_io_analog_state *out); + +static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg); + +static const struct swdc_io_backend swdc_xi_backend = { + .get_gamebtns = swdc_xi_get_gamebtns, + .get_analogs = swdc_xi_get_analogs, +}; + +static bool swdc_xi_single_stick_steering; + +HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend) +{ + HRESULT hr; + assert(cfg != NULL); + assert(backend != NULL); + + hr = swdc_xi_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + dprintf("XInput: Using XInput controller\n"); + *backend = &swdc_xi_backend; + + return S_OK; +} + +HRESULT swdc_io_poll(void) +{ + return S_OK; +} + +static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg) +{ + dprintf("XInput: --- Begin configuration ---\n"); + dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); + dprintf("XInput: --- End configuration ---\n"); + + swdc_xi_single_stick_steering = cfg->single_stick_steering; + + return S_OK; +} + +static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out) +{ + uint16_t gamebtn; + XINPUT_STATE xi; + WORD xb; + + assert(gamebtn_out != NULL); + + gamebtn = 0; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xb & XINPUT_GAMEPAD_DPAD_UP) { + gamebtn |= SWDC_IO_GAMEBTN_UP; + } + + if (xb & XINPUT_GAMEPAD_DPAD_DOWN) { + gamebtn |= SWDC_IO_GAMEBTN_DOWN; + } + + if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + gamebtn |= SWDC_IO_GAMEBTN_LEFT; + } + + if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + gamebtn |= SWDC_IO_GAMEBTN_RIGHT; + } + + if (xb & XINPUT_GAMEPAD_START) { + gamebtn |= SWDC_IO_GAMEBTN_START; + } + + if (xb & XINPUT_GAMEPAD_BACK) { + gamebtn |= SWDC_IO_GAMEBTN_VIEW_CHANGE; + } + + if (xb & XINPUT_GAMEPAD_A) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_GREEN; + } + + if (xb & XINPUT_GAMEPAD_B) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_RED; + } + + if (xb & XINPUT_GAMEPAD_X) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_BLUE; + } + + if (xb & XINPUT_GAMEPAD_Y) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_YELLOW; + } + + if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT; + } + + if (xb & XINPUT_GAMEPAD_RIGHT_SHOULDER) { + gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT; + } + + *gamebtn_out = gamebtn; +} + +static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) +{ + XINPUT_STATE xi; + int left; + int right; + + assert(out != NULL); + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + left = xi.Gamepad.sThumbLX; + + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + right = xi.Gamepad.sThumbRX; + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } + + if (swdc_xi_single_stick_steering) { + out->wheel = left; + } else { + out->wheel = (left + right) / 2; + } + + out->accel = xi.Gamepad.bRightTrigger << 8; + out->brake = xi.Gamepad.bLeftTrigger << 8; +} diff --git a/swdcio/xi.h b/swdcio/xi.h new file mode 100644 index 0000000..15937ff --- /dev/null +++ b/swdcio/xi.h @@ -0,0 +1,10 @@ +#pragma once + +/* Can't call this xinput.h or it will conflict with */ + +#include + +#include "swdcio/backend.h" +#include "swdcio/config.h" + +HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend); From 90a6f1be7c25b0ca6f48bcfccf0c16d7a1aa6a34 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:54:30 +0200 Subject: [PATCH 014/204] mu3: coin input added --- dist/mu3/segatools.ini | 10 +++++++--- mu3hook/io4.c | 6 ++++++ mu3io/config.c | 22 ++++++++++++++++++++++ mu3io/config.h | 16 ++++++++++++++++ mu3io/meson.build | 2 ++ mu3io/mu3io.c | 17 +++++++++++++++-- mu3io/mu3io.h | 1 + 7 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 mu3io/config.c create mode 100644 mu3io/config.h diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 3279509..ef6df83 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -1,11 +1,11 @@ [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) -amfs=amfs +amfs= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. -appdata=appdata -option=option +appdata= +option= [dns] ; Insert the hostname or IP address of the server you wish to use here. @@ -40,8 +40,12 @@ enable=1 ; Set "1" to use a xinput gamepad and set "2" to use keyboard. mode=2 +; Test button virtual-key code. Default is the 1 key. test=0x31 +; Service button virtual-key code. Default is the 2 key. service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 [dinput] LEFT_A=0x53 diff --git a/mu3hook/io4.c b/mu3hook/io4.c index 7edcb0c..9515b50 100644 --- a/mu3hook/io4.c +++ b/mu3hook/io4.c @@ -11,6 +11,7 @@ #include "util/dprintf.h" static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; static const struct io4_ops mu3_io4_ops = { .poll = mu3_io4_poll, @@ -69,6 +70,11 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state) state->buttons[0] |= IO4_BUTTON_SERVICE; } + if (opbtn & MU3_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + if (left & MU3_IO_GAMEBTN_1) { state->buttons[0] |= 1 << 0; } diff --git a/mu3io/config.c b/mu3io/config.c new file mode 100644 index 0000000..2fd4989 --- /dev/null +++ b/mu3io/config.c @@ -0,0 +1,22 @@ +#include + +#include +#include +#include + +#include "mu3io/config.h" + +void mu3_io_config_load( + struct mu3_io_config *cfg, + const wchar_t *filename) +{ + wchar_t key[16]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); +} diff --git a/mu3io/config.h b/mu3io/config.h new file mode 100644 index 0000000..f3632ce --- /dev/null +++ b/mu3io/config.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +struct mu3_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; +}; + +void mu3_io_config_load( + struct mu3_io_config *cfg, + const wchar_t *filename); diff --git a/mu3io/meson.build b/mu3io/meson.build index 3d6e60e..0b509bd 100644 --- a/mu3io/meson.build +++ b/mu3io/meson.build @@ -10,5 +10,7 @@ mu3io_lib = static_library( sources : [ 'mu3io.c', 'mu3io.h', + 'config.c', + 'config.h', ], ) diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index 0bbd37f..775a1b4 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -5,12 +5,15 @@ #include #include "mu3io/mu3io.h" +#include "mu3io/config.h" static uint8_t mu3_opbtn; static uint8_t mu3_left_btn; static uint8_t mu3_right_btn; static int16_t mu3_lever_pos; static int16_t mu3_lever_xpos; +static struct mu3_io_config mu3_io_cfg; +static bool mu3_io_coin; uint16_t mu3_io_get_api_version(void) { @@ -19,6 +22,7 @@ uint16_t mu3_io_get_api_version(void) HRESULT mu3_io_init(void) { + mu3_io_config_load(&mu3_io_cfg, L".\\segatools.ini"); return S_OK; } @@ -33,14 +37,23 @@ HRESULT mu3_io_poll(void) mu3_left_btn = 0; mu3_right_btn = 0; - if (GetAsyncKeyState('1') & 0x8000) { + if (GetAsyncKeyState(mu3_io_cfg.vk_test) & 0x8000) { mu3_opbtn |= MU3_IO_OPBTN_TEST; } - if (GetAsyncKeyState('2') & 0x8000) { + if (GetAsyncKeyState(mu3_io_cfg.vk_service) & 0x8000) { mu3_opbtn |= MU3_IO_OPBTN_SERVICE; } + if (GetAsyncKeyState(mu3_io_cfg.vk_coin) & 0x8000) { + if (!mu3_io_coin) { + mu3_io_coin = true; + mu3_opbtn |= MU3_IO_OPBTN_COIN; + } + } else { + mu3_io_coin = false; + } + memset(&xi, 0, sizeof(xi)); XInputGetState(0, &xi); xb = xi.Gamepad.wButtons; diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h index d46a475..a156038 100644 --- a/mu3io/mu3io.h +++ b/mu3io/mu3io.h @@ -7,6 +7,7 @@ enum { MU3_IO_OPBTN_TEST = 0x01, MU3_IO_OPBTN_SERVICE = 0x02, + MU3_IO_OPBTN_COIN = 0x04, }; enum { From 2a6a8bf8b22365509701dd031dcc14fc6e30ebbc Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:58:02 +0200 Subject: [PATCH 015/204] chusan: added chusanhook, led board fix, config added credits go to @domeori https://dev.s-ul.net/domeori/segatools/-/tree/mr-imports --- Package.mk | 21 ++ board/led1509306-cmd.h | 45 +++++ board/led1509306-frame.c | 194 +++++++++++++++++++ board/led1509306-frame.h | 26 +++ board/meson.build | 3 + chunihook/config.c | 30 +++ chunihook/config.h | 2 + chunihook/dllmain.c | 7 + chunihook/jvs.c | 4 +- chunihook/led1509306.c | 377 ++++++++++++++++++++++++++++++++++++ chunihook/led1509306.h | 16 ++ chunihook/meson.build | 2 + chuniio/chuniio.c | 110 +++++++++-- chuniio/chuniio.h | 6 + chuniio/config.c | 22 ++- chuniio/config.h | 4 +- chusanhook/chuni-dll.c | 118 ++++++++++++ chusanhook/chuni-dll.h | 24 +++ chusanhook/chusanhook.def | 22 +++ chusanhook/config.c | 122 ++++++++++++ chusanhook/config.h | 34 ++++ chusanhook/dllmain.c | 147 ++++++++++++++ chusanhook/io4.c | 107 +++++++++++ chusanhook/io4.h | 5 + chusanhook/led1509306.c | 389 ++++++++++++++++++++++++++++++++++++++ chusanhook/led1509306.h | 15 ++ chusanhook/meson.build | 34 ++++ chusanhook/slider.c | 249 ++++++++++++++++++++++++ chusanhook/slider.h | 11 ++ dist/chusan/segatools.ini | 112 +++++++++++ dist/chusan/start.bat | 11 ++ meson.build | 1 + 32 files changed, 2253 insertions(+), 17 deletions(-) create mode 100644 board/led1509306-cmd.h create mode 100644 board/led1509306-frame.c create mode 100644 board/led1509306-frame.h create mode 100644 chunihook/led1509306.c create mode 100644 chunihook/led1509306.h create mode 100644 chusanhook/chuni-dll.c create mode 100644 chusanhook/chuni-dll.h create mode 100644 chusanhook/chusanhook.def create mode 100644 chusanhook/config.c create mode 100644 chusanhook/config.h create mode 100644 chusanhook/dllmain.c create mode 100644 chusanhook/io4.c create mode 100644 chusanhook/io4.h create mode 100644 chusanhook/led1509306.c create mode 100644 chusanhook/led1509306.h create mode 100644 chusanhook/meson.build create mode 100644 chusanhook/slider.c create mode 100644 chusanhook/slider.h create mode 100644 dist/chusan/segatools.ini create mode 100644 dist/chusan/start.bat diff --git a/Package.mk b/Package.mk index 4562bf1..bb8335c 100644 --- a/Package.mk +++ b/Package.mk @@ -118,6 +118,26 @@ $(BUILD_DIR_ZIP)/mercury.zip: $(V)strip $(BUILD_DIR_ZIP)/mercury/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/mercury ; zip -r ../mercury.zip * +$(BUILD_DIR_ZIP)/chusan.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/chusan + $(V)mkdir -p $(BUILD_DIR_ZIP)/chusan/DEVICE + $(V)cp $(DIST_DIR)/chusan/segatools.ini \ + $(DIST_DIR)/chusan/start.bat \ + $(BUILD_DIR_ZIP)/chusan + $(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \ + $(BUILD_DIR_ZIP)/chusan/chusanhook_x86.dll + $(V)cp $(BUILD_DIR_64)/chusanhook/chusanhook.dll \ + $(BUILD_DIR_ZIP)/chusan/chusanhook_x64.dll + $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_ZIP)/chusan/inject_x86.exe + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_ZIP)/chusan/inject_x64.exe + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/chusan/DEVICE + for x in exe dll; do strip $(BUILD_DIR_ZIP)/chusan/*.$$x; done + $(V)cd $(BUILD_DIR_ZIP)/chusan ; zip -r ../chusan.zip * $(BUILD_DIR_ZIP)/mu3.zip: $(V)echo ... $@ @@ -152,6 +172,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/idac.zip \ $(BUILD_DIR_ZIP)/swdc.zip \ $(BUILD_DIR_ZIP)/mercury.zip \ + $(BUILD_DIR_ZIP)/chusan.zip \ $(BUILD_DIR_ZIP)/mu3.zip \ CHANGELOG.md \ README.md \ diff --git a/board/led1509306-cmd.h b/board/led1509306-cmd.h new file mode 100644 index 0000000..78019dc --- /dev/null +++ b/board/led1509306-cmd.h @@ -0,0 +1,45 @@ +#pragma once + +#include "board/led1509306-frame.h" + +enum { + LED_15093_06_CMD_RESET = 0x10, + LED_15093_06_CMD_SET_TIMEOUT = 0x11, + LED_15093_06_CMD_SET_DISABLE_RESPONSE = 0x14, + LED_15093_06_CMD_SET_LED = 0x82, + LED_15093_06_CMD_SET_LED_COUNT = 0x86, + LED_15093_06_CMD_BOARD_INFO = 0xF0, + LED_15093_06_CMD_BOARD_STATUS = 0xF1, + LED_15093_06_CMD_FW_SUM = 0xF2, + LED_15093_06_CMD_PROTOCOL_VER = 0xF3, + LED_15093_06_CMD_BOOTLOADER = 0xFD, +}; + +struct led1509306_req_any { + struct led1509306_hdr hdr; + uint8_t cmd; + uint8_t payload[256]; +}; + +struct led1509306_resp_any { + struct led1509306_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t data[32]; +}; + +struct led1509306_resp_board_info { + struct led1509306_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + struct { + char board_num[8]; + uint8_t _0a; + char chip_num[5]; + uint8_t _ff; + uint8_t fw_ver; + // may be some more data after this that isn't checked + } data; +}; \ No newline at end of file diff --git a/board/led1509306-frame.c b/board/led1509306-frame.c new file mode 100644 index 0000000..8e11e8c --- /dev/null +++ b/board/led1509306-frame.c @@ -0,0 +1,194 @@ +#include + +#include +#include +#include +#include + +#include "board/led1509306-frame.h" + +#include "hook/iobuf.h" + +static void led1509306_frame_sync(struct iobuf *src); +static HRESULT led1509306_frame_accept(const struct iobuf *dest); +static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte); + +/* Frame structure: + + [0] Sync byte (0xE0) + [1] Destination address + [2] Source Address + [3] Length of data/payload + [4] Data/payload + For requests (host to board): + [0] Command + ... Payload + For responses (board to host): + [0] Status + [1] Command + [2] Report + ... Payload + [n] Checksum: Sum of all prior bytes (excluding sync byte) + + Byte stuffing: + + 0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */ + +static void led1509306_frame_sync(struct iobuf *src) +{ + size_t i; + + for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++); + + src->pos -= i; + memmove(&src->bytes[0], &src->bytes[i], i); +} + +static HRESULT led1509306_frame_accept(const struct iobuf *dest) +{ + uint8_t checksum; + size_t i; + + if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) { + return S_FALSE; + } + + checksum = 0; + + for (i = 1 ; i < dest->pos - 1 ; i++) { + checksum += dest->bytes[i]; + } + + //dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]); + + if (checksum != dest->bytes[dest->pos - 1]) { + return HRESULT_FROM_WIN32(ERROR_CRC); + } + + return S_OK; +} + +HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) +{ + uint8_t byte; + bool escape; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(src != NULL); + assert(src->bytes != NULL || src->nbytes == 0); + assert(src->pos <= src->nbytes); + + led1509306_frame_sync(src); + + dest->pos = 0; + escape = false; + + for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) { + /* Step the FSM to unstuff another byte */ + + byte = src->bytes[i]; + + if (dest->pos >= dest->nbytes) { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } else if (i == 0) { + dest->bytes[dest->pos++] = byte; + } else if (byte == 0xE0) { + hr = E_FAIL; + } else if (byte == 0xD0) { + if (escape) { + hr = E_FAIL; + } + + escape = true; + } else if (escape) { + dest->bytes[dest->pos++] = byte + 1; + escape = false; + } else { + dest->bytes[dest->pos++] = byte; + } + + /* Try to accept the packet we've built up so far */ + + if (SUCCEEDED(hr)) { + hr = led1509306_frame_accept(dest); + } + } + + /* Handle FSM terminal state */ + + if (hr != S_FALSE) { + /* Frame was either accepted or rejected, remove it from src */ + memmove(&src->bytes[0], &src->bytes[i], src->pos - i); + src->pos -= i; + } + + return hr; +} + +HRESULT led1509306_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes) +{ + const uint8_t *src; + uint8_t checksum; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes); + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xE0; + checksum = 0; + // dprintf("%02x ", 0xe0); + + for (i = 1 ; i < nbytes ; i++) { + byte = src[i]; + checksum += byte; + // dprintf("%02x ", byte); + + hr = led1509306_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } + // dprintf("%02x \n", checksum); + + return led1509306_frame_encode_byte(dest, checksum); +} + +static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte) +{ + if (byte == 0xE0 || byte == 0xD0) { + if (dest->pos + 2 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = byte - 1; + } else { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + } + + return S_OK; +} diff --git a/board/led1509306-frame.h b/board/led1509306-frame.h new file mode 100644 index 0000000..a39493e --- /dev/null +++ b/board/led1509306-frame.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + LED_15093_06_FRAME_SYNC = 0xE0, +}; + +struct led1509306_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src); + +HRESULT led1509306_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/meson.build b/board/meson.build index d463d9a..df6ce92 100644 --- a/board/meson.build +++ b/board/meson.build @@ -20,6 +20,9 @@ board_lib = static_library( 'io3.h', 'io4.c', 'io4.h', + 'led1509306-cmd.h', + 'led1509306-frame.c', + 'led1509306-frame.h', 'sg-cmd.c', 'sg-cmd.h', 'sg-frame.c', diff --git a/chunihook/config.c b/chunihook/config.c index 0f049b2..afc7fae 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -43,6 +43,35 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); } +void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); + + GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } +} + void chuni_hook_config_load( struct chuni_hook_config *cfg, const wchar_t *filename) @@ -58,4 +87,5 @@ void chuni_hook_config_load( gfx_config_load(&cfg->gfx, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); + led1509306_config_load(&cfg->led1509306, filename); } diff --git a/chunihook/config.h b/chunihook/config.h index 7740822..d7a392b 100644 --- a/chunihook/config.h +++ b/chunihook/config.h @@ -9,6 +9,7 @@ #include "chunihook/chuni-dll.h" #include "chunihook/slider.h" +#include "chunihook/led1509306.h" #include "gfxhook/gfx.h" @@ -21,6 +22,7 @@ struct chuni_hook_config { struct gfx_config gfx; struct chuni_dll_config dll; struct slider_config slider; + struct led1509306_config led1509306; }; void chuni_dll_config_load( diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 5350eb9..5303378 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -9,6 +9,7 @@ #include "chunihook/config.h" #include "chunihook/jvs.h" #include "chunihook/slider.h" +#include "chunihook/led1509306.h" #include "chuniio/chuniio.h" @@ -96,6 +97,12 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } + hr = led1509306_hook_init(&chuni_hook_cfg.led1509306); + + if (FAILED(hr)) { + goto fail; + } + hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, chuni_hook_mod); if (FAILED(hr)) { diff --git a/chunihook/jvs.c b/chunihook/jvs.c index 8c630d4..85c2076 100644 --- a/chunihook/jvs.c +++ b/chunihook/jvs.c @@ -101,13 +101,13 @@ static void chunithm_jvs_read_switches(void *ctx, struct io3_switch_state *out) out->p1 = 0x0000; out->p2 = 0x0000; - if (opbtn & 0x01) { + if (opbtn & CHUNI_IO_OPBTN_TEST) { out->system = 0x80; } else { out->system = 0x00; } - if (opbtn & 0x02) { + if (opbtn & CHUNI_IO_OPBTN_SERVICE) { out->p1 |= 0x4000; } diff --git a/chunihook/led1509306.c b/chunihook/led1509306.c new file mode 100644 index 0000000..16a3b32 --- /dev/null +++ b/chunihook/led1509306.c @@ -0,0 +1,377 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/led1509306-cmd.h" +#include "board/led1509306-frame.h" + +#include "chunihook/led1509306.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT led1509306_handle_irp(struct irp *irp); +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_get_board_info(int board); +static HRESULT led1509306_req_get_fw_sum(int board); +static HRESULT led1509306_req_get_protocol_ver(int board); +static HRESULT led1509306_req_get_board_status(int board); +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); + +static char led1509306_board_num[8]; +static char led1509306_chip_num[5]; +static uint8_t led1509306_fw_ver; +static uint16_t led1509306_fw_sum; +static uint8_t led1509306_board_adr = 2; +static uint8_t led1509306_host_adr = 1; + +#define led1509306_nboards 2 + +typedef struct { + CRITICAL_SECTION lock; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + bool enable_response; +} _led1509306_per_board_vars; + +_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); + memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); + led1509306_fw_ver = cfg->fw_ver; + led1509306_fw_sum = cfg->fw_sum; + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + + InitializeCriticalSection(&v->lock); + + uart_init(&v->boarduart, 10 + i); + v->boarduart.written.bytes = v->written_bytes; + v->boarduart.written.nbytes = sizeof(v->written_bytes); + v->boarduart.readable.bytes = v->readable_bytes; + v->boarduart.readable.nbytes = sizeof(v->readable_bytes); + + v->enable_response = true; + } + + return iohook_push_handler(led1509306_handle_irp); +} + +static HRESULT led1509306_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led1509306_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) +{ + struct led1509306_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led1509306_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); + } + } +} + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) +{ + switch (req->cmd) { + case LED_15093_06_CMD_RESET: + return led1509306_req_reset(board, req); + + case LED_15093_06_CMD_BOARD_INFO: + return led1509306_req_get_board_info(board); + + case LED_15093_06_CMD_FW_SUM: + return led1509306_req_get_fw_sum(board); + + case LED_15093_06_CMD_PROTOCOL_VER: + return led1509306_req_get_protocol_ver(board); + + case LED_15093_06_CMD_BOARD_STATUS: + return led1509306_req_get_board_status(board); + + case LED_15093_06_CMD_SET_LED: + return led1509306_req_set_led(board, req); + + case LED_15093_06_CMD_SET_DISABLE_RESPONSE: + return led1509306_req_set_disable_response(board, req); + + case LED_15093_06_CMD_SET_TIMEOUT: + return led1509306_req_set_timeout(board, req); + + default: + dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); + + return S_OK; + } +} + +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); + + if (req->payload[0] != 0xd9) + dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); + + led1509306_per_board_vars[board].enable_response = true; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_RESET; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_info(int board) +{ + dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); + + struct led1509306_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = sizeof(resp.data) + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_INFO; + resp.report = 1; + + memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); + resp.data._0a = 0x0a; + memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); + resp.data._ff = 0xff; + resp.data.fw_ver = led1509306_fw_ver; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_fw_sum(int board) +{ + dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_FW_SUM; + resp.report = 1; + + resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; + resp.data[1] = led1509306_fw_sum & 0xff; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_protocol_ver(int board) +{ + dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; + resp.report = 1; + + resp.data[0] = 1; + resp.data[1] = 1; + resp.data[2] = 4; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_status(int board) +{ + dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 4 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_STATUS; + resp.report = 1; + + resp.data[0] = 0; + resp.data[1] = 0; + resp.data[2] = 0; + resp.data[3] = 0; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) +{ + // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); + + if (!led1509306_per_board_vars[board].enable_response) + return S_OK; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_LED; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); + + led1509306_per_board_vars[board].enable_response = !req->payload[0]; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 1 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; + resp.report = 1; + + resp.data[0] = req->payload[0]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); + + // not actually implemented, but respond correctly anyway + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; + resp.report = 1; + + resp.data[0] = req->payload[0]; + resp.data[1] = req->payload[1]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} diff --git a/chunihook/led1509306.h b/chunihook/led1509306.h new file mode 100644 index 0000000..03dc62a --- /dev/null +++ b/chunihook/led1509306.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include + +struct led1509306_config { + bool enable; + bool cvt_port; + char board_number[8]; + char chip_number[5]; + uint8_t fw_ver; + uint16_t fw_sum; +}; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/chunihook/meson.build b/chunihook/meson.build index 3f4a35d..b4c464d 100644 --- a/chunihook/meson.build +++ b/chunihook/meson.build @@ -30,5 +30,7 @@ shared_library( 'jvs.h', 'slider.c', 'slider.h', + 'led1509306.c', + 'led1509306.h', ], ) diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 4fffe69..86938be 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -3,10 +3,13 @@ #include #include #include +#include #include "chuniio/chuniio.h" #include "chuniio/config.h" +#include "util/dprintf.h" + static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx); static bool chuni_io_coin; @@ -15,6 +18,7 @@ static uint8_t chuni_io_hand_pos; static HANDLE chuni_io_slider_thread; static bool chuni_io_slider_stop_flag; static struct chuni_io_config chuni_io_cfg; +static HANDLE chuni_io_slider_led_port; uint16_t chuni_io_get_api_version(void) { @@ -50,27 +54,48 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) { size_t i; - if (GetAsyncKeyState(chuni_io_cfg.vk_test)) { - *opbtn |= 0x01; /* Test */ + if (GetAsyncKeyState(chuni_io_cfg.vk_test) & 0x8000) { + *opbtn |= CHUNI_IO_OPBTN_TEST; } - if (GetAsyncKeyState(chuni_io_cfg.vk_service)) { - *opbtn |= 0x02; /* Service */ + if (GetAsyncKeyState(chuni_io_cfg.vk_service) & 0x8000) { + *opbtn |= CHUNI_IO_OPBTN_SERVICE; } - if (GetAsyncKeyState(chuni_io_cfg.vk_ir)) { - if (chuni_io_hand_pos < 6) { - chuni_io_hand_pos++; + if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) { + if (!chuni_io_coin) { + chuni_io_coin = true; + *opbtn |= CHUNI_IO_OPBTN_COIN; } } else { - if (chuni_io_hand_pos > 0) { - chuni_io_hand_pos--; - } + chuni_io_coin = false; } - for (i = 0 ; i < 6 ; i++) { - if (chuni_io_hand_pos > i) { - *beams |= (1 << i); + if (chuni_io_cfg.vk_ir_emu) { + // Use emulated AIR + if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) { + if (chuni_io_hand_pos < 6) { + chuni_io_hand_pos++; + } + } else { + if (chuni_io_hand_pos > 0) { + chuni_io_hand_pos--; + } + } + + for (i = 0 ; i < 6 ; i++) { + if (chuni_io_hand_pos > i) { + *beams |= (1 << i); + } + } + } else { + // Use actual AIR + // IR format is beams[5:0] = {b5,b6,b3,b4,b1,b2}; + for (i = 0 ; i < 3 ; i++) { + if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2]) & 0x8000) + *beams |= (1 << (i*2+1)); + if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2+1]) & 0x8000) + *beams |= (1 << (i*2)); } } } @@ -82,6 +107,8 @@ HRESULT chuni_io_slider_init(void) void chuni_io_slider_start(chuni_io_slider_callback_t callback) { + BOOL status; + if (chuni_io_slider_thread != NULL) { return; } @@ -93,6 +120,39 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback) callback, 0, NULL); + + chuni_io_slider_led_port = CreateFileW(chuni_io_cfg.led_com, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (chuni_io_slider_led_port == INVALID_HANDLE_VALUE) + dprintf("Chunithm LEDs: Failed to open COM port (Attempted on %S)\n", chuni_io_cfg.led_com); + else + dprintf("Chunithm LEDs: COM Port Success!\n"); + + DCB dcb_serial_params = { 0 }; + dcb_serial_params.DCBlength = sizeof(dcb_serial_params); + status = GetCommState(chuni_io_slider_led_port, &dcb_serial_params); + + dcb_serial_params.BaudRate = CBR_115200; // Setting BaudRate = 115200 + dcb_serial_params.ByteSize = 8; // Setting ByteSize = 8 + dcb_serial_params.StopBits = ONESTOPBIT;// Setting StopBits = 1 + dcb_serial_params.Parity = NOPARITY; // Setting Parity = None + SetCommState(chuni_io_slider_led_port, &dcb_serial_params); + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; // in milliseconds + timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds + timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds + timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds + timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds + + SetCommTimeouts(chuni_io_slider_led_port, &timeouts); + } void chuni_io_slider_stop(void) @@ -107,10 +167,34 @@ void chuni_io_slider_stop(void) CloseHandle(chuni_io_slider_thread); chuni_io_slider_thread = NULL; chuni_io_slider_stop_flag = false; + + dprintf("Chunithm LEDs: Closing COM port\n"); + CloseHandle(chuni_io_slider_led_port); } void chuni_io_slider_set_leds(const uint8_t *rgb) { + if (chuni_io_slider_led_port != INVALID_HANDLE_VALUE) + { + char led_buffer[100]; + DWORD bytes_to_write; // No of bytes to write into the port + DWORD bytes_written = 0; // No of bytes written to the port + bytes_to_write = sizeof(led_buffer); + BOOL status; + + led_buffer[0] = 0xAA; + led_buffer[1] = 0xAA; + memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96); + led_buffer[98] = 0xDD; + led_buffer[99] = 0xDD; + + status = WriteFile(chuni_io_slider_led_port, // Handle to the Serial port + led_buffer, // Data to be written to the port + bytes_to_write, //No of bytes to write + &bytes_written, //Bytes written + NULL); + } + } static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index 2a24600..08a30ca 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -15,6 +15,12 @@ #include #include +enum { + CHUNI_IO_OPBTN_TEST = 0x01, + CHUNI_IO_OPBTN_SERVICE = 0x02, + CHUNI_IO_OPBTN_COIN = 0x04, +}; + /* Get the version of the Chunithm IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the diff --git a/chuniio/config.c b/chuniio/config.c index 7365f2c..580a056 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "chuniio/config.h" @@ -17,20 +18,35 @@ static const int chuni_io_default_cells[] = { 'S', 'S', 'S', 'S', }; +static const int chuni_io_default_ir[] = { + '4', '5', '6', '7', '8', '9' +}; + void chuni_io_config_load( struct chuni_io_config *cfg, const wchar_t *filename) { wchar_t key[16]; int i; + wchar_t port_input[6]; assert(cfg != NULL); assert(filename != NULL); + // Technically it's io4 but leave this for compatibility with old configs. cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); - cfg->vk_ir = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename); + cfg->vk_ir_emu = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename); + + for (i = 0 ; i < 6 ; i++) { + swprintf_s(key, _countof(key), L"ir%i", i + 1); + cfg->vk_ir[i] = GetPrivateProfileIntW( + L"ir", + key, + chuni_io_default_ir[i], + filename); + } for (i = 0 ; i < 32 ; i++) { swprintf_s(key, _countof(key), L"cell%i", i + 1); @@ -40,4 +56,8 @@ void chuni_io_config_load( chuni_io_default_cells[i], filename); } + + GetPrivateProfileStringW(L"slider", L"ledport", L"COM2", port_input, 6, filename); + wcsncpy(cfg->led_com, L"\\\\.\\", 4); + wcsncat_s(cfg->led_com, 11, port_input, 6); } diff --git a/chuniio/config.h b/chuniio/config.h index fa2e2b0..b615804 100644 --- a/chuniio/config.h +++ b/chuniio/config.h @@ -7,8 +7,10 @@ struct chuni_io_config { uint8_t vk_test; uint8_t vk_service; uint8_t vk_coin; - uint8_t vk_ir; + uint8_t vk_ir_emu; + uint8_t vk_ir[6]; uint8_t vk_cell[32]; + wchar_t led_com[12]; }; void chuni_io_config_load( diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c new file mode 100644 index 0000000..c946043 --- /dev/null +++ b/chusanhook/chuni-dll.c @@ -0,0 +1,118 @@ +#include + +#include +#include + +#include "chusanhook/chuni-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym chuni_dll_syms[] = { + { + .sym = "chuni_io_jvs_init", + .off = offsetof(struct chuni_dll, jvs_init), + }, { + .sym = "chuni_io_jvs_poll", + .off = offsetof(struct chuni_dll, jvs_poll), + }, { + .sym = "chuni_io_jvs_read_coin_counter", + .off = offsetof(struct chuni_dll, jvs_read_coin_counter), + }, { + .sym = "chuni_io_slider_init", + .off = offsetof(struct chuni_dll, slider_init), + }, { + .sym = "chuni_io_slider_start", + .off = offsetof(struct chuni_dll, slider_start), + }, { + .sym = "chuni_io_slider_stop", + .off = offsetof(struct chuni_dll, slider_stop), + }, { + .sym = "chuni_io_slider_set_leds", + .off = offsetof(struct chuni_dll, slider_set_leds), + } +}; + +struct chuni_dll chuni_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Chunithm IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version"); + + if (get_api_version != NULL) { + chuni_dll.api_version = get_api_version(); + } else { + chuni_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose chuni_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (chuni_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Chunithm IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + chuni_dll.api_version); + + goto end; + } + + sym = chuni_dll_syms; + hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Chunithm IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/chusanhook/chuni-dll.h b/chusanhook/chuni-dll.h new file mode 100644 index 0000000..ecd88ee --- /dev/null +++ b/chusanhook/chuni-dll.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "chuniio/chuniio.h" + +struct chuni_dll { + uint16_t api_version; + HRESULT (*jvs_init)(void); + void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams); + void (*jvs_read_coin_counter)(uint16_t *total); + HRESULT (*slider_init)(void); + void (*slider_start)(chuni_io_slider_callback_t callback); + void (*slider_stop)(void); + void (*slider_set_leds)(const uint8_t *rgb); +}; + +struct chuni_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct chuni_dll chuni_dll; + +HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self); diff --git a/chusanhook/chusanhook.def b/chusanhook/chusanhook.def new file mode 100644 index 0000000..5039c7d --- /dev/null +++ b/chusanhook/chusanhook.def @@ -0,0 +1,22 @@ +LIBRARY chusanhook + +EXPORTS + Direct3DCreate9 + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + chuni_io_get_api_version + chuni_io_jvs_init + chuni_io_jvs_poll + chuni_io_jvs_read_coin_counter + chuni_io_slider_init + chuni_io_slider_set_leds + chuni_io_slider_start + chuni_io_slider_stop diff --git a/chusanhook/config.c b/chusanhook/config.c new file mode 100644 index 0000000..7b290f3 --- /dev/null +++ b/chusanhook/config.c @@ -0,0 +1,122 @@ +#include +#include + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "gfxhook/config.h" + +#include "platform/config.h" + +#include "chusanhook/config.h" + +// Check windows +#if _WIN32 || _WIN64 + #if _WIN64 + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +// Check GCC +#if __GNUC__ + #if __x86_64__ || __ppc64__ + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +void chuni_dll_config_load( + struct chuni_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + // Workaround for x64/x86 external IO dlls + // path32 for 32bit, path64 for 64bit + // for else.. is that possible? idk + + #if defined(ENV32BIT) + GetPrivateProfileStringW( + L"chuniio", + L"path32", + L"", + cfg->path, + _countof(cfg->path), + filename); + #elif defined(ENV64BIT) + GetPrivateProfileStringW( + L"chuniio", + L"path64", + L"", + cfg->path, + _countof(cfg->path), + filename); + #else + #error "Unknown environment" + #endif + +} + +void slider_config_load(struct slider_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); +} + +void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); + cfg->cvt_port = GetPrivateProfileIntW(L"ledstrip", L"cvt_port", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); + + GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } +} + + +void chusan_hook_config_load( + struct chusan_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + memset(cfg, 0, sizeof(*cfg)); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + gfx_config_load(&cfg->gfx, filename); + chuni_dll_config_load(&cfg->dll, filename); + slider_config_load(&cfg->slider, filename); + led1509306_config_load(&cfg->led1509306, filename); +} diff --git a/chusanhook/config.h b/chusanhook/config.h new file mode 100644 index 0000000..e98059e --- /dev/null +++ b/chusanhook/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" + +#include "gfxhook/config.h" + +#include "platform/config.h" + +#include "chusanhook/chuni-dll.h" +#include "chusanhook/slider.h" +#include "chunihook/led1509306.h" + +struct chusan_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct gfx_config gfx; + struct chuni_dll_config dll; + struct slider_config slider; + struct led1509306_config led1509306; +}; + +void chuni_dll_config_load( + struct chuni_dll_config *cfg, + const wchar_t *filename); +void slider_config_load(struct slider_config *cfg, const wchar_t *filename); +void chusan_hook_config_load( + struct chusan_hook_config *cfg, + const wchar_t *filename); diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c new file mode 100644 index 0000000..28aa8e3 --- /dev/null +++ b/chusanhook/dllmain.c @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include "amex/amex.h" + +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "chusanhook/config.h" +#include "chusanhook/io4.h" +#include "chusanhook/slider.h" +#include "chunihook/led1509306.h" + +#include "chuniio/chuniio.h" + +#include "hook/process.h" + +#include "gfxhook/d3d9.h" +#include "gfxhook/gfx.h" + +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE chusan_hook_mod; +static process_entry_t chusan_startup; +static struct chusan_hook_config chusan_hook_cfg; + +static DWORD CALLBACK chusan_pre_startup(void) +{ + HMODULE d3dc; + HMODULE dbghelp; + HRESULT hr; + + dprintf("--- Begin chusan_pre_startup ---\n"); + + /* Pin the D3D shader compiler. This makes startup much faster. */ + + d3dc = LoadLibraryW(L"D3DCompiler_43.dll"); + + if (d3dc != NULL) { + dprintf("Pinned shader compiler, hMod=%p\n", d3dc); + } else { + dprintf("Failed to load shader compiler!\n"); + } + + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } else { + dprintf("Failed to load debug helper library!\n"); + } + + /* Config load */ + + chusan_hook_config_load(&chusan_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&chusan_hook_cfg.dvd, chusan_hook_mod); + gfx_hook_init(&chusan_hook_cfg.gfx); + gfx_d3d9_hook_init(&chusan_hook_cfg.gfx, chusan_hook_mod); + serial_hook_init(); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &chusan_hook_cfg.platform, + "SDHD", + "ACA2", + chusan_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = chuni_dll_init(&chusan_hook_cfg.dll, chusan_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = chusan_io4_hook_init(&chusan_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + hr = slider_hook_init(&chusan_hook_cfg.slider); + + if (FAILED(hr)) { + goto fail; + } + + hr = led1509306_hook_init(&chusan_hook_cfg.led1509306); + + if (FAILED(hr)) { + goto fail; + } + + + hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, chusan_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End chusan_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return chusan_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + chusan_hook_mod = mod; + + hr = process_hijack_startup(chusan_pre_startup, &chusan_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/chusanhook/io4.c b/chusanhook/io4.c new file mode 100644 index 0000000..2495369 --- /dev/null +++ b/chusanhook/io4.c @@ -0,0 +1,107 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "chusanhook/chuni-dll.h" +#include "util/dprintf.h" + +struct chunithm_jvs_ir_mask { + uint16_t p1; + uint16_t p2; +}; + +// Incorrect IR beam mappings retained for backward compatibility +static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks_v1[] = { + { 0, 1 << 13 }, + { 1 << 13, 0 }, + { 0, 1 << 12 }, + { 1 << 12, 0 }, + { 0, 1 << 11 }, + { 1 << 11, 0 }, +}; + +static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks[] = { + { 1 << 13, 0 }, + { 0, 1 << 13 }, + { 1 << 12, 0 }, + { 0, 1 << 12 }, + { 1 << 11, 0 }, + { 0, 1 << 11 }, +}; + +static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state); +static uint16_t coins; + +static const struct io4_ops chusan_io4_ops = { + .poll = chusan_io4_poll, +}; + +HRESULT chusan_io4_hook_init(const struct io4_config* cfg) +{ + HRESULT hr; + + assert(chuni_dll.jvs_init != NULL); + + dprintf("USB I/O: Starting IO backend\n"); + hr = chuni_dll.jvs_init(); + + if (FAILED(hr)) { + dprintf("USB I/O: Backend error, I/O disconnected: %x\n", (int)hr); + + return hr; + } + + io4_hook_init(cfg, &chusan_io4_ops, NULL); + + return S_OK; +} + +static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) +{ + const struct chunithm_jvs_ir_mask *masks; + uint8_t opbtn; + uint8_t beams; + size_t i; + + memset(state, 0, sizeof(*state)); + + opbtn = 0; + beams = 0; + + chuni_dll.jvs_poll(&opbtn, &beams); + + if (chuni_dll.api_version >= 0x0101) { + // Use correct mapping + masks = chunithm_jvs_ir_masks; + } else { + // Use backwards-compatible incorrect mapping + masks = chunithm_jvs_ir_masks_v1; + } + + if (opbtn & CHUNI_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & CHUNI_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & CHUNI_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + for (i = 0; i < 6; i++) { + /* Beam "press" is active-low hence the ~ */ + if (~beams & (1 << i)) { + state->buttons[0] |= masks[i].p1; + state->buttons[1] |= masks[i].p2; + } + } + + return S_OK; +} diff --git a/chusanhook/io4.h b/chusanhook/io4.h new file mode 100644 index 0000000..8d56491 --- /dev/null +++ b/chusanhook/io4.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +HRESULT chusan_io4_hook_init(const struct io4_config *cfg); diff --git a/chusanhook/led1509306.c b/chusanhook/led1509306.c new file mode 100644 index 0000000..6863fa1 --- /dev/null +++ b/chusanhook/led1509306.c @@ -0,0 +1,389 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/led1509306-cmd.h" +#include "board/led1509306-frame.h" + +#include "chunihook/led1509306.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT led1509306_handle_irp(struct irp *irp); +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_get_board_info(int board); +static HRESULT led1509306_req_get_fw_sum(int board); +static HRESULT led1509306_req_get_protocol_ver(int board); +static HRESULT led1509306_req_get_board_status(int board); +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); + +static char led1509306_board_num[8]; +static char led1509306_chip_num[5]; +static uint8_t led1509306_fw_ver; +static uint16_t led1509306_fw_sum; +static uint8_t led1509306_board_adr = 2; +static uint8_t led1509306_host_adr = 1; + +#define led1509306_nboards 2 + +typedef struct { + CRITICAL_SECTION lock; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + bool enable_response; +} _led1509306_per_board_vars; + +_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); + memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); + led1509306_fw_ver = cfg->fw_ver; + led1509306_fw_sum = cfg->fw_sum; + + int com_ports[2]; + + if (!cfg->cvt_port) { + // SP mode: COM20, COM21 + com_ports[0] = 20; + com_ports[1] = 21; + } else { + // CVT mode: COM3, COM23 + com_ports[0] = 2; + com_ports[1] = 3; + } + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + + InitializeCriticalSection(&v->lock); + + uart_init(&v->boarduart, com_ports[i]); + v->boarduart.written.bytes = v->written_bytes; + v->boarduart.written.nbytes = sizeof(v->written_bytes); + v->boarduart.readable.bytes = v->readable_bytes; + v->boarduart.readable.nbytes = sizeof(v->readable_bytes); + + v->enable_response = true; + } + + return iohook_push_handler(led1509306_handle_irp); +} + +static HRESULT led1509306_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led1509306_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) +{ + struct led1509306_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led1509306_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); + } + } +} + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) +{ + switch (req->cmd) { + case LED_15093_06_CMD_RESET: + return led1509306_req_reset(board, req); + + case LED_15093_06_CMD_BOARD_INFO: + return led1509306_req_get_board_info(board); + + case LED_15093_06_CMD_FW_SUM: + return led1509306_req_get_fw_sum(board); + + case LED_15093_06_CMD_PROTOCOL_VER: + return led1509306_req_get_protocol_ver(board); + + case LED_15093_06_CMD_BOARD_STATUS: + return led1509306_req_get_board_status(board); + + case LED_15093_06_CMD_SET_LED: + return led1509306_req_set_led(board, req); + + case LED_15093_06_CMD_SET_DISABLE_RESPONSE: + return led1509306_req_set_disable_response(board, req); + + case LED_15093_06_CMD_SET_TIMEOUT: + return led1509306_req_set_timeout(board, req); + + default: + dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); + + return S_OK; + } +} + +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); + + if (req->payload[0] != 0xd9) + dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); + + led1509306_per_board_vars[board].enable_response = true; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_RESET; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_info(int board) +{ + dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); + + struct led1509306_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = sizeof(resp.data) + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_INFO; + resp.report = 1; + + memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); + resp.data._0a = 0x0a; + memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); + resp.data._ff = 0xff; + resp.data.fw_ver = led1509306_fw_ver; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_fw_sum(int board) +{ + dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_FW_SUM; + resp.report = 1; + + resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; + resp.data[1] = led1509306_fw_sum & 0xff; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_protocol_ver(int board) +{ + dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; + resp.report = 1; + + resp.data[0] = 1; + resp.data[1] = 1; + resp.data[2] = 4; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_status(int board) +{ + dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 4 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_STATUS; + resp.report = 1; + + resp.data[0] = 0; + resp.data[1] = 0; + resp.data[2] = 0; + resp.data[3] = 0; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) +{ + // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); + + if (!led1509306_per_board_vars[board].enable_response) + return S_OK; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_LED; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); + + led1509306_per_board_vars[board].enable_response = !req->payload[0]; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 1 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; + resp.report = 1; + + resp.data[0] = req->payload[0]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) +{ + dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); + + // not actually implemented, but respond correctly anyway + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; + resp.report = 1; + + resp.data[0] = req->payload[0]; + resp.data[1] = req->payload[1]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} diff --git a/chusanhook/led1509306.h b/chusanhook/led1509306.h new file mode 100644 index 0000000..15c7c3e --- /dev/null +++ b/chusanhook/led1509306.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include + +struct led1509306_config { + bool enable; + char board_number[8]; + char chip_number[5]; + uint8_t fw_ver; + uint16_t fw_sum; +}; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/chusanhook/meson.build b/chusanhook/meson.build new file mode 100644 index 0000000..02c82b0 --- /dev/null +++ b/chusanhook/meson.build @@ -0,0 +1,34 @@ +shared_library( + 'chusanhook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'chusanhook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + ], + link_with : [ + aimeio_lib, + board_lib, + chuniio_lib, + gfxhook_lib, + hooklib_lib, + platform_lib, + util_lib, + ], + sources : [ + 'chuni-dll.c', + 'chuni-dll.h', + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'slider.c', + 'slider.h', + 'led1509306.c', + 'led1509306.h', + ], +) diff --git a/chusanhook/slider.c b/chusanhook/slider.c new file mode 100644 index 0000000..78f5d53 --- /dev/null +++ b/chusanhook/slider.c @@ -0,0 +1,249 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/slider-cmd.h" +#include "board/slider-frame.h" + +#include "chusanhook/chuni-dll.h" +#include "chusanhook/slider.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT slider_handle_irp(struct irp *irp); +static HRESULT slider_handle_irp_locked(struct irp *irp); + +static HRESULT slider_req_dispatch(const union slider_req_any *req); +static HRESULT slider_req_reset(void); +static HRESULT slider_req_get_board_info(void); +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 void slider_res_auto_scan(const uint8_t *state); + +static CRITICAL_SECTION slider_lock; +static struct uart slider_uart; +static uint8_t slider_written_bytes[520]; +static uint8_t slider_readable_bytes[520]; + +HRESULT slider_hook_init(const struct slider_config *cfg) +{ + assert(cfg != NULL); + assert(chuni_dll.slider_init != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + InitializeCriticalSection(&slider_lock); + + uart_init(&slider_uart, 1); + slider_uart.written.bytes = slider_written_bytes; + slider_uart.written.nbytes = sizeof(slider_written_bytes); + slider_uart.readable.bytes = slider_readable_bytes; + slider_uart.readable.nbytes = sizeof(slider_readable_bytes); + + return iohook_push_handler(slider_handle_irp); +} + +static HRESULT slider_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + if (!uart_match_irp(&slider_uart, irp)) { + return iohook_invoke_next(irp); + } + + EnterCriticalSection(&slider_lock); + hr = slider_handle_irp_locked(irp); + LeaveCriticalSection(&slider_lock); + + return hr; +} + +static HRESULT slider_handle_irp_locked(struct irp *irp) +{ + union slider_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + if (irp->op == IRP_OP_OPEN) { + dprintf("Chunithm slider: Starting backend\n"); + hr = chuni_dll.slider_init(); + + if (FAILED(hr)) { + dprintf("Chunithm slider: Backend error: %x\n", (int) hr); + + return hr; + } + } + + hr = uart_handle_irp(&slider_uart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&slider_uart.written); +#endif + + req_iobuf.bytes = req.bytes; + req_iobuf.nbytes = sizeof(req.bytes); + req_iobuf.pos = 0; + + hr = slider_frame_decode(&req_iobuf, &slider_uart.written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("Chunithm slider: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = slider_req_dispatch(&req); + + if (FAILED(hr)) { + dprintf("Chunithm slider: Processing error: %x\n", (int) hr); + } + } +} + +static HRESULT slider_req_dispatch(const union slider_req_any *req) +{ + switch (req->hdr.cmd) { + case SLIDER_CMD_RESET: + return slider_req_reset(); + + case SLIDER_CMD_GET_BOARD_INFO: + return slider_req_get_board_info(); + + case SLIDER_CMD_SET_LED: + return slider_req_set_led(&req->set_led); + + case SLIDER_CMD_AUTO_SCAN_START: + return slider_req_auto_scan_start(); + + case SLIDER_CMD_AUTO_SCAN_STOP: + return slider_req_auto_scan_stop(); + + default: + dprintf("Unhandled command %02x\n", req->hdr.cmd); + + return S_OK; + } +} + +static HRESULT slider_req_reset(void) +{ + struct slider_hdr resp; + + dprintf("Chunithm slider: Reset\n"); + + resp.sync = 0xFF; + resp.cmd = SLIDER_CMD_RESET; + resp.nbytes = 0; + + return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT slider_req_get_board_info(void) +{ + struct slider_resp_get_board_info resp; + + dprintf("Chunithm slider: Get firmware version\n"); + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = SLIDER_FRAME_SYNC; + resp.hdr.cmd = SLIDER_CMD_GET_BOARD_INFO; + resp.hdr.nbytes = sizeof(resp.version); + + strcpy_s( + resp.version, + sizeof(resp.version), + "15330 \xA0" "06712\xFF" "\x90"); + + return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT slider_req_auto_scan_start(void) +{ + assert(chuni_dll.slider_start != NULL); + + dprintf("Chunithm slider: Start slider notifications\n"); + chuni_dll.slider_start(slider_res_auto_scan); + + /* This message is not acknowledged */ + + return S_OK; +} + +static HRESULT slider_req_auto_scan_stop(void) +{ + struct slider_hdr resp; + + assert(chuni_dll.slider_stop != NULL); + + dprintf("Chunithm slider: Stop slider notifications\n"); + + /* 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. */ + + LeaveCriticalSection(&slider_lock); + chuni_dll.slider_stop(); + EnterCriticalSection(&slider_lock); + + resp.sync = SLIDER_FRAME_SYNC; + resp.cmd = SLIDER_CMD_AUTO_SCAN_STOP; + resp.nbytes = 0; + + return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT slider_req_set_led(const struct slider_req_set_led *req) +{ + assert(chuni_dll.slider_set_leds != NULL); + + chuni_dll.slider_set_leds(req->payload.rgb); + + /* This message is not acknowledged */ + + return S_OK; +} + +static void slider_res_auto_scan(const uint8_t *state) +{ + struct slider_resp_auto_scan resp; + + resp.hdr.sync = SLIDER_FRAME_SYNC; + resp.hdr.cmd = SLIDER_CMD_AUTO_SCAN; + resp.hdr.nbytes = sizeof(resp.pressure); + memcpy(resp.pressure, state, sizeof(resp.pressure)); + + EnterCriticalSection(&slider_lock); + slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp)); + LeaveCriticalSection(&slider_lock); +} diff --git a/chusanhook/slider.h b/chusanhook/slider.h new file mode 100644 index 0000000..7053e04 --- /dev/null +++ b/chusanhook/slider.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +struct slider_config { + bool enable; +}; + +HRESULT slider_hook_init(const struct slider_config *cfg); diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini new file mode 100644 index 0000000..196766f --- /dev/null +++ b/dist/chusan/segatools.ini @@ -0,0 +1,112 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +[aime] +; Enable aime reader emulation. +enable=1 +; Enable high baud rate. +;highbaud=1 + +[aimeio] +; x64 aimeio dll path. +; Uncomment this if you have custom aime implementation. +;path64= + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; Chunithm is extremely picky about its LAN environment, so leaving this +; setting enabled is strongly recommended. +enable=1 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.100.0 + +[gfx] +; Force the game to run windowed. +windowed=1 +; Add a frame to the game window if running windowed. +framed=1 +; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) +monitor=0 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io3] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 +; Set to 0 for enable separate ir control. Deafult is space key. +ir=0x20 + +[io4] +enable=1 + +[ledstrip] +; Set to 1 if running game in CVT mode. +cvt_port=0 + +[chuniio] +; Uncomment this if you have custom chuniio implementation. +; x86 chuniio to path32, x64 to path64. Both are necessary. +;path32= +;path64= + +[slider] +; Enable slider emulation. If you have real AC slider, set this to 0. +; Slider serial port must be COM1. +;enable=1 + +; Key bindings for each of the 32 touch cells. The default key map, depicted +; in left-to-right order, is as follows: +; +; SSSSDDDDFFFFGGGGHHHHJJJJKKKKLLLL +; +; Touch cells are numbered FROM RIGHT TO LEFT! starting from 1. This is in +; order to match the numbering used in the operator menu and service manual. +; +; Uncomment and complete the following sequence of settings to configure a +; custom high-precision touch strip controller if you have one. +;cell1=0x53 +;cell2=0x53 +; ... etc ... +;cell31=0x53 +;cell32=0x53 + +; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. +; eg. COM5 +;ledport= + +[ir] +; Uncomment and complete the following sequence of settings to configure a +; custom ir-cappable controller if you have one. +;ir6=0x53 +; ... etc ... +;ir1=0x53 \ No newline at end of file diff --git a/dist/chusan/start.bat b/dist/chusan/start.bat new file mode 100644 index 0000000..dbd1a8b --- /dev/null +++ b/dist/chusan/start.bat @@ -0,0 +1,11 @@ +@echo off + +pushd %~dp0 + +start /min inject_x64.exe -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_sp.json +inject_x86.exe -d -k chusanhook_x86.dll chusanApp.exe +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/meson.build b/meson.build index e346cea..5972de2 100644 --- a/meson.build +++ b/meson.build @@ -71,6 +71,7 @@ subdir('idzhook') subdir('idachook') subdir('swdchook') subdir('minihook') +subdir('chusanhook') subdir('mu3hook') subdir('mercuryhook') subdir('cxbhook') From 01be6ee33c3ccfcac3ae7a47194da8b6beb45f1c Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:59:10 +0200 Subject: [PATCH 016/204] cardmaker: hook, touch screen hook added Thanks @domeori https://dev.s-ul.net/domeori/segatools/-/tree/mr-imports --- cmhook/cm-dll.c | 106 ++++++++++++++++++++++++++ cmhook/cm-dll.h | 20 +++++ cmhook/cmhook.def | 17 +++++ cmhook/config.c | 42 +++++++++++ cmhook/config.h | 29 +++++++ cmhook/dllmain.c | 119 +++++++++++++++++++++++++++++ cmhook/io4.c | 69 +++++++++++++++++ cmhook/io4.h | 7 ++ cmhook/meson.build | 32 ++++++++ cmhook/unity.c | 95 +++++++++++++++++++++++ cmhook/unity.h | 3 + cmio/cmio.c | 54 +++++++++++++ cmio/cmio.h | 44 +++++++++++ cmio/config.c | 22 ++++++ cmio/config.h | 16 ++++ cmio/meson.build | 13 ++++ dist/cm/segatools.ini | 53 +++++++++++++ dist/cm/start.bat | 12 +++ hooklib/config.c | 8 ++ hooklib/config.h | 2 + hooklib/meson.build | 2 + hooklib/touch.c | 171 ++++++++++++++++++++++++++++++++++++++++++ hooklib/touch.h | 14 ++++ meson.build | 2 + 24 files changed, 952 insertions(+) create mode 100644 cmhook/cm-dll.c create mode 100644 cmhook/cm-dll.h create mode 100644 cmhook/cmhook.def create mode 100644 cmhook/config.c create mode 100644 cmhook/config.h create mode 100644 cmhook/dllmain.c create mode 100644 cmhook/io4.c create mode 100644 cmhook/io4.h create mode 100644 cmhook/meson.build create mode 100644 cmhook/unity.c create mode 100644 cmhook/unity.h create mode 100644 cmio/cmio.c create mode 100644 cmio/cmio.h create mode 100644 cmio/config.c create mode 100644 cmio/config.h create mode 100644 cmio/meson.build create mode 100644 dist/cm/segatools.ini create mode 100644 dist/cm/start.bat create mode 100644 hooklib/touch.c create mode 100644 hooklib/touch.h diff --git a/cmhook/cm-dll.c b/cmhook/cm-dll.c new file mode 100644 index 0000000..d10719e --- /dev/null +++ b/cmhook/cm-dll.c @@ -0,0 +1,106 @@ +#include + +#include +#include + +#include "cmhook/cm-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym cm_dll_syms[] = { + { + .sym = "cm_io_init", + .off = offsetof(struct cm_dll, init), + }, { + .sym = "cm_io_poll", + .off = offsetof(struct cm_dll, poll), + }, { + .sym = "cm_io_get_opbtns", + .off = offsetof(struct cm_dll, get_opbtns), + } +}; + +struct cm_dll cm_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT cm_dll_init(const struct cm_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("CardMaker IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("CardMaker IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "cm_io_get_api_version"); + + if (get_api_version != NULL) { + cm_dll.api_version = get_api_version(); + } else { + cm_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose cm_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (cm_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("CardMaker IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + cm_dll.api_version); + + goto end; + } + + sym = cm_dll_syms; + hr = dll_bind(&cm_dll, src, &sym, _countof(cm_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("CardMaker IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/cmhook/cm-dll.h b/cmhook/cm-dll.h new file mode 100644 index 0000000..c217efd --- /dev/null +++ b/cmhook/cm-dll.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "cmio/cmio.h" + +struct cm_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); +}; + +struct cm_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct cm_dll cm_dll; + +HRESULT cm_dll_init(const struct cm_dll_config *cfg, HINSTANCE self); diff --git a/cmhook/cmhook.def b/cmhook/cmhook.def new file mode 100644 index 0000000..8590794 --- /dev/null +++ b/cmhook/cmhook.def @@ -0,0 +1,17 @@ +LIBRARY cmhook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + cm_io_get_api_version + cm_io_get_opbtns + cm_io_init + cm_io_poll diff --git a/cmhook/config.c b/cmhook/config.c new file mode 100644 index 0000000..64cbbb2 --- /dev/null +++ b/cmhook/config.c @@ -0,0 +1,42 @@ +#include +#include + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "cmhook/config.h" + +#include "platform/config.h" + +void cm_dll_config_load( + struct cm_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"cmio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void cm_hook_config_load( + struct cm_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + touch_screen_config_load(&cfg->touch, filename); + cm_dll_config_load(&cfg->dll, filename); +} diff --git a/cmhook/config.h b/cmhook/config.h new file mode 100644 index 0000000..c79f47a --- /dev/null +++ b/cmhook/config.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" + +#include "cmhook/cm-dll.h" + +#include "platform/config.h" + +struct cm_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct cm_dll_config dll; + struct touch_screen_config touch; +}; + +void cm_dll_config_load( + struct cm_dll_config *cfg, + const wchar_t *filename); + +void cm_hook_config_load( + struct cm_hook_config *cfg, + const wchar_t *filename); diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c new file mode 100644 index 0000000..ce11763 --- /dev/null +++ b/cmhook/dllmain.c @@ -0,0 +1,119 @@ +#include + +#include + +#include "board/io4.h" +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "cmhook/config.h" +#include "cmhook/io4.h" +#include "cmhook/cm-dll.h" +#include "cmhook/unity.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE cm_hook_mod; +static process_entry_t cm_startup; +static struct cm_hook_config cm_hook_cfg; + +static DWORD CALLBACK cm_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin cm_pre_startup ---\n"); + + /* Load config */ + + cm_hook_config_load(&cm_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&cm_hook_cfg.dvd, cm_hook_mod); + touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod); + serial_hook_init(); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &cm_hook_cfg.platform, + "SDED", + "ACA1", + cm_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, cm_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = vfd_hook_init(3); + + if (FAILED(hr)) { + goto fail; + } + + hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = cm_io4_hook_init(&cm_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize Unity native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the `cmhook` initialization. */ + + unity_hook_init(); + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End cm_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return cm_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + cm_hook_mod = mod; + + hr = process_hijack_startup(cm_pre_startup, &cm_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/cmhook/io4.c b/cmhook/io4.c new file mode 100644 index 0000000..073f681 --- /dev/null +++ b/cmhook/io4.c @@ -0,0 +1,69 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "cmhook/cm-dll.h" + +#include "util/dprintf.h" + +static HRESULT cm_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops cm_io4_ops = { + .poll = cm_io4_poll, +}; + +HRESULT cm_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(cm_dll.init != NULL); + + hr = io4_hook_init(cfg, &cm_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return cm_dll.init(); +} + +static HRESULT cm_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + HRESULT hr; + + assert(cm_dll.poll != NULL); + assert(cm_dll.get_opbtns != NULL); + + memset(state, 0, sizeof(*state)); + + hr = cm_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + + cm_dll.get_opbtns(&opbtn); + + if (opbtn & CM_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & CM_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & CM_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + return S_OK; +} diff --git a/cmhook/io4.h b/cmhook/io4.h new file mode 100644 index 0000000..fb06118 --- /dev/null +++ b/cmhook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT cm_io4_hook_init(const struct io4_config *cfg); diff --git a/cmhook/meson.build b/cmhook/meson.build new file mode 100644 index 0000000..338f773 --- /dev/null +++ b/cmhook/meson.build @@ -0,0 +1,32 @@ +shared_library( + 'cmhook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'cmhook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + cmio_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'cm-dll.c', + 'cm-dll.h', + 'unity.h', + 'unity.c', + ], +) diff --git a/cmhook/unity.c b/cmhook/unity.c new file mode 100644 index 0000000..efefc32 --- /dev/null +++ b/cmhook/unity.c @@ -0,0 +1,95 @@ +#include + +#include + +#include "hook/table.h" + +#include "hooklib/dll.h" +#include "hooklib/path.h" + +#include "util/dprintf.h" + +static void dll_hook_insert_hooks(HMODULE target); + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); +static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); + +static const struct hook_symbol unity_kernel32_syms[] = { + { + .name = "LoadLibraryW", + .patch = my_LoadLibraryW, + .link = (void **) &next_LoadLibraryW, + }, +}; + +static const wchar_t *target_modules[] = { + L"mono.dll", + L"cri_ware_unity.dll", +}; +static const size_t target_modules_len = _countof(target_modules); + +void unity_hook_init(void) +{ + dll_hook_insert_hooks(NULL); +} + +static void dll_hook_insert_hooks(HMODULE target) +{ + hook_table_apply( + target, + "kernel32.dll", + unity_kernel32_syms, + _countof(unity_kernel32_syms)); +} + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) +{ + const wchar_t *name_end; + const wchar_t *target_module; + bool already_loaded; + HMODULE result; + size_t name_len; + size_t target_module_len; + + if (name == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + + return NULL; + } + + // Check if the module is already loaded + already_loaded = GetModuleHandleW(name) != NULL; + + // Must call the next handler so the DLL reference count is incremented + result = next_LoadLibraryW(name); + + if (!already_loaded && result != NULL) { + name_len = wcslen(name); + + for (size_t i = 0; i < target_modules_len; i++) { + target_module = target_modules[i]; + target_module_len = wcslen(target_module); + + // Check if the newly loaded library is at least the length of + // the name of the target module + if (name_len < target_module_len) { + continue; + } + + name_end = &name[name_len - target_module_len]; + + // Check if the name of the newly loaded library is one of the + // modules the path hooks should be injected into + if (_wcsicmp(name_end, target_module) != 0) { + continue; + } + + dprintf("Unity: Loaded %S\n", target_module); + + dll_hook_insert_hooks(result); + path_hook_insert_hooks(result); + } + } + + return result; +} diff --git a/cmhook/unity.h b/cmhook/unity.h new file mode 100644 index 0000000..99c3bd9 --- /dev/null +++ b/cmhook/unity.h @@ -0,0 +1,3 @@ +#pragma once + +void unity_hook_init(void); diff --git a/cmio/cmio.c b/cmio/cmio.c new file mode 100644 index 0000000..c2dbfa5 --- /dev/null +++ b/cmio/cmio.c @@ -0,0 +1,54 @@ +#include +#include + +#include +#include + +#include "cmio/cmio.h" +#include "cmio/config.h" + +static uint8_t cm_opbtn; +static struct cm_io_config cm_io_cfg; +static bool cm_io_coin; + +uint16_t cm_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT cm_io_init(void) +{ + cm_io_config_load(&cm_io_cfg, L".\\segatools.ini"); + return S_OK; +} + +HRESULT cm_io_poll(void) +{ + cm_opbtn = 0; + + if (GetAsyncKeyState(cm_io_cfg.vk_test) & 0x8000) { + cm_opbtn |= CM_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(cm_io_cfg.vk_service) & 0x8000) { + cm_opbtn |= CM_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(cm_io_cfg.vk_coin) & 0x8000) { + if (!cm_io_coin) { + cm_io_coin = true; + cm_opbtn |= CM_IO_OPBTN_COIN; + } + } else { + cm_io_coin = false; + } + + return S_OK; +} + +void cm_io_get_opbtns(uint8_t *opbtn) +{ + if (opbtn != NULL) { + *opbtn = cm_opbtn; + } +} diff --git a/cmio/cmio.h b/cmio/cmio.h new file mode 100644 index 0000000..cb4aa9c --- /dev/null +++ b/cmio/cmio.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include + +enum { + CM_IO_OPBTN_TEST = 0x01, + CM_IO_OPBTN_SERVICE = 0x02, + CM_IO_OPBTN_COIN = 0x04, +}; + +/* Get the version of the CardMaker IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t cm_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after cm_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT cm_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT cm_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + cm_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void cm_io_get_opbtns(uint8_t *opbtn); \ No newline at end of file diff --git a/cmio/config.c b/cmio/config.c new file mode 100644 index 0000000..4c37f96 --- /dev/null +++ b/cmio/config.c @@ -0,0 +1,22 @@ +#include + +#include +#include +#include + +#include "cmio/config.h" + +void cm_io_config_load( + struct cm_io_config *cfg, + const wchar_t *filename) +{ + wchar_t key[16]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); +} diff --git a/cmio/config.h b/cmio/config.h new file mode 100644 index 0000000..d73f6c5 --- /dev/null +++ b/cmio/config.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +struct cm_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; +}; + +void cm_io_config_load( + struct cm_io_config *cfg, + const wchar_t *filename); diff --git a/cmio/meson.build b/cmio/meson.build new file mode 100644 index 0000000..74fadda --- /dev/null +++ b/cmio/meson.build @@ -0,0 +1,13 @@ +cmio_lib = static_library( + 'cmio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + sources : [ + 'cmio.c', + 'cmio.h', + 'config.c', + 'config.h', + ], +) diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini new file mode 100644 index 0000000..f2b4ca3 --- /dev/null +++ b/dist/cm/segatools.ini @@ -0,0 +1,53 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + + +[aime] +; Enable aime reader emulation. +enable=1 +aimePath=C:\SEGA\DEVICE\aime.txt +felicaGen=0 + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.100.0 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io4] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 \ No newline at end of file diff --git a/dist/cm/start.bat b/dist/cm/start.bat new file mode 100644 index 0000000..b51c839 --- /dev/null +++ b/dist/cm/start.bat @@ -0,0 +1,12 @@ +@echo off + +pushd %~dp0 + +start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_server.json config_common.json +inject.exe -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 + +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/hooklib/config.c b/hooklib/config.c index 5fc9383..30f6a4b 100644 --- a/hooklib/config.c +++ b/hooklib/config.c @@ -14,3 +14,11 @@ void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"dvd", L"enable", 1, filename); } + +void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename); +} diff --git a/hooklib/config.h b/hooklib/config.h index 5da045d..9763274 100644 --- a/hooklib/config.h +++ b/hooklib/config.h @@ -3,5 +3,7 @@ #include #include "hooklib/dvd.h" +#include "hooklib/touch.h" void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename); +void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename); diff --git a/hooklib/meson.build b/hooklib/meson.build index d112da6..d835904 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -27,5 +27,7 @@ hooklib_lib = static_library( 'setupapi.h', 'spike.c', 'spike.h', + 'touch.c', + 'touch.h', ], ) diff --git a/hooklib/touch.c b/hooklib/touch.c new file mode 100644 index 0000000..ca0b8a9 --- /dev/null +++ b/hooklib/touch.c @@ -0,0 +1,171 @@ +/* +This part (touch screen hook) is mostly taken from spicetools, which is GPL. +This means there can be some license issues if you do use this code in some other places without including source code. +*/ +#include + +#include +#include +#include + +#include "hook/com-proxy.h" +#include "hook/table.h" + +#include "hooklib/config.h" +#include "hooklib/dll.h" +#include "hooklib/touch.h" + +#include "util/dprintf.h" + +/* API hooks */ + +static int WINAPI hook_GetSystemMetrics( + int nIndex +); + +static BOOL WINAPI hook_RegisterTouchWindow( + HWND hwnd, + ULONG ulFlags +); + +static BOOL WINAPI hook_GetTouchInputInfo( + HANDLE hTouchInput, + UINT cInputs, + PTOUCHINPUT pInputs, + int cbSize +); + +/* Link pointers */ + +static int (WINAPI *next_GetSystemMetrics)( + int nIndex +); + +static BOOL (WINAPI *next_RegisterTouchWindow)( + HWND hwnd, + ULONG ulFlags +); + +static BOOL (WINAPI *next_GetTouchInputInfo)( + HANDLE hTouchInput, + UINT cInputs, + PTOUCHINPUT pInputs, + int cbSize +); + +static bool touch_hook_initted; +static struct touch_screen_config touch_config; + +static const struct hook_symbol touch_hooks[] = { + { + .name = "GetSystemMetrics", + .patch = hook_GetSystemMetrics, + .link = (void **) &next_GetSystemMetrics + }, + { + .name = "RegisterTouchWindow", + .patch = hook_RegisterTouchWindow, + .link = (void **) &next_RegisterTouchWindow + }, + { + .name = "GetTouchInputInfo", + .patch = hook_GetTouchInputInfo, + .link = (void **) &next_GetTouchInputInfo + }, +}; + +void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + if (touch_hook_initted) { + return; + } + + touch_hook_initted = true; + + memcpy(&touch_config, cfg, sizeof(*cfg)); + hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks)); + dprintf("TOUCH: hook enabled.\n"); +} + +// Spicetools misc/wintouchemu.cpp + +static int WINAPI hook_GetSystemMetrics( + int nIndex +) +{ + if (nIndex == 94) return 0x01 | 0x02 | 0x40 | 0x80; + + int orig = next_GetSystemMetrics(nIndex); + + return orig; +} + +static BOOL WINAPI hook_RegisterTouchWindow( + HWND hwnd, + ULONG ulFlags +) +{ + return true; +} + +// Converting mouse event to touch event +// Does not work at current stage +static BOOL WINAPI hook_GetTouchInputInfo( + HANDLE hTouchInput, + UINT cInputs, + PTOUCHINPUT pInputs, + int cbSize +) +{ + bool result = false; + static bool mouse_state_old = false; + for (UINT input = 0; input < cInputs; input++) { + TOUCHINPUT *touch_input = &pInputs[input]; + + touch_input->x = 0; + touch_input->y = 0; + touch_input->hSource = NULL; + touch_input->dwID = 0; + touch_input->dwFlags = 0; + touch_input->dwMask = 0; + touch_input->dwTime = 0; + touch_input->dwExtraInfo = 0; + touch_input->cxContact = 0; + touch_input->cyContact = 0; + + bool mouse_state = (GetKeyState(VK_LBUTTON) & 0x100) != 0; + + if (mouse_state || mouse_state_old) { + POINT cursorPos; + GetCursorPos(&cursorPos); + + result = true; + touch_input->x = cursorPos.x * 100; + touch_input->y = cursorPos.y * 100; + touch_input->hSource = hTouchInput; + touch_input->dwID = 0; + touch_input->dwFlags = 0; + if (mouse_state && !mouse_state_old) { + touch_input->dwFlags |= TOUCHEVENTF_DOWN; + } else if (mouse_state && mouse_state_old) { + touch_input->dwFlags |= TOUCHEVENTF_MOVE; + } else if (!mouse_state && mouse_state_old) { + touch_input->dwFlags |= TOUCHEVENTF_UP; + } + touch_input->dwMask = 0; + touch_input->dwTime = 0; + touch_input->dwExtraInfo = 0; + touch_input->cxContact = 0; + touch_input->cyContact = 0; + } + mouse_state_old = mouse_state; + } + + return result; +} \ No newline at end of file diff --git a/hooklib/touch.h b/hooklib/touch.h new file mode 100644 index 0000000..f80a25e --- /dev/null +++ b/hooklib/touch.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include + +struct touch_screen_config { + bool enable; +}; + +/* Init is not thread safe because API hook init is not thread safe blah + blah blah you know the drill by now. */ + +void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self); \ No newline at end of file diff --git a/meson.build b/meson.build index 5972de2..851e57a 100644 --- a/meson.build +++ b/meson.build @@ -61,6 +61,7 @@ subdir('idzio') subdir('idacio') subdir('swdcio') subdir('mu3io') +subdir('cmio') subdir('mercuryio') subdir('cxbio') @@ -73,5 +74,6 @@ subdir('swdchook') subdir('minihook') subdir('chusanhook') subdir('mu3hook') +subdir('cmhook') subdir('mercuryhook') subdir('cxbhook') From 0ee081ca1bf2cba8ba8ad89801992afda8ff640b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 01:00:28 +0200 Subject: [PATCH 017/204] mai2: segatools added --- README.md | 6 ++ dist/mai2/segatools.ini | 70 ++++++++++++++++++ dist/mai2/start.bat | 11 +++ mai2hook/config.c | 41 +++++++++++ mai2hook/config.h | 27 +++++++ mai2hook/dllmain.c | 116 ++++++++++++++++++++++++++++++ mai2hook/io4.c | 153 ++++++++++++++++++++++++++++++++++++++++ mai2hook/io4.h | 7 ++ mai2hook/mai2-dll.c | 109 ++++++++++++++++++++++++++++ mai2hook/mai2-dll.h | 21 ++++++ mai2hook/mai2hook.def | 18 +++++ mai2hook/meson.build | 31 ++++++++ mai2hook/unity.c | 95 +++++++++++++++++++++++++ mai2hook/unity.h | 3 + mai2io/config.c | 48 +++++++++++++ mai2io/config.h | 18 +++++ mai2io/mai2io.c | 143 +++++++++++++++++++++++++++++++++++++ mai2io/mai2io.h | 68 ++++++++++++++++++ mai2io/meson.build | 13 ++++ meson.build | 2 + 20 files changed, 1000 insertions(+) create mode 100644 dist/mai2/segatools.ini create mode 100644 dist/mai2/start.bat create mode 100644 mai2hook/config.c create mode 100644 mai2hook/config.h create mode 100644 mai2hook/dllmain.c create mode 100644 mai2hook/io4.c create mode 100644 mai2hook/io4.h create mode 100644 mai2hook/mai2-dll.c create mode 100644 mai2hook/mai2-dll.h create mode 100644 mai2hook/mai2hook.def create mode 100644 mai2hook/meson.build create mode 100644 mai2hook/unity.c create mode 100644 mai2hook/unity.h create mode 100644 mai2io/config.c create mode 100644 mai2io/config.h create mode 100644 mai2io/mai2io.c create mode 100644 mai2io/mai2io.h create mode 100644 mai2io/meson.build diff --git a/README.md b/README.md index 4f48d8d..7077fde 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo * Initial D The Arcade * SEGA World Drivers Championship * SEGA World Drivers Championship 2019 +* ONGEKI + * bright MEMORY +* maimai DX + * maimai DX FESTiVAL +* Card Maker + * Card Maker 1.35 * Wacca * Wacca Lilly R (WIP) diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini new file mode 100644 index 0000000..8676568 --- /dev/null +++ b/dist/mai2/segatools.ini @@ -0,0 +1,70 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx, Bxxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +[aime] +; Enable aime reader emulation. +enable=1 + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default= + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about its LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.100.0 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io4] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 + +; Key bindings for buttons around screen. The default key map, depicted +; in clockwise order, is as follows: +; +; Player 1 Ring buttons: WEDCXZAQ, Select button: 3 +; Player 2 Ring buttons: (Numpad) 89632147, Select button: (Numpad) * +; +; Select buttons are considered as button 9. +; +; Uncomment and complete the following sequence of settings to configure a +; custom keybinding. +[button] +;1p_btn1=0x53 +;1p_btn2=0x53 +;1p_btn3=0x53 +; ... etc ... +;2p_btn1=0x53 +;2p_btn2=0x53 +;2p_btn3=0x53 +; ... etc ... diff --git a/dist/mai2/start.bat b/dist/mai2/start.bat new file mode 100644 index 0000000..a89a1d5 --- /dev/null +++ b/dist/mai2/start.bat @@ -0,0 +1,11 @@ +@echo off + +pushd %~dp0 + +start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/mai2hook/config.c b/mai2hook/config.c new file mode 100644 index 0000000..87615e9 --- /dev/null +++ b/mai2hook/config.c @@ -0,0 +1,41 @@ +#include +#include + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "mai2hook/config.h" + +#include "platform/config.h" + +void mai2_dll_config_load( + struct mai2_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"mai2io", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void mai2_hook_config_load( + struct mai2_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + mai2_dll_config_load(&cfg->dll, filename); +} diff --git a/mai2hook/config.h b/mai2hook/config.h new file mode 100644 index 0000000..3b7fc22 --- /dev/null +++ b/mai2hook/config.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" + +#include "mai2hook/mai2-dll.h" + +#include "platform/config.h" + +struct mai2_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct mai2_dll_config dll; +}; + +void mai2_dll_config_load( + struct mai2_dll_config *cfg, + const wchar_t *filename); + +void mai2_hook_config_load( + struct mai2_hook_config *cfg, + const wchar_t *filename); diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c new file mode 100644 index 0000000..3232d6c --- /dev/null +++ b/mai2hook/dllmain.c @@ -0,0 +1,116 @@ +#include + +#include "board/io4.h" +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "hook/process.h" + +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "mai2hook/config.h" +#include "mai2hook/io4.h" +#include "mai2hook/mai2-dll.h" +#include "mai2hook/unity.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE mai2_hook_mod; +static process_entry_t mai2_startup; +static struct mai2_hook_config mai2_hook_cfg; + +/* This hook is based on mu3hook, with leaked mai2hook i/o codes. */ + +static DWORD CALLBACK mai2_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin mai2_pre_startup ---\n"); + + /* Load config */ + + mai2_hook_config_load(&mai2_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&mai2_hook_cfg.dvd, mai2_hook_mod); + serial_hook_init(); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &mai2_hook_cfg.platform, + "SDEZ", + "ACA1", + mai2_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, mai2_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = vfd_hook_init(2); + + if (FAILED(hr)) { + goto fail; + } + + hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = mai2_io4_hook_init(&mai2_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize Unity native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the `mai2hook` initialization. */ + + unity_hook_init(); + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End mai2_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return mai2_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + mai2_hook_mod = mod; + + hr = process_hijack_startup(mai2_pre_startup, &mai2_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/mai2hook/io4.c b/mai2hook/io4.c new file mode 100644 index 0000000..4eb7f6b --- /dev/null +++ b/mai2hook/io4.c @@ -0,0 +1,153 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "mai2hook/mai2-dll.h" + +#include "util/dprintf.h" + +static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops mai2_io4_ops = { + .poll = mai2_io4_poll, +}; + +HRESULT mai2_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(mai2_dll.init != NULL); + + hr = io4_hook_init(cfg, &mai2_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return mai2_dll.init(); +} + +static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + uint16_t player1; + uint16_t player2; + HRESULT hr; + + assert(mai2_dll.poll != NULL); + assert(mai2_dll.get_opbtns != NULL); + assert(mai2_dll.get_gamebtns != NULL); + + memset(state, 0, sizeof(*state)); + + hr = mai2_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + player1 = 0; + player2 = 0; + + mai2_dll.get_opbtns(&opbtn); + mai2_dll.get_gamebtns(&player1, &player2); + + if (opbtn & MAI2_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & MAI2_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & MAI2_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + // Buttons around screen are active-low, select button is active-high + + // Player 1 + + if (!(player1 & MAI2_IO_GAMEBTN_1)) { + state->buttons[0] |= 1 << 2; + } + + if (!(player1 & MAI2_IO_GAMEBTN_2)) { + state->buttons[0] |= 1 << 3; + } + + if (!(player1 & MAI2_IO_GAMEBTN_3)) { + state->buttons[0] |= 1 << 0; + } + + if (!(player1 & MAI2_IO_GAMEBTN_4)) { + state->buttons[0] |= 1 << 15; + } + + if (!(player1 & MAI2_IO_GAMEBTN_5)) { + state->buttons[0] |= 1 << 14; + } + + if (!(player1 & MAI2_IO_GAMEBTN_6)) { + state->buttons[0] |= 1 << 13; + } + + if (!(player1 & MAI2_IO_GAMEBTN_7)) { + state->buttons[0] |= 1 << 12; + } + + if (!(player1 & MAI2_IO_GAMEBTN_8)) { + state->buttons[0] |= 1 << 11; + } + + if (player1 & MAI2_IO_GAMEBTN_SELECT) { + state->buttons[0] |= 1 << 1; + } + + // Player 2 + + if (!(player2 & MAI2_IO_GAMEBTN_1)) { + state->buttons[1] |= 1 << 2; + } + + if (!(player2 & MAI2_IO_GAMEBTN_2)) { + state->buttons[1] |= 1 << 3; + } + + if (!(player2 & MAI2_IO_GAMEBTN_3)) { + state->buttons[1] |= 1 << 0; + } + + if (!(player2 & MAI2_IO_GAMEBTN_4)) { + state->buttons[1] |= 1 << 15; + } + + if (!(player2 & MAI2_IO_GAMEBTN_5)) { + state->buttons[1] |= 1 << 14; + } + + if (!(player2 & MAI2_IO_GAMEBTN_6)) { + state->buttons[1] |= 1 << 13; + } + + if (!(player2 & MAI2_IO_GAMEBTN_7)) { + state->buttons[1] |= 1 << 12; + } + + if (!(player2 & MAI2_IO_GAMEBTN_8)) { + state->buttons[1] |= 1 << 11; + } + + if (player2 & MAI2_IO_GAMEBTN_SELECT) { + state->buttons[1] |= 1 << 4; + } + + return S_OK; +} diff --git a/mai2hook/io4.h b/mai2hook/io4.h new file mode 100644 index 0000000..5a0a2a0 --- /dev/null +++ b/mai2hook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT mai2_io4_hook_init(const struct io4_config *cfg); diff --git a/mai2hook/mai2-dll.c b/mai2hook/mai2-dll.c new file mode 100644 index 0000000..dd172c3 --- /dev/null +++ b/mai2hook/mai2-dll.c @@ -0,0 +1,109 @@ +#include + +#include +#include + +#include "mai2hook/mai2-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym mai2_dll_syms[] = { + { + .sym = "mai2_io_init", + .off = offsetof(struct mai2_dll, init), + }, { + .sym = "mai2_io_poll", + .off = offsetof(struct mai2_dll, poll), + }, { + .sym = "mai2_io_get_opbtns", + .off = offsetof(struct mai2_dll, get_opbtns), + }, { + .sym = "mai2_io_get_gamebtns", + .off = offsetof(struct mai2_dll, get_gamebtns), + } +}; + +struct mai2_dll mai2_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Maimai DX IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Maimai DX IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "mai2_io_get_api_version"); + + if (get_api_version != NULL) { + mai2_dll.api_version = get_api_version(); + } else { + mai2_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose mai2_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (mai2_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Maimai DX IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + mai2_dll.api_version); + + goto end; + } + + sym = mai2_dll_syms; + hr = dll_bind(&mai2_dll, src, &sym, _countof(mai2_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Maimai DX IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/mai2hook/mai2-dll.h b/mai2hook/mai2-dll.h new file mode 100644 index 0000000..6e53454 --- /dev/null +++ b/mai2hook/mai2-dll.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "mai2io/mai2io.h" + +struct mai2_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint16_t *player1, uint16_t *player2); +}; + +struct mai2_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct mai2_dll mai2_dll; + +HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self); diff --git a/mai2hook/mai2hook.def b/mai2hook/mai2hook.def new file mode 100644 index 0000000..2d0ac8b --- /dev/null +++ b/mai2hook/mai2hook.def @@ -0,0 +1,18 @@ +LIBRARY mai2hook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + mai2_io_get_api_version + mai2_io_get_gamebtns + mai2_io_get_opbtns + mai2_io_init + mai2_io_poll \ No newline at end of file diff --git a/mai2hook/meson.build b/mai2hook/meson.build new file mode 100644 index 0000000..8578c51 --- /dev/null +++ b/mai2hook/meson.build @@ -0,0 +1,31 @@ +shared_library( + 'mai2hook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'mai2hook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + mai2io_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'mai2-dll.c', + 'mai2-dll.h', + 'unity.h', + 'unity.c', + ], +) diff --git a/mai2hook/unity.c b/mai2hook/unity.c new file mode 100644 index 0000000..64195be --- /dev/null +++ b/mai2hook/unity.c @@ -0,0 +1,95 @@ +#include + +#include + +#include "hook/table.h" + +#include "hooklib/dll.h" +#include "hooklib/path.h" + +#include "util/dprintf.h" + +static void dll_hook_insert_hooks(HMODULE target); + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); +static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); + +static const struct hook_symbol unity_kernel32_syms[] = { + { + .name = "LoadLibraryW", + .patch = my_LoadLibraryW, + .link = (void **) &next_LoadLibraryW, + }, +}; + +static const wchar_t *target_modules[] = { + L"mono-2.0-bdwgc.dll", + L"cri_ware_unity.dll", +}; +static const size_t target_modules_len = _countof(target_modules); + +void unity_hook_init(void) +{ + dll_hook_insert_hooks(NULL); +} + +static void dll_hook_insert_hooks(HMODULE target) +{ + hook_table_apply( + target, + "kernel32.dll", + unity_kernel32_syms, + _countof(unity_kernel32_syms)); +} + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) +{ + const wchar_t *name_end; + const wchar_t *target_module; + bool already_loaded; + HMODULE result; + size_t name_len; + size_t target_module_len; + + if (name == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + + return NULL; + } + + // Check if the module is already loaded + already_loaded = GetModuleHandleW(name) != NULL; + + // Must call the next handler so the DLL reference count is incremented + result = next_LoadLibraryW(name); + + if (!already_loaded && result != NULL) { + name_len = wcslen(name); + + for (size_t i = 0; i < target_modules_len; i++) { + target_module = target_modules[i]; + target_module_len = wcslen(target_module); + + // Check if the newly loaded library is at least the length of + // the name of the target module + if (name_len < target_module_len) { + continue; + } + + name_end = &name[name_len - target_module_len]; + + // Check if the name of the newly loaded library is one of the + // modules the path hooks should be injected into + if (_wcsicmp(name_end, target_module) != 0) { + continue; + } + + dprintf("Unity: Loaded %S\n", target_module); + + dll_hook_insert_hooks(result); + path_hook_insert_hooks(result); + } + } + + return result; +} diff --git a/mai2hook/unity.h b/mai2hook/unity.h new file mode 100644 index 0000000..99c3bd9 --- /dev/null +++ b/mai2hook/unity.h @@ -0,0 +1,3 @@ +#pragma once + +void unity_hook_init(void); diff --git a/mai2io/config.c b/mai2io/config.c new file mode 100644 index 0000000..75e842a --- /dev/null +++ b/mai2io/config.c @@ -0,0 +1,48 @@ +#include + +#include +#include +#include + +#include "mai2io/config.h" + +/* +Maimai DX Default key binding +1P: self-explanatory +2P: (Numpad) 8, 9, 6, 3, 2, 1, 4, 7, * +*/ +static const int mai2_io_1p_default[] = {'W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q', '3'}; +static const int mai2_io_2p_default[] = {0x68, 0x69, 0x66, 0x63, 0x62, 0x61, 0x64, 0x67, 0x54}; + +void mai2_io_config_load( + struct mai2_io_config *cfg, + const wchar_t *filename) +{ + wchar_t key[16]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + + for (i = 0 ; i < 9 ; i++) { + swprintf_s(key, _countof(key), L"1p_btn%i", i + 1); + cfg->vk_1p_btn[i] = GetPrivateProfileIntW( + L"button", + key, + mai2_io_1p_default[i], + filename); + } + + for (i = 0 ; i < 9 ; i++) { + swprintf_s(key, _countof(key), L"2p_btn%i", i + 1); + cfg->vk_2p_btn[i] = GetPrivateProfileIntW( + L"button", + key, + mai2_io_2p_default[i], + filename); + } +} diff --git a/mai2io/config.h b/mai2io/config.h new file mode 100644 index 0000000..568b832 --- /dev/null +++ b/mai2io/config.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include + +struct mai2_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + uint8_t vk_1p_btn[9]; + uint8_t vk_2p_btn[9]; +}; + +void mai2_io_config_load( + struct mai2_io_config *cfg, + const wchar_t *filename); diff --git a/mai2io/mai2io.c b/mai2io/mai2io.c new file mode 100644 index 0000000..40d6bfb --- /dev/null +++ b/mai2io/mai2io.c @@ -0,0 +1,143 @@ +#include + +#include +#include + +#include "mai2io/mai2io.h" +#include "mai2io/config.h" + +static uint8_t mai2_opbtn; +static uint16_t mai2_player1_btn; +static uint16_t mai2_player2_btn; +static struct mai2_io_config mai2_io_cfg; +static bool mai2_io_coin; + +uint16_t mai2_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT mai2_io_init(void) +{ + mai2_io_config_load(&mai2_io_cfg, L".\\segatools.ini"); + + return S_OK; +} + +HRESULT mai2_io_poll(void) +{ + mai2_opbtn = 0; + mai2_player1_btn = 0; + mai2_player2_btn = 0; + + if (GetAsyncKeyState(mai2_io_cfg.vk_test) & 0x8000) { + mai2_opbtn |= MAI2_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_service) & 0x8000) { + mai2_opbtn |= MAI2_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_coin) & 0x8000) { + if (!mai2_io_coin) { + mai2_io_coin = true; + mai2_opbtn |= MAI2_IO_OPBTN_COIN; + } + } else { + mai2_io_coin = false; + } + + //Player 1 + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[0])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_1; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[1])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_2; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[2])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_3; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[3])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_4; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[4])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_5; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[5])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_6; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[6])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_7; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[7])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_8; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[8])) { + mai2_player1_btn |= MAI2_IO_GAMEBTN_SELECT; + } + + //Player 2 + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[0])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_1; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[1])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_2; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[2])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_3; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[3])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_4; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[4])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_5; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[5])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_6; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[6])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_7; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[7])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_8; + } + + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[8])) { + mai2_player2_btn |= MAI2_IO_GAMEBTN_SELECT; + } + + return S_OK; +} + +void mai2_io_get_opbtns(uint8_t *opbtn) +{ + if (opbtn != NULL) { + *opbtn = mai2_opbtn; + } +} + +void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) +{ + if (player1 != NULL) { + *player1 = mai2_player1_btn; + } + + if (player2 != NULL ){ + *player2 = mai2_player2_btn; + } +} \ No newline at end of file diff --git a/mai2io/mai2io.h b/mai2io/mai2io.h new file mode 100644 index 0000000..084228c --- /dev/null +++ b/mai2io/mai2io.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include + +enum { + MAI2_IO_OPBTN_TEST = 0x01, + MAI2_IO_OPBTN_SERVICE = 0x02, + MAI2_IO_OPBTN_COIN = 0x04, +}; + +enum { + MAI2_IO_GAMEBTN_1 = 0x01, + MAI2_IO_GAMEBTN_2 = 0x02, + MAI2_IO_GAMEBTN_3 = 0x04, + MAI2_IO_GAMEBTN_4 = 0x08, + MAI2_IO_GAMEBTN_5 = 0x10, + MAI2_IO_GAMEBTN_6 = 0x20, + MAI2_IO_GAMEBTN_7 = 0x40, + MAI2_IO_GAMEBTN_8 = 0x80, + MAI2_IO_GAMEBTN_SELECT = 0x100, +}; + +/* Get the version of the Maimai IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t mai2_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after mai2_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT mai2_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT mai2_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + MAI2_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void mai2_io_get_opbtns(uint8_t *opbtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + MAI2_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + a left hand side set of inputs and a right hand side set of inputs: the bit + mappings are the same in both cases. + + All buttons are active-high, even though some buttons' electrical signals + on a real cabinet are active-low. + + Minimum API version: 0x0100 */ + +void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2); diff --git a/mai2io/meson.build b/mai2io/meson.build new file mode 100644 index 0000000..c448136 --- /dev/null +++ b/mai2io/meson.build @@ -0,0 +1,13 @@ +mai2io_lib = static_library( + 'mai2io', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + sources : [ + 'mai2io.c', + 'mai2io.h', + 'config.c', + 'config.h', + ], +) diff --git a/meson.build b/meson.build index 851e57a..2032f0e 100644 --- a/meson.build +++ b/meson.build @@ -61,6 +61,7 @@ subdir('idzio') subdir('idacio') subdir('swdcio') subdir('mu3io') +subdir('mai2io') subdir('cmio') subdir('mercuryio') subdir('cxbio') @@ -74,6 +75,7 @@ subdir('swdchook') subdir('minihook') subdir('chusanhook') subdir('mu3hook') +subdir('mai2hook') subdir('cmhook') subdir('mercuryhook') subdir('cxbhook') From e5d17b82b2d038651c97971b2bdd4014077a6da0 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 01:03:36 +0200 Subject: [PATCH 018/204] updated Package.mk for mai2, cm --- Package.mk | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Package.mk b/Package.mk index bb8335c..f7c85ea 100644 --- a/Package.mk +++ b/Package.mk @@ -154,6 +154,36 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip * +$(BUILD_DIR_ZIP)/mai2.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2 + $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ + $(DIST_DIR)/mai2/segatools.ini \ + $(DIST_DIR)/mai2/start.bat \ + $(BUILD_DIR_ZIP)/mai2 + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/mai2/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/mai2/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/mai2 ; zip -r ../mai2.zip * + +$(BUILD_DIR_ZIP)/cm.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/cm + $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/cmhook/cmhook.dll \ + $(DIST_DIR)/cm/segatools.ini \ + $(DIST_DIR)/cm/start.bat \ + $(BUILD_DIR_ZIP)/cm + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/cm/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip * + $(BUILD_DIR_ZIP)/doc.zip: \ $(DOC_DIR)/config \ $(DOC_DIR)/chunihook.md \ @@ -174,6 +204,8 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/mercury.zip \ $(BUILD_DIR_ZIP)/chusan.zip \ $(BUILD_DIR_ZIP)/mu3.zip \ + $(BUILD_DIR_ZIP)/mai2.zip \ + $(BUILD_DIR_ZIP)/cm.zip \ CHANGELOG.md \ README.md \ From 600f79510463e9f6dfdcd0b1d78a81afc10ebe90 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 01:07:22 +0200 Subject: [PATCH 019/204] disable dipsw by default --- dist/idac/segatools.ini | 1 + platform/config.c | 2 +- platform/dipsw.c | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index c6660ca..feae701 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -41,6 +41,7 @@ region=4 [gpio] ; ALLS DIP switches. +enable=1 ; If multiple machines are present on the same LAN then set this to 1 on ; exactly one machine and set this to 0 on all others. diff --git a/platform/config.c b/platform/config.c index 62f2707..a9f4759 100644 --- a/platform/config.c +++ b/platform/config.c @@ -327,7 +327,7 @@ void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 1, filename); + cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 0, filename); wcscpy_s(name, _countof(name), L"dipsw0"); diff --git a/platform/dipsw.c b/platform/dipsw.c index e6af610..ee6dd91 100644 --- a/platform/dipsw.c +++ b/platform/dipsw.c @@ -3,7 +3,6 @@ #include #include -// #include #include "platform/dipsw.h" #include "platform/vfs.h" From 28ef2d719a894f7622d5d834c281cf427a37ed6b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 19 Jul 2023 12:31:57 +0200 Subject: [PATCH 020/204] dinput: fixed POV bug --- cmhook/dllmain.c | 4 ++-- idachook/dllmain.c | 2 +- idacio/di.c | 2 +- idzhook/dllmain.c | 2 +- idzio/di.c | 2 +- swdcio/di.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index ce11763..5d78ace 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -60,7 +60,7 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = vfd_hook_init(3); + hr = vfd_hook_init(2); if (FAILED(hr)) { goto fail; @@ -89,7 +89,7 @@ static DWORD CALLBACK cm_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End cm_pre_startup ---\n"); + dprintf("--- End cm_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 5d6f695..fd3d447 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -75,7 +75,7 @@ static DWORD CALLBACK idac_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End idac_pre_startup ---\n"); + dprintf("--- End idac_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idacio/di.c b/idacio/di.c index 110a2ed..0d741cd 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -409,7 +409,7 @@ static uint8_t idac_di_decode_pov(DWORD pov) case 9000: return IDAC_IO_GAMEBTN_RIGHT; case 13500: return IDAC_IO_GAMEBTN_RIGHT | IDAC_IO_GAMEBTN_DOWN; case 18000: return IDAC_IO_GAMEBTN_DOWN; - case 22500: return IDAC_IO_GAMEBTN_DOWN | IDAC_IO_GAMEBTN_RIGHT; + case 22500: return IDAC_IO_GAMEBTN_DOWN | IDAC_IO_GAMEBTN_LEFT; case 27000: return IDAC_IO_GAMEBTN_LEFT; case 31500: return IDAC_IO_GAMEBTN_LEFT | IDAC_IO_GAMEBTN_UP; default: return 0; diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index fe78b6f..88fffbf 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -107,7 +107,7 @@ static DWORD CALLBACK idz_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End idz_pre_startup ---\n"); + dprintf("--- End idz_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idzio/di.c b/idzio/di.c index 3ee27ff..c363650 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -409,7 +409,7 @@ static uint8_t idz_di_decode_pov(DWORD pov) case 9000: return IDZ_IO_GAMEBTN_RIGHT; case 13500: return IDZ_IO_GAMEBTN_RIGHT | IDZ_IO_GAMEBTN_DOWN; case 18000: return IDZ_IO_GAMEBTN_DOWN; - case 22500: return IDZ_IO_GAMEBTN_DOWN | IDZ_IO_GAMEBTN_RIGHT; + case 22500: return IDZ_IO_GAMEBTN_DOWN | IDZ_IO_GAMEBTN_LEFT; case 27000: return IDZ_IO_GAMEBTN_LEFT; case 31500: return IDZ_IO_GAMEBTN_LEFT | IDZ_IO_GAMEBTN_UP; default: return 0; diff --git a/swdcio/di.c b/swdcio/di.c index f75aa6b..dd3d737 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -379,7 +379,7 @@ static uint8_t swdc_di_decode_pov(DWORD pov) case 9000: return SWDC_IO_GAMEBTN_RIGHT; case 13500: return SWDC_IO_GAMEBTN_RIGHT | SWDC_IO_GAMEBTN_DOWN; case 18000: return SWDC_IO_GAMEBTN_DOWN; - case 22500: return SWDC_IO_GAMEBTN_DOWN | SWDC_IO_GAMEBTN_RIGHT; + case 22500: return SWDC_IO_GAMEBTN_DOWN | SWDC_IO_GAMEBTN_LEFT; case 27000: return SWDC_IO_GAMEBTN_LEFT; case 31500: return SWDC_IO_GAMEBTN_LEFT | SWDC_IO_GAMEBTN_UP; default: return 0; From 3dc2ec6e69da347a52a585f164ba475fd85f27f8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 15 Aug 2023 17:20:27 +0200 Subject: [PATCH 021/204] idac, idz, swdc: Fixed DInput brake/accel, added cubic steering --- dist/idac/segatools.ini | 21 +++++++-- dist/idz/segatools.ini | 30 ++++++++++++- dist/swdc/segatools.ini | 21 +++++++-- idachook/dllmain.c | 2 +- idacio/config.c | 6 +++ idacio/config.h | 1 + idacio/di.c | 8 ++-- idacio/xi.c | 94 ++++++++++++++++++++++++++--------------- idzhook/dllmain.c | 2 +- idzio/config.c | 6 +++ idzio/config.h | 1 + idzio/di.c | 8 ++-- idzio/xi.c | 64 +++++++++++++++++++++------- swdcio/config.c | 6 +++ swdcio/config.h | 1 + swdcio/di.c | 8 ++-- swdcio/xi.c | 62 +++++++++++++++++++++------ 17 files changed, 257 insertions(+), 84 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index feae701..ce5fc8a 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -65,6 +65,18 @@ path= ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io4] ; Test button virtual-key code. Default is the 1 key. test=0x31 @@ -72,6 +84,7 @@ test=0x31 service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. coin=0x33 + ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput @@ -79,20 +92,22 @@ mode=xinput ; pressed (e.g. when navigating menus between races). autoNeutral=1 ; Use the left thumbstick for steering instead of both on XInput Controllers. -; Not recommended as it will not give you the precision needed for this game +; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 +; Use linear steering instead of the default non-linear cubing steering. +linearSteering=0 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive ; and minimum negative steering inputs reported in the operator menu's input ; test screen do not exceed the value below. The maximum possible value is 128, -; and the value that matches the input range of a real cabinet is 97. +; and the value that matches the input range of a real cabinet is 128. ; ; NOTE: This is not the same thing as DirectInput steering wheel movement ; range! Segatools cannot control the maximum angle of your physical steering ; wheel controller, this setting is vendor-specific and can only be adjusted ; in the Control Panel. -restrict=97 +restrict=128 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 367d27e..6c68321 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -8,6 +8,11 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -50,7 +55,26 @@ path= ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io3] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 + ; Input API selection for JVS input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput @@ -58,8 +82,10 @@ mode=xinput ; pressed (e.g. when navigating menus between races). autoNeutral=1 ; Use the left thumbstick for steering instead of both on XInput Controllers. -; Not recommended as it will not give you the precision needed for this game -singleStickSteering=0 +; Not recommended as it will not give you the precision needed for this game. +singleStickSteering=1 +; Use linear steering instead of the default non-linear cubing steering. +linearSteering=0 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index dc0c003..ef762c5 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -40,6 +40,18 @@ path= ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io4] ; Test button virtual-key code. Default is the 1 key. test=0x31 @@ -49,22 +61,25 @@ service=0x32 coin=0x33 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. + mode=xinput ; Use the left thumbstick for steering instead of both on XInput Controllers. -; Not recommended as it will not give you the precision needed for this game +; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 +; Use linear steering instead of the default non-linear cubing steering. +linearSteering=0 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive ; and minimum negative steering inputs reported in the operator menu's input ; test screen do not exceed the value below. The maximum possible value is 128, -; and the value that matches the input range of a real cabinet is 97. +; and the value that matches the input range of a real cabinet is 128. ; ; NOTE: This is not the same thing as DirectInput steering wheel movement ; range! Segatools cannot control the maximum angle of your physical steering ; wheel controller, this setting is vendor-specific and can only be adjusted ; in the Control Panel. -restrict=97 +restrict=128 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) diff --git a/idachook/dllmain.c b/idachook/dllmain.c index fd3d447..5d6f695 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -75,7 +75,7 @@ static DWORD CALLBACK idac_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End idac_pre_startup ---\n"); + dprintf("--- End idac_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idacio/config.c b/idacio/config.c index 700f18b..ce7e201 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -81,6 +81,12 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) L"singleStickSteering", 0, filename); + + cfg->linear_steering = GetPrivateProfileIntW( + L"io4", + L"linearSteering", + 0, + filename); } void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) diff --git a/idacio/config.h b/idacio/config.h index 6e5563d..05332da 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -24,6 +24,7 @@ struct idac_di_config { struct idac_xi_config { bool single_stick_steering; + bool linear_steering; }; struct idac_io_config { diff --git a/idacio/di.c b/idacio/di.c index 0d741cd..2494082 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -262,8 +262,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name); - dprintf("Wheel: Accelerator axis . : %S\n", brake_axis->name); + dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); dprintf("Wheel: Start button . . . : %i\n", cfg->start); dprintf("Wheel: View Change button : %i\n", cfg->view_chg); dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); @@ -286,8 +286,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) dprintf("Shifter: --- End configuration ---\n"); } - idac_di_off_brake = accel_axis->off; - idac_di_off_accel = brake_axis->off; + idac_di_off_brake = brake_axis->off; + idac_di_off_accel = accel_axis->off; idac_di_start = cfg->start; idac_di_view_chg = cfg->view_chg; idac_di_shift_dn = cfg->shift_dn; diff --git a/idacio/xi.c b/idacio/xi.c index 87f3fbd..3a41aaa 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -1,16 +1,16 @@ -#include -#include +#include "idacio/xi.h" #include +#include #include #include +#include +#include #include "idacio/backend.h" #include "idacio/config.h" #include "idacio/idacio.h" #include "idacio/shifter.h" -#include "idacio/xi.h" - #include "util/dprintf.h" static void idac_xi_get_gamebtns(uint8_t *gamebtn_out); @@ -20,15 +20,15 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out); static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg); static const struct idac_io_backend idac_xi_backend = { - .get_gamebtns = idac_xi_get_gamebtns, - .get_shifter = idac_xi_get_shifter, - .get_analogs = idac_xi_get_analogs, + .get_gamebtns = idac_xi_get_gamebtns, + .get_shifter = idac_xi_get_shifter, + .get_analogs = idac_xi_get_analogs, }; static bool idac_xi_single_stick_steering; +static bool idac_xi_linear_steering; -HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) -{ +HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) { HRESULT hr; assert(cfg != NULL); assert(backend != NULL); @@ -45,24 +45,23 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back return S_OK; } -HRESULT idac_io_poll(void) -{ +HRESULT idac_io_poll(void) { return S_OK; } -static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) -{ +static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) { dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); + dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); dprintf("XInput: --- End configuration ---\n"); idac_xi_single_stick_steering = cfg->single_stick_steering; + idac_xi_linear_steering = cfg->linear_steering; return S_OK; } -static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) -{ +static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) { uint8_t gamebtn; XINPUT_STATE xi; WORD xb; @@ -102,8 +101,7 @@ static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) *gamebtn_out = gamebtn; } -static void idac_xi_get_shifter(uint8_t *gear) -{ +static void idac_xi_get_shifter(uint8_t *gear) { bool shift_dn; bool shift_up; XINPUT_STATE xi; @@ -144,8 +142,32 @@ static void idac_xi_get_shifter(uint8_t *gear) *gear = idac_shifter_current_gear(); } -static void idac_xi_get_analogs(struct idac_io_analog_state *out) -{ +static int apply_non_linear_transform(int value, int deadzone_center) { + const int max_input = 32767; + const double power_factor = 3.0; + + // Apply deadzone only after passing the center threshold + if (abs(value) < deadzone_center) { + return 0; + } + + // Scale the value to the range [-1.0, 1.0] + double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + + // Apply a non-linear transform (cubing in this case) and preserve the sign + double signed_value = copysign(pow(scaled_value, power_factor), value); + + // Scale the value back to the range [-32770, 32767] + int transformed_value = (int)(signed_value * max_input); + + // Clamp the value to the range [-32767, 32767] + transformed_value = (transformed_value > max_input) ? max_input : transformed_value; + transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; + + return transformed_value; +} + +static void idac_xi_get_analogs(struct idac_io_analog_state *out) { XINPUT_STATE xi; int left; int right; @@ -156,27 +178,33 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) XInputGetState(0, &xi); left = xi.Gamepad.sThumbLX; - - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else { - left = 0; - } - right = xi.Gamepad.sThumbRX; - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + if (!idac_xi_linear_steering) { + // Apply non-linear transform for both sticks + left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); } else { - right = 0; + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } } if (idac_xi_single_stick_steering) { out->wheel = left; + // dprintf("XInput: Single Stick Steering: %i\n", out->wheel); } else { out->wheel = (left + right) / 2; } diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index 88fffbf..fe78b6f 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -107,7 +107,7 @@ static DWORD CALLBACK idz_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End idz_pre_startup ---\n"); + dprintf("--- End idz_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/idzio/config.c b/idzio/config.c index d06476b..e49b550 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -81,6 +81,12 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) L"singleStickSteering", 0, filename); + + cfg->linear_steering = GetPrivateProfileIntW( + L"io3", + L"linearSteering", + 0, + filename); } void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename) diff --git a/idzio/config.h b/idzio/config.h index 19b837a..3d2668b 100644 --- a/idzio/config.h +++ b/idzio/config.h @@ -24,6 +24,7 @@ struct idz_di_config { struct idz_xi_config { bool single_stick_steering; + bool linear_steering; }; struct idz_io_config { diff --git a/idzio/di.c b/idzio/di.c index c363650..c16be14 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -262,8 +262,8 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name); - dprintf("Wheel: Accelerator axis . : %S\n", brake_axis->name); + dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); dprintf("Wheel: Start button . . . : %i\n", cfg->start); dprintf("Wheel: View Change button : %i\n", cfg->view_chg); dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); @@ -286,8 +286,8 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) dprintf("Shifter: --- End configuration ---\n"); } - idz_di_off_brake = accel_axis->off; - idz_di_off_accel = brake_axis->off; + idz_di_off_brake = brake_axis->off; + idz_di_off_accel = accel_axis->off; idz_di_start = cfg->start; idz_di_view_chg = cfg->view_chg; idz_di_shift_dn = cfg->shift_dn; diff --git a/idzio/xi.c b/idzio/xi.c index c3d33d6..ebd1ea9 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ static const struct idz_io_backend idz_xi_backend = { }; static bool idz_xi_single_stick_steering; +static bool idz_xi_linear_steering; HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend) { @@ -49,9 +51,11 @@ static HRESULT idz_xi_config_apply(const struct idz_xi_config *cfg) { dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); + dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); dprintf("XInput: --- End configuration ---\n"); idz_xi_single_stick_steering = cfg->single_stick_steering; + idz_xi_linear_steering = cfg->linear_steering; return S_OK; } @@ -123,6 +127,31 @@ static void idz_xi_jvs_read_shifter(uint8_t *gear) *gear = idz_shifter_current_gear(); } +static int apply_non_linear_transform(int value, int deadzone_center) { + const int max_input = 32767; + const double power_factor = 3.0; + + // Apply deadzone only after passing the center threshold + if (abs(value) < deadzone_center) { + return 0; + } + + // Scale the value to the range [-1.0, 1.0] + double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + + // Apply a non-linear transform (cubing in this case) and preserve the sign + double signed_value = copysign(pow(scaled_value, power_factor), value); + + // Scale the value back to the range [-32770, 32767] + int transformed_value = (int)(signed_value * max_input); + + // Clamp the value to the range [-32767, 32767] + transformed_value = (transformed_value > max_input) ? max_input : transformed_value; + transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; + + return transformed_value; +} + static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) { XINPUT_STATE xi; @@ -135,23 +164,28 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) XInputGetState(0, &xi); left = xi.Gamepad.sThumbLX; - - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else { - left = 0; - } - right = xi.Gamepad.sThumbRX; - - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + + if (!idz_xi_linear_steering) { + // Apply non-linear transform for both sticks + left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); } else { - right = 0; + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } } if(idz_xi_single_stick_steering) { diff --git a/swdcio/config.c b/swdcio/config.c index 7396338..ae4a1f5 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -71,6 +71,12 @@ void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) L"singleStickSteering", 0, filename); + + cfg->linear_steering = GetPrivateProfileIntW( + L"io4", + L"linearSteering", + 0, + filename); } void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) diff --git a/swdcio/config.h b/swdcio/config.h index 4fa482f..0225d59 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -26,6 +26,7 @@ struct swdc_di_config { struct swdc_xi_config { bool single_stick_steering; + bool linear_steering; }; struct swdc_io_config { diff --git a/swdcio/di.c b/swdcio/di.c index dd3d737..0fd0118 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -246,8 +246,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . . . : %S\n", accel_axis->name); - dprintf("Wheel: Accelerator axis . . . : %S\n", brake_axis->name); + dprintf("Wheel: Brake axis . . . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . . . : %S\n", accel_axis->name); dprintf("Wheel: Start button . . . . . : %i\n", cfg->start); dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg); dprintf("Wheel: Shift Down button . . : %i\n", cfg->shift_dn); @@ -260,8 +260,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) dprintf("Wheel: Reverse Accel Axis . . : %i\n", cfg->reverse_accel_axis); dprintf("Wheel: --- End configuration ---\n"); - swdc_di_off_brake = accel_axis->off; - swdc_di_off_accel = brake_axis->off; + swdc_di_off_brake = brake_axis->off; + swdc_di_off_accel = accel_axis->off; swdc_di_start = cfg->start; swdc_di_view_chg = cfg->view_chg; swdc_di_shift_dn = cfg->shift_dn; diff --git a/swdcio/xi.c b/swdcio/xi.c index 9be56a2..9a98ec4 100644 --- a/swdcio/xi.c +++ b/swdcio/xi.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ static const struct swdc_io_backend swdc_xi_backend = { }; static bool swdc_xi_single_stick_steering; +static bool swdc_xi_linear_steering; HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend) { @@ -51,9 +53,11 @@ static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg) { dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); + dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); dprintf("XInput: --- End configuration ---\n"); swdc_xi_single_stick_steering = cfg->single_stick_steering; + swdc_xi_linear_steering = cfg->linear_steering; return S_OK; } @@ -123,6 +127,31 @@ static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out) *gamebtn_out = gamebtn; } +static int apply_non_linear_transform(int value, int deadzone_center) { + const int max_input = 32767; + const double power_factor = 3.0; + + // Apply deadzone only after passing the center threshold + if (abs(value) < deadzone_center) { + return 0; + } + + // Scale the value to the range [-1.0, 1.0] + double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + + // Apply a non-linear transform (cubing in this case) and preserve the sign + double signed_value = copysign(pow(scaled_value, power_factor), value); + + // Scale the value back to the range [-32770, 32767] + int transformed_value = (int)(signed_value * max_input); + + // Clamp the value to the range [-32767, 32767] + transformed_value = (transformed_value > max_input) ? max_input : transformed_value; + transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; + + return transformed_value; +} + static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) { XINPUT_STATE xi; @@ -135,23 +164,28 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) XInputGetState(0, &xi); left = xi.Gamepad.sThumbLX; - - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else { - left = 0; - } - right = xi.Gamepad.sThumbRX; - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + if (!swdc_xi_linear_steering) { + // Apply non-linear transform for both sticks + left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); } else { - right = 0; + if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + } else { + left = 0; + } + + if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + } else { + right = 0; + } } if (swdc_xi_single_stick_steering) { From 608c9ac1a6b770bd3b0c4b68b8074689ec7ca17b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 15 Aug 2023 17:28:19 +0200 Subject: [PATCH 022/204] chusan, cm, mai2, mu3: Added dipSw support and highBaudrate AiMe --- board/config.c | 1 + board/sg-reader.c | 4 +++ board/sg-reader.h | 1 + cmhook/dllmain.c | 2 +- dist/chusan/segatools.ini | 12 +++++++ dist/chusan/start.bat | 4 +-- dist/cm/segatools.ini | 17 +++++++-- dist/cm/start.bat | 4 +-- dist/mai2/segatools.ini | 10 +++++- dist/mu3/segatools.ini | 74 +++++++++++++++++++++++--------------- dist/mu3/start.bat | 16 ++++----- doc/config/common.md | 34 ++++++++++++++++++ hooklib/touch.c | 76 +++++++++++++++++++++++++++++++++++++-- hooklib/touch.h | 4 ++- 14 files changed, 209 insertions(+), 50 deletions(-) diff --git a/board/config.c b/board/config.c index 191425a..9d015e9 100644 --- a/board/config.c +++ b/board/config.c @@ -30,6 +30,7 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highbaud", 1, filename); } void io4_config_load(struct io4_config *cfg, const wchar_t *filename) diff --git a/board/sg-reader.c b/board/sg-reader.c index dbf0392..e8fbfba 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -70,6 +70,10 @@ HRESULT sg_reader_hook_init( InitializeCriticalSection(&sg_reader_lock); + if (!cfg->high_baudrate) { + sg_reader_uart.baud.BaudRate = 38400; + } + uart_init(&sg_reader_uart, port_no); sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); diff --git a/board/sg-reader.h b/board/sg-reader.h index 673a8bd..b9f19c5 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -9,6 +9,7 @@ struct aime_config { struct aime_dll_config dll; bool enable; + bool high_baudrate; }; HRESULT sg_reader_hook_init( diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 5d78ace..9fd12cd 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -89,7 +89,7 @@ static DWORD CALLBACK cm_pre_startup(void) spike_hook_init(L".\\segatools.ini"); - dprintf("--- End cm_pre_startup ---\n"); + dprintf("--- End cm_pre_startup ---\n"); /* Jump to EXE start address */ diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 196766f..a2189f9 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -36,6 +36,18 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.100.0 +[gpio] +; ALLS DIP switches. +enable=1 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 1 on exactly one machine and set this to 0 on all others. +dipsw1=1 +; Monitor type: 0 = 120FPS, 1 = 60FPS +dipsw2=1 +; Aime reader hardware type: 0 = SP, 1 = CVT +dipsw3=1 + [gfx] ; Force the game to run windowed. windowed=1 diff --git a/dist/chusan/start.bat b/dist/chusan/start.bat index dbd1a8b..9a91cd2 100644 --- a/dist/chusan/start.bat +++ b/dist/chusan/start.bat @@ -2,8 +2,8 @@ pushd %~dp0 -start /min inject_x64.exe -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_sp.json -inject_x86.exe -d -k chusanhook_x86.dll chusanApp.exe +start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json +inject_x86 -d -k chusanhook_x86.dll chusanApp.exe taskkill /f /im amdaemon.exe > nul 2>&1 echo. diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index f2b4ca3..0097e7e 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -8,11 +8,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= - [aime] ; Enable aime reader emulation. enable=1 -aimePath=C:\SEGA\DEVICE\aime.txt +aimePath=DEVICE\aime.txt felicaGen=0 [dns] @@ -32,6 +31,18 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.100.0 +[gpio] +; ALLS DIP switches. +enable=1 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 1 on exactly one machine and set this to 0 on all others. +dipsw1=1 + +[touch] +; Enable/Disable WinTouch emulation +enable=0 + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -50,4 +61,4 @@ test=0x31 ; Service button virtual-key code. Default is the 2 key. service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 \ No newline at end of file +coin=0x33 diff --git a/dist/cm/start.bat b/dist/cm/start.bat index b51c839..d4e6b66 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,8 +2,8 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_server.json config_common.json -inject.exe -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 +start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 8676568..a86bee4 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -15,7 +15,7 @@ enable=1 [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. -default= +default=127.0.0.1 [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. @@ -29,6 +29,14 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.100.0 +[gpio] +; ALLS DIP switches. +enable=1 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 1 on exactly one machine and set this to 0 on all others. +dipsw1=1 + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index ef6df83..9c8f46f 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -1,25 +1,24 @@ [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= -option= + +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt +felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 -[ds] -; Region code on the emulated AMEX board DS EEPROM. -; 1: Japan -; 4: Export (some UI elements in English) -; -; NOTE: Changing this setting causes a factory reset. -region=1 - [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. ; SEGA games are somewhat picky about their LAN environment, so leaving this @@ -30,16 +29,33 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.250.0 +subnet=192.168.100.0 + +[gpio] +; ALLS DIP switches. +enable=1 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 1 on exactly one machine and set this to 0 on all others. +dipsw1=1 [gfx] enable=1 +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io4] ; Input API selection for JVS input emulator. -; Set "1" to use a xinput gamepad and set "2" to use keyboard. -mode=2 - ; Test button virtual-key code. Default is the 1 key. test=0x31 ; Service button virtual-key code. Default is the 2 key. @@ -47,18 +63,20 @@ service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. coin=0x33 -[dinput] -LEFT_A=0x53 -LEFT_B=0x44 -LEFT_C=0x46 -LEFT_MENU=0x51 -LEFT_SIDE=0x52 -RIGHT_A=0x4A -RIGHT_B=0x4B -RIGHT_C=0x4C -RIGHT_MENU=0x50 -RIGHT_SIDE=0x55 -SLIDER_LEFT=0x54 -SLIDER_RIGHT=0x59 -;Change move speed of slider when use dinput -SLIDER_SPEED=1000 \ No newline at end of file +; Set "1" to enable mouse lever emulation, "0" to use XInput +mouse=1 + +; Keyboard input bindings +left1=0x41 ; A +left2=0x53 ; S +left3=0x44 ; D + +leftSide=0x01 ; Mouse Left +rightSide=0x02 ; Mouse Right + +right1=0x4A ; J +right1=0x4B ; K +right3=0x4C ; L + +leftMenu=0x55 ; U +rightMenu=0x4F ; O diff --git a/dist/mu3/start.bat b/dist/mu3/start.bat index c00f2ea..8058daf 100644 --- a/dist/mu3/start.bat +++ b/dist/mu3/start.bat @@ -1,15 +1,11 @@ @echo off + pushd %~dp0 +start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +inject -d -k mu3hook.dll mu3 -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 -REM USA -REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json - -REM JP -start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json -inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe - -taskkill /f /im amdaemon.exe > nul 2>&1 - -echo Game processes have terminated \ No newline at end of file +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/doc/config/common.md b/doc/config/common.md index 7dc14c1..de6f267 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -31,6 +31,13 @@ Default: `1` Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime reader (COM port number varies by game). +### `highbaud` + +Default: `1` + +Enables the high baudrate of the Aime card reader to be 115200 (instead of 38400). +This is required for some games (e.g. Chunithm) but not others (e.g. WACCA). + ### `aimePath` Default: `DEVICE\aime.txt` @@ -270,6 +277,33 @@ Default `1` Enable JVS port emulation. Disable to use the JVS port on a real AMEX. +## `[io4]` + +Configure emulation of the IO4 board. Same settings also apply to `[io3]`. + +### `enable` + +Default `1` + +Enable IO4 port emulation. Disable to use the IO4 port on a real ALLS. + +### `test` +Default `0x31` + +Test button virtual-key code. Default is the 1 key. + +### `service` + +Default `0x32` + +Service button virtual-key code. Default is the 2 key. + +### `coin` + +Default `0x33` + +Keyboard button to increment coin counter. Default is the 3 key. + ## `[keychip]` Configure keychip emulation. diff --git a/hooklib/touch.c b/hooklib/touch.c index ca0b8a9..9911514 100644 --- a/hooklib/touch.c +++ b/hooklib/touch.c @@ -19,6 +19,12 @@ This means there can be some license issues if you do use this code in some othe /* API hooks */ +static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +static ATOM WINAPI hook_RegisterClassExA( + WNDCLASSEXA* wndClass +); + static int WINAPI hook_GetSystemMetrics( int nIndex ); @@ -35,8 +41,14 @@ static BOOL WINAPI hook_GetTouchInputInfo( int cbSize ); +static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor); + /* Link pointers */ +static ATOM (WINAPI *next_RegisterClassExA)( + const WNDCLASSEXA* wndClass +); + static int (WINAPI *next_GetSystemMetrics)( int nIndex ); @@ -53,10 +65,20 @@ static BOOL (WINAPI *next_GetTouchInputInfo)( int cbSize ); +static HCURSOR(WINAPI *next_SetCursor)(HCURSOR cursor); + static bool touch_hook_initted; +static bool touch_held; +static HWND registered_hWnd; static struct touch_screen_config touch_config; +static WNDPROC orig_wndProc; static const struct hook_symbol touch_hooks[] = { + { + .name = "RegisterClassExA", + .patch = hook_RegisterClassExA, + .link = (void**)&next_RegisterClassExA + }, { .name = "GetSystemMetrics", .patch = hook_GetSystemMetrics, @@ -72,6 +94,11 @@ static const struct hook_symbol touch_hooks[] = { .patch = hook_GetTouchInputInfo, .link = (void **) &next_GetTouchInputInfo }, + { + .name = "SetCursor", + .patch = hook_SetCursor, + .link = (void **) &next_SetCursor + }, }; void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self) @@ -93,6 +120,34 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel dprintf("TOUCH: hook enabled.\n"); } +static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) { + if (cursor == 0 && touch_config.cursor) + return 0; + + return next_SetCursor(cursor); +} + +// remap mouse events to touch events + +static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + if (hWnd == registered_hWnd && (Msg == WM_LBUTTONDOWN || Msg == WM_LBUTTONUP || (touch_held && Msg == WM_MOUSEMOVE))) { + orig_wndProc(hWnd, WM_TOUCH, 1, 1); + } + + return orig_wndProc(hWnd, Msg, wParam, lParam); +} + +static ATOM WINAPI hook_RegisterClassExA( + WNDCLASSEXA* wndClass +) { + if (wndClass->lpfnWndProc) { + orig_wndProc = wndClass->lpfnWndProc; + wndClass->lpfnWndProc = (WNDPROC) hook_wndProc; + } + + return next_RegisterClassExA(wndClass); +} + // Spicetools misc/wintouchemu.cpp static int WINAPI hook_GetSystemMetrics( @@ -111,11 +166,11 @@ static BOOL WINAPI hook_RegisterTouchWindow( ULONG ulFlags ) { + registered_hWnd = hwnd; return true; } // Converting mouse event to touch event -// Does not work at current stage static BOOL WINAPI hook_GetTouchInputInfo( HANDLE hTouchInput, UINT cInputs, @@ -124,7 +179,15 @@ static BOOL WINAPI hook_GetTouchInputInfo( ) { bool result = false; + int sw, sh, cw, ch; + RECT cRect; + sw = GetSystemMetrics(SM_CXSCREEN); + sh = GetSystemMetrics(SM_CYSCREEN); + GetClientRect(registered_hWnd, &cRect); + cw = cRect.right - cRect.left; + ch = cRect.bottom - cRect.top; static bool mouse_state_old = false; + for (UINT input = 0; input < cInputs; input++) { TOUCHINPUT *touch_input = &pInputs[input]; @@ -143,8 +206,15 @@ static BOOL WINAPI hook_GetTouchInputInfo( if (mouse_state || mouse_state_old) { POINT cursorPos; + GetCursorPos(&cursorPos); + if (touch_config.remap) { + ScreenToClient(registered_hWnd, &cursorPos); + cursorPos.x = (long)(cursorPos.x * ((double)sw / cw)); + cursorPos.y = (long)(cursorPos.y * ((double)sh / ch)); + } + result = true; touch_input->x = cursorPos.x * 100; touch_input->y = cursorPos.y * 100; @@ -153,10 +223,12 @@ static BOOL WINAPI hook_GetTouchInputInfo( touch_input->dwFlags = 0; if (mouse_state && !mouse_state_old) { touch_input->dwFlags |= TOUCHEVENTF_DOWN; + touch_held = true; } else if (mouse_state && mouse_state_old) { touch_input->dwFlags |= TOUCHEVENTF_MOVE; } else if (!mouse_state && mouse_state_old) { touch_input->dwFlags |= TOUCHEVENTF_UP; + touch_held = false; } touch_input->dwMask = 0; touch_input->dwTime = 0; @@ -168,4 +240,4 @@ static BOOL WINAPI hook_GetTouchInputInfo( } return result; -} \ No newline at end of file +} diff --git a/hooklib/touch.h b/hooklib/touch.h index f80a25e..dad00ad 100644 --- a/hooklib/touch.h +++ b/hooklib/touch.h @@ -6,9 +6,11 @@ struct touch_screen_config { bool enable; + bool remap; + bool cursor; }; /* Init is not thread safe because API hook init is not thread safe blah blah blah you know the drill by now. */ -void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self); \ No newline at end of file +void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self); From 80d5fc4bb2ad00be084887282b39400b2c33d4e7 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 15 Aug 2023 17:40:32 +0200 Subject: [PATCH 023/204] mu3: Added basic keyboard and mouse lever emulation support --- mu3io/config.c | 17 ++++++++++--- mu3io/config.h | 13 ++++++++++ mu3io/mu3io.c | 66 ++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/mu3io/config.c b/mu3io/config.c index 2fd4989..b47a4dc 100644 --- a/mu3io/config.c +++ b/mu3io/config.c @@ -6,17 +6,28 @@ #include "mu3io/config.h" + void mu3_io_config_load( struct mu3_io_config *cfg, const wchar_t *filename) { - wchar_t key[16]; - int i; - assert(cfg != NULL); assert(filename != NULL); cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + + cfg->use_mouse = GetPrivateProfileIntW(L"io4", L"mouse", 0, filename); + + cfg->vk_left_1 = GetPrivateProfileIntW(L"io4", L"left1", 'A', filename); + cfg->vk_left_2 = GetPrivateProfileIntW(L"io4", L"left2", 'S', filename); + cfg->vk_left_3 = GetPrivateProfileIntW(L"io4", L"left3", 'D', filename); + cfg->vk_left_side = GetPrivateProfileIntW(L"io4", L"leftSide", 'Q', filename); + cfg->vk_right_side = GetPrivateProfileIntW(L"io4", L"rightSide", 'E', filename); + cfg->vk_right_1 = GetPrivateProfileIntW(L"io4", L"right1", 'J', filename); + cfg->vk_right_2 = GetPrivateProfileIntW(L"io4", L"right2", 'K', filename); + cfg->vk_right_3 = GetPrivateProfileIntW(L"io4", L"right3", 'L', filename); + cfg->vk_left_menu = GetPrivateProfileIntW(L"io4", L"leftMenu", 'U', filename); + cfg->vk_right_menu = GetPrivateProfileIntW(L"io4", L"rightMenu", 'O', filename); } diff --git a/mu3io/config.h b/mu3io/config.h index f3632ce..ff74c3b 100644 --- a/mu3io/config.h +++ b/mu3io/config.h @@ -9,6 +9,19 @@ struct mu3_io_config { uint8_t vk_test; uint8_t vk_service; uint8_t vk_coin; + + bool use_mouse; + + uint8_t vk_left_1; + uint8_t vk_left_2; + uint8_t vk_left_3; + uint8_t vk_left_side; + uint8_t vk_right_side; + uint8_t vk_right_1; + uint8_t vk_right_2; + uint8_t vk_right_3; + uint8_t vk_left_menu; + uint8_t vk_right_menu; }; void mu3_io_config_load( diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index 775a1b4..cb8d6e3 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -6,6 +6,7 @@ #include "mu3io/mu3io.h" #include "mu3io/config.h" +#include "util/dprintf.h" static uint8_t mu3_opbtn; static uint8_t mu3_left_btn; @@ -15,6 +16,9 @@ static int16_t mu3_lever_xpos; static struct mu3_io_config mu3_io_cfg; static bool mu3_io_coin; +// Mouse control factor to adjust the speed of mouse movement +const double MOUSE_SENSITIVITY = 0.5; + uint16_t mu3_io_get_api_version(void) { return 0x0100; @@ -23,6 +27,11 @@ uint16_t mu3_io_get_api_version(void) HRESULT mu3_io_init(void) { mu3_io_config_load(&mu3_io_cfg, L".\\segatools.ini"); + + dprintf("XInput: --- Begin configuration ---\n"); + dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse); + dprintf("XInput: --- End configuration ---\n"); + return S_OK; } @@ -58,54 +67,81 @@ HRESULT mu3_io_poll(void) XInputGetState(0, &xi); xb = xi.Gamepad.wButtons; - if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + if (GetAsyncKeyState(mu3_io_cfg.vk_left_1) || (xb & XINPUT_GAMEPAD_DPAD_LEFT)) { mu3_left_btn |= MU3_IO_GAMEBTN_1; } - if (xb & XINPUT_GAMEPAD_DPAD_UP) { + if (GetAsyncKeyState(mu3_io_cfg.vk_left_2) || (xb & XINPUT_GAMEPAD_DPAD_UP)) { mu3_left_btn |= MU3_IO_GAMEBTN_2; } - if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + if (GetAsyncKeyState(mu3_io_cfg.vk_left_3) || (xb & XINPUT_GAMEPAD_DPAD_RIGHT)) { mu3_left_btn |= MU3_IO_GAMEBTN_3; } - if (xb & XINPUT_GAMEPAD_X) { + if (GetAsyncKeyState(mu3_io_cfg.vk_right_1) || (xb & XINPUT_GAMEPAD_X)) { mu3_right_btn |= MU3_IO_GAMEBTN_1; } - if (xb & XINPUT_GAMEPAD_Y) { + if (GetAsyncKeyState(mu3_io_cfg.vk_right_2) || (xb & XINPUT_GAMEPAD_Y)) { mu3_right_btn |= MU3_IO_GAMEBTN_2; } - if (xb & XINPUT_GAMEPAD_B) { + if (GetAsyncKeyState(mu3_io_cfg.vk_right_3) || (xb & XINPUT_GAMEPAD_B)) { mu3_right_btn |= MU3_IO_GAMEBTN_3; } - if (xb & XINPUT_GAMEPAD_BACK) { + if (GetAsyncKeyState(mu3_io_cfg.vk_left_menu) || (xb & XINPUT_GAMEPAD_BACK)) { mu3_left_btn |= MU3_IO_GAMEBTN_MENU; } - if (xb & XINPUT_GAMEPAD_START) { + if (GetAsyncKeyState(mu3_io_cfg.vk_right_menu) || (xb & XINPUT_GAMEPAD_START)) { mu3_right_btn |= MU3_IO_GAMEBTN_MENU; } - if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) { + if (GetAsyncKeyState(mu3_io_cfg.vk_left_side) || (xb & XINPUT_GAMEPAD_LEFT_SHOULDER)) { mu3_left_btn |= MU3_IO_GAMEBTN_SIDE; } - if (xb & XINPUT_GAMEPAD_RIGHT_SHOULDER) { + if (GetAsyncKeyState(mu3_io_cfg.vk_right_side) || (xb & XINPUT_GAMEPAD_RIGHT_SHOULDER)) { mu3_right_btn |= MU3_IO_GAMEBTN_SIDE; } lever = mu3_lever_pos; - if (abs(xi.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - lever += xi.Gamepad.sThumbLX / 24; - } + if (mu3_io_cfg.use_mouse) { + // mouse movement + POINT mousePos; + GetCursorPos(&mousePos); - if (abs(xi.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - lever += xi.Gamepad.sThumbRX / 24; + // int mouseMovement = (int)(xi.Gamepad.sThumbLX * MOUSE_SENSITIVITY); + // int newXPos = mousePos.x + mouseMovement; + int mouse_x = mousePos.x; + + // clamp the mouse_x position to the screen width + int screenWidth = GetSystemMetrics(SM_CXSCREEN); + if (mouse_x < 0) { + mouse_x = 0; + } + else if (mouse_x > screenWidth) { + mouse_x = screenWidth; + } + + // normalize the mouse_x position from 0 to 1 + double mouse_x_norm = (double)mouse_x / screenWidth; + + // scale the mouse_x_norm to the range of INT16_MIN to INT16_MAX + mouse_x = (int)((mouse_x_norm * (INT16_MAX - INT16_MIN)) + INT16_MIN); + + lever = mouse_x; + } else { + if (abs(xi.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + lever += xi.Gamepad.sThumbLX / 24; + } + + if (abs(xi.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { + lever += xi.Gamepad.sThumbRX / 24; + } } if (lever < INT16_MIN) { From 2277bf752613da2f616441ae6fad85310030a81d Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 15 Aug 2023 20:23:28 +0200 Subject: [PATCH 024/204] all: fix accounting issue (my bad) --- platform/vfs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platform/vfs.c b/platform/vfs.c index 9f620d8..02e3ea2 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -28,9 +28,7 @@ static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); static wchar_t vfs_nthome_real[MAX_PATH]; -// new home for ALLS -static const wchar_t vfs_nthome[] = L"C:\\Users\\AppUser"; -// static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; +static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; static const wchar_t vfs_option[] = L"C:\\Mount\\Option"; From 97234f26d722b18a32051a5b8fb8034b732efe39 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 15 Aug 2023 21:59:14 +0200 Subject: [PATCH 025/204] cm, chusan, mai2, mu3, swdc: added emoney config --- Package.mk | 5 +++++ dist/chusan/config_hook.json | 10 ++++++++++ dist/chusan/start.bat | 2 +- dist/cm/config_hook.json | 6 ++++++ dist/cm/segatools.ini | 4 ++-- dist/cm/start.bat | 2 +- dist/mai2/config_hook.json | 6 ++++++ dist/mai2/start.bat | 2 +- dist/mu3/config_hook.json | 6 ++++++ dist/mu3/start.bat | 2 +- dist/swdc/config_hook.json | 6 ++++++ dist/swdc/start.bat | 2 +- 12 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 dist/chusan/config_hook.json create mode 100644 dist/cm/config_hook.json create mode 100644 dist/mai2/config_hook.json create mode 100644 dist/mu3/config_hook.json create mode 100644 dist/swdc/config_hook.json diff --git a/Package.mk b/Package.mk index f7c85ea..587906f 100644 --- a/Package.mk +++ b/Package.mk @@ -94,6 +94,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/swdchook/swdchook.dll \ + $(DIST_DIR)/chusan/config_hook.json \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/start.bat \ $(BUILD_DIR_ZIP)/swdc @@ -123,6 +124,7 @@ $(BUILD_DIR_ZIP)/chusan.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/chusan $(V)mkdir -p $(BUILD_DIR_ZIP)/chusan/DEVICE $(V)cp $(DIST_DIR)/chusan/segatools.ini \ + $(DIST_DIR)/chusan/config_hook.json \ $(DIST_DIR)/chusan/start.bat \ $(BUILD_DIR_ZIP)/chusan $(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \ @@ -145,6 +147,7 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mu3hook/mu3hook.dll \ + $(DIST_DIR)/mu3/config_hook.json \ $(DIST_DIR)/mu3/segatools.ini \ $(DIST_DIR)/mu3/start.bat \ $(BUILD_DIR_ZIP)/mu3 @@ -160,6 +163,7 @@ $(BUILD_DIR_ZIP)/mai2.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ + $(DIST_DIR)/mai2/config_hook.json \ $(DIST_DIR)/mai2/segatools.ini \ $(DIST_DIR)/mai2/start.bat \ $(BUILD_DIR_ZIP)/mai2 @@ -175,6 +179,7 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/cmhook/cmhook.dll \ + $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ $(DIST_DIR)/cm/start.bat \ $(BUILD_DIR_ZIP)/cm diff --git a/dist/chusan/config_hook.json b/dist/chusan/config_hook.json new file mode 100644 index 0000000..2fb68b1 --- /dev/null +++ b/dist/chusan/config_hook.json @@ -0,0 +1,10 @@ +{ + "allnet_auth": + { + "type": "1.0" + }, + "emoney" : + { + "enable" : false + } +} diff --git a/dist/chusan/start.bat b/dist/chusan/start.bat index 9a91cd2..4125873 100644 --- a/dist/chusan/start.bat +++ b/dist/chusan/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json +start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json inject_x86 -d -k chusanhook_x86.dll chusanApp.exe taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/cm/config_hook.json b/dist/cm/config_hook.json new file mode 100644 index 0000000..b73cf5c --- /dev/null +++ b/dist/cm/config_hook.json @@ -0,0 +1,6 @@ +{ + "emoney" : + { + "enable" : false + } +} diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 0097e7e..31e9d96 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -36,8 +36,8 @@ subnet=192.168.100.0 enable=1 ; LAN Install: If multiple machines are present on the same LAN then set -; this to 1 on exactly one machine and set this to 0 on all others. -dipsw1=1 +; this to 0 on exactly one machine and set this to 1 on all others. +dipsw1=0 [touch] ; Enable/Disable WinTouch emulation diff --git a/dist/cm/start.bat b/dist/cm/start.bat index d4e6b66..3c6b6f5 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mai2/config_hook.json b/dist/mai2/config_hook.json new file mode 100644 index 0000000..b73cf5c --- /dev/null +++ b/dist/mai2/config_hook.json @@ -0,0 +1,6 @@ +{ + "emoney" : + { + "enable" : false + } +} diff --git a/dist/mai2/start.bat b/dist/mai2/start.bat index a89a1d5..889e030 100644 --- a/dist/mai2/start.bat +++ b/dist/mai2/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mu3/config_hook.json b/dist/mu3/config_hook.json new file mode 100644 index 0000000..b73cf5c --- /dev/null +++ b/dist/mu3/config_hook.json @@ -0,0 +1,6 @@ +{ + "emoney" : + { + "enable" : false + } +} diff --git a/dist/mu3/start.bat b/dist/mu3/start.bat index 8058daf..60141fc 100644 --- a/dist/mu3/start.bat +++ b/dist/mu3/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json inject -d -k mu3hook.dll mu3 -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/swdc/config_hook.json b/dist/swdc/config_hook.json new file mode 100644 index 0000000..b73cf5c --- /dev/null +++ b/dist/swdc/config_hook.json @@ -0,0 +1,6 @@ +{ + "emoney" : + { + "enable" : false + } +} diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index ae33ae9..7121754 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -17,7 +17,7 @@ if not exist "%APP_DIR%" ( echo Mounted the Y:\ drive to the %TEMP%\SWDC folder REM start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanClient.json config_MiniCabinet.json -start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanServer.json config_MiniCabinet.json +start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 From a69a9b5917258508d0dbd5ad9060b670189e741a Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 20 Aug 2023 16:21:55 +0200 Subject: [PATCH 026/204] swdc: disabled built in XInput --- swdchook/dllmain.c | 2 +- swdchook/zinput.c | 202 +++++++++++---------------------------------- swdchook/zinput.h | 2 +- 3 files changed, 50 insertions(+), 156 deletions(-) diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index a37c3b0..d3e09b0 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -39,7 +39,7 @@ static DWORD CALLBACK swdc_pre_startup(void) /* Hook Win32 APIs */ serial_hook_init(); - zinput_hook_init(&swdc_hook_cfg.zinput); + zinput_hook_init(&swdc_hook_cfg.zinput, swdc_hook_mod); dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod); /* Initialize emulation hooks */ diff --git a/swdchook/zinput.c b/swdchook/zinput.c index bd18392..264102b 100644 --- a/swdchook/zinput.c +++ b/swdchook/zinput.c @@ -1,9 +1,8 @@ #include -#include +#include -#include +#include #include -#include #include "swdchook/config.h" #include "swdchook/zinput.h" @@ -12,175 +11,70 @@ #include "util/dprintf.h" -HRESULT WINAPI hook_DirectInput8Create( - HINSTANCE hinst, - DWORD dwVersion, - REFIID riidltf, - LPVOID *ppvOut, - LPUNKNOWN punkOuter); - -static unsigned long WINAPI hook_AddRef(IUnknown *self); - -static unsigned long WINAPI hook_Release(IUnknown *self); - -static HRESULT WINAPI hook_CreateDevice( - IDirectInput8W *self, - REFGUID rguid, - LPDIRECTINPUTDEVICE8W * lplpDirectInputDevice, - LPUNKNOWN pUnkOuter); - -static HRESULT WINAPI hook_EnumDevices( - IDirectInput8W *self, - DWORD dwDevType, - LPDIENUMDEVICESCALLBACKW lpCallback, - LPVOID pvRef, - DWORD dwFlags); - -static HRESULT WINAPI hook_SetDataFormat( - IDirectInputDevice8W *self, - LPCDIDATAFORMAT lpdf); - -static HRESULT WINAPI hook_SetCooperativeLevel( - IDirectInputDevice8W *self, - HWND hwnd, - DWORD flags); - -static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self); - -static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self); - -static HRESULT WINAPI hook_GetDeviceState( - IDirectInputDevice8W *self, - DWORD cbData, - LPVOID lpvData); - -static const IDirectInput8WVtbl api_vtbl = { - .AddRef = (void *) hook_AddRef, - .Release = (void *) hook_Release, - .CreateDevice = hook_CreateDevice, - .EnumDevices = hook_EnumDevices, -}; - -static const IDirectInput8W api = { (void *) &api_vtbl }; - -static const IDirectInputDevice8WVtbl dev_vtbl = { - .AddRef = (void *) hook_AddRef, - .Release = (void *) hook_Release, - .SetDataFormat = hook_SetDataFormat, - .SetCooperativeLevel= hook_SetCooperativeLevel, - .Acquire = hook_Acquire, - .Unacquire = hook_Unacquire, - .GetDeviceState = hook_GetDeviceState, -}; - -static const IDirectInputDevice8W dev = { (void *) &dev_vtbl }; +DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState); static const struct hook_symbol zinput_hook_syms[] = { { - .name = "DirectInput8Create", - .patch = hook_DirectInput8Create, - } + .name = "XInputGetState", + .patch = hook_XInputGetState, + .link = NULL + }, }; -HRESULT zinput_hook_init(struct zinput_config *cfg) +static struct zinput_config zinput_config; +static bool zinput_hook_initted; + +void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self) { assert(cfg != NULL); if (!cfg->enable) { - return S_FALSE; + return; } + if (zinput_hook_initted) { + return; + } + + memcpy(&zinput_config, cfg, sizeof(*cfg)); hook_table_apply( NULL, - "dinput8.dll", + "XINPUT9_1_0.dll", zinput_hook_syms, _countof(zinput_hook_syms)); - return S_OK; + hook_table_apply( + NULL, + "XINPUT1_1.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + hook_table_apply( + NULL, + "XINPUT1_2.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + hook_table_apply( + NULL, + "XINPUT1_3.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + hook_table_apply( + NULL, + "XINPUT1_4.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + zinput_hook_initted = true; + + dprintf("ZInput: Blocking built-in XInput support\n"); } -HRESULT WINAPI hook_DirectInput8Create( - HINSTANCE hinst, - DWORD dwVersion, - REFIID riidltf, - LPVOID *ppvOut, - LPUNKNOWN punkOuter) +DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) { - dprintf("ZInput: Blocking built-in DirectInput support\n"); - *ppvOut = (void *) &api; + // dprintf("ZInput: XInputGetState hook hit\n"); - return S_OK; -} - -static unsigned long WINAPI hook_AddRef(IUnknown *self) -{ - return 1; -} - -static unsigned long WINAPI hook_Release(IUnknown *self) -{ - return 1; -} - -static HRESULT WINAPI hook_CreateDevice( - IDirectInput8W *self, - REFGUID rguid, - LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, - LPUNKNOWN pUnkOuter) -{ - dprintf("ZInput: %s\n", __func__); - *lplpDirectInputDevice = (void *) &dev; - - return S_OK; -} - -static HRESULT WINAPI hook_EnumDevices( - IDirectInput8W *self, - DWORD dwDevType, - LPDIENUMDEVICESCALLBACKW lpCallback, - LPVOID pvRef, - DWORD dwFlags) -{ - dprintf("ZInput: %s\n", __func__); - - return S_OK; -} - -static HRESULT WINAPI hook_SetDataFormat( - IDirectInputDevice8W *self, - LPCDIDATAFORMAT lpdf) -{ - dprintf("ZInput: %s\n", __func__); - - return S_OK; -} - -static HRESULT WINAPI hook_SetCooperativeLevel( - IDirectInputDevice8W *self, - HWND hwnd, - DWORD flags) -{ - dprintf("ZInput: %s\n", __func__); - - return S_OK; -} - -static HRESULT WINAPI hook_Acquire(IDirectInputDevice8W *self) -{ - return S_OK; -} - -static HRESULT WINAPI hook_Unacquire(IDirectInputDevice8W *self) -{ - return S_OK; -} - -static HRESULT WINAPI hook_GetDeviceState( - IDirectInputDevice8W *self, - DWORD cbData, - LPVOID lpvData) -{ - memset(lpvData, 0, cbData); - - return S_OK; + return ERROR_SUCCESS; } diff --git a/swdchook/zinput.h b/swdchook/zinput.h index 13a46cd..ee3e6ad 100644 --- a/swdchook/zinput.h +++ b/swdchook/zinput.h @@ -8,4 +8,4 @@ struct zinput_config { bool enable; }; -HRESULT zinput_hook_init(struct zinput_config *cfg); +void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self); From f6e961d4f4a0b55d72fe173745ee44d1af24eee6 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 29 Aug 2023 00:49:58 +0200 Subject: [PATCH 027/204] Removed `-f` from start.bat and fixed idz --- board/io4.c | 18 +++++++++--------- dist/chusan/start.bat | 2 +- dist/cm/start.bat | 2 +- dist/idac/start.bat | 2 +- dist/idz/start.bat | 4 ++-- dist/swdc/start.bat | 6 +++--- idacio/idacio.h | 6 +++--- idzhook/dllmain.c | 8 ++++++-- idzhook/idzhook.def | 5 ----- 9 files changed, 26 insertions(+), 27 deletions(-) diff --git a/board/io4.c b/board/io4.c index e7fe9e3..cc0165c 100644 --- a/board/io4.c +++ b/board/io4.c @@ -28,7 +28,7 @@ enum { IO4_CMD_CLEAR_BOARD_STATUS = 0x03, IO4_CMD_SET_GENERAL_OUTPUT = 0x04, IO4_CMD_SET_PWM_OUTPUT = 0x05, - IO4_CMD_UNIMPLEMENTED = 0x41, + IO4_CMD_SET_UNIQUE_OUTPUT = 0x41, IO4_CMD_UPDATE_FIRMWARE = 0x85, }; @@ -40,7 +40,7 @@ struct io4_report_in { uint16_t buttons[2]; uint8_t system_status; uint8_t usb_status; - uint8_t unknown[29]; + uint8_t unique_input[29]; }; static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size"); @@ -232,15 +232,15 @@ static HRESULT io4_handle_write(struct irp *irp) return S_OK; + case IO4_CMD_SET_UNIQUE_OUTPUT: + dprintf("USB I/O: Unique Out\n"); + + return S_OK; + case IO4_CMD_UPDATE_FIRMWARE: dprintf("USB I/O: Update firmware..?\n"); - return E_FAIL; - - case IO4_CMD_UNIMPLEMENTED: - //dprintf("USB I/O: Unimplemented cmd 41\n"); - - return S_OK; + return E_FAIL; default: dprintf("USB I/O: Unknown command %02x\n", out.cmd); @@ -316,7 +316,7 @@ static HRESULT io4_async_poll(void *ctx, struct irp *irp) /* Delay long enough for the instigating thread in amdaemon to be satisfied that all queued-up reports have been drained. */ - Sleep(1); + // Sleep(1); /* Call into ops to poll the underlying inputs */ diff --git a/dist/chusan/start.bat b/dist/chusan/start.bat index 4125873..78de368 100644 --- a/dist/chusan/start.bat +++ b/dist/chusan/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json +start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json inject_x86 -d -k chusanhook_x86.dll chusanApp.exe taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/cm/start.bat b/dist/cm/start.bat index 3c6b6f5..b17a6a1 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json +start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/idac/start.bat b/dist/idac/start.bat index 4b2d8e9..d87a3ca 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -16,7 +16,7 @@ if not exist "%APP_DIR%" ( echo Mounted the Y:\ drive to the %TEMP%\SDGT folder -start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json +start /min inject -d -k idachook.dll amdaemon.exe -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/idz/start.bat b/dist/idz/start.bat index b8d6b18..66ce606 100644 --- a/dist/idz/start.bat +++ b/dist/idz/start.bat @@ -2,8 +2,8 @@ pushd %~dp0 -.\inject.exe -k .\idzhook.dll .\InitialD0_DX11_Nu.exe -.\inject.exe -d -k .\idzhook.dll .\amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json +inject -k idzhook.dll InitialD0_DX11_Nu.exe +inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json echo. echo Game processes have terminated diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index 7121754..b06b6e0 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -16,9 +16,9 @@ if not exist "%APP_DIR%" ( echo Mounted the Y:\ drive to the %TEMP%\SWDC folder -REM start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanClient.json config_MiniCabinet.json -start /min inject -d -k swdchook.dll amdaemon.exe -f -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json -inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json +start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json +inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 REM unmount the APP_DIR diff --git a/idacio/idacio.h b/idacio/idacio.h index 035c5c4..c0e743e 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -64,7 +64,7 @@ HRESULT idac_io_init(void); HRESULT idac_io_poll(void); /* Get the state of the cabinet's operator buttons as of the last poll. See - MU3_IO_OPBTN enum above: this contains bit mask definitions for button + IDAC_IO_OPBTN enum above: this contains bit mask definitions for button states returned in *opbtn. All buttons are active-high. Minimum API version: 0x0100 */ @@ -72,7 +72,7 @@ HRESULT idac_io_poll(void); void idac_io_get_opbtns(uint8_t *opbtn); /* Get the state of the cabinet's gameplay buttons as of the last poll. See - MU3_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + IDAC_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into a left hand side set of inputs and a right hand side set of inputs: the bit mappings are the same in both cases. @@ -83,7 +83,7 @@ void idac_io_get_opbtns(uint8_t *opbtn); void idac_io_get_gamebtns(uint8_t *gamebtn); -/* Poll the current state of the cabinet's JVS analog inputs. See structure +/* Poll the current state of the cabinet's IO4 analog inputs. See structure definition above for details. Minimum API version: 0x0100 */ diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index fe78b6f..b358470 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -44,7 +44,8 @@ static DWORD CALLBACK idz_pre_startup(void) /* Config load */ idz_hook_config_load(&idz_hook_cfg, L".\\segatools.ini"); - + + /* module_path = module_file_name(NULL); if (module_path != NULL) { @@ -52,7 +53,7 @@ static DWORD CALLBACK idz_pre_startup(void) _wcslwr(file_name); - if (wcsstr(file_name, L"serverbox") != NULL) { + if (wcsstr(file_name, L"ServerBox") != NULL) { dprintf("Executable filename contains 'ServerBox', disabling full-screen mode\n"); idz_hook_cfg.gfx.windowed = true; @@ -63,13 +64,16 @@ static DWORD CALLBACK idz_pre_startup(void) module_path = NULL; } + */ /* Hook Win32 APIs */ serial_hook_init(); + /* gfx_hook_init(&idz_hook_cfg.gfx); gfx_d3d11_hook_init(&idz_hook_cfg.gfx, idz_hook_mod); gfx_dxgi_hook_init(&idz_hook_cfg.gfx, idz_hook_mod); + */ zinput_hook_init(&idz_hook_cfg.zinput); dvd_hook_init(&idz_hook_cfg.dvd, idz_hook_mod); diff --git a/idzhook/idzhook.def b/idzhook/idzhook.def index d8db3b0..486400c 100644 --- a/idzhook/idzhook.def +++ b/idzhook/idzhook.def @@ -1,11 +1,6 @@ LIBRARY idzhook EXPORTS - CreateDXGIFactory - CreateDXGIFactory1 - CreateDXGIFactory2 - D3D11CreateDevice - D3D11CreateDeviceAndSwapChain aime_io_get_api_version aime_io_init aime_io_led_set_color From ca4a8bd84df7be5f30871f6772e0f58edd557223 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 29 Aug 2023 02:22:05 +0200 Subject: [PATCH 028/204] idz, idac, swdc: Added deadzone config --- dist/idac/segatools.ini | 31 +++++++++++++---------- dist/idz/segatools.ini | 34 +++++++++++++++----------- dist/swdc/segatools.ini | 5 ++++ idacio/config.c | 12 +++++++++ idacio/config.h | 2 ++ idacio/xi.c | 54 ++++++++++++++++++++--------------------- idzio/config.c | 12 +++++++++ idzio/config.h | 2 ++ idzio/xi.c | 40 +++++++++++++++++++++--------- swdcio/config.c | 12 +++++++++ swdcio/config.h | 2 ++ swdcio/xi.c | 40 +++++++++++++++++++++--------- 12 files changed, 168 insertions(+), 78 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index ce5fc8a..0994d84 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -96,6 +96,11 @@ autoNeutral=1 singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. linearSteering=0 +; Configure deadzones for the left and right thumbsticks. +; The default value for the left stick is 7849, max value is 32767. +leftStickDeadzone=7849 +; The default value for the right stick is 8689, max value is 32767. +rightStickDeadzone=8689 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive @@ -111,7 +116,7 @@ restrict=128 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) -; Example: TMX +; Example: G29 ; ; If this is left blank then the first DirectInput device will be used. deviceName= @@ -122,30 +127,30 @@ deviceName= ; ; Can be the same device as the wheel. ; -; Example: T500 +; Example: G29 shifterName= ; Pedal mappings. Valid axis names are: ; ; X, Y, Z, RX, RY, RZ, U, V ; ; (U and V are old names for Slider 1 and Slider 2). -; The examples below are valid for a Thrustmaster TMX. +; The examples below are valid for a Logitech G29. brakeAxis=RZ accelAxis=Y ; DirectInput button numbers to map to menu inputs. Note that buttons are ; numbered from 1; some software numbers buttons from 0. -start=3 -viewChg=10 +start=1 +viewChg=2 ; Button mappings for the simulated six-speed shifter. -shiftDn=1 -shiftUp=2 +shiftDn=5 +shiftUp=6 ; Button mappings for the positional shifter, if present. -gear1=1 -gear2=2 -gear3=3 -gear4=4 -gear5=5 -gear6=6 +gear1=13 +gear2=14 +gear3=15 +gear4=16 +gear5=17 +gear6=18 ; Invert the accelerator and or brake axis ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 6c68321..8c45076 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -12,6 +12,7 @@ appdata= ; Controls emulation of the Aime card reader assembly. enable=1 aimePath=DEVICE\aime.txt +felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. @@ -86,6 +87,11 @@ autoNeutral=1 singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. linearSteering=0 +; Configure deadzones for the left and right thumbsticks. +; The default value for the left stick is 7849, max value is 32767. +leftStickDeadzone=7849 +; The default value for the right stick is 8689, max value is 32767. +rightStickDeadzone=8689 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive @@ -101,7 +107,7 @@ restrict=97 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) -; Example: TMX +; Example: G29 ; ; If this is left blank then the first DirectInput device will be used. deviceName= @@ -112,30 +118,30 @@ deviceName= ; ; Can be the same device as the wheel. ; -; Example: T500 +; Example: G29 shifterName= ; Pedal mappings. Valid axis names are: ; ; X, Y, Z, RX, RY, RZ, U, V ; ; (U and V are old names for Slider 1 and Slider 2). -; The examples below are valid for a Thrustmaster TMX. -brakeAxis=RZ +; The examples below are valid for a Logitech G29. +brakeAxis=U accelAxis=Y ; DirectInput button numbers to map to menu inputs. Note that buttons are ; numbered from 1; some software numbers buttons from 0. -start=3 -viewChg=10 +start=1 +viewChg=2 ; Button mappings for the simulated six-speed shifter. -shiftDn=1 -shiftUp=2 +shiftDn=5 +shiftUp=6 ; Button mappings for the positional shifter, if present. -gear1=1 -gear2=2 -gear3=3 -gear4=4 -gear5=5 -gear6=6 +gear1=13 +gear2=14 +gear3=15 +gear4=16 +gear5=17 +gear6=18 ; Invert the accelerator and or brake axis ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index ef762c5..24cbb8f 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -68,6 +68,11 @@ mode=xinput singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. linearSteering=0 +; Configure deadzones for the left and right thumbsticks. +; The default value for the left stick is 7849, max value is 32767. +leftStickDeadzone=7849 +; The default value for the right stick is 8689, max value is 32767. +rightStickDeadzone=8689 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive diff --git a/idacio/config.c b/idacio/config.c index ce7e201..fc0f832 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -87,6 +87,18 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) L"linearSteering", 0, filename); + + cfg->left_stick_deadzone = GetPrivateProfileIntW( + L"io4", + L"leftStickDeadzone", + 7849, + filename); + + cfg->right_stick_deadzone = GetPrivateProfileIntW( + L"io4", + L"rightStickDeadzone", + 8689, + filename); } void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) diff --git a/idacio/config.h b/idacio/config.h index 05332da..4b8a3eb 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -25,6 +25,8 @@ struct idac_di_config { struct idac_xi_config { bool single_stick_steering; bool linear_steering; + uint16_t left_stick_deadzone; + uint16_t right_stick_deadzone; }; struct idac_io_config { diff --git a/idacio/xi.c b/idacio/xi.c index 3a41aaa..918acad 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -27,6 +27,8 @@ static const struct idac_io_backend idac_xi_backend = { static bool idac_xi_single_stick_steering; static bool idac_xi_linear_steering; +static uint16_t idac_xi_left_stick_deadzone; +static uint16_t idac_xi_right_stick_deadzone; HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) { HRESULT hr; @@ -50,13 +52,28 @@ HRESULT idac_io_poll(void) { } static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) { + /* Deadzones check */ + if (cfg->left_stick_deadzone > 32767 || cfg->left_stick_deadzone < 0) { + dprintf("XInput: Left stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + + if (cfg->right_stick_deadzone > 32767 || cfg->right_stick_deadzone < 0) { + dprintf("XInput: Right stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); + dprintf("XInput: Left Deadzone . . . . : %i\n", cfg->left_stick_deadzone); + dprintf("XInput: Right Deadzone . . . : %i\n", cfg->right_stick_deadzone); dprintf("XInput: --- End configuration ---\n"); idac_xi_single_stick_steering = cfg->single_stick_steering; idac_xi_linear_steering = cfg->linear_steering; + idac_xi_left_stick_deadzone = cfg->left_stick_deadzone; + idac_xi_right_stick_deadzone = cfg->right_stick_deadzone; return S_OK; } @@ -118,22 +135,6 @@ static void idac_xi_get_shifter(uint8_t *gear) { idac_shifter_set(0); } - /* - // Alternative shifting mode - if (xb & XINPUT_GAMEPAD_X) { - // Set to Gear 2 when X is pressed - idac_shifter_set(2); - } - - if (xb & XINPUT_GAMEPAD_Y) { - // Set to Gear 3 when Y is pressed - idac_shifter_set(3); - } - - shift_dn = xb & XINPUT_GAMEPAD_LEFT_SHOULDER; - shift_up = xb & XINPUT_GAMEPAD_RIGHT_SHOULDER; - */ - shift_dn = xb & (XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER); shift_up = xb & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_RIGHT_SHOULDER); @@ -182,21 +183,21 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) { if (!idac_xi_linear_steering) { // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + left = apply_non_linear_transform(left, idac_xi_left_stick_deadzone); + right = apply_non_linear_transform(right, idac_xi_right_stick_deadzone); } else { - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + if (left < -idac_xi_left_stick_deadzone) { + left += idac_xi_left_stick_deadzone; + } else if (left > idac_xi_left_stick_deadzone) { + left -= idac_xi_left_stick_deadzone; } else { left = 0; } - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + if (right < -idac_xi_right_stick_deadzone) { + right += idac_xi_right_stick_deadzone; + } else if (right > idac_xi_right_stick_deadzone) { + right -= idac_xi_right_stick_deadzone; } else { right = 0; } @@ -204,7 +205,6 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) { if (idac_xi_single_stick_steering) { out->wheel = left; - // dprintf("XInput: Single Stick Steering: %i\n", out->wheel); } else { out->wheel = (left + right) / 2; } diff --git a/idzio/config.c b/idzio/config.c index e49b550..2bb51ff 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -87,6 +87,18 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) L"linearSteering", 0, filename); + + cfg->left_stick_deadzone = GetPrivateProfileIntW( + L"io3", + L"leftStickDeadzone", + 7849, + filename); + + cfg->right_stick_deadzone = GetPrivateProfileIntW( + L"io3", + L"rightStickDeadzone", + 8689, + filename); } void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename) diff --git a/idzio/config.h b/idzio/config.h index 3d2668b..24934ca 100644 --- a/idzio/config.h +++ b/idzio/config.h @@ -25,6 +25,8 @@ struct idz_di_config { struct idz_xi_config { bool single_stick_steering; bool linear_steering; + uint16_t left_stick_deadzone; + uint16_t right_stick_deadzone; }; struct idz_io_config { diff --git a/idzio/xi.c b/idzio/xi.c index ebd1ea9..413fa56 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -28,6 +28,8 @@ static const struct idz_io_backend idz_xi_backend = { static bool idz_xi_single_stick_steering; static bool idz_xi_linear_steering; +static uint16_t idz_xi_left_stick_deadzone; +static uint16_t idz_xi_right_stick_deadzone; HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend) { @@ -47,15 +49,29 @@ HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend return S_OK; } -static HRESULT idz_xi_config_apply(const struct idz_xi_config *cfg) -{ +static HRESULT idz_xi_config_apply(const struct idz_xi_config *cfg) { + /* Deadzones check */ + if (cfg->left_stick_deadzone > 32767 || cfg->left_stick_deadzone < 0) { + dprintf("XInput: Left stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + + if (cfg->right_stick_deadzone > 32767 || cfg->right_stick_deadzone < 0) { + dprintf("XInput: Right stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); + dprintf("XInput: Left Deadzone . . . . : %i\n", cfg->left_stick_deadzone); + dprintf("XInput: Right Deadzone . . . : %i\n", cfg->right_stick_deadzone); dprintf("XInput: --- End configuration ---\n"); idz_xi_single_stick_steering = cfg->single_stick_steering; idz_xi_linear_steering = cfg->linear_steering; + idz_xi_left_stick_deadzone = cfg->left_stick_deadzone; + idz_xi_right_stick_deadzone = cfg->right_stick_deadzone; return S_OK; } @@ -168,21 +184,21 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) if (!idz_xi_linear_steering) { // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + left = apply_non_linear_transform(left, idz_xi_left_stick_deadzone); + right = apply_non_linear_transform(right, idz_xi_right_stick_deadzone); } else { - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + if (left < -idz_xi_left_stick_deadzone) { + left += idz_xi_left_stick_deadzone; + } else if (left > idz_xi_left_stick_deadzone) { + left -= idz_xi_left_stick_deadzone; } else { left = 0; } - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + if (right < -idz_xi_right_stick_deadzone) { + right += idz_xi_right_stick_deadzone; + } else if (right > idz_xi_right_stick_deadzone) { + right -= idz_xi_right_stick_deadzone; } else { right = 0; } diff --git a/swdcio/config.c b/swdcio/config.c index ae4a1f5..c7494fe 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -77,6 +77,18 @@ void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) L"linearSteering", 0, filename); + + cfg->left_stick_deadzone = GetPrivateProfileIntW( + L"io4", + L"leftStickDeadzone", + 7849, + filename); + + cfg->right_stick_deadzone = GetPrivateProfileIntW( + L"io4", + L"rightStickDeadzone", + 8689, + filename); } void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) diff --git a/swdcio/config.h b/swdcio/config.h index 0225d59..1b09380 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -27,6 +27,8 @@ struct swdc_di_config { struct swdc_xi_config { bool single_stick_steering; bool linear_steering; + uint16_t left_stick_deadzone; + uint16_t right_stick_deadzone; }; struct swdc_io_config { diff --git a/swdcio/xi.c b/swdcio/xi.c index 9a98ec4..3067d3f 100644 --- a/swdcio/xi.c +++ b/swdcio/xi.c @@ -25,6 +25,8 @@ static const struct swdc_io_backend swdc_xi_backend = { static bool swdc_xi_single_stick_steering; static bool swdc_xi_linear_steering; +static uint16_t swdc_xi_left_stick_deadzone; +static uint16_t swdc_xi_right_stick_deadzone; HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend) { @@ -49,15 +51,29 @@ HRESULT swdc_io_poll(void) return S_OK; } -static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg) -{ +static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg) { + /* Deadzones check */ + if (cfg->left_stick_deadzone > 32767 || cfg->left_stick_deadzone < 0) { + dprintf("XInput: Left stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + + if (cfg->right_stick_deadzone > 32767 || cfg->right_stick_deadzone < 0) { + dprintf("XInput: Right stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Single Stick Steering : %i\n", cfg->single_stick_steering); dprintf("XInput: Linear Steering . . . : %i\n", cfg->linear_steering); + dprintf("XInput: Left Deadzone . . . . : %i\n", cfg->left_stick_deadzone); + dprintf("XInput: Right Deadzone . . . : %i\n", cfg->right_stick_deadzone); dprintf("XInput: --- End configuration ---\n"); swdc_xi_single_stick_steering = cfg->single_stick_steering; swdc_xi_linear_steering = cfg->linear_steering; + swdc_xi_left_stick_deadzone = cfg->left_stick_deadzone; + swdc_xi_right_stick_deadzone = cfg->right_stick_deadzone; return S_OK; } @@ -168,21 +184,21 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) if (!swdc_xi_linear_steering) { // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - right = apply_non_linear_transform(right, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + left = apply_non_linear_transform(left, swdc_xi_left_stick_deadzone); + right = apply_non_linear_transform(right, swdc_xi_right_stick_deadzone); } else { - if (left < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left += XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - } else if (left > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - left -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + if (left < -swdc_xi_left_stick_deadzone) { + left += swdc_xi_left_stick_deadzone; + } else if (left > swdc_xi_left_stick_deadzone) { + left -= swdc_xi_left_stick_deadzone; } else { left = 0; } - if (right < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right += XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; - } else if (right > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - right -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; + if (right < -swdc_xi_right_stick_deadzone) { + right += swdc_xi_right_stick_deadzone; + } else if (right > swdc_xi_right_stick_deadzone) { + right -= swdc_xi_right_stick_deadzone; } else { right = 0; } From f0dc51d01e1e2e860f3e9c3483f851918c0b4bd8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 29 Aug 2023 20:03:33 +0200 Subject: [PATCH 029/204] idac: added config_hook.json --- Package.mk | 1 + dist/idac/config_hook.json | 18 ++++++++++++++++++ dist/idac/start.bat | 26 +++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 dist/idac/config_hook.json diff --git a/Package.mk b/Package.mk index 587906f..5dc90c9 100644 --- a/Package.mk +++ b/Package.mk @@ -80,6 +80,7 @@ $(BUILD_DIR_ZIP)/idac.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/idachook/idachook.dll \ $(DIST_DIR)/idac/segatools.ini \ + $(DIST_DIR)/idac/config_hook.json \ $(DIST_DIR)/idac/start.bat \ $(BUILD_DIR_ZIP)/idac $(V)cp pki/billing.pub \ diff --git a/dist/idac/config_hook.json b/dist/idac/config_hook.json new file mode 100644 index 0000000..12fae62 --- /dev/null +++ b/dist/idac/config_hook.json @@ -0,0 +1,18 @@ +{ + "aime" : + { + "firmware_path" : + [ + ".\\aime_firm\\TN32MSEC003S_V12.hex", + ".\\aime_firm\\update_15396_6728_94.bin" + ], + "high_baudrate" : true + }, + "network" : + { + "property" : + { + "dhcp" : true + } + } +} diff --git a/dist/idac/start.bat b/dist/idac/start.bat index d87a3ca..5706b03 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -16,7 +16,31 @@ if not exist "%APP_DIR%" ( echo Mounted the Y:\ drive to the %TEMP%\SDGT folder -start /min inject -d -k idachook.dll amdaemon.exe -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json +set AMDAEMON_CFG=config_common.json ^ +config_common.json ^ +config_ex.json ^ +config_jp.json ^ +config_laninstall_client_ex.json ^ +config_laninstall_client_jp.json ^ +config_laninstall_server_ex.json ^ +config_laninstall_server_jp.json ^ +config_aime_high_ex.json ^ +config_aime_high_jp.json ^ +config_aime_normal_ex.json ^ +config_aime_normal_jp.json ^ +config_seat_1_ex.json ^ +config_seat_1_jp.json ^ +config_seat_2_ex.json ^ +config_seat_2_jp.json ^ +config_seat_3_ex.json ^ +config_seat_3_jp.json ^ +config_seat_4_ex.json ^ +config_seat_4_jp.json ^ +config_seat_single_ex.json ^ +config_seat_single_jp.json ^ +config_hook.json + +start /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG% inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 From 51b11469d007f0e07b606d3d3c9a5571920455f0 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 29 Aug 2023 22:57:04 +0200 Subject: [PATCH 030/204] added `aimeGen` as default instead of `feliciaGen` --- aimeio/aimeio.c | 73 +++++++++++++++++++++++++++++++++++++-- dist/chusan/segatools.ini | 1 + dist/cm/segatools.ini | 1 - dist/idac/segatools.ini | 1 - dist/mai2/segatools.ini | 1 + dist/mu3/segatools.ini | 1 - dist/swdc/segatools.ini | 1 - doc/config/common.md | 9 ++++- 8 files changed, 81 insertions(+), 7 deletions(-) diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index f505aac..fa0db03 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -17,6 +17,7 @@ struct aime_io_config { wchar_t aime_path[MAX_PATH]; wchar_t felica_path[MAX_PATH]; bool felica_gen; + bool aime_gen; uint8_t vk_scan; }; @@ -40,6 +41,11 @@ static HRESULT aime_io_generate_felica( uint8_t *bytes, size_t nbytes); +static HRESULT aime_io_generate_aime( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes); + static void aime_io_config_read( struct aime_io_config *cfg, const wchar_t *filename) @@ -67,6 +73,12 @@ static void aime_io_config_read( cfg->felica_gen = GetPrivateProfileIntW( L"aime", L"felicaGen", + 0, + filename); + + cfg->aime_gen = GetPrivateProfileIntW( + L"aime", + L"aimeGen", 1, filename); @@ -136,7 +148,7 @@ static HRESULT aime_io_generate_felica( srand(time(NULL)); - for (i = 0 ; i < nbytes ; i++) { + for (i = 0; i < nbytes; i++) { bytes[i] = rand(); } @@ -151,7 +163,7 @@ static HRESULT aime_io_generate_felica( return E_FAIL; } - for (i = 0 ; i < nbytes ; i++) { + for (i = 0; i < nbytes; i++) { fprintf(f, "%02X", bytes[i]); } @@ -163,6 +175,47 @@ static HRESULT aime_io_generate_felica( return S_OK; } +static HRESULT aime_io_generate_aime( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes) +{ + size_t i; + FILE *f; + + assert(path != NULL); + assert(bytes != NULL); + assert(nbytes > 0); + + srand(time(NULL)); + + /* AiMe IDs should not start with 3, due to a missing check for BananaPass IDs */ + do { + for (i = 0; i < nbytes; i++) { + bytes[i] = rand() % 10 << 4 | rand() % 10; + } + } while (bytes[0] >> 4 == 3); + + f = _wfopen(path, L"w"); + + if (f == NULL) { + dprintf("AimeIO DLL: %S: fopen failed: %i\n", path, (int) errno); + + return E_FAIL; + } + + for (i = 0; i < nbytes; i++) { + fprintf(f, "%02x", bytes[i]); + } + + fprintf(f, "\n"); + fclose(f); + + dprintf("AimeIO DLL: Generated random AiMe ID\n"); + + return S_OK; +} + uint16_t aime_io_get_api_version(void) { return 0x0100; @@ -210,6 +263,22 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) return S_OK; } + /* Try generating AiMe IC (if enabled) */ + + if (aime_io_cfg.aime_gen) { + hr = aime_io_generate_aime( + aime_io_cfg.aime_path, + aime_io_aime_id, + sizeof(aime_io_aime_id)); + + if (FAILED(hr)) { + return hr; + } + + aime_io_aime_id_present = true; + return S_OK; + } + /* Try FeliCa IC */ hr = aime_io_read_id_file( diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index a2189f9..b1da417 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -11,6 +11,7 @@ appdata= [aime] ; Enable aime reader emulation. enable=1 +aimePath=DEVICE\aime.txt ; Enable high baud rate. ;highbaud=1 diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 31e9d96..93b2151 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -12,7 +12,6 @@ appdata= ; Enable aime reader emulation. enable=1 aimePath=DEVICE\aime.txt -felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 0994d84..2d8b164 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -12,7 +12,6 @@ appdata= ; Controls emulation of the Aime card reader assembly. enable=1 aimePath=DEVICE\aime.txt -felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index a86bee4..148d852 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -11,6 +11,7 @@ appdata= [aime] ; Enable aime reader emulation. enable=1 +aimePath=DEVICE\aime.txt [dns] ; Insert the hostname or IP address of the server you wish to use here. diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 9c8f46f..a9f82e1 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -12,7 +12,6 @@ appdata= ; Controls emulation of the Aime card reader assembly. enable=1 aimePath=DEVICE\aime.txt -felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 24cbb8f..5a3493b 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -12,7 +12,6 @@ appdata= ; Controls emulation of the Aime card reader assembly. enable=1 aimePath=DEVICE\aime.txt -felicaGen=0 [dns] ; Insert the hostname or IP address of the server you wish to use here. diff --git a/doc/config/common.md b/doc/config/common.md index de6f267..0236eaf 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -45,6 +45,13 @@ Default: `DEVICE\aime.txt` Path to a text file containing a classic Aime IC card ID. **This does not currently work**. +### `aimeGen` + +Default: `1` + +Whether to generate a random AiMe ID if the file at `aimePath` does not +exist. + ### `felicaPath` Default: `DEVICE\felica.txt` @@ -53,7 +60,7 @@ Path to a text file containing a FeliCa e-cash card IDm serial number. ### `felicaGen` -Default: `1` +Default: `0` Whether to generate a random FeliCa ID if the file at `felicaPath` does not exist. From 91f69beae6a7a78ec623d2e3dfd91adb1f493bb5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 30 Aug 2023 02:24:02 +0200 Subject: [PATCH 031/204] idac: fixed config error --- dist/idac/start.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/dist/idac/start.bat b/dist/idac/start.bat index 5706b03..fb40211 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -17,7 +17,6 @@ if not exist "%APP_DIR%" ( echo Mounted the Y:\ drive to the %TEMP%\SDGT folder set AMDAEMON_CFG=config_common.json ^ -config_common.json ^ config_ex.json ^ config_jp.json ^ config_laninstall_client_ex.json ^ From 49f729c501d54c5e65724f86edf8c497aa81b598 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 4 Sep 2023 02:03:31 +0200 Subject: [PATCH 032/204] idz, idac, swdc: switched to `[xinput]` config instead of [io] --- Package.mk | 2 +- dist/idac/segatools.ini | 2 ++ dist/idz/segatools.ini | 14 ++++++++++++-- dist/idz/start.bat | 4 ++++ dist/swdc/segatools.ini | 7 +++++-- idacio/config.c | 8 ++++---- idzio/config.c | 8 ++++---- swdcio/config.c | 8 ++++---- 8 files changed, 36 insertions(+), 17 deletions(-) diff --git a/Package.mk b/Package.mk index 5dc90c9..72e90a9 100644 --- a/Package.mk +++ b/Package.mk @@ -95,7 +95,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/swdchook/swdchook.dll \ - $(DIST_DIR)/chusan/config_hook.json \ + $(DIST_DIR)/swdc/config_hook.json \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/start.bat \ $(BUILD_DIR_ZIP)/swdc diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 2d8b164..2da93ef 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -87,6 +87,8 @@ coin=0x33 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput + +[xinput] ; Automatically reset the simulated shifter to Neutral when XInput Start is ; pressed (e.g. when navigating menus between races). autoNeutral=1 diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 8c45076..7ddf1ad 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -11,8 +11,10 @@ appdata= [aime] ; Controls emulation of the Aime card reader assembly. enable=1 +; Necessary for IDZ Version 2+ to work aimePath=DEVICE\aime.txt felicaGen=0 +aimeGen=1 [dns] ; Insert the hostname or IP address of the server you wish to use here. @@ -25,7 +27,7 @@ default=127.0.0.1 ; 4: Export (some UI elements in English) ; ; NOTE: Changing this setting causes a factory reset. -region=1 +region=4 [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. @@ -33,11 +35,17 @@ region=1 ; setting enabled is recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet +; (so, if the keychip subnet is 192.168.32.0 and this value is set to 11, +; then the local host's virtualized LAN IP is 192.168.32.11). +; Needed for in store battle, one needs to set it to 12. +;addrSuffix=12 + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.100.0 +subnet=192.168.158.0 [gpio] ; Emulated Nu DIP switch for Distribution Server setting. @@ -79,6 +87,8 @@ coin=0x33 ; Input API selection for JVS input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput + +[xinput] ; Automatically reset the simulated shifter to Neutral when XInput Start is ; pressed (e.g. when navigating menus between races). autoNeutral=1 diff --git a/dist/idz/start.bat b/dist/idz/start.bat index 66ce606..2d3d9c3 100644 --- a/dist/idz/start.bat +++ b/dist/idz/start.bat @@ -3,8 +3,12 @@ pushd %~dp0 inject -k idzhook.dll InitialD0_DX11_Nu.exe +rem Set dipsw1=0 and uncomment the ServerBox for in store battle? +rem inject -k idzhook.dll ServerBoxD8_Nu_x64.exe inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json +taskkill /im ServerBoxD8_Nu_x64.exe > nul 2>&1 + echo. echo Game processes have terminated pause \ No newline at end of file diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 5a3493b..2f3ca91 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -26,7 +26,8 @@ enable=1 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. -; You must set this to your LAN's IP subnet, and that subnet must start with 192.168. +; You must set this to your LAN's IP subnet, and that subnet must start with 192.168, +; in order to find the MAIN cabinet. subnet=192.168.100.0 [aimeio] @@ -58,10 +59,12 @@ test=0x31 service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. coin=0x33 + ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. - mode=xinput + +[xinput] ; Use the left thumbstick for steering instead of both on XInput Controllers. ; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 diff --git a/idacio/config.c b/idacio/config.c index fc0f832..934caf4 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -77,25 +77,25 @@ void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->single_stick_steering = GetPrivateProfileIntW( - L"io4", + L"xinput", L"singleStickSteering", 0, filename); cfg->linear_steering = GetPrivateProfileIntW( - L"io4", + L"xinput", L"linearSteering", 0, filename); cfg->left_stick_deadzone = GetPrivateProfileIntW( - L"io4", + L"xinput", L"leftStickDeadzone", 7849, filename); cfg->right_stick_deadzone = GetPrivateProfileIntW( - L"io4", + L"xinput", L"rightStickDeadzone", 8689, filename); diff --git a/idzio/config.c b/idzio/config.c index 2bb51ff..ceea591 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -77,25 +77,25 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->single_stick_steering = GetPrivateProfileIntW( - L"io3", + L"xinput", L"singleStickSteering", 0, filename); cfg->linear_steering = GetPrivateProfileIntW( - L"io3", + L"xinput", L"linearSteering", 0, filename); cfg->left_stick_deadzone = GetPrivateProfileIntW( - L"io3", + L"xinput", L"leftStickDeadzone", 7849, filename); cfg->right_stick_deadzone = GetPrivateProfileIntW( - L"io3", + L"xinput", L"rightStickDeadzone", 8689, filename); diff --git a/swdcio/config.c b/swdcio/config.c index c7494fe..770240f 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -67,25 +67,25 @@ void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->single_stick_steering = GetPrivateProfileIntW( - L"io4", + L"xinput", L"singleStickSteering", 0, filename); cfg->linear_steering = GetPrivateProfileIntW( - L"io4", + L"xinput", L"linearSteering", 0, filename); cfg->left_stick_deadzone = GetPrivateProfileIntW( - L"io4", + L"xinput", L"leftStickDeadzone", 7849, filename); cfg->right_stick_deadzone = GetPrivateProfileIntW( - L"io4", + L"xinput", L"rightStickDeadzone", 8689, filename); From d5a551482b1ce02e367a71f811482017895f5bdd Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 4 Sep 2023 02:04:42 +0200 Subject: [PATCH 033/204] idac: mapped left and right thumbstick to dpad left and right --- dist/idac/segatools.ini | 2 ++ idacio/xi.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 2da93ef..a99f2f8 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -89,6 +89,8 @@ coin=0x33 mode=xinput [xinput] +; Left and right thumbsticks are mapped to left and right dpad buttons. +; Press both thumbsticks to trigger "Time Up" and exit the course. ; Automatically reset the simulated shifter to Neutral when XInput Start is ; pressed (e.g. when navigating menus between races). autoNeutral=1 diff --git a/idacio/xi.c b/idacio/xi.c index 918acad..b83aa9d 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -99,11 +99,11 @@ static void idac_xi_get_gamebtns(uint8_t *gamebtn_out) { gamebtn |= IDAC_IO_GAMEBTN_DOWN; } - if (xb & XINPUT_GAMEPAD_DPAD_LEFT) { + if (xb & (XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_LEFT_THUMB)) { gamebtn |= IDAC_IO_GAMEBTN_LEFT; } - if (xb & XINPUT_GAMEPAD_DPAD_RIGHT) { + if (xb & (XINPUT_GAMEPAD_DPAD_RIGHT | XINPUT_GAMEPAD_RIGHT_THUMB)) { gamebtn |= IDAC_IO_GAMEBTN_RIGHT; } From 9bef9e49f8913c06dbfbbbd7429c8906d49437b1 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 4 Sep 2023 02:05:37 +0200 Subject: [PATCH 034/204] swdc: added aime firm to config_hook.json --- dist/swdc/config_hook.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dist/swdc/config_hook.json b/dist/swdc/config_hook.json index b73cf5c..789e2ff 100644 --- a/dist/swdc/config_hook.json +++ b/dist/swdc/config_hook.json @@ -1,4 +1,12 @@ { + "aime" : + { + "firmware_path" : + [ + ".\\aime_firm\\TN32MSEC003S_V12.hex", + ".\\aime_firm\\update_15396_6728_94.bin" + ] + }, "emoney" : { "enable" : false From eb2eef927a27ffc2733270e6a969025128732b80 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 4 Sep 2023 23:31:52 +0200 Subject: [PATCH 035/204] idac: added left and right button mapping --- dist/idac/segatools.ini | 5 +++++ idacio/config.c | 2 ++ idacio/config.h | 2 ++ idacio/di.c | 26 ++++++++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index a99f2f8..8b72d4e 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -144,6 +144,11 @@ accelAxis=Y ; numbered from 1; some software numbers buttons from 0. start=1 viewChg=2 +; DPad is already emulated, but in order to trigger "Time Up" and exit the +; course you need to press both left and right on the DPad at the same time. +; This is not possible on most devices, so we set the left and right button again. +left=7 +right=8 ; Button mappings for the simulated six-speed shifter. shiftDn=5 shiftUp=6 diff --git a/idacio/config.c b/idacio/config.c index 934caf4..48410c5 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -50,6 +50,8 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename) cfg->start = GetPrivateProfileIntW(L"dinput", L"start", 0, filename); cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename); + cfg->left = GetPrivateProfileIntW(L"dinput", L"left", 0, filename); + cfg->right = GetPrivateProfileIntW(L"dinput", L"right", 0, filename); cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename); cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename); diff --git a/idacio/config.h b/idacio/config.h index 4b8a3eb..8f6517a 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -15,6 +15,8 @@ struct idac_di_config { wchar_t accel_axis[16]; uint8_t start; uint8_t view_chg; + uint8_t left; + uint8_t right; uint8_t shift_dn; uint8_t shift_up; uint8_t gear[6]; diff --git a/idacio/di.c b/idacio/di.c index 2494082..1edaf9b 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -65,6 +65,8 @@ static uint8_t idac_di_shift_dn; static uint8_t idac_di_shift_up; static uint8_t idac_di_view_chg; static uint8_t idac_di_start; +static uint8_t idac_di_left; +static uint8_t idac_di_right; static uint8_t idac_di_gear[6]; static bool idac_di_reverse_brake_axis; static bool idac_di_reverse_accel_axis; @@ -235,6 +237,18 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) return E_INVALIDARG; } + if (cfg->left > 32) { + dprintf("Wheel: Invalid left button: %i\n", cfg->left); + + return E_INVALIDARG; + } + + if (cfg->right > 32) { + dprintf("Wheel: Invalid right button: %i\n", cfg->right); + + return E_INVALIDARG; + } + if (cfg->shift_dn > 32) { dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn); @@ -266,6 +280,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); dprintf("Wheel: Start button . . . : %i\n", cfg->start); dprintf("Wheel: View Change button : %i\n", cfg->view_chg); + dprintf("Wheel: Left button . . . . : %i\n", cfg->left); + dprintf("Wheel: Right button . . . : %i\n", cfg->right); dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); dprintf("Wheel: Shift Up button . . : %i\n", cfg->shift_up); dprintf("Wheel: Reverse Brake Axis : %i\n", cfg->reverse_brake_axis); @@ -290,6 +306,8 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) idac_di_off_accel = accel_axis->off; idac_di_start = cfg->start; idac_di_view_chg = cfg->view_chg; + idac_di_left = cfg->left; + idac_di_right = cfg->right; idac_di_shift_dn = cfg->shift_dn; idac_di_shift_up = cfg->shift_up; idac_di_reverse_brake_axis = cfg->reverse_brake_axis; @@ -398,6 +416,14 @@ static void idac_di_get_buttons(uint8_t *gamebtn_out) gamebtn |= IDAC_IO_GAMEBTN_VIEW_CHANGE; } + if (idac_di_left && state.st.rgbButtons[idac_di_left - 1]) { + gamebtn |= IDAC_IO_GAMEBTN_LEFT; + } + + if (idac_di_right && state.st.rgbButtons[idac_di_right - 1]) { + gamebtn |= IDAC_IO_GAMEBTN_RIGHT; + } + *gamebtn_out = gamebtn; } From 80718104f6c2de9f42426cc27e5765f59b6ad592 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 5 Sep 2023 00:23:17 +0200 Subject: [PATCH 036/204] swdc: updated config, fixed start.bat --- dist/swdc/segatools.ini | 23 +++++++++++------------ dist/swdc/start.bat | 18 +----------------- swdcio/config.c | 21 +++------------------ swdcio/config.h | 12 ++---------- swdcio/di.c | 24 ++++++++++++------------ 5 files changed, 29 insertions(+), 69 deletions(-) diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 2f3ca91..4f2ff03 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -90,7 +90,7 @@ restrict=128 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) -; Example: TMX +; Example: G29 ; ; If this is left blank then the first DirectInput device will be used. deviceName= @@ -99,22 +99,21 @@ deviceName= ; X, Y, Z, RX, RY, RZ, U, V ; ; (U and V are old names for Slider 1 and Slider 2). -; The examples below are valid for a Thrustmaster TMX. +; The examples below are valid for a Logitech G29. brakeAxis=RZ accelAxis=Y ; DirectInput button numbers to map to menu inputs. Note that buttons are ; numbered from 1; some software numbers buttons from 0. -start=3 -viewChg=10 -; Button mappings for the steering wheel paddles. Note shiftDn is the -; left paddle and shiftUp is the right paddle. -shiftDn=1 -shiftUp=2 +start=1 +viewChg=2 +; Button mappings for the steering wheel paddles. +paddleLeft=6 +paddleRight=5 ; Button mappings for the steering wheel buttons. -wheelGreen=4 -wheelRed=5 -wheelBlue=6 -wheelYellow=7 +wheelRed=7 +wheelBlue=8 +wheelYellow=9 +wheelGreen=10 ; Invert the accelerator and or brake axis ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index b06b6e0..526cfdc 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -2,28 +2,12 @@ pushd %~dp0 -REM set the APP_DIR to the Y drive -set APP_DIR=Y:\SWDC - -REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder -if not exist "%APP_DIR%" ( - subst Y: %TEMP% - REM timeout /t 1 - if not exist "%APP_DIR%" ( - mkdir "%APP_DIR%" - ) -) - -echo Mounted the Y:\ drive to the %TEMP%\SWDC folder - REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json +REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 -REM unmount the APP_DIR -subst Y: /d > nul 2>&1 - echo. echo Game processes have terminated pause \ No newline at end of file diff --git a/swdcio/config.c b/swdcio/config.c index 770240f..6fdd659 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -42,8 +42,8 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename) cfg->start = GetPrivateProfileIntW(L"dinput", L"start", 0, filename); cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename); - cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename); - cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename); + cfg->paddle_left = GetPrivateProfileIntW(L"dinput", L"paddleLeft", 0, filename); + cfg->paddle_right = GetPrivateProfileIntW(L"dinput", L"paddleRight", 0, filename); cfg->wheel_green = GetPrivateProfileIntW(L"dinput", L"wheelGreen", 0, filename); cfg->wheel_red = GetPrivateProfileIntW(L"dinput", L"wheelRed", 0, filename); cfg->wheel_blue = GetPrivateProfileIntW(L"dinput", L"wheelBlue", 0, filename); @@ -99,7 +99,7 @@ void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); - cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 97, filename); + cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 128, filename); GetPrivateProfileStringW( L"io4", @@ -109,21 +109,6 @@ void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) _countof(cfg->mode), filename); - swdc_shifter_config_load(&cfg->shifter, filename); swdc_di_config_load(&cfg->di, filename); swdc_xi_config_load(&cfg->xi, filename); } - -void swdc_shifter_config_load( - struct swdc_shifter_config *cfg, - const wchar_t *filename) -{ - assert(cfg != NULL); - assert(filename != NULL); - - cfg->auto_neutral = GetPrivateProfileIntW( - L"io4", - L"autoNeutral", - 0, - filename); -} diff --git a/swdcio/config.h b/swdcio/config.h index 1b09380..c878d58 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -4,18 +4,14 @@ #include #include -struct swdc_shifter_config { - bool auto_neutral; -}; - struct swdc_di_config { wchar_t device_name[64]; wchar_t brake_axis[16]; wchar_t accel_axis[16]; uint8_t start; uint8_t view_chg; - uint8_t shift_dn; - uint8_t shift_up; + uint8_t paddle_left; + uint8_t paddle_right; uint8_t wheel_green; uint8_t wheel_red; uint8_t wheel_blue; @@ -37,7 +33,6 @@ struct swdc_io_config { uint8_t vk_coin; wchar_t mode[8]; int restrict_; - struct swdc_shifter_config shifter; struct swdc_di_config di; struct swdc_xi_config xi; }; @@ -45,6 +40,3 @@ struct swdc_io_config { void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename); void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename); void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename); -void swdc_shifter_config_load( - struct swdc_shifter_config *cfg, - const wchar_t *filename); diff --git a/swdcio/di.c b/swdcio/di.c index 0fd0118..2fc7bc1 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -55,8 +55,8 @@ static IDirectInputDevice8W *swdc_di_dev; static IDirectInputEffect *swdc_di_fx; static size_t swdc_di_off_brake; static size_t swdc_di_off_accel; -static uint8_t swdc_di_shift_dn; -static uint8_t swdc_di_shift_up; +static uint8_t swdc_di_paddle_left; +static uint8_t swdc_di_paddle_right; static uint8_t swdc_di_view_chg; static uint8_t swdc_di_start; static uint8_t swdc_di_wheel_green; @@ -205,14 +205,14 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) return E_INVALIDARG; } - if (cfg->shift_dn > 32) { - dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn); + if (cfg->paddle_left > 32) { + dprintf("Wheel: Invalid left paddle button: %i\n", cfg->paddle_left); return E_INVALIDARG; } - if (cfg->shift_up > 32) { - dprintf("Wheel: Invalid shift up button: %i\n", cfg->shift_up); + if (cfg->paddle_right > 32) { + dprintf("Wheel: Invalid right paddle button: %i\n", cfg->paddle_right); return E_INVALIDARG; } @@ -250,8 +250,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) dprintf("Wheel: Accel axis . . . . . . : %S\n", accel_axis->name); dprintf("Wheel: Start button . . . . . : %i\n", cfg->start); dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg); - dprintf("Wheel: Shift Down button . . : %i\n", cfg->shift_dn); - dprintf("Wheel: Shift Up button . . . : %i\n", cfg->shift_up); + dprintf("Wheel: Paddle Left button . . : %i\n", cfg->paddle_left); + dprintf("Wheel: Paddle Right button . : %i\n", cfg->paddle_right); dprintf("Wheel: Steering Green button : %i\n", cfg->wheel_green); dprintf("Wheel: Steering Red button . : %i\n", cfg->wheel_red); dprintf("Wheel: Steering Blue button . : %i\n", cfg->wheel_blue); @@ -264,8 +264,8 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) swdc_di_off_accel = accel_axis->off; swdc_di_start = cfg->start; swdc_di_view_chg = cfg->view_chg; - swdc_di_shift_dn = cfg->shift_dn; - swdc_di_shift_up = cfg->shift_up; + swdc_di_paddle_left = cfg->paddle_left; + swdc_di_paddle_right = cfg->paddle_right; swdc_di_wheel_green = cfg->wheel_green; swdc_di_wheel_red = cfg->wheel_red; swdc_di_wheel_blue = cfg->wheel_blue; @@ -344,11 +344,11 @@ static void swdc_di_get_buttons(uint16_t *gamebtn_out) gamebtn |= SWDC_IO_GAMEBTN_VIEW_CHANGE; } - if (swdc_di_shift_dn && state.st.rgbButtons[swdc_di_shift_dn - 1]) { + if (swdc_di_paddle_left && state.st.rgbButtons[swdc_di_paddle_left - 1]) { gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT; } - if (swdc_di_shift_up && state.st.rgbButtons[swdc_di_shift_up - 1]) { + if (swdc_di_paddle_right && state.st.rgbButtons[swdc_di_paddle_right - 1]) { gamebtn |= SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT; } From 31203daa09f3f888a5c342f71d9fb722855f0fcf Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 5 Sep 2023 00:24:43 +0200 Subject: [PATCH 037/204] idz, idac, swdc: fixed `restrict` config setting --- dist/idac/segatools.ini | 24 ++++++++++++------------ dist/idz/segatools.ini | 24 ++++++++++++------------ dist/swdc/segatools.ini | 24 ++++++++++++------------ idacio/config.c | 2 +- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 8b72d4e..7f8988e 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -87,6 +87,18 @@ coin=0x33 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput +; Adjust scaling for steering wheel input. +; +; This setting scales the steering wheel input so that the maximum positive +; and minimum negative steering inputs reported in the operator menu's input +; test screen do not exceed the value below. The maximum possible value is 128, +; and the value that matches the input range of a real cabinet is 128. +; +; NOTE: This is not the same thing as DirectInput steering wheel movement +; range! Segatools cannot control the maximum angle of your physical steering +; wheel controller, this setting is vendor-specific and can only be adjusted +; in the Control Panel. +restrict=128 [xinput] ; Left and right thumbsticks are mapped to left and right dpad buttons. @@ -104,18 +116,6 @@ linearSteering=0 leftStickDeadzone=7849 ; The default value for the right stick is 8689, max value is 32767. rightStickDeadzone=8689 -; Adjust scaling for steering wheel input. -; -; This setting scales the steering wheel input so that the maximum positive -; and minimum negative steering inputs reported in the operator menu's input -; test screen do not exceed the value below. The maximum possible value is 128, -; and the value that matches the input range of a real cabinet is 128. -; -; NOTE: This is not the same thing as DirectInput steering wheel movement -; range! Segatools cannot control the maximum angle of your physical steering -; wheel controller, this setting is vendor-specific and can only be adjusted -; in the Control Panel. -restrict=128 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 7ddf1ad..adb0e97 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -87,6 +87,18 @@ coin=0x33 ; Input API selection for JVS input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput +; Adjust scaling for steering wheel input. +; +; This setting scales the steering wheel input so that the maximum positive +; and minimum negative steering inputs reported in the operator menu's input +; test screen do not exceed the value below. The maximum possible value is 128, +; and the value that matches the input range of a real cabinet is 97. +; +; NOTE: This is not the same thing as DirectInput steering wheel movement +; range! Segatools cannot control the maximum angle of your physical steering +; wheel controller, this setting is vendor-specific and can only be adjusted +; in the Control Panel. +restrict=97 [xinput] ; Automatically reset the simulated shifter to Neutral when XInput Start is @@ -102,18 +114,6 @@ linearSteering=0 leftStickDeadzone=7849 ; The default value for the right stick is 8689, max value is 32767. rightStickDeadzone=8689 -; Adjust scaling for steering wheel input. -; -; This setting scales the steering wheel input so that the maximum positive -; and minimum negative steering inputs reported in the operator menu's input -; test screen do not exceed the value below. The maximum possible value is 128, -; and the value that matches the input range of a real cabinet is 97. -; -; NOTE: This is not the same thing as DirectInput steering wheel movement -; range! Segatools cannot control the maximum angle of your physical steering -; wheel controller, this setting is vendor-specific and can only be adjusted -; in the Control Panel. -restrict=97 [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 4f2ff03..74a5400 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -63,18 +63,6 @@ coin=0x33 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. mode=xinput - -[xinput] -; Use the left thumbstick for steering instead of both on XInput Controllers. -; Not recommended as it will not give you the precision needed for this game. -singleStickSteering=1 -; Use linear steering instead of the default non-linear cubing steering. -linearSteering=0 -; Configure deadzones for the left and right thumbsticks. -; The default value for the left stick is 7849, max value is 32767. -leftStickDeadzone=7849 -; The default value for the right stick is 8689, max value is 32767. -rightStickDeadzone=8689 ; Adjust scaling for steering wheel input. ; ; This setting scales the steering wheel input so that the maximum positive @@ -88,6 +76,18 @@ rightStickDeadzone=8689 ; in the Control Panel. restrict=128 +[xinput] +; Use the left thumbstick for steering instead of both on XInput Controllers. +; Not recommended as it will not give you the precision needed for this game. +singleStickSteering=1 +; Use linear steering instead of the default non-linear cubing steering. +linearSteering=0 +; Configure deadzones for the left and right thumbsticks. +; The default value for the left stick is 7849, max value is 32767. +leftStickDeadzone=7849 +; The default value for the right stick is 8689, max value is 32767. +rightStickDeadzone=8689 + [dinput] ; Name of the DirectInput wheel to use (or any text that occurs in its name) ; Example: G29 diff --git a/idacio/config.c b/idacio/config.c index 48410c5..968124b 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -111,7 +111,7 @@ void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); - cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 97, filename); + cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 128, filename); GetPrivateProfileStringW( L"io4", From 98d2ea139095c84ec84ce13836dc70ccad6a43d9 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Wed, 13 Sep 2023 11:25:29 -0400 Subject: [PATCH 038/204] vfs: add hook for C:\Users\AppUser --- platform/vfs.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/platform/vfs.c b/platform/vfs.c index 7bd2953..befc87d 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -20,6 +20,10 @@ static HRESULT vfs_path_hook_nthome( const wchar_t *src, wchar_t *dest, size_t *count); +static HRESULT vfs_path_hook_w10home( + const wchar_t *src, + wchar_t *dest, + size_t *count); static HRESULT vfs_path_hook_option( const wchar_t *src, wchar_t *dest, @@ -31,6 +35,9 @@ static wchar_t vfs_nthome_real[MAX_PATH]; static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; +static const wchar_t vfs_w10home[] = L"C:\\Users\\AppUser"; +static const size_t vfs_w10home_len = _countof(vfs_w10home) - 1; + static const wchar_t vfs_option[] = L"C:\\Mount\\Option"; static const size_t vfs_option_len = _countof(vfs_option) - 1; @@ -144,6 +151,12 @@ HRESULT vfs_hook_init(const struct vfs_config *config) return hr; } + hr = path_hook_push(vfs_path_hook_w10home); + + if (FAILED(hr)) { + return hr; + } + if (vfs_config.option[0] != L'\0') { hr = path_hook_push(vfs_path_hook_option); @@ -357,6 +370,53 @@ static HRESULT vfs_path_hook_nthome( return S_OK; } +static HRESULT vfs_path_hook_w10home( + const wchar_t *src, + wchar_t *dest, + size_t *count) +{ + size_t required; + size_t redir_len; + size_t shift; + + assert(src != NULL); + assert(count != NULL); + + /* Case-insensitive check to see if src starts with vfs_w10home */ + + if (path_compare_w(src, vfs_w10home, vfs_w10home_len) != 0) { + return S_FALSE; + } + + /* Check if the character after vfs_w10home is a separator or the end of + the string */ + + if (!path_is_separator_w(src[vfs_w10home_len]) && + src[vfs_w10home_len] != L'\0') + { + return S_FALSE; + } + + /* Cut off the matched \, add the replaced prefix, count NUL */ + + shift = path_is_separator_w(src[vfs_w10home_len]) ? 1 : 0; + redir_len = wcslen(vfs_nthome_real); + required = wcslen(src) - vfs_w10home_len - shift + redir_len + 1; + + if (dest != NULL) { + if (required > *count) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + wcscpy_s(dest, *count, vfs_nthome_real); + wcscpy_s(dest + redir_len, *count - redir_len, src + vfs_w10home_len + shift); + } + + *count = required; + + return S_OK; +} + static HRESULT vfs_path_hook_option( const wchar_t *src, wchar_t *dest, From 3d7d9fcaa5fa145db5a14532426e1f9e0e664a55 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Wed, 13 Sep 2023 17:54:40 -0400 Subject: [PATCH 039/204] hooklib: add createprocess hook skeleton --- hooklib/createprocess.c | 176 ++++++++++++++++++++++++++++++++++++++++ hooklib/createprocess.h | 14 ++++ 2 files changed, 190 insertions(+) create mode 100644 hooklib/createprocess.c create mode 100644 hooklib/createprocess.h diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c new file mode 100644 index 0000000..1b1ebad --- /dev/null +++ b/hooklib/createprocess.c @@ -0,0 +1,176 @@ +#include + +#include +#include +#include +#include + +#include "hook/table.h" + +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); +BOOL my_CreateProcessW( + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); + +static BOOL (WINAPI *next_CreateProcessA)( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); + +static BOOL (WINAPI *next_CreateProcessW)( + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); + +static const struct hook_symbol win32_hooks[] = { + { + .name = "CreateProcessA", + .patch = my_CreateProcessA, + .link = (void **) &next_CreateProcessA + }, + { + .name = "CreateProcessW", + .patch = my_CreateProcessW, + .link = (void **) &next_CreateProcessW + }, +}; + +static bool did_init = false; + +static struct process_hook_sym_w *processe_syms_w; +static struct process_hook_sym_a *processe_syms_a; + +static size_t processe_nsyms_a = 0; +static size_t processe_nsyms_w = 0; + +void createprocess_push_hook_w(const wchar_t *name, const wchar_t *dll_name, const wchar_t *tail) { + createprocess_hook_init(); +} + +void createprocess_push_hook_a(const char *name, const char *dll_name, const char *tail) { + createprocess_hook_init(); +} + +void createprocess_hook_init() { + if (did_init) { + return; + } + did_init = true; + + hook_table_apply( + NULL, + "kernel32.dll", + win32_hooks, + _countof(win32_hooks)); + + dprintf("CreateProcess: Init\n"); +} + + +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +) +{ + if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) { + return next_CreateProcessA( + lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); + } + + dprintf("CreateProcess: Hooking child process %s\n", lpCommandLine); + char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll "; + strcat_s(new_cmd, MAX_PATH, lpCommandLine); + + return next_CreateProcessA( + lpApplicationName, + new_cmd, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); +} + +BOOL my_CreateProcessW( + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) +{ + return next_CreateProcessW( + lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); +} \ No newline at end of file diff --git a/hooklib/createprocess.h b/hooklib/createprocess.h new file mode 100644 index 0000000..fdbaa9b --- /dev/null +++ b/hooklib/createprocess.h @@ -0,0 +1,14 @@ +void createprocess_push_hook_w(); +void createprocess_push_hook_a(); + +struct process_hook_sym_w { + const wchar_t *name; + const wchar_t *dll_name; + const wchar_t *tail; +}; + +struct process_hook_sym_a { + const char *name; + const char *dll_name; + const char *tail; +}; \ No newline at end of file From 2dbb4aec8cacdfbddd8fc7b5a76c7c98d4bba416 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 13 Sep 2023 19:54:22 -0400 Subject: [PATCH 040/204] hooklib: add createprocess to meson --- hooklib/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hooklib/meson.build b/hooklib/meson.build index d112da6..4a381b4 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -9,6 +9,8 @@ hooklib_lib = static_library( sources : [ 'config.c', 'config.h', + 'createprocess.c', + 'createprocess.h', 'dll.c', 'dll.h', 'dns.c', From dca84e08d0973e9b77bdb81c327dd459359be577 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 13 Sep 2023 19:57:10 -0400 Subject: [PATCH 041/204] hooklib: fix createprocess imports --- hooklib/createprocess.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c index 1b1ebad..9e6ea7c 100644 --- a/hooklib/createprocess.c +++ b/hooklib/createprocess.c @@ -7,6 +7,9 @@ #include "hook/table.h" +#include "util/dprintf.h" + +void createprocess_hook_init(); static BOOL WINAPI my_CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, From 0d839770738b5ed589497643a23da4746565f2c8 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Wed, 13 Sep 2023 20:23:40 -0400 Subject: [PATCH 042/204] hooklib: fill out my_CreateProcessA --- hooklib/createprocess.c | 142 ++++++++++++++++++++++++++++++---------- hooklib/createprocess.h | 16 +++-- 2 files changed, 119 insertions(+), 39 deletions(-) diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c index 9e6ea7c..656487c 100644 --- a/hooklib/createprocess.c +++ b/hooklib/createprocess.c @@ -7,6 +7,8 @@ #include "hook/table.h" +#include "hooklib/createprocess.h" + #include "util/dprintf.h" void createprocess_hook_init(); @@ -76,18 +78,80 @@ static const struct hook_symbol win32_hooks[] = { static bool did_init = false; -static struct process_hook_sym_w *processe_syms_w; -static struct process_hook_sym_a *processe_syms_a; +static struct process_hook_sym_w *process_syms_w; +static struct process_hook_sym_a *process_syms_a; -static size_t processe_nsyms_a = 0; -static size_t processe_nsyms_w = 0; +static size_t process_nsyms_a = 0; +static size_t process_nsyms_w = 0; + +static CRITICAL_SECTION createproc_lock; + +HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail) { + struct process_hook_sym_w *new_mem; + struct process_hook_sym_w *new_proc; + HRESULT hr; + + assert(name != NULL); + assert(head != NULL); -void createprocess_push_hook_w(const wchar_t *name, const wchar_t *dll_name, const wchar_t *tail) { createprocess_hook_init(); + EnterCriticalSection(&createproc_lock); + + new_mem = realloc( + process_syms_w, + (process_nsyms_w + 1) * sizeof(struct process_hook_sym_w)); + + if (new_mem == NULL) { + + LeaveCriticalSection(&createproc_lock); + return E_OUTOFMEMORY; + } + + new_proc = &new_mem[process_nsyms_w]; + memset(new_proc, 0, sizeof(*new_proc)); + new_proc->name = name; + new_proc->head = head; + new_proc->tail = tail; + + process_syms_w = new_mem; + process_nsyms_w++; + + LeaveCriticalSection(&createproc_lock); + return S_OK; } -void createprocess_push_hook_a(const char *name, const char *dll_name, const char *tail) { +HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail) { + struct process_hook_sym_a *new_mem; + struct process_hook_sym_a *new_proc; + + assert(name != NULL); + assert(head != NULL); + createprocess_hook_init(); + + EnterCriticalSection(&createproc_lock); + + new_mem = realloc( + process_syms_a, + (process_nsyms_a + 1) * sizeof(struct process_hook_sym_a)); + + if (new_mem == NULL) { + + LeaveCriticalSection(&createproc_lock); + return E_OUTOFMEMORY; + } + + new_proc = &new_mem[process_nsyms_a]; + memset(new_proc, 0, sizeof(*new_proc)); + new_proc->name = name; + new_proc->head = head; + new_proc->tail = tail; + + process_syms_a = new_mem; + process_nsyms_a++; + + LeaveCriticalSection(&createproc_lock); + return S_OK; } void createprocess_hook_init() { @@ -101,7 +165,7 @@ void createprocess_hook_init() { "kernel32.dll", win32_hooks, _countof(win32_hooks)); - + InitializeCriticalSection(&createproc_lock); dprintf("CreateProcess: Init\n"); } @@ -119,37 +183,45 @@ static BOOL WINAPI my_CreateProcessA( LPPROCESS_INFORMATION lpProcessInformation ) { - if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) { + for (int i = 0; i < process_nsyms_a; i++) { + if (strncmp(process_syms_a->name, lpCommandLine, strlen(process_syms_a->name))) { + continue; + } + + dprintf("CreateProcess: Hooking child process %s\n", lpCommandLine); + char new_cmd[MAX_PATH]; + strcat_s(new_cmd, MAX_PATH, process_syms_a->head); + strcat_s(new_cmd, MAX_PATH, lpCommandLine); + + if (process_syms_a->tail[0]) { + strcat_s(new_cmd, MAX_PATH, process_syms_a->tail); + } + return next_CreateProcessA( - lpApplicationName, - lpCommandLine, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - lpEnvironment, - lpCurrentDirectory, - lpStartupInfo, - lpProcessInformation - ); + lpApplicationName, + new_cmd, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); } - - dprintf("CreateProcess: Hooking child process %s\n", lpCommandLine); - char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll "; - strcat_s(new_cmd, MAX_PATH, lpCommandLine); - return next_CreateProcessA( - lpApplicationName, - new_cmd, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - lpEnvironment, - lpCurrentDirectory, - lpStartupInfo, - lpProcessInformation - ); + lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); } BOOL my_CreateProcessW( diff --git a/hooklib/createprocess.h b/hooklib/createprocess.h index fdbaa9b..aedd9b6 100644 --- a/hooklib/createprocess.h +++ b/hooklib/createprocess.h @@ -1,14 +1,22 @@ -void createprocess_push_hook_w(); -void createprocess_push_hook_a(); +#include + +HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail); +HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail); struct process_hook_sym_w { const wchar_t *name; - const wchar_t *dll_name; + size_t name_size; + const wchar_t *head; + size_t head_size; const wchar_t *tail; + size_t tail_size; }; struct process_hook_sym_a { const char *name; - const char *dll_name; + size_t name_size; + const char *head; + size_t head_size; const char *tail; + size_t tail_size; }; \ No newline at end of file From 157f52da4cbe2dd0875a8c4ef018a668d1e734cd Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 15 Sep 2023 01:35:33 -0400 Subject: [PATCH 043/204] platform: add epay hook --- hooklib/createprocess.c | 7 +- hooklib/createprocess.h | 2 + platform/config.c | 9 ++ platform/config.h | 2 + platform/epay.c | 335 ++++++++++++++++++++++++++++++++++++++++ platform/epay.h | 63 ++++++++ platform/meson.build | 2 + platform/platform.c | 7 + platform/platform.h | 2 + 9 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 platform/epay.c create mode 100644 platform/epay.h diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c index 656487c..d411aaf 100644 --- a/hooklib/createprocess.c +++ b/hooklib/createprocess.c @@ -188,15 +188,16 @@ static BOOL WINAPI my_CreateProcessA( continue; } - dprintf("CreateProcess: Hooking child process %s\n", lpCommandLine); - char new_cmd[MAX_PATH]; + dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine); + char new_cmd[MAX_PATH] = {0}; strcat_s(new_cmd, MAX_PATH, process_syms_a->head); strcat_s(new_cmd, MAX_PATH, lpCommandLine); - if (process_syms_a->tail[0]) { + if (process_syms_a->tail != NULL) { strcat_s(new_cmd, MAX_PATH, process_syms_a->tail); } + dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd); return next_CreateProcessA( lpApplicationName, new_cmd, diff --git a/hooklib/createprocess.h b/hooklib/createprocess.h index aedd9b6..93ed8f7 100644 --- a/hooklib/createprocess.h +++ b/hooklib/createprocess.h @@ -1,3 +1,5 @@ +#pragma once + #include HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail); diff --git a/platform/config.c b/platform/config.c index 1c6be62..93bc73e 100644 --- a/platform/config.c +++ b/platform/config.c @@ -13,6 +13,7 @@ #include "platform/clock.h" #include "platform/config.h" #include "platform/dns.h" +#include "platform/epay.h" #include "platform/hwmon.h" #include "platform/hwreset.h" #include "platform/misc.h" @@ -30,6 +31,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) amvideo_config_load(&cfg->amvideo, filename); clock_config_load(&cfg->clock, filename); dns_config_load(&cfg->dns, filename); + epay_config_load(&cfg->epay, filename); hwmon_config_load(&cfg->hwmon, filename); hwreset_config_load(&cfg->hwreset, filename); misc_config_load(&cfg->misc, filename); @@ -317,3 +319,10 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) filename); } +void epay_config_load(struct epay_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); +} diff --git a/platform/config.h b/platform/config.h index 7ece41d..93df65a 100644 --- a/platform/config.h +++ b/platform/config.h @@ -9,6 +9,7 @@ #include "platform/amvideo.h" #include "platform/clock.h" #include "platform/dns.h" +#include "platform/epay.h" #include "platform/hwmon.h" #include "platform/hwreset.h" #include "platform/misc.h" @@ -25,6 +26,7 @@ void platform_config_load( void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename); void clock_config_load(struct clock_config *cfg, const wchar_t *filename); void dns_config_load(struct dns_config *cfg, const wchar_t *filename); +void epay_config_load(struct epay_config *cfg, const wchar_t *filename); void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename); void hwreset_config_load(struct hwreset_config *cfg, const wchar_t *filename); void misc_config_load(struct misc_config *cfg, const wchar_t *filename); diff --git a/platform/epay.c b/platform/epay.c new file mode 100644 index 0000000..0faf145 --- /dev/null +++ b/platform/epay.c @@ -0,0 +1,335 @@ +#include + +#include +#include +#include +#include + +#include "hook/table.h" + +#include "hooklib/reg.h" + +#include "platform/epay.h" + +#include "util/dprintf.h" + +static HRESULT misc_read_thinca_adapter(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_ca_loc(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_ca_client_loc(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_network_timeout(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_pattern0(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_network_timeout0(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_pattern1(void *bytes, uint32_t *nbytes); +static HRESULT misc_read_network_timeout1(void *bytes, uint32_t *nbytes); + +static uint64_t thinca_initialize(struct thinca_impl * self, uint64_t val); +static uint64_t thinca_dispose(struct thinca_impl * self); +static uint64_t thinca_set_resource(struct thinca_impl * self, char * res); +static uint64_t thinca_set_pay_log(struct thinca_impl * self, uint64_t val, char * log, uint64_t val2, const char * size_lim); +static uint64_t thinca_set_client_log(struct thinca_impl * self, uint64_t val, char * log); +static uint64_t thinca_set_client_cfg(struct thinca_impl * self, char * log, uint64_t val); +static uint64_t thinca_set_goods_code(struct thinca_impl * self, char * code); +static uint64_t thinca_set_evt_handler(struct thinca_impl * self, void* handler); +static uint64_t thinca_set_cert(struct thinca_impl * self, char * cert, uint64_t val); +static uint64_t thinca_set_serial(struct thinca_impl * self, char * cert); +static uint64_t thinca_check_deal(struct thinca_impl * self, void* deal); +static uint64_t thinca_cancel(struct thinca_impl * self); +static uint64_t thinca_select(struct thinca_impl * self); +static uint64_t thinca_unk(struct thinca_impl * self, uint64_t val); +static void thinca_unk8(struct thinca_impl * self); + +static uint64_t my_ThincaPaymentGetVersion(); +static uint64_t (*next_ThincaPaymentGetVersion)(); + +static struct thinca_main* my_ThincaPaymentGetInstance(uint64_t ver); +static struct thinca_main* (*next_ThincaPaymentGetInstance)(uint64_t ver); + +static struct thinca_main* thinca_stub; + +static const struct reg_hook_val epay_adapter_keys[] = { + { + .name = L"TfpsAimeRwAdapter", + .read = misc_read_thinca_adapter, + .type = REG_SZ, + } +}; + +static const struct reg_hook_val epay_tcap_keys[] = { + { + .name = L"CaLocation", + .read = misc_read_ca_loc, + .type = REG_SZ, + }, + { + .name = L"ThincaTcapClientPath", + .read = misc_read_ca_client_loc, + .type = REG_SZ, + }, + { + .name = L"ClientNetworkTimeout", + .read = misc_read_network_timeout, + .type = REG_DWORD, + } +}; + +static const struct reg_hook_val epay_tcap_url0_keys[] = { + { + .name = L"Pattern", + .read = misc_read_pattern0, + .type = REG_SZ, + }, + { + .name = L"ClientNetworkTimeout", + .read = misc_read_network_timeout0, + .type = REG_DWORD, + } +}; + +static const struct reg_hook_val epay_tcap_url1_keys[] = { + { + .name = L"Pattern", + .read = misc_read_pattern1, + .type = REG_SZ, + }, + { + .name = L"ClientNetworkTimeout", + .read = misc_read_network_timeout1, + .type = REG_DWORD, + } +}; + +static const struct hook_symbol epay_syms[] = { + { + .name = "ThincaPaymentGetVersion", + .patch = my_ThincaPaymentGetVersion, + .link = (void **) &next_ThincaPaymentGetVersion, + .ordinal = 1, + }, + { + .name = "__imp_ThincaPaymentGetInstance", + .patch = my_ThincaPaymentGetInstance, + .link = (void **) &next_ThincaPaymentGetInstance, + .ordinal = 2, + }, + { + .name = "ThincaPaymentGetInstance", + .patch = my_ThincaPaymentGetInstance, + .link = (void **) &next_ThincaPaymentGetInstance, + .ordinal = 2, + } +}; + +HRESULT epay_hook_init(const struct epay_config *cfg) { + HRESULT hr; + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\TFPaymentService\\ThincaRwAdapter", + epay_adapter_keys, + _countof(epay_adapter_keys)); + + if (FAILED(hr)) { + return hr; + } + + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\TFPaymentService\\ThincaTcapClient", + epay_tcap_keys, + _countof(epay_tcap_keys)); + + if (FAILED(hr)) { + return hr; + } + + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\TFPaymentService\\ThincaTcapClient\\URL0", + epay_tcap_url0_keys, + _countof(epay_tcap_url0_keys)); + + if (FAILED(hr)) { + return hr; + } + + hr = reg_hook_push_key( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\TFPaymentService\\ThincaTcapClient\\URL1", + epay_tcap_url1_keys, + _countof(epay_tcap_url1_keys)); + + hook_table_apply( + NULL, + "ThincaPayment.dll", + epay_syms, + _countof(epay_syms)); + + thinca_stub = (struct thinca_main *)malloc(sizeof(struct thinca_main)); + thinca_stub->impl1 = (struct thinca_impl *)malloc(sizeof(struct thinca_impl)); + + thinca_stub->impl1->unk8 = thinca_unk8; + thinca_stub->impl1->initialize = thinca_initialize; + thinca_stub->impl1->dispose = thinca_dispose; + thinca_stub->impl1->setResource = thinca_set_resource; + thinca_stub->impl1->setThincaPaymentLog = thinca_set_pay_log; + thinca_stub->impl1->setThincaEventInterface = thinca_set_evt_handler; + thinca_stub->impl1->setIcasClientLog = thinca_set_client_log; + thinca_stub->impl1->setIcasClientConfig = thinca_set_client_cfg; + thinca_stub->impl1->setGoodsCode = thinca_set_goods_code; + thinca_stub->impl1->setTerminalSerial = thinca_set_serial; + thinca_stub->impl1->setClientCertificate = thinca_set_cert; + thinca_stub->impl1->checkDeal = thinca_check_deal; + thinca_stub->impl1->cancelRequest = thinca_cancel; + thinca_stub->impl1->selectButton = thinca_select; + thinca_stub->impl1->unk220 = thinca_unk; + thinca_stub->impl1->unk228 = thinca_unk; + + dprintf("Epay: Init\n"); + + return hr; +} + +static HRESULT misc_read_thinca_adapter(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L"aime_rw_adapterMD.dll"); +} + +static HRESULT misc_read_ca_loc(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L"ca.pem"); +} + +static HRESULT misc_read_ca_client_loc(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L"thincatcapclient.dll"); +} + +static HRESULT misc_read_network_timeout(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_u32(bytes, nbytes, 20000); +} + +static HRESULT misc_read_pattern0(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L".*\\.jsp"); +} + +static HRESULT misc_read_network_timeout0(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_u32(bytes, nbytes, 5000); +} + +static HRESULT misc_read_pattern1(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L".*(closing|remove).*"); +} + +static HRESULT misc_read_network_timeout1(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_u32(bytes, nbytes, 60000); +} + +static uint64_t thinca_initialize(struct thinca_impl * self, uint64_t val) +{ + dprintf("Epay: Thinca Initialize %lld\n", val); + return 0; +} + +static uint64_t thinca_dispose(struct thinca_impl * self) +{ + dprintf("Epay: Thinca Dispose\n"); + return 0; +} + +static uint64_t thinca_set_resource(struct thinca_impl * self, char * res) +{ + dprintf("Epay: Thinca Set Resource %s\n", res); + return 0; +} + +static uint64_t thinca_set_pay_log(struct thinca_impl * self, uint64_t val, char * log, uint64_t val2, const char * size_lim) +{ + dprintf("Epay: Thinca Set Paylog %lld | %s | %lld | %s\n", val, log, val2, size_lim); + return 0; +} + +static uint64_t thinca_set_client_log(struct thinca_impl * self, uint64_t val, char * log) +{ + dprintf("Epay: Thinca Set ICAS Client log %lld | %s\n", val, log); + return 0; +} + +static uint64_t thinca_set_client_cfg(struct thinca_impl * self, char * log, uint64_t val) +{ + dprintf("Epay: Thinca Set ICAS Client Config %s | %lld\n", log, val); + return 0; +} + +static uint64_t thinca_set_goods_code(struct thinca_impl * self, char * code) +{ + dprintf("Epay: Thinca Set Goods Code %s\n", code); + return 0; +} + +static uint64_t thinca_set_evt_handler(struct thinca_impl * self, void* handler) +{ + dprintf("Epay: Thinca Set Event Handler %p\n", handler); + return 0; +} + +static uint64_t thinca_set_cert(struct thinca_impl * self, char * cert, uint64_t val) +{ + dprintf("Epay: Thinca Set Client Cert %s | %lld\n", cert, val); + return 0; +} + +static uint64_t thinca_set_serial(struct thinca_impl * self, char * cert) +{ + dprintf("Epay: Thinca Set Terminal Serial %s\n", cert); + return 0; +} + +static uint64_t thinca_check_deal(struct thinca_impl * self, void* deal) +{ + dprintf("Epay: Thinca Check Deal %p\n", deal); + return 0; +} + +static uint64_t thinca_cancel(struct thinca_impl * self) +{ + dprintf("Epay: Thinca Cancel\n"); + return 0; +} + +static uint64_t thinca_select(struct thinca_impl * self) +{ + dprintf("Epay: Thinca Select\n"); + return 0; +} + +static uint64_t thinca_unk(struct thinca_impl * self, uint64_t val) +{ + dprintf("Epay: Thinca Unknown 220/228 %lld\n", val); + return 0; +} + +static void thinca_unk8(struct thinca_impl * self) +{ + dprintf("Epay: Thinca Unknown 8\n"); +} + +static uint64_t my_ThincaPaymentGetVersion() +{ + return 0x1040B00; +} + +static struct thinca_main* my_ThincaPaymentGetInstance(uint64_t ver) +{ + dprintf("Epay: my_ThincaPaymentGetInstance hit!\n"); + return thinca_stub; +} \ No newline at end of file diff --git a/platform/epay.h b/platform/epay.h new file mode 100644 index 0000000..c94eceb --- /dev/null +++ b/platform/epay.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +#pragma pack(push,1) +struct epay_config { + bool enable; +}; + +/* The functions in these structs are how clients like amdaemon interface + * with thinca. We can simply replace these functions with our own stubs + * to bypass errors and such. Currently this DOES NOT allow for epay, and + * trying to do so will most likely just lead to misery. My goal isn't to + * reimplement epay, just to give amdaemon SOMETHING so we can boot properly. + */ +struct thinca_impl { + uint64_t* unk0; + void (*unk8)(struct thinca_impl *); + uint64_t (*initialize)(struct thinca_impl *, uint64_t); + uint64_t (*dispose)(struct thinca_impl *); + uint64_t (*setResource)(struct thinca_impl *, char *); + uint64_t (*setThincaPaymentLog)(struct thinca_impl *, uint64_t, char *, uint64_t, const char *); + uint64_t (*setIcasClientLog)(struct thinca_impl *, uint64_t, char *); + uint64_t (*setIcasClientConfig)(struct thinca_impl *, char *, uint64_t); + uint64_t* unk40; + uint64_t* unk48; + uint64_t (*setClientCertificate)(struct thinca_impl *, char *, uint64_t); + uint64_t (*setTerminalSerial)(struct thinca_impl *, char *); + uint64_t (*setGoodsCode)(struct thinca_impl *, char *); + uint64_t unk68; + uint64_t (*setThincaEventInterface)(struct thinca_impl *, void*); // probably a struct + uint64_t unkGap78[7]; + uint64_t (*checkDeal)(struct thinca_impl *, void *); // probably a struct + uint64_t unkGapB8[41]; + uint64_t (*cancelRequest)(struct thinca_impl *); + uint64_t (*selectButton)(struct thinca_impl *); + uint64_t unkGap210[2]; + uint64_t (*unk220)(struct thinca_impl *, uint64_t); + uint64_t (*unk228)(struct thinca_impl *, uint64_t); +}; + +/* I believe the actual struct is 0x310 bytes, so for now I'm just + * implementing what I need and hoping the rest don't cause issues + * later. AMDaemon seems to only care about impl1 and deal_thing, + * at least from what I can tell + */ +struct thinca_main { + struct thinca_impl* impl1; + struct thinca_impl* impl2; + HANDLE* mutex1; + HANDLE* mutex2; + HANDLE* mutex3; + uint64_t* unk28; + uint64_t* unk30; + uint64_t* unk38; + uint64_t* unk40; + uint64_t* deal_thing; + uint64_t filler[88]; +}; + +#pragma pack(pop) +HRESULT epay_hook_init(const struct epay_config *cfg); \ No newline at end of file diff --git a/platform/meson.build b/platform/meson.build index 4f0fbc9..a3e1fe5 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -16,6 +16,8 @@ platform_lib = static_library( 'config.h', 'dns.c', 'dns.h', + 'epay.c', + 'epay.h', 'hwmon.c', 'hwmon.h', 'hwreset.c', diff --git a/platform/platform.c b/platform/platform.c index 218204c..bf44800 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -5,6 +5,7 @@ #include "platform/amvideo.h" #include "platform/clock.h" #include "platform/dns.h" +#include "platform/epay.h" #include "platform/hwmon.h" #include "platform/misc.h" #include "platform/netenv.h" @@ -80,5 +81,11 @@ HRESULT platform_hook_init( return hr; } + hr = epay_hook_init(&cfg->epay); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/platform/platform.h b/platform/platform.h index 69c65e2..def496c 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -5,6 +5,7 @@ #include "platform/amvideo.h" #include "platform/clock.h" #include "platform/dns.h" +#include "platform/epay.h" #include "platform/hwmon.h" #include "platform/hwreset.h" #include "platform/misc.h" @@ -17,6 +18,7 @@ struct platform_config { struct amvideo_config amvideo; struct clock_config clock; struct dns_config dns; + struct epay_config epay; struct hwmon_config hwmon; struct hwreset_config hwreset; struct misc_config misc; From f5a7e5b821ac0e9e5e1b46c1b2aae6b084dd6caa Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 15 Sep 2023 19:58:46 +0200 Subject: [PATCH 044/204] epay: added config because git is dumb --- platform/config.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/config.c b/platform/config.c index 279c4f2..8e71847 100644 --- a/platform/config.c +++ b/platform/config.c @@ -339,3 +339,10 @@ void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) } } +void epay_config_load(struct epay_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); +} From 5a4e947354c70c1941368f3f6cf289f10c13aa1d Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 15 Sep 2023 19:52:26 -0400 Subject: [PATCH 045/204] carol: use createprocess hook --- carolhook/controlbd.c | 88 ------------------------------------------- carolhook/dllmain.c | 8 +++- 2 files changed, 7 insertions(+), 89 deletions(-) diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index a59fe65..63a65f4 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -8,8 +8,6 @@ #include "hook/iobuf.h" #include "hook/iohook.h" -#include "hook/table.h" - #include "carolhook/carol-dll.h" #include "carolhook/controlbd.h" @@ -38,39 +36,6 @@ static struct uart controlbd_uart; static uint8_t controlbd_written_bytes[520]; static uint8_t controlbd_readable_bytes[520]; -static BOOL WINAPI my_CreateProcessA( - LPCSTR lpApplicationName, - LPSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCSTR lpCurrentDirectory, - LPSTARTUPINFOA lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation -); -static BOOL (WINAPI *next_CreateProcessA)( - LPCSTR lpApplicationName, - LPSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCSTR lpCurrentDirectory, - LPSTARTUPINFOA lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation -); - -static const struct hook_symbol win32_hooks[] = { - { - .name = "CreateProcessA", - .patch = my_CreateProcessA, - .link = (void **) &next_CreateProcessA - } -}; - HRESULT controlbd_hook_init(const struct controlbd_config *cfg) { if (!cfg->enable) { @@ -85,12 +50,6 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) controlbd_uart.readable.bytes = controlbd_readable_bytes; controlbd_uart.readable.nbytes = sizeof(controlbd_readable_bytes); - hook_table_apply( - NULL, - "kernel32.dll", - win32_hooks, - _countof(win32_hooks)); - dprintf("Control Board: Init\n"); return iohook_push_handler(controlbd_handle_irp); @@ -378,50 +337,3 @@ static HRESULT controlbd_req_ack_any(uint8_t cmd) return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); } - -static BOOL WINAPI my_CreateProcessA( - LPCSTR lpApplicationName, - LPSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCSTR lpCurrentDirectory, - LPSTARTUPINFOA lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation -) -{ - dprintf("Control Board: my_CreateProcessA Hit! %s\n", lpCommandLine); - if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) { - return next_CreateProcessA( - lpApplicationName, - lpCommandLine, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - lpEnvironment, - lpCurrentDirectory, - lpStartupInfo, - lpProcessInformation - ); - } - - dprintf("Control Board: Hooking child process\n"); - char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll "; - strcat_s(new_cmd, MAX_PATH, lpCommandLine); - - return next_CreateProcessA( - lpApplicationName, - new_cmd, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - lpEnvironment, - lpCurrentDirectory, - lpStartupInfo, - lpProcessInformation - ); -} \ No newline at end of file diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 55608c7..a80ea07 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -19,6 +19,7 @@ #include "hooklib/serial.h" #include "hooklib/spike.h" +#include "hooklib/createprocess.h" #include "platform/platform.h" @@ -122,7 +123,12 @@ static DWORD CALLBACK carol_pre_startup(void) if (FAILED(hr)) { goto fail; } - + + hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL); + + if (FAILED(hr)) { + goto fail; + } /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); From 528ec4379c0740cea9fed3545798eba1f20c36e2 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 15 Sep 2023 19:57:11 -0400 Subject: [PATCH 046/204] createprocess: add replace_all flag --- carolhook/dllmain.c | 2 +- hooklib/createprocess.c | 19 ++++++++++++------- hooklib/createprocess.h | 13 +++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index a80ea07..eca445b 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -124,7 +124,7 @@ static DWORD CALLBACK carol_pre_startup(void) goto fail; } - hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL); + hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL, false); if (FAILED(hr)) { goto fail; diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c index d411aaf..e44ebdb 100644 --- a/hooklib/createprocess.c +++ b/hooklib/createprocess.c @@ -86,7 +86,7 @@ static size_t process_nsyms_w = 0; static CRITICAL_SECTION createproc_lock; -HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail) { +HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) { struct process_hook_sym_w *new_mem; struct process_hook_sym_w *new_proc; HRESULT hr; @@ -112,6 +112,7 @@ HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, cons new_proc->name = name; new_proc->head = head; new_proc->tail = tail; + new_proc->replace_all = replace_all; process_syms_w = new_mem; process_nsyms_w++; @@ -120,7 +121,7 @@ HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, cons return S_OK; } -HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail) { +HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) { struct process_hook_sym_a *new_mem; struct process_hook_sym_a *new_proc; @@ -146,6 +147,7 @@ HRESULT createprocess_push_hook_a(const char *name, const char *head, const char new_proc->name = name; new_proc->head = head; new_proc->tail = tail; + new_proc->replace_all = replace_all; process_syms_a = new_mem; process_nsyms_a++; @@ -184,17 +186,20 @@ static BOOL WINAPI my_CreateProcessA( ) { for (int i = 0; i < process_nsyms_a; i++) { - if (strncmp(process_syms_a->name, lpCommandLine, strlen(process_syms_a->name))) { + if (strncmp(process_syms_a[i].name, lpCommandLine, strlen(process_syms_a[i].name))) { continue; } dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine); char new_cmd[MAX_PATH] = {0}; - strcat_s(new_cmd, MAX_PATH, process_syms_a->head); - strcat_s(new_cmd, MAX_PATH, lpCommandLine); + strcat_s(new_cmd, MAX_PATH, process_syms_a[i].head); - if (process_syms_a->tail != NULL) { - strcat_s(new_cmd, MAX_PATH, process_syms_a->tail); + if (!process_syms_a[i].replace_all) { + strcat_s(new_cmd, MAX_PATH, lpCommandLine); + } + + if (process_syms_a[i].tail != NULL) { + strcat_s(new_cmd, MAX_PATH, process_syms_a[i].tail); } dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd); diff --git a/hooklib/createprocess.h b/hooklib/createprocess.h index 93ed8f7..bf226d5 100644 --- a/hooklib/createprocess.h +++ b/hooklib/createprocess.h @@ -1,24 +1,21 @@ #pragma once #include +#include -HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail); -HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail); +HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all); +HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all); struct process_hook_sym_w { const wchar_t *name; - size_t name_size; const wchar_t *head; - size_t head_size; const wchar_t *tail; - size_t tail_size; + bool replace_all; }; struct process_hook_sym_a { const char *name; - size_t name_size; const char *head; - size_t head_size; const char *tail; - size_t tail_size; + bool replace_all; }; \ No newline at end of file From 5d04685c739ca0d92daf2bce3cca64c8acecc4cb Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 19 Sep 2023 10:33:30 -0400 Subject: [PATCH 047/204] update gitignore --- .gitignore | 13 ++++++++++++- .vscode/settings.json | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 31da392..5b84f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,17 @@ .*.swp -.vscode/ +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix # Suggested names for build dirs build/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 49872e4..9eb12eb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { "editor.formatOnSave": false, + "mesonbuild.configureOnOpen": false, } From a4bd570cfcecc6ebd755292074d82940a49d094a Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 5 Oct 2023 00:35:55 +0200 Subject: [PATCH 048/204] chusan, mai2, mu3, swdc: removed emoney config --- dist/chusan/config_hook.json | 4 ---- dist/cm/config_hook.json | 6 ------ dist/cm/start.bat | 2 +- dist/mai2/config_hook.json | 6 ------ dist/mai2/start.bat | 2 +- dist/mu3/config_hook.json | 6 ------ dist/mu3/start.bat | 2 +- dist/swdc/config_hook.json | 4 ---- doc/config/common.md | 3 +-- 9 files changed, 4 insertions(+), 31 deletions(-) delete mode 100644 dist/cm/config_hook.json delete mode 100644 dist/mai2/config_hook.json delete mode 100644 dist/mu3/config_hook.json diff --git a/dist/chusan/config_hook.json b/dist/chusan/config_hook.json index 2fb68b1..626eb7c 100644 --- a/dist/chusan/config_hook.json +++ b/dist/chusan/config_hook.json @@ -2,9 +2,5 @@ "allnet_auth": { "type": "1.0" - }, - "emoney" : - { - "enable" : false } } diff --git a/dist/cm/config_hook.json b/dist/cm/config_hook.json deleted file mode 100644 index b73cf5c..0000000 --- a/dist/cm/config_hook.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "emoney" : - { - "enable" : false - } -} diff --git a/dist/cm/start.bat b/dist/cm/start.bat index b17a6a1..865498b 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json +start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mai2/config_hook.json b/dist/mai2/config_hook.json deleted file mode 100644 index b73cf5c..0000000 --- a/dist/mai2/config_hook.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "emoney" : - { - "enable" : false - } -} diff --git a/dist/mai2/start.bat b/dist/mai2/start.bat index 889e030..a89a1d5 100644 --- a/dist/mai2/start.bat +++ b/dist/mai2/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json +start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mu3/config_hook.json b/dist/mu3/config_hook.json deleted file mode 100644 index b73cf5c..0000000 --- a/dist/mu3/config_hook.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "emoney" : - { - "enable" : false - } -} diff --git a/dist/mu3/start.bat b/dist/mu3/start.bat index 60141fc..8058daf 100644 --- a/dist/mu3/start.bat +++ b/dist/mu3/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json +start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json inject -d -k mu3hook.dll mu3 -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/swdc/config_hook.json b/dist/swdc/config_hook.json index 789e2ff..d0d8767 100644 --- a/dist/swdc/config_hook.json +++ b/dist/swdc/config_hook.json @@ -6,9 +6,5 @@ ".\\aime_firm\\TN32MSEC003S_V12.hex", ".\\aime_firm\\update_15396_6728_94.bin" ] - }, - "emoney" : - { - "enable" : false } } diff --git a/doc/config/common.md b/doc/config/common.md index 0236eaf..9648386 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -42,8 +42,7 @@ This is required for some games (e.g. Chunithm) but not others (e.g. WACCA). Default: `DEVICE\aime.txt` -Path to a text file containing a classic Aime IC card ID. **This does not -currently work**. +Path to a text file containing a classic Aime IC card ID. ### `aimeGen` From 6c45d0995b8e3a55225f995db0740b8c2594b6fb Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 5 Oct 2023 00:37:25 +0200 Subject: [PATCH 049/204] fix cursor being annoying by @OLEG https://dev.s-ul.net/OLEG/segatools-kancolle/-/commit/95273ccecb30583a6398256682898aa77fdcf8ca --- hooklib/touch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hooklib/touch.c b/hooklib/touch.c index 9911514..df6a9ea 100644 --- a/hooklib/touch.c +++ b/hooklib/touch.c @@ -72,6 +72,7 @@ static bool touch_held; static HWND registered_hWnd; static struct touch_screen_config touch_config; static WNDPROC orig_wndProc; +static HCURSOR defaultCursor; static const struct hook_symbol touch_hooks[] = { { @@ -115,6 +116,8 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel touch_hook_initted = true; + defaultCursor = LoadCursorA(NULL, IDC_CROSS); + memcpy(&touch_config, cfg, sizeof(*cfg)); hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks)); dprintf("TOUCH: hook enabled.\n"); @@ -122,7 +125,7 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) { if (cursor == 0 && touch_config.cursor) - return 0; + return next_SetCursor(defaultCursor); return next_SetCursor(cursor); } From d521eeb43e6c67a181746184b8c362bd290bd8da Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 5 Oct 2023 00:46:54 +0200 Subject: [PATCH 050/204] idz, idac, swdc: Added separate pedals config, better XInput controls - Configure separate pedals which are not part of the steering wheel (base) - It is now possible to have a different steering wheel, pedal and shifter brand all connected to 3 different USB ports - XInput does not have a deadzone at the end of the max steering anymore and the `restrict` setting works as intended --- Package.mk | 3 -- dist/idac/segatools.ini | 12 ++++-- dist/idz/segatools.ini | 8 +++- dist/swdc/segatools.ini | 8 +++- dist/swdc/start.bat | 4 ++ doc/config/initiald.md | 10 +++++ idacio/config.c | 8 ++++ idacio/config.h | 1 + idacio/di.c | 95 +++++++++++++++++++++++++++++++++++++++-- idacio/xi.c | 77 ++++++++++++++++----------------- idzio/config.c | 10 ++++- idzio/config.h | 1 + idzio/di.c | 95 +++++++++++++++++++++++++++++++++++++++-- idzio/xi.c | 77 ++++++++++++++++----------------- swdcio/config.c | 8 ++++ swdcio/config.h | 1 + swdcio/di.c | 95 +++++++++++++++++++++++++++++++++++++++-- swdcio/xi.c | 79 +++++++++++++++++----------------- 18 files changed, 450 insertions(+), 142 deletions(-) diff --git a/Package.mk b/Package.mk index 72e90a9..69cdbc1 100644 --- a/Package.mk +++ b/Package.mk @@ -148,7 +148,6 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mu3hook/mu3hook.dll \ - $(DIST_DIR)/mu3/config_hook.json \ $(DIST_DIR)/mu3/segatools.ini \ $(DIST_DIR)/mu3/start.bat \ $(BUILD_DIR_ZIP)/mu3 @@ -164,7 +163,6 @@ $(BUILD_DIR_ZIP)/mai2.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ - $(DIST_DIR)/mai2/config_hook.json \ $(DIST_DIR)/mai2/segatools.ini \ $(DIST_DIR)/mai2/start.bat \ $(BUILD_DIR_ZIP)/mai2 @@ -180,7 +178,6 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/cmhook/cmhook.dll \ - $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ $(DIST_DIR)/cm/start.bat \ $(BUILD_DIR_ZIP)/cm diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 7f8988e..22a0568 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -110,7 +110,7 @@ autoNeutral=1 ; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. -linearSteering=0 +linearSteering=1 ; Configure deadzones for the left and right thumbsticks. ; The default value for the left stick is 7849, max value is 32767. leftStickDeadzone=7849 @@ -123,6 +123,12 @@ rightStickDeadzone=8689 ; ; If this is left blank then the first DirectInput device will be used. deviceName= +; Name of the DirectInput pedals to use (or any subset thereof). +; Leave blank if you do not have separate pedals; aka the pedals are part of +; the wheel. +; +; The pedals will be mapped to the accelAxis and brakeAxis. +pedalsName= ; Name of the positional shifter to use (or any subset thereof). ; Leave blank if you do not have a positional shifter; a positional shifter ; will be simulated using the configured Shift Down and Shift Up buttons @@ -150,8 +156,8 @@ viewChg=2 left=7 right=8 ; Button mappings for the simulated six-speed shifter. -shiftDn=5 -shiftUp=6 +shiftDn=6 +shiftUp=5 ; Button mappings for the positional shifter, if present. gear1=13 gear2=14 diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index adb0e97..3fae262 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -108,7 +108,7 @@ autoNeutral=1 ; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. -linearSteering=0 +linearSteering=1 ; Configure deadzones for the left and right thumbsticks. ; The default value for the left stick is 7849, max value is 32767. leftStickDeadzone=7849 @@ -130,6 +130,12 @@ deviceName= ; ; Example: G29 shifterName= +; Name of the DirectInput pedals to use (or any subset thereof). +; Leave blank if you do not have separate pedals; aka the pedals are part of +; the wheel. +; +; The pedals will be mapped to the accelAxis and brakeAxis. +pedalsName= ; Pedal mappings. Valid axis names are: ; ; X, Y, Z, RX, RY, RZ, U, V diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 74a5400..7f030d0 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -81,7 +81,7 @@ restrict=128 ; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 ; Use linear steering instead of the default non-linear cubing steering. -linearSteering=0 +linearSteering=1 ; Configure deadzones for the left and right thumbsticks. ; The default value for the left stick is 7849, max value is 32767. leftStickDeadzone=7849 @@ -94,6 +94,12 @@ rightStickDeadzone=8689 ; ; If this is left blank then the first DirectInput device will be used. deviceName= +; Name of the DirectInput pedals to use (or any subset thereof). +; Leave blank if you do not have separate pedals; aka the pedals are part of +; the wheel. +; +; The pedals will be mapped to the accelAxis and brakeAxis. +pedalsName= ; Pedal mappings. Valid axis names are: ; ; X, Y, Z, RX, RY, RZ, U, V diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index 526cfdc..020c27f 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -2,11 +2,15 @@ pushd %~dp0 +rem Matching Server +start /min ..\..\..\Tools\tdrserver.exe REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED + taskkill /f /im amdaemon.exe > nul 2>&1 +taskkill /f /im tdrserver.exe > nul 2>&1 echo. echo Game processes have terminated diff --git a/doc/config/initiald.md b/doc/config/initiald.md index d7d6e60..42ec781 100644 --- a/doc/config/initiald.md +++ b/doc/config/initiald.md @@ -92,6 +92,16 @@ don't know the name of your input device, you can find it in the windows controller panel. The quickest way to access it is to press Win+R, then type in `joy.cpl` and look at the list it will display. +### `pedalsName` + +Default ` ` + +Name of the pedals to use (or any subset thereof). Leave blank if you do not +have separate pedals; aka the pedals are part of the wheel. The pedals will +be mapped to the `accelAxis` and `brakeAxis` which would normally be used by +the wheel defined under `deviceName`. The quickest way to access it is to press +Win+R, then type in `joy.cpl` and look at the list it will display. + ### `shifterName` Default ` ` diff --git a/idacio/config.c b/idacio/config.c index 968124b..f6ed605 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -24,6 +24,14 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename) _countof(cfg->device_name), filename); + GetPrivateProfileStringW( + L"dinput", + L"pedalsName", + L"", + cfg->pedals_name, + _countof(cfg->pedals_name), + filename); + GetPrivateProfileStringW( L"dinput", L"shifterName", diff --git a/idacio/config.h b/idacio/config.h index 8f6517a..ec91ce6 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -10,6 +10,7 @@ struct idac_shifter_config { struct idac_di_config { wchar_t device_name[64]; + wchar_t pedals_name[64]; wchar_t shifter_name[64]; wchar_t brake_axis[16]; wchar_t accel_axis[16]; diff --git a/idacio/di.c b/idacio/di.c index 1edaf9b..75e2c50 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -26,6 +26,9 @@ static const struct idac_di_axis *idac_di_get_axis(const wchar_t *name); static BOOL CALLBACK idac_di_enum_callback( const DIDEVICEINSTANCEW *dev, void *ctx); +static BOOL CALLBACK idac_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx); static BOOL CALLBACK idac_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx); @@ -57,6 +60,7 @@ static const struct idac_io_backend idac_di_backend = { static HWND idac_di_wnd; static IDirectInput8W *idac_di_api; static IDirectInputDevice8W *idac_di_dev; +static IDirectInputDevice8W *idac_di_pedals; static IDirectInputDevice8W *idac_di_shifter; static IDirectInputEffect *idac_di_fx; static size_t idac_di_off_brake; @@ -68,6 +72,7 @@ static uint8_t idac_di_start; static uint8_t idac_di_left; static uint8_t idac_di_right; static uint8_t idac_di_gear[6]; +static bool idac_di_use_pedals; static bool idac_di_reverse_brake_axis; static bool idac_di_reverse_accel_axis; @@ -170,6 +175,37 @@ HRESULT idac_di_init( idac_di_dev_start_fx(idac_di_dev, &idac_di_fx); + if (cfg->pedals_name[0] != L'\0') { + hr = IDirectInput8_EnumDevices( + idac_di_api, + DI8DEVCLASS_GAMECTRL, + idac_di_enum_callback_pedals, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (idac_di_dev == NULL) { + dprintf("Pedals: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = idac_di_dev_start(idac_di_pedals, idac_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + idac_di_use_pedals = true; + } else { + idac_di_use_pedals = false; + } + if (cfg->shifter_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( idac_di_api, @@ -276,8 +312,10 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); - dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); + if (cfg->pedals_name[0] == L'\0') { + dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); + } dprintf("Wheel: Start button . . . : %i\n", cfg->start); dprintf("Wheel: View Change button : %i\n", cfg->view_chg); dprintf("Wheel: Left button . . . . : %i\n", cfg->left); @@ -288,6 +326,15 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) dprintf("Wheel: Reverse Accel Axis : %i\n", cfg->reverse_accel_axis); dprintf("Wheel: --- End configuration ---\n"); + if (cfg->pedals_name[0] != L'\0') { + dprintf("Pedals: --- Begin configuration ---\n"); + dprintf("Pedals: Device name . . . : Contains \"%S\"\n", + cfg->pedals_name); + dprintf("Pedals: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Pedals: Accel axis . . . . : %S\n", accel_axis->name); + dprintf("Pedals: --- End configuration ---\n"); + } + if (cfg->shifter_name[0] != L'\0') { dprintf("Shifter: --- Begin configuration ---\n"); dprintf("Shifter: Device name . . . : Contains \"%S\"\n", @@ -364,6 +411,34 @@ static BOOL CALLBACK idac_di_enum_callback( return DIENUM_STOP; } +static BOOL CALLBACK idac_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct idac_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->pedals_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Pedals: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + idac_di_api, + &dev->guidInstance, + &idac_di_pedals, + NULL); + + if (FAILED(hr)) { + dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + static BOOL CALLBACK idac_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx) @@ -518,6 +593,7 @@ static void idac_di_get_shifter_virt(uint8_t *gear) static void idac_di_get_analogs(struct idac_io_analog_state *out) { union idac_di_state state; + union idac_di_state pedals_state; const LONG *brake; const LONG *accel; HRESULT hr; @@ -530,8 +606,19 @@ static void idac_di_get_analogs(struct idac_io_analog_state *out) return; } - brake = (LONG *) &state.bytes[idac_di_off_brake]; - accel = (LONG *) &state.bytes[idac_di_off_accel]; + if (idac_di_use_pedals) { + hr = idac_di_dev_poll(idac_di_pedals, idac_di_wnd, &pedals_state); + + if (FAILED(hr)) { + return; + } + + brake = (LONG *) &pedals_state.bytes[idac_di_off_brake]; + accel = (LONG *) &pedals_state.bytes[idac_di_off_accel]; + } else { + brake = (LONG *) &state.bytes[idac_di_off_brake]; + accel = (LONG *) &state.bytes[idac_di_off_accel]; + } out->wheel = state.st.lX - 32768; diff --git a/idacio/xi.c b/idacio/xi.c index b83aa9d..3b912fc 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -30,6 +30,11 @@ static bool idac_xi_linear_steering; static uint16_t idac_xi_left_stick_deadzone; static uint16_t idac_xi_right_stick_deadzone; +const uint16_t max_stick_value = 32767; +/* Apply steering wheel restriction. Real cabs only report about 76% of + the output value when the wheel is turned to either of its maximum positions. */ +const uint16_t max_wheel_value = 24831; + HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_backend **backend) { HRESULT hr; assert(cfg != NULL); @@ -143,29 +148,39 @@ static void idac_xi_get_shifter(uint8_t *gear) { *gear = idac_shifter_current_gear(); } -static int apply_non_linear_transform(int value, int deadzone_center) { - const int max_input = 32767; - const double power_factor = 3.0; +static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) { + // determine how far the controller is pushed + float magnitude = sqrt(axis*axis); - // Apply deadzone only after passing the center threshold - if (abs(value) < deadzone_center) { - return 0; + // determine the direction the controller is pushed + float norm_axis = axis / magnitude; + + float norm_magnitude = 0.0; + + // check if the controller is outside a circular dead zone + if (magnitude > deadzone) + { + // clip the magnitude at its expected maximum value + if (magnitude > max_stick_value) magnitude = max_stick_value; + + // adjust magnitude relative to the end of the dead zone + magnitude -= deadzone; + + // optionally normalize the magnitude with respect to its expected range + // giving a magnitude value of 0.0 to 1.0 + norm_magnitude = magnitude / (max_stick_value - deadzone); + } else // if the controller is in the deadzone zero out the magnitude + { + magnitude = 0.0; + norm_magnitude = 0.0; } - // Scale the value to the range [-1.0, 1.0] - double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + // apply non-linear transform to the axis + if (!linear_steering) { + return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + } - // Apply a non-linear transform (cubing in this case) and preserve the sign - double signed_value = copysign(pow(scaled_value, power_factor), value); - - // Scale the value back to the range [-32770, 32767] - int transformed_value = (int)(signed_value * max_input); - - // Clamp the value to the range [-32767, 32767] - transformed_value = (transformed_value > max_input) ? max_input : transformed_value; - transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; - - return transformed_value; + return norm_axis * norm_magnitude * max_wheel_value; } static void idac_xi_get_analogs(struct idac_io_analog_state *out) { @@ -181,27 +196,9 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) { left = xi.Gamepad.sThumbLX; right = xi.Gamepad.sThumbRX; - if (!idac_xi_linear_steering) { - // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, idac_xi_left_stick_deadzone); - right = apply_non_linear_transform(right, idac_xi_right_stick_deadzone); - } else { - if (left < -idac_xi_left_stick_deadzone) { - left += idac_xi_left_stick_deadzone; - } else if (left > idac_xi_left_stick_deadzone) { - left -= idac_xi_left_stick_deadzone; - } else { - left = 0; - } - - if (right < -idac_xi_right_stick_deadzone) { - right += idac_xi_right_stick_deadzone; - } else if (right > idac_xi_right_stick_deadzone) { - right -= idac_xi_right_stick_deadzone; - } else { - right = 0; - } - } + // normalize the steering axis + left = calculate_norm_steering(left, idac_xi_left_stick_deadzone, idac_xi_linear_steering); + right = calculate_norm_steering(right, idac_xi_right_stick_deadzone, idac_xi_linear_steering); if (idac_xi_single_stick_steering) { out->wheel = left; diff --git a/idzio/config.c b/idzio/config.c index ceea591..25b188d 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -24,6 +24,14 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename) _countof(cfg->device_name), filename); + GetPrivateProfileStringW( + L"dinput", + L"pedalsName", + L"", + cfg->pedals_name, + _countof(cfg->pedals_name), + filename); + GetPrivateProfileStringW( L"dinput", L"shifterName", @@ -79,7 +87,7 @@ void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) cfg->single_stick_steering = GetPrivateProfileIntW( L"xinput", L"singleStickSteering", - 0, + 1, filename); cfg->linear_steering = GetPrivateProfileIntW( diff --git a/idzio/config.h b/idzio/config.h index 24934ca..6b4cd20 100644 --- a/idzio/config.h +++ b/idzio/config.h @@ -11,6 +11,7 @@ struct idz_shifter_config { struct idz_di_config { wchar_t device_name[64]; wchar_t shifter_name[64]; + wchar_t pedals_name[64]; wchar_t brake_axis[16]; wchar_t accel_axis[16]; uint8_t start; diff --git a/idzio/di.c b/idzio/di.c index c16be14..5d0a454 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -26,6 +26,9 @@ static const struct idz_di_axis *idz_di_get_axis(const wchar_t *name); static BOOL CALLBACK idz_di_enum_callback( const DIDEVICEINSTANCEW *dev, void *ctx); +static BOOL CALLBACK idz_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx); static BOOL CALLBACK idz_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx); @@ -57,6 +60,7 @@ static const struct idz_io_backend idz_di_backend = { static HWND idz_di_wnd; static IDirectInput8W *idz_di_api; static IDirectInputDevice8W *idz_di_dev; +static IDirectInputDevice8W *idz_di_pedals; static IDirectInputDevice8W *idz_di_shifter; static IDirectInputEffect *idz_di_fx; static size_t idz_di_off_brake; @@ -66,6 +70,7 @@ static uint8_t idz_di_shift_up; static uint8_t idz_di_view_chg; static uint8_t idz_di_start; static uint8_t idz_di_gear[6]; +static bool idz_di_use_pedals; static bool idz_di_reverse_brake_axis; static bool idz_di_reverse_accel_axis; @@ -168,6 +173,37 @@ HRESULT idz_di_init( idz_di_dev_start_fx(idz_di_dev, &idz_di_fx); + if (cfg->pedals_name[0] != L'\0') { + hr = IDirectInput8_EnumDevices( + idz_di_api, + DI8DEVCLASS_GAMECTRL, + idz_di_enum_callback_pedals, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (idz_di_dev == NULL) { + dprintf("Pedals: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = idz_di_dev_start(idz_di_pedals, idz_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + idz_di_use_pedals = true; + } else { + idz_di_use_pedals = false; + } + if (cfg->shifter_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( idz_di_api, @@ -262,8 +298,10 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); - dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); + if (cfg->pedals_name[0] == L'\0') { + dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); + } dprintf("Wheel: Start button . . . : %i\n", cfg->start); dprintf("Wheel: View Change button : %i\n", cfg->view_chg); dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); @@ -272,6 +310,15 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) dprintf("Wheel: Reverse Accel Axis : %i\n", cfg->reverse_accel_axis); dprintf("Wheel: --- End configuration ---\n"); + if (cfg->pedals_name[0] != L'\0') { + dprintf("Pedals: --- Begin configuration ---\n"); + dprintf("Pedals: Device name . . . : Contains \"%S\"\n", + cfg->pedals_name); + dprintf("Pedals: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Pedals: Accel axis . . . . : %S\n", accel_axis->name); + dprintf("Pedals: --- End configuration ---\n"); + } + if (cfg->shifter_name[0] != L'\0') { dprintf("Shifter: --- Begin configuration ---\n"); dprintf("Shifter: Device name . . . : Contains \"%S\"\n", @@ -346,6 +393,34 @@ static BOOL CALLBACK idz_di_enum_callback( return DIENUM_STOP; } +static BOOL CALLBACK idz_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct idz_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->pedals_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Pedals: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + idz_di_api, + &dev->guidInstance, + &idz_di_pedals, + NULL); + + if (FAILED(hr)) { + dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + static BOOL CALLBACK idz_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx) @@ -492,6 +567,7 @@ static void idz_di_jvs_read_shifter_virt(uint8_t *gear) static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out) { union idz_di_state state; + union idz_di_state pedals_state; const LONG *brake; const LONG *accel; HRESULT hr; @@ -504,8 +580,19 @@ static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out) return; } - brake = (LONG *) &state.bytes[idz_di_off_brake]; - accel = (LONG *) &state.bytes[idz_di_off_accel]; + if (idz_di_use_pedals) { + hr = idz_di_dev_poll(idz_di_pedals, idz_di_wnd, &pedals_state); + + if (FAILED(hr)) { + return; + } + + brake = (LONG *) &pedals_state.bytes[idz_di_off_brake]; + accel = (LONG *) &pedals_state.bytes[idz_di_off_accel]; + } else { + brake = (LONG *) &state.bytes[idz_di_off_brake]; + accel = (LONG *) &state.bytes[idz_di_off_accel]; + } out->wheel = state.st.lX - 32768; diff --git a/idzio/xi.c b/idzio/xi.c index 413fa56..4a8391d 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -31,6 +31,11 @@ static bool idz_xi_linear_steering; static uint16_t idz_xi_left_stick_deadzone; static uint16_t idz_xi_right_stick_deadzone; +const uint16_t max_stick_value = 32767; +/* Apply steering wheel restriction. Real cabs only report about 76% of + the output value when the wheel is turned to either of its maximum positions. */ +const uint16_t max_wheel_value = 24831; + HRESULT idz_xi_init(const struct idz_xi_config *cfg, const struct idz_io_backend **backend) { HRESULT hr; @@ -143,29 +148,39 @@ static void idz_xi_jvs_read_shifter(uint8_t *gear) *gear = idz_shifter_current_gear(); } -static int apply_non_linear_transform(int value, int deadzone_center) { - const int max_input = 32767; - const double power_factor = 3.0; +static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) { + // determine how far the controller is pushed + float magnitude = sqrt(axis*axis); - // Apply deadzone only after passing the center threshold - if (abs(value) < deadzone_center) { - return 0; + // determine the direction the controller is pushed + float norm_axis = axis / magnitude; + + float norm_magnitude = 0.0; + + // check if the controller is outside a circular dead zone + if (magnitude > deadzone) + { + // clip the magnitude at its expected maximum value + if (magnitude > max_stick_value) magnitude = max_stick_value; + + // adjust magnitude relative to the end of the dead zone + magnitude -= deadzone; + + // optionally normalize the magnitude with respect to its expected range + // giving a magnitude value of 0.0 to 1.0 + norm_magnitude = magnitude / (max_stick_value - deadzone); + } else // if the controller is in the deadzone zero out the magnitude + { + magnitude = 0.0; + norm_magnitude = 0.0; } - // Scale the value to the range [-1.0, 1.0] - double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + // apply non-linear transform to the axis + if (!linear_steering) { + return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + } - // Apply a non-linear transform (cubing in this case) and preserve the sign - double signed_value = copysign(pow(scaled_value, power_factor), value); - - // Scale the value back to the range [-32770, 32767] - int transformed_value = (int)(signed_value * max_input); - - // Clamp the value to the range [-32767, 32767] - transformed_value = (transformed_value > max_input) ? max_input : transformed_value; - transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; - - return transformed_value; + return norm_axis * norm_magnitude * max_wheel_value; } static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) @@ -182,27 +197,9 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) left = xi.Gamepad.sThumbLX; right = xi.Gamepad.sThumbRX; - if (!idz_xi_linear_steering) { - // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, idz_xi_left_stick_deadzone); - right = apply_non_linear_transform(right, idz_xi_right_stick_deadzone); - } else { - if (left < -idz_xi_left_stick_deadzone) { - left += idz_xi_left_stick_deadzone; - } else if (left > idz_xi_left_stick_deadzone) { - left -= idz_xi_left_stick_deadzone; - } else { - left = 0; - } - - if (right < -idz_xi_right_stick_deadzone) { - right += idz_xi_right_stick_deadzone; - } else if (right > idz_xi_right_stick_deadzone) { - right -= idz_xi_right_stick_deadzone; - } else { - right = 0; - } - } + // normalize the steering axis + left = calculate_norm_steering(left, idz_xi_left_stick_deadzone, idz_xi_linear_steering); + right = calculate_norm_steering(right, idz_xi_right_stick_deadzone, idz_xi_linear_steering); if(idz_xi_single_stick_steering) { out->wheel = left; diff --git a/swdcio/config.c b/swdcio/config.c index 6fdd659..0dce00e 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -24,6 +24,14 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename) _countof(cfg->device_name), filename); + GetPrivateProfileStringW( + L"dinput", + L"pedalsName", + L"", + cfg->pedals_name, + _countof(cfg->pedals_name), + filename); + GetPrivateProfileStringW( L"dinput", L"brakeAxis", diff --git a/swdcio/config.h b/swdcio/config.h index c878d58..d6f9667 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -6,6 +6,7 @@ struct swdc_di_config { wchar_t device_name[64]; + wchar_t pedals_name[64]; wchar_t brake_axis[16]; wchar_t accel_axis[16]; uint8_t start; diff --git a/swdcio/di.c b/swdcio/di.c index 2fc7bc1..35c6463 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -25,6 +25,9 @@ static const struct swdc_di_axis *swdc_di_get_axis(const wchar_t *name); static BOOL CALLBACK swdc_di_enum_callback( const DIDEVICEINSTANCEW *dev, void *ctx); +static BOOL CALLBACK swdc_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx); static BOOL CALLBACK swdc_di_enum_callback_shifter( const DIDEVICEINSTANCEW *dev, void *ctx); @@ -52,6 +55,7 @@ static const struct swdc_io_backend swdc_di_backend = { static HWND swdc_di_wnd; static IDirectInput8W *swdc_di_api; static IDirectInputDevice8W *swdc_di_dev; +static IDirectInputDevice8W *swdc_di_pedals; static IDirectInputEffect *swdc_di_fx; static size_t swdc_di_off_brake; static size_t swdc_di_off_accel; @@ -63,6 +67,7 @@ static uint8_t swdc_di_wheel_green; static uint8_t swdc_di_wheel_red; static uint8_t swdc_di_wheel_blue; static uint8_t swdc_di_wheel_yellow; +static bool swdc_di_use_pedals; static bool swdc_di_reverse_brake_axis; static bool swdc_di_reverse_accel_axis; @@ -165,6 +170,37 @@ HRESULT swdc_di_init( swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx); + if (cfg->pedals_name[0] != L'\0') { + hr = IDirectInput8_EnumDevices( + swdc_di_api, + DI8DEVCLASS_GAMECTRL, + swdc_di_enum_callback_pedals, + (void *) cfg, + DIEDFL_ATTACHEDONLY); + + if (FAILED(hr)) { + dprintf("DirectInput: EnumDevices failed: %08x\n", (int) hr); + + return hr; + } + + if (swdc_di_dev == NULL) { + dprintf("Pedals: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + hr = swdc_di_dev_start(swdc_di_pedals, swdc_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + swdc_di_use_pedals = true; + } else { + swdc_di_use_pedals = false; + } + dprintf("DirectInput: Controller initialized\n"); *backend = &swdc_di_backend; @@ -246,8 +282,10 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) dprintf("Wheel: --- Begin configuration ---\n"); dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", cfg->device_name); - dprintf("Wheel: Brake axis . . . . . . : %S\n", brake_axis->name); - dprintf("Wheel: Accel axis . . . . . . : %S\n", accel_axis->name); + if (cfg->pedals_name[0] == L'\0') { + dprintf("Wheel: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Wheel: Accel axis . . . . : %S\n", accel_axis->name); + } dprintf("Wheel: Start button . . . . . : %i\n", cfg->start); dprintf("Wheel: View Change button . . : %i\n", cfg->view_chg); dprintf("Wheel: Paddle Left button . . : %i\n", cfg->paddle_left); @@ -260,6 +298,15 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) dprintf("Wheel: Reverse Accel Axis . . : %i\n", cfg->reverse_accel_axis); dprintf("Wheel: --- End configuration ---\n"); + if (cfg->pedals_name[0] != L'\0') { + dprintf("Pedals: --- Begin configuration ---\n"); + dprintf("Pedals: Device name . . . : Contains \"%S\"\n", + cfg->pedals_name); + dprintf("Pedals: Brake axis . . . . : %S\n", brake_axis->name); + dprintf("Pedals: Accel axis . . . . : %S\n", accel_axis->name); + dprintf("Pedals: --- End configuration ---\n"); + } + swdc_di_off_brake = brake_axis->off; swdc_di_off_accel = accel_axis->off; swdc_di_start = cfg->start; @@ -320,6 +367,34 @@ static BOOL CALLBACK swdc_di_enum_callback( return DIENUM_STOP; } +static BOOL CALLBACK swdc_di_enum_callback_pedals( + const DIDEVICEINSTANCEW *dev, + void *ctx) +{ + const struct swdc_di_config *cfg; + HRESULT hr; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->pedals_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Pedals: Using DirectInput device \"%S\"\n", dev->tszProductName); + + hr = IDirectInput8_CreateDevice( + swdc_di_api, + &dev->guidInstance, + &swdc_di_pedals, + NULL); + + if (FAILED(hr)) { + dprintf("Pedals: CreateDevice failed: %08x\n", (int) hr); + } + + return DIENUM_STOP; +} + static void swdc_di_get_buttons(uint16_t *gamebtn_out) { union swdc_di_state state; @@ -389,6 +464,7 @@ static uint8_t swdc_di_decode_pov(DWORD pov) static void swdc_di_get_analogs(struct swdc_io_analog_state *out) { union swdc_di_state state; + union swdc_di_state pedals_state; const LONG *brake; const LONG *accel; HRESULT hr; @@ -401,8 +477,19 @@ static void swdc_di_get_analogs(struct swdc_io_analog_state *out) return; } - brake = (LONG *) &state.bytes[swdc_di_off_brake]; - accel = (LONG *) &state.bytes[swdc_di_off_accel]; + if (swdc_di_use_pedals) { + hr = swdc_di_dev_poll(swdc_di_pedals, swdc_di_wnd, &pedals_state); + + if (FAILED(hr)) { + return; + } + + brake = (LONG *) &pedals_state.bytes[swdc_di_off_brake]; + accel = (LONG *) &pedals_state.bytes[swdc_di_off_accel]; + } else { + brake = (LONG *) &state.bytes[swdc_di_off_brake]; + accel = (LONG *) &state.bytes[swdc_di_off_accel]; + } out->wheel = state.st.lX - 32768; diff --git a/swdcio/xi.c b/swdcio/xi.c index 3067d3f..eb59ce6 100644 --- a/swdcio/xi.c +++ b/swdcio/xi.c @@ -28,6 +28,11 @@ static bool swdc_xi_linear_steering; static uint16_t swdc_xi_left_stick_deadzone; static uint16_t swdc_xi_right_stick_deadzone; +const uint16_t max_stick_value = 32767; +/* Apply steering wheel restriction. Real cabs only report about 76% of + the output value when the wheel is turned to either of its maximum positions. */ +const uint16_t max_wheel_value = 24831; + HRESULT swdc_xi_init(const struct swdc_xi_config *cfg, const struct swdc_io_backend **backend) { HRESULT hr; @@ -143,29 +148,39 @@ static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out) *gamebtn_out = gamebtn; } -static int apply_non_linear_transform(int value, int deadzone_center) { - const int max_input = 32767; - const double power_factor = 3.0; +static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool linear_steering) { + // determine how far the controller is pushed + float magnitude = sqrt(axis*axis); - // Apply deadzone only after passing the center threshold - if (abs(value) < deadzone_center) { - return 0; + // determine the direction the controller is pushed + float norm_axis = axis / magnitude; + + float norm_magnitude = 0.0; + + // check if the controller is outside a circular dead zone + if (magnitude > deadzone) + { + // clip the magnitude at its expected maximum value + if (magnitude > max_stick_value) magnitude = max_stick_value; + + // adjust magnitude relative to the end of the dead zone + magnitude -= deadzone; + + // optionally normalize the magnitude with respect to its expected range + // giving a magnitude value of 0.0 to 1.0 + norm_magnitude = magnitude / (max_stick_value - deadzone); + } else // if the controller is in the deadzone zero out the magnitude + { + magnitude = 0.0; + norm_magnitude = 0.0; } - // Scale the value to the range [-1.0, 1.0] - double scaled_value = (abs(value) - deadzone_center) / (double)(max_input - deadzone_center); + // apply non-linear transform to the axis + if (!linear_steering) { + return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + } - // Apply a non-linear transform (cubing in this case) and preserve the sign - double signed_value = copysign(pow(scaled_value, power_factor), value); - - // Scale the value back to the range [-32770, 32767] - int transformed_value = (int)(signed_value * max_input); - - // Clamp the value to the range [-32767, 32767] - transformed_value = (transformed_value > max_input) ? max_input : transformed_value; - transformed_value = (transformed_value < -max_input) ? -max_input : transformed_value; - - return transformed_value; + return norm_axis * norm_magnitude * max_wheel_value; } static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) @@ -182,28 +197,10 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) left = xi.Gamepad.sThumbLX; right = xi.Gamepad.sThumbRX; - if (!swdc_xi_linear_steering) { - // Apply non-linear transform for both sticks - left = apply_non_linear_transform(left, swdc_xi_left_stick_deadzone); - right = apply_non_linear_transform(right, swdc_xi_right_stick_deadzone); - } else { - if (left < -swdc_xi_left_stick_deadzone) { - left += swdc_xi_left_stick_deadzone; - } else if (left > swdc_xi_left_stick_deadzone) { - left -= swdc_xi_left_stick_deadzone; - } else { - left = 0; - } - - if (right < -swdc_xi_right_stick_deadzone) { - right += swdc_xi_right_stick_deadzone; - } else if (right > swdc_xi_right_stick_deadzone) { - right -= swdc_xi_right_stick_deadzone; - } else { - right = 0; - } - } - + // normalize the steering axis + left = calculate_norm_steering(left, swdc_xi_left_stick_deadzone, swdc_xi_linear_steering); + right = calculate_norm_steering(right, swdc_xi_right_stick_deadzone, swdc_xi_linear_steering); + if (swdc_xi_single_stick_steering) { out->wheel = left; } else { From 25562e37f930d0e822c0991431dd2c4fa30bd969 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 2 Nov 2023 23:32:13 +0100 Subject: [PATCH 051/204] nusec: fixes keychip not found error 0949 --- board/io4.c | 2 +- platform/nusec.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/board/io4.c b/board/io4.c index cc0165c..912f733 100644 --- a/board/io4.c +++ b/board/io4.c @@ -233,7 +233,7 @@ static HRESULT io4_handle_write(struct irp *irp) return S_OK; case IO4_CMD_SET_UNIQUE_OUTPUT: - dprintf("USB I/O: Unique Out\n"); + // dprintf("USB I/O: Unique Out\n"); return S_OK; diff --git a/platform/nusec.c b/platform/nusec.c index cc1030b..6094408 100644 --- a/platform/nusec.c +++ b/platform/nusec.c @@ -16,6 +16,7 @@ enum { NUSEC_IOCTL_PING = 0x22A114, NUSEC_IOCTL_ERASE_TRACE_LOG = 0x22E188, + NUSEC_IOCTL_TD_ERASE_USED = 0x22E18C, NUSEC_IOCTL_ADD_PLAY_COUNT = 0x22E154, NUSEC_IOCTL_GET_BILLING_CA_CERT = 0x22E1C4, NUSEC_IOCTL_GET_BILLING_PUBKEY = 0x22E1C8, @@ -42,6 +43,7 @@ static HRESULT nusec_handle_ioctl(struct irp *irp); static HRESULT nusec_ioctl_ping(struct irp *irp); static HRESULT nusec_ioctl_erase_trace_log(struct irp *irp); +static HRESULT nusec_ioctl_td_erase_used(struct irp *irp); static HRESULT nusec_ioctl_add_play_count(struct irp *irp); static HRESULT nusec_ioctl_get_billing_ca_cert(struct irp *irp); static HRESULT nusec_ioctl_get_billing_pubkey(struct irp *irp); @@ -208,6 +210,9 @@ static HRESULT nusec_handle_ioctl(struct irp *irp) case NUSEC_IOCTL_ERASE_TRACE_LOG: return nusec_ioctl_erase_trace_log(irp); + + case NUSEC_IOCTL_TD_ERASE_USED: + return nusec_ioctl_td_erase_used(irp); case NUSEC_IOCTL_ADD_PLAY_COUNT: return nusec_ioctl_add_play_count(irp); @@ -288,6 +293,16 @@ static HRESULT nusec_ioctl_erase_trace_log(struct irp *irp) return S_OK; } +static HRESULT nusec_ioctl_td_erase_used(struct irp *irp) +{ + dprintf("Security: %s\n", __func__); + + nusec_log_head = 0; + nusec_log_tail = 0; + + return S_OK; +} + static HRESULT nusec_ioctl_add_play_count(struct irp *irp) { uint32_t delta; From 962e14dc9b3905fd9d2b4260119da8b989f84613 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Sun, 5 Nov 2023 21:51:36 -0500 Subject: [PATCH 052/204] ongeki: fix start.bat and segatools.ini --- dist/mu3/segatools.ini | 4 ++-- dist/mu3/start.bat | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 3279509..98cdb31 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -30,7 +30,7 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.250.0 +subnet=192.168.162.0 [gfx] enable=1 @@ -57,4 +57,4 @@ RIGHT_SIDE=0x55 SLIDER_LEFT=0x54 SLIDER_RIGHT=0x59 ;Change move speed of slider when use dinput -SLIDER_SPEED=1000 \ No newline at end of file +SLIDER_SPEED=1000 diff --git a/dist/mu3/start.bat b/dist/mu3/start.bat index c00f2ea..3aceffb 100644 --- a/dist/mu3/start.bat +++ b/dist/mu3/start.bat @@ -3,12 +3,8 @@ pushd %~dp0 taskkill /f /im amdaemon.exe > nul 2>&1 -REM USA -REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json - -REM JP -start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json -inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe +start inject -d -k mu3hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json +inject -d -k mu3hook.dll mu3.exe taskkill /f /im amdaemon.exe > nul 2>&1 From 946ea7ef3bc6058b704e8b66e9493b8bd5e371bf Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sat, 11 Nov 2023 22:41:04 +0100 Subject: [PATCH 053/204] chusan: fixed LED configs --- chunihook/led1509306.h | 1 - chusanhook/config.h | 2 +- chusanhook/dllmain.c | 2 +- chusanhook/led1509306.c | 4 ++-- chusanhook/led1509306.h | 1 + 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chunihook/led1509306.h b/chunihook/led1509306.h index 03dc62a..15c7c3e 100644 --- a/chunihook/led1509306.h +++ b/chunihook/led1509306.h @@ -6,7 +6,6 @@ struct led1509306_config { bool enable; - bool cvt_port; char board_number[8]; char chip_number[5]; uint8_t fw_ver; diff --git a/chusanhook/config.h b/chusanhook/config.h index e98059e..856112b 100644 --- a/chusanhook/config.h +++ b/chusanhook/config.h @@ -12,7 +12,7 @@ #include "chusanhook/chuni-dll.h" #include "chusanhook/slider.h" -#include "chunihook/led1509306.h" +#include "chusanhook/led1509306.h" struct chusan_hook_config { struct platform_config platform; diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 28aa8e3..4b23983 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -11,7 +11,7 @@ #include "chusanhook/config.h" #include "chusanhook/io4.h" #include "chusanhook/slider.h" -#include "chunihook/led1509306.h" +#include "chusanhook/led1509306.h" #include "chuniio/chuniio.h" diff --git a/chusanhook/led1509306.c b/chusanhook/led1509306.c index 6863fa1..c657c84 100644 --- a/chusanhook/led1509306.c +++ b/chusanhook/led1509306.c @@ -9,7 +9,7 @@ #include "board/led1509306-cmd.h" #include "board/led1509306-frame.h" -#include "chunihook/led1509306.h" +#include "chusanhook/led1509306.h" #include "hook/iobuf.h" #include "hook/iohook.h" @@ -71,7 +71,7 @@ HRESULT led1509306_hook_init(const struct led1509306_config *cfg) com_ports[0] = 20; com_ports[1] = 21; } else { - // CVT mode: COM3, COM23 + // CVT mode: COM2, COM3 com_ports[0] = 2; com_ports[1] = 3; } diff --git a/chusanhook/led1509306.h b/chusanhook/led1509306.h index 15c7c3e..03dc62a 100644 --- a/chusanhook/led1509306.h +++ b/chusanhook/led1509306.h @@ -6,6 +6,7 @@ struct led1509306_config { bool enable; + bool cvt_port; char board_number[8]; char chip_number[5]; uint8_t fw_ver; From a2db39c58c9596d4ee49d8f5996242371b033cc6 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sat, 11 Nov 2023 22:47:47 +0100 Subject: [PATCH 054/204] fgo: fgohook finally added Credits: - Coburn - domeori - Mitsuhide - OLEG - rakisaionji --- Package.mk | 16 + dist/fgo/config_hook.json | 12 + dist/fgo/segatools.ini | 84 ++ dist/fgo/start.bat | 11 + fgohook/config.c | 94 ++ fgohook/config.h | 37 + fgohook/deck.c | 511 ++++++++ fgohook/deck.h | 11 + fgohook/dllmain.c | 144 +++ fgohook/fgo-dll.c | 112 ++ fgohook/fgo-dll.h | 22 + fgohook/fgohook.def | 82 ++ fgohook/ftdi.c | 55 + fgohook/ftdi.h | 20 + fgohook/io4.c | 104 ++ fgohook/io4.h | 7 + fgohook/led1509306.c | 379 ++++++ fgohook/led1509306.h | 16 + fgohook/meson.build | 36 + fgoio/config.c | 20 + fgoio/config.h | 16 + fgoio/fgoio.c | 141 +++ fgoio/fgoio.h | 71 ++ fgoio/meson.build | 16 + hooklib/config.c | 59 + hooklib/config.h | 2 + hooklib/meson.build | 2 + hooklib/printer.c | 2380 +++++++++++++++++++++++++++++++++++++ hooklib/printer.h | 16 + meson.build | 2 + 30 files changed, 4478 insertions(+) create mode 100644 dist/fgo/config_hook.json create mode 100644 dist/fgo/segatools.ini create mode 100644 dist/fgo/start.bat create mode 100644 fgohook/config.c create mode 100644 fgohook/config.h create mode 100644 fgohook/deck.c create mode 100644 fgohook/deck.h create mode 100644 fgohook/dllmain.c create mode 100644 fgohook/fgo-dll.c create mode 100644 fgohook/fgo-dll.h create mode 100644 fgohook/fgohook.def create mode 100644 fgohook/ftdi.c create mode 100644 fgohook/ftdi.h create mode 100644 fgohook/io4.c create mode 100644 fgohook/io4.h create mode 100644 fgohook/led1509306.c create mode 100644 fgohook/led1509306.h create mode 100644 fgohook/meson.build create mode 100644 fgoio/config.c create mode 100644 fgoio/config.h create mode 100644 fgoio/fgoio.c create mode 100644 fgoio/fgoio.h create mode 100644 fgoio/meson.build create mode 100644 hooklib/printer.c create mode 100644 hooklib/printer.h diff --git a/Package.mk b/Package.mk index 69cdbc1..6ccc6d0 100644 --- a/Package.mk +++ b/Package.mk @@ -73,6 +73,22 @@ $(BUILD_DIR_ZIP)/idz.zip: $(V)strip $(BUILD_DIR_ZIP)/idz/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/idz ; zip -r ../idz.zip * +$(BUILD_DIR_ZIP)/fgo.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo + $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/fgohook/fgohook.dll \ + $(DIST_DIR)/fgo/config_hook.json \ + $(DIST_DIR)/fgo/segatools.ini \ + $(DIST_DIR)/fgo/start.bat \ + $(BUILD_DIR_ZIP)/fgo + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/fgo/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/fgo/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/fgo ; zip -r ../fgo.zip * + $(BUILD_DIR_ZIP)/idac.zip: $(V)echo ... $@ $(V)mkdir -p $(BUILD_DIR_ZIP)/idac diff --git a/dist/fgo/config_hook.json b/dist/fgo/config_hook.json new file mode 100644 index 0000000..cc1ab5d --- /dev/null +++ b/dist/fgo/config_hook.json @@ -0,0 +1,12 @@ +{ + "aime" : + { + "firmware_path" : + [ + "am\\aime_firm\\update_15396_6728_94.bin", + "am\\aime_firm\\TN32MSEC003S_V12.hex", + "am\\aime_firm\\837-15286-P_LPC1112_NFC_RW_LED_BD_0x92.bin" + ], + "high_baudrate" : true + } +} diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini new file mode 100644 index 0000000..67c0f91 --- /dev/null +++ b/dist/fgo/segatools.ini @@ -0,0 +1,84 @@ +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.172.0 + +[touch] +; WinTouch emulation setting. +enable=1 +remap=1 +cursor=1 + +[printer] +; Sinfonia CHC-C330 printer emulation setting. +enable=1 +; Change the printer serial number here. +serial_no="5A-A123" +; Insert the path to the image output directory here. +printerOutPath="DEVICE\print" +; Rotate all printed images by 180 degrees. +rotate180=1 + +[deckReader] +; 837-15345 RFID deck reader emulation setting. +enable=1 + +[ledstrip] +; 837-15093-06 LED strip emulation setting. +enable=1 +; FTDI board currently not working properly. Use com0com (Create a virtual pair +; for 21 and 51) or use any USB to Serial Adapter. +port=21 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io4] +; Input API selection for JVS input emulator. +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 diff --git a/dist/fgo/start.bat b/dist/fgo/start.bat new file mode 100644 index 0000000..3be4f8a --- /dev/null +++ b/dist/fgo/start.bat @@ -0,0 +1,11 @@ +@echo off + +cd /d %~dp0 + +inject -d -k fgohook.dll ago.exe + +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/fgohook/config.c b/fgohook/config.c new file mode 100644 index 0000000..d6971ac --- /dev/null +++ b/fgohook/config.c @@ -0,0 +1,94 @@ +#include +#include + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "fgohook/config.h" + +#include "platform/config.h" + +void fgo_dll_config_load( + struct fgo_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"fgoio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename); +} + +void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 21, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); + + GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710A", tmpstr, _countof(tmpstr), filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } +} + +void fgo_deck_config_load( + struct deck_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"deck", L"enable", 1, filename); +} + +void fgo_hook_config_load( + struct fgo_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + touch_screen_config_load(&cfg->touch, filename); + printer_config_load(&cfg->printer, filename); + fgo_deck_config_load(&cfg->deck, filename); + ftdi_config_load(&cfg->ftdi, filename); + led1509306_config_load(&cfg->led1509306, filename); + fgo_dll_config_load(&cfg->dll, filename); +} diff --git a/fgohook/config.h b/fgohook/config.h new file mode 100644 index 0000000..a2cad3b --- /dev/null +++ b/fgohook/config.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" +#include "hooklib/printer.h" + +#include "fgohook/deck.h" +#include "fgohook/ftdi.h" +#include "fgohook/led1509306.h" +#include "fgohook/fgo-dll.h" + +#include "platform/config.h" + +struct fgo_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct touch_screen_config touch; + struct printer_config printer; + struct deck_config deck; + struct ftdi_config ftdi; + struct led1509306_config led1509306; + struct fgo_dll_config dll; +}; + +void fgo_dll_config_load( + struct fgo_dll_config *cfg, + const wchar_t *filename); + +void fgo_hook_config_load( + struct fgo_hook_config *cfg, + const wchar_t *filename); diff --git a/fgohook/deck.c b/fgohook/deck.c new file mode 100644 index 0000000..e712724 --- /dev/null +++ b/fgohook/deck.c @@ -0,0 +1,511 @@ +/* + SEGA 837-15345 RFID Deck Reader emulator + + Credits: + + OLEG + Coburn + Mitsuhide +*/ + +#include + +#include + +#include "board/sg-frame.h" + +#include "fgohook/deck.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +#define MAX_CARDS 30 + +// request format: +// 0xe0 - sync +// 0x?? - command +// 0x?? - payload length +// ... - payload +// 0x?? - checksum (sum of everything except the sync byte) +// +// response format: +// 0xe0 - sync +// 0x?? - command +// 0x?? - status code +// 0x?? - payload length +// ... - payload +// 0x?? - checksum + +enum { + DECK_CMD_RESET = 0x41, + DECK_CMD_GET_BOOT_FW_VERSION = 0x84, + DECK_CMD_GET_BOARD_INFO = 0x85, + DECK_CMD_INIT_UNK1 = 0x81, + DECK_CMD_GET_APP_FW_VERSION = 0x42, + DECK_CMD_INIT_UNK2 = 0x04, + DECK_CMD_INIT_UNK3 = 0x05, + DECK_CMD_READ = 0x06 +}; + +enum { + DECK_READ_START = 0x81, + DECK_READ_DATA = 0x82, + DECK_READ_END = 0x83 +}; + +struct deck_hdr { + uint8_t sync; + uint8_t cmd; + uint8_t nbytes; +}; + +struct deck_resp_hdr { + uint8_t sync; + uint8_t cmd; + uint8_t status; + uint8_t nbytes; +}; + +struct deck_resp_get_boot_fw_version { + struct deck_resp_hdr hdr; + uint8_t boot_fw_version; +}; + +struct deck_resp_get_app_fw_version { + struct deck_resp_hdr hdr; + uint8_t app_fw_version; +}; + +struct deck_resp_get_board_info { + struct deck_resp_hdr hdr; + uint8_t board[9]; +}; + +struct deck_resp_read { + struct deck_resp_hdr hdr; + uint8_t card_data[44]; +}; + +union deck_req_any { + struct deck_hdr hdr; + uint8_t bytes[520]; +}; + +struct card_collection { + uint8_t nCards; + uint8_t cards[MAX_CARDS][44]; +}; + +static HRESULT init_mmf(void); + +static HRESULT deck_handle_irp(struct irp *irp); +static HRESULT deck_handle_irp_locked(struct irp *irp); +static HRESULT deck_req_dispatch(const union deck_req_any* req); +static HRESULT deck_req_get_boot_fw_version(void); +static HRESULT deck_req_get_app_fw_version(void); +static HRESULT deck_req_get_board_info(void); +static HRESULT deck_req_read(void); +static HRESULT deck_req_nop(uint8_t cmd); +static void deck_read_one(void); + +static HRESULT deck_frame_accept(const struct iobuf* dest); +static void deck_frame_sync(struct iobuf* src); +static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src); +static HRESULT deck_frame_encode(struct iobuf* dest, const void* ptr, size_t nbytes); +static HRESULT deck_frame_encode_byte(struct iobuf* dest, uint8_t byte); + +static CRITICAL_SECTION deck_lock; +static struct uart deck_uart; +static uint8_t deck_written_bytes[1024]; +static uint8_t deck_readable_bytes[1024]; +static HANDLE mutex; +static HANDLE mmf; +static struct card_collection* cards_ptr; +static uint8_t current_card_idx = 0; +static bool read_pending = false; + +HRESULT deck_hook_init(const struct deck_config *cfg, int port) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + InitializeCriticalSection(&deck_lock); + + uart_init(&deck_uart, port); + deck_uart.written.bytes = deck_written_bytes; + deck_uart.written.nbytes = sizeof(deck_written_bytes); + deck_uart.readable.bytes = deck_readable_bytes; + deck_uart.readable.nbytes = sizeof(deck_readable_bytes); + + if (FAILED(init_mmf())) { + return S_FALSE; + } + + dprintf("Deck Reader: hook enabled.\n"); + + return iohook_push_handler(deck_handle_irp); +} + +static HRESULT init_mmf(void) { + mutex = CreateMutexA(NULL, FALSE, "FGODeckMutex"); + if (mutex == NULL) { + return S_FALSE; + } + + mmf = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAX_CARDS * 44 + 1, "FGODeck"); + if (mmf == NULL) { + return S_FALSE; + } + + cards_ptr = (struct card_collection*)MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, MAX_CARDS * 44 + 1); + + return S_OK; +} + +static HRESULT deck_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + if (!uart_match_irp(&deck_uart, irp)) { + return iohook_invoke_next(irp); + } + + EnterCriticalSection(&deck_lock); + hr = deck_handle_irp_locked(irp); + LeaveCriticalSection(&deck_lock); + + return hr; +} + +static HRESULT deck_handle_irp_locked(struct irp *irp) +{ + uint8_t req[1024]; + struct iobuf req_iobuf; + HRESULT hr; + + if (irp->op == IRP_OP_OPEN) { + dprintf("Deck Reader: Starting backend\n"); + } + + hr = uart_handle_irp(&deck_uart, irp); + + if (SUCCEEDED(hr) && irp->op == IRP_OP_READ && read_pending == true) { + deck_read_one(); + return S_OK; + } + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { + // if (deck_uart.written.pos != 0) { + // dprintf("Deck Reader: TX Buffer:\n"); + // dump_iobuf(&deck_uart.written); + // } + + req_iobuf.bytes = req; + req_iobuf.nbytes = sizeof(req); + req_iobuf.pos = 0; + + hr = deck_frame_decode(&req_iobuf, &deck_uart.written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("Deck Reader: Deframe error: %x, %d %d\n", (int) hr, (int) req_iobuf.nbytes, (int) req_iobuf.pos); + } + + return hr; + } + + // dprintf("Deck Reader: Deframe Buffer:\n"); + // dump_iobuf(&req_iobuf); + + hr = deck_req_dispatch((const union deck_req_any *) &req); + + if (FAILED(hr)) { + dprintf("Deck Reader: Processing error: %x\n", (int) hr); + } + + // dprintf("Deck Reader: Written bytes:\n"); + // dump_iobuf(&deck_uart.readable); + } +} + +static HRESULT deck_req_dispatch(const union deck_req_any *req) { + switch (req->hdr.cmd) { + case DECK_CMD_RESET: + case DECK_CMD_INIT_UNK1: + case DECK_CMD_INIT_UNK2: + case DECK_CMD_INIT_UNK3: + return deck_req_nop(req->hdr.cmd); + + case DECK_CMD_GET_BOOT_FW_VERSION: + return deck_req_get_boot_fw_version(); + + case DECK_CMD_GET_APP_FW_VERSION: + return deck_req_get_app_fw_version(); + + case DECK_CMD_GET_BOARD_INFO: + return deck_req_get_board_info(); + + case DECK_CMD_READ: + return deck_req_read(); + + default: + dprintf("Deck Reader: Unhandled command %#02x\n", req->hdr.cmd); + + return S_OK; + } +} + +static HRESULT deck_req_get_boot_fw_version(void) { + struct deck_resp_get_boot_fw_version resp; + + dprintf("Deck Reader: Get Boot FW Version\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_BOOT_FW_VERSION; + resp.hdr.status = 0; + resp.hdr.nbytes = 1; + resp.boot_fw_version = 0x90; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_get_app_fw_version(void) { + struct deck_resp_get_app_fw_version resp; + + dprintf("Deck Reader: Get App FW Version\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_APP_FW_VERSION; + resp.hdr.status = 0; + resp.hdr.nbytes = 1; + resp.app_fw_version = 0x91; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_get_board_info(void) { + struct deck_resp_get_board_info resp; + + dprintf("Deck Reader: Get Board Info\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_BOARD_INFO; + resp.hdr.status = 0; + resp.hdr.nbytes = 9; + memcpy(resp.board, (void*)"837-15345", 9); + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_read(void) { + struct deck_resp_read resp; + + dprintf("Deck Reader: Read Card\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_READ; + resp.hdr.status = DECK_READ_START; + resp.hdr.nbytes = 0; + + ReleaseMutex(mutex); + WaitForSingleObject(mutex, INFINITE); + current_card_idx = 0; + read_pending = true; + + return deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); +} + +static void deck_read_one(void) { + struct deck_resp_read resp; + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_READ; + + if (current_card_idx < cards_ptr->nCards) { + resp.hdr.status = DECK_READ_DATA; + resp.hdr.nbytes = 44; + memcpy(resp.card_data, cards_ptr->cards[current_card_idx], 44); + dump(resp.card_data, 44); + + deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); + current_card_idx++; + } else { + resp.hdr.status = DECK_READ_END; + resp.hdr.nbytes = 0; + deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); + read_pending = false; + ReleaseMutex(mutex); + } +} + +static HRESULT deck_req_nop(uint8_t cmd) { + struct deck_resp_hdr resp; + + dprintf("Deck Reader: No-op cmd %#02x\n", cmd); + + resp.sync = 0xE0; + resp.cmd = cmd; + resp.status = 0; + resp.nbytes = 0; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + + +static void deck_frame_sync(struct iobuf* src) +{ + size_t i; + + for (i = 0; i < src->pos && src->bytes[i] != 0xE0; i++); + + src->pos -= i; + memmove(&src->bytes[0], &src->bytes[i], i); +} + +static HRESULT deck_frame_accept(const struct iobuf* dest) +{ + if (dest->pos < 2 || dest->pos != dest->bytes[2] + 4) { + return S_FALSE; + } + + return S_OK; +} + +static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src) { + uint8_t byte; + bool escape; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(src != NULL); + assert(src->bytes != NULL || src->nbytes == 0); + assert(src->pos <= src->nbytes); + + dest->pos = 0; + escape = false; + + for (i = 0, hr = S_FALSE; i < src->pos && hr == S_FALSE; i++) { + /* Step the FSM to unstuff another byte */ + + byte = src->bytes[i]; + + if (dest->pos >= dest->nbytes) { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + else if (i == 0) { + dest->bytes[dest->pos++] = byte; + } + else if (byte == 0xE0) { + hr = E_FAIL; + } + else if (byte == 0xD0) { + if (escape) { + hr = E_FAIL; + } + + escape = true; + } + else if (escape) { + dest->bytes[dest->pos++] = byte + 1; + escape = false; + } + else { + dest->bytes[dest->pos++] = byte; + } + + /* Try to accept the packet we've built up so far */ + + if (SUCCEEDED(hr)) { + hr = deck_frame_accept(dest); + } + } + + /* Handle FSM terminal state */ + + if (hr != S_FALSE) { + /* Frame was either accepted or rejected, remove it from src */ + memmove(&src->bytes[0], &src->bytes[i], src->pos - i); + src->pos -= i; + } + + return hr; +} + +static HRESULT deck_frame_encode( + struct iobuf* dest, + const void* ptr, + size_t nbytes) +{ + const uint8_t* src; + uint8_t checksum; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + assert(nbytes >= 2 && src[0] == 0xE0 && src[3] + 4 == nbytes); + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xE0; + checksum = 0x0; + + for (i = 1; i < nbytes; i++) { + byte = src[i]; + checksum += byte; + + hr = deck_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } + + return deck_frame_encode_byte(dest, checksum); +} + +static HRESULT deck_frame_encode_byte(struct iobuf* dest, uint8_t byte) +{ + if (byte == 0xD0 || byte == 0xE0) { + if (dest->pos + 2 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = byte - 1; + } + else { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + } + + return S_OK; +} diff --git a/fgohook/deck.h b/fgohook/deck.h new file mode 100644 index 0000000..32c1ef9 --- /dev/null +++ b/fgohook/deck.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +struct deck_config { + bool enable; +}; + +HRESULT deck_hook_init(const struct deck_config *cfg, int port); diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c new file mode 100644 index 0000000..69269b5 --- /dev/null +++ b/fgohook/dllmain.c @@ -0,0 +1,144 @@ +#include + +#include + +#include "board/io4.h" +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" +#include "hooklib/printer.h" +#include "hooklib/createprocess.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "fgohook/config.h" +#include "fgohook/io4.h" +#include "fgohook/fgo-dll.h" +#include "fgohook/deck.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE fgo_hook_mod; +static process_entry_t fgo_startup; +static struct fgo_hook_config fgo_hook_cfg; + +static DWORD CALLBACK fgo_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin fgo_pre_startup ---\n"); + + /* Load config */ + + fgo_hook_config_load(&fgo_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&fgo_hook_cfg.dvd, fgo_hook_mod); + touch_screen_hook_init(&fgo_hook_cfg.touch, fgo_hook_mod); + serial_hook_init(); + + /* Hook external DLL APIs */ + + printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &fgo_hook_cfg.platform, + "SDEJ", + "ACA1", + fgo_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&fgo_hook_cfg.aime, 3, fgo_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = vfd_hook_init(1); + + if (FAILED(hr)) { + goto fail; + } + + hr = fgo_dll_init(&fgo_hook_cfg.dll, fgo_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = fgo_io4_hook_init(&fgo_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + hr = deck_hook_init(&fgo_hook_cfg.deck, 2); + + if (FAILED(hr)) { + goto fail; + } + + /* + hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); + + if (FAILED(hr)) { + goto fail; + } + */ + + hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); + + if (FAILED(hr)) { + goto fail; + } + + hr = createprocess_push_hook_a("am/amdaemon.exe", "inject -d -k fgohook.dll ", " -c config_hook.json", false); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End fgo_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return fgo_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + fgo_hook_mod = mod; + + hr = process_hijack_startup(fgo_pre_startup, &fgo_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/fgohook/fgo-dll.c b/fgohook/fgo-dll.c new file mode 100644 index 0000000..2f4ef7d --- /dev/null +++ b/fgohook/fgo-dll.c @@ -0,0 +1,112 @@ +#include + +#include +#include + +#include "fgohook/fgo-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym fgo_dll_syms[] = { + { + .sym = "fgo_io_init", + .off = offsetof(struct fgo_dll, init), + }, { + .sym = "fgo_io_poll", + .off = offsetof(struct fgo_dll, poll), + }, { + .sym = "fgo_io_get_opbtns", + .off = offsetof(struct fgo_dll, get_opbtns), + }, { + .sym = "fgo_io_get_gamebtns", + .off = offsetof(struct fgo_dll, get_gamebtns), + }, { + .sym = "fgo_io_get_analogs", + .off = offsetof(struct fgo_dll, get_analogs), + } +}; + +struct fgo_dll fgo_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT fgo_dll_init(const struct fgo_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Ongeki IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Ongeki IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "fgo_io_get_api_version"); + + if (get_api_version != NULL) { + fgo_dll.api_version = get_api_version(); + } else { + fgo_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose fgo_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (fgo_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Ongeki IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + fgo_dll.api_version); + + goto end; + } + + sym = fgo_dll_syms; + hr = dll_bind(&fgo_dll, src, &sym, _countof(fgo_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Ongeki IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/fgohook/fgo-dll.h b/fgohook/fgo-dll.h new file mode 100644 index 0000000..41d6e92 --- /dev/null +++ b/fgohook/fgo-dll.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "fgoio/fgoio.h" + +struct fgo_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_analogs)(int16_t *stick_x, int16_t *stick_y); +}; + +struct fgo_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct fgo_dll fgo_dll; + +HRESULT fgo_dll_init(const struct fgo_dll_config *cfg, HINSTANCE self); diff --git a/fgohook/fgohook.def b/fgohook/fgohook.def new file mode 100644 index 0000000..04bf2f0 --- /dev/null +++ b/fgohook/fgohook.def @@ -0,0 +1,82 @@ +LIBRARY fgohook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + fgo_io_get_api_version + fgo_io_get_gamebtns + fgo_io_get_analogs + fgo_io_get_opbtns + fgo_io_init + fgo_io_poll + fwdlusb_open + fwdlusb_close + fwdlusb_listupPrinter + fwdlusb_listupPrinterSN + fwdlusb_selectPrinter + fwdlusb_selectPrinterSN + fwdlusb_getPrinterInfo + fwdlusb_status + fwdlusb_statusAll + fwdlusb_resetPrinter + fwdlusb_updateFirmware + fwdlusb_getFirmwareInfo + fwdlusb_MakeThread + fwdlusb_ReleaseThread + fwdlusb_AttachThreadCount + fwdlusb_getErrorLog + chcusb_MakeThread + chcusb_open + chcusb_close + chcusb_ReleaseThread + chcusb_listupPrinter + chcusb_listupPrinterSN + chcusb_selectPrinter + chcusb_selectPrinterSN + chcusb_getPrinterInfo + chcusb_imageformat + chcusb_setmtf + chcusb_makeGamma + chcusb_setIcctable + chcusb_copies + chcusb_status + chcusb_statusAll + chcusb_startpage + chcusb_endpage + chcusb_write + chcusb_writeLaminate + chcusb_writeHolo + chcusb_setPrinterInfo + chcusb_getGamma + chcusb_getMtf + chcusb_cancelCopies + chcusb_setPrinterToneCurve + chcusb_getPrinterToneCurve + chcusb_blinkLED + chcusb_resetPrinter + chcusb_AttachThreadCount + chcusb_getPrintIDStatus + chcusb_setPrintStandby + chcusb_testCardFeed + chcusb_exitCard + chcusb_getCardRfidTID + chcusb_commCardRfidReader + chcusb_updateCardRfidReader + chcusb_getErrorLog + chcusb_getErrorStatus + chcusb_setCutList + chcusb_setLaminatePattern + chcusb_color_adjustment + chcusb_color_adjustmentEx + chcusb_getEEPROM + chcusb_setParameter + chcusb_getParameter + chcusb_universal_command diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c new file mode 100644 index 0000000..50b7d11 --- /dev/null +++ b/fgohook/ftdi.c @@ -0,0 +1,55 @@ +/* + SEGA 837-14509-02 USB -> Serial Adapter hook + + The 837-15093-06 LED controller is connected to the ALLS with an adapter. + This tiny board has a FTDI FT232BL chip, and is referenced in schematics as + "USB-SER I/F BD". + + The game queries the presence of the FTDI board itself, followed by a + registry check to see which port number is assigned to the FTDI board. + If these fail, the "CABINET LED" check on startup will always return "NG". +*/ + +#include + +#include + +#include "fgohook/ftdi.h" + +#include "hook/iohook.h" + +#include "hooklib/setupapi.h" + +#include "util/dprintf.h" + +static struct ftdi_config ftdi_cfg; + +static HANDLE ftdi_fd; + +HRESULT ftdi_hook_init(const struct ftdi_config *cfg) +{ + HRESULT hr; + + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + memcpy(&ftdi_cfg, cfg, sizeof(*cfg)); + + hr = iohook_open_nul_fd(&ftdi_fd); + + if (FAILED(hr)) { + return hr; + } + + hr = setupapi_add_phantom_dev(&ftdi_guid, L"$ftdi"); + + if (FAILED(hr)) { + return hr; + } + + dprintf("FTDI: Hook enabled.\n"); + return S_OK; +} diff --git a/fgohook/ftdi.h b/fgohook/ftdi.h new file mode 100644 index 0000000..c40fb3b --- /dev/null +++ b/fgohook/ftdi.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include +#include + +struct ftdi_config { + bool enable; +}; + +DEFINE_GUID( + ftdi_guid, + 0x86E0D1E0, + 0x8089, + 0x11D0, + 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73); + +HRESULT ftdi_hook_init(const struct ftdi_config *cfg); diff --git a/fgohook/io4.c b/fgohook/io4.c new file mode 100644 index 0000000..b2deb5f --- /dev/null +++ b/fgohook/io4.c @@ -0,0 +1,104 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "fgohook/fgo-dll.h" + +#include "util/dprintf.h" + +static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops fgo_io4_ops = { + .poll = fgo_io4_poll, +}; + +HRESULT fgo_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(fgo_dll.init != NULL); + + hr = io4_hook_init(cfg, &fgo_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return fgo_dll.init(); +} + +static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + uint8_t gamebtn; + int16_t stick_x; + int16_t stick_y; + HRESULT hr; + + assert(fgo_dll.poll != NULL); + assert(fgo_dll.get_opbtns != NULL); + assert(fgo_dll.get_gamebtns != NULL); + assert(fgo_dll.get_analogs != NULL); + + memset(state, 0, sizeof(*state)); + + hr = fgo_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + gamebtn = 0; + stick_x = 0; + stick_y = 0; + + fgo_dll.get_opbtns(&opbtn); + fgo_dll.get_gamebtns(&gamebtn); + fgo_dll.get_analogs(&stick_x, &stick_y); + + if (opbtn & FGO_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & FGO_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & FGO_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + if (gamebtn & FGO_IO_GAMEBTN_SPEED_UP) { + state->buttons[0] |= 1 << 4; + } + + if (gamebtn & FGO_IO_GAMEBTN_TARGET) { + state->buttons[0] |= 1 << 5; + } + + if (gamebtn & FGO_IO_GAMEBTN_ATTACK) { + state->buttons[0] |= 1 << 1; + } + + if (gamebtn & FGO_IO_GAMEBTN_NOBLE_PHANTASHM) { + state->buttons[0] |= 1 << 0; + } + + if (gamebtn & FGO_IO_GAMEBTN_CAMERA) { + state->buttons[0] |= 1 << 14; + } + + /* Stick x and y movement */ + + state->adcs[0] = 0x8000 - stick_x; + state->adcs[4] = 0x8000 + stick_y; + + return S_OK; +} diff --git a/fgohook/io4.h b/fgohook/io4.h new file mode 100644 index 0000000..9739e89 --- /dev/null +++ b/fgohook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT fgo_io4_hook_init(const struct io4_config *cfg); diff --git a/fgohook/led1509306.c b/fgohook/led1509306.c new file mode 100644 index 0000000..17f3451 --- /dev/null +++ b/fgohook/led1509306.c @@ -0,0 +1,379 @@ +#include + +#include +#include +#include +#include +#include + +#include "board/led1509306-cmd.h" +#include "board/led1509306-frame.h" + +#include "fgohook/led1509306.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT led1509306_handle_irp(struct irp *irp); +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_get_board_info(int board); +static HRESULT led1509306_req_get_fw_sum(int board); +static HRESULT led1509306_req_get_protocol_ver(int board); +static HRESULT led1509306_req_get_board_status(int board); +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); + +static char led1509306_board_num[8]; +static char led1509306_chip_num[5]; +static uint8_t led1509306_fw_ver; +static uint16_t led1509306_fw_sum; +static uint8_t led1509306_board_adr = 2; +static uint8_t led1509306_host_adr = 1; + +#define led1509306_nboards 2 + +typedef struct { + CRITICAL_SECTION lock; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + bool enable_response; +} _led1509306_per_board_vars; + +_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); + memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); + led1509306_fw_ver = cfg->fw_ver; + led1509306_fw_sum = cfg->fw_sum; + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + + InitializeCriticalSection(&v->lock); + + uart_init(&v->boarduart, cfg->port_no + i); + v->boarduart.written.bytes = v->written_bytes; + v->boarduart.written.nbytes = sizeof(v->written_bytes); + v->boarduart.readable.bytes = v->readable_bytes; + v->boarduart.readable.nbytes = sizeof(v->readable_bytes); + + v->enable_response = true; + } + + dprintf("LED Strip: hook enabled.\n"); + + return iohook_push_handler(led1509306_handle_irp); +} + +static HRESULT led1509306_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led1509306_nboards; i++) + { + _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led1509306_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) +{ + struct led1509306_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("LED Strip: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led1509306_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("LED Strip: Processing error: %x\n", (int) hr); + } + } +} + +static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) +{ + switch (req->cmd) { + case LED_15093_06_CMD_RESET: + return led1509306_req_reset(board, req); + + case LED_15093_06_CMD_BOARD_INFO: + return led1509306_req_get_board_info(board); + + case LED_15093_06_CMD_FW_SUM: + return led1509306_req_get_fw_sum(board); + + case LED_15093_06_CMD_PROTOCOL_VER: + return led1509306_req_get_protocol_ver(board); + + case LED_15093_06_CMD_BOARD_STATUS: + return led1509306_req_get_board_status(board); + + case LED_15093_06_CMD_SET_LED: + return led1509306_req_set_led(board, req); + + case LED_15093_06_CMD_SET_DISABLE_RESPONSE: + return led1509306_req_set_disable_response(board, req); + + case LED_15093_06_CMD_SET_TIMEOUT: + return led1509306_req_set_timeout(board, req); + + default: + dprintf("LED Strip: Unhandled command %02x\n", req->cmd); + + return S_OK; + } +} + +static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) +{ + dprintf("LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); + + if (req->payload[0] != 0xd9) + dprintf("LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); + + led1509306_per_board_vars[board].enable_response = true; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_RESET; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_info(int board) +{ + dprintf("LED Strip: Get board info (board %u)\n", board); + + struct led1509306_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = sizeof(resp.data) + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_INFO; + resp.report = 1; + + memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); + resp.data._0a = 0x0a; + memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); + resp.data._ff = 0xff; + resp.data.fw_ver = led1509306_fw_ver; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_fw_sum(int board) +{ + dprintf("LED Strip: Get firmware checksum (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_FW_SUM; + resp.report = 1; + + resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; + resp.data[1] = led1509306_fw_sum & 0xff; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_protocol_ver(int board) +{ + dprintf("LED Strip: Get protocol version (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; + resp.report = 1; + + resp.data[0] = 1; + resp.data[1] = 1; + resp.data[2] = 4; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_get_board_status(int board) +{ + dprintf("LED Strip: Get board status (board %u)\n", board); + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 4 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_BOARD_STATUS; + resp.report = 1; + + resp.data[0] = 0; + resp.data[1] = 0; + resp.data[2] = 0; + resp.data[3] = 0; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) +{ + // dprintf("LED Strip: Set LED (board %u)\n", board); + + if (!led1509306_per_board_vars[board].enable_response) + return S_OK; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_LED; + resp.report = 1; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) +{ + dprintf("LED Strip: Disable LED responses (board %u)\n", board); + + led1509306_per_board_vars[board].enable_response = !req->payload[0]; + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 1 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; + resp.report = 1; + + resp.data[0] = req->payload[0]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) +{ + dprintf("LED Strip: Set timeout (board %u)\n", board); + + // not actually implemented, but respond correctly anyway + + struct led1509306_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_06_FRAME_SYNC; + resp.hdr.dest_adr = led1509306_host_adr; + resp.hdr.src_adr = led1509306_board_adr; + resp.hdr.nbytes = 2 + 3; + + resp.status = 1; + resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; + resp.report = 1; + + resp.data[0] = req->payload[0]; + resp.data[1] = req->payload[1]; + + return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} diff --git a/fgohook/led1509306.h b/fgohook/led1509306.h new file mode 100644 index 0000000..f4b3260 --- /dev/null +++ b/fgohook/led1509306.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include + +struct led1509306_config { + bool enable; + unsigned int port_no; + char board_number[8]; + char chip_number[5]; + uint8_t fw_ver; + uint16_t fw_sum; +}; + +HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/fgohook/meson.build b/fgohook/meson.build new file mode 100644 index 0000000..11737b2 --- /dev/null +++ b/fgohook/meson.build @@ -0,0 +1,36 @@ +shared_library( + 'fgohook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'fgohook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + fgoio_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'fgo-dll.c', + 'fgo-dll.h', + 'deck.c', + 'deck.h', + 'ftdi.c', + 'ftdi.h', + 'led1509306.c', + 'led1509306.h', + ], +) diff --git a/fgoio/config.c b/fgoio/config.c new file mode 100644 index 0000000..7f1f5e4 --- /dev/null +++ b/fgoio/config.c @@ -0,0 +1,20 @@ +#include + +#include +#include +#include + +#include "fgoio/config.h" + + +void fgo_io_config_load( + struct fgo_io_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); +} diff --git a/fgoio/config.h b/fgoio/config.h new file mode 100644 index 0000000..835e5e8 --- /dev/null +++ b/fgoio/config.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +struct fgo_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; +}; + +void fgo_io_config_load( + struct fgo_io_config *cfg, + const wchar_t *filename); diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c new file mode 100644 index 0000000..c6bd88f --- /dev/null +++ b/fgoio/fgoio.c @@ -0,0 +1,141 @@ +#include +#include +#include + +#include +#include + +#include "fgoio/fgoio.h" +#include "fgoio/config.h" +#include "util/dprintf.h" + +static uint8_t fgo_opbtn; +static uint8_t fgo_gamebtn; +static int16_t fgo_stick_x; +static int16_t fgo_stick_y; +static struct fgo_io_config fgo_io_cfg; +static bool fgo_io_coin; + +uint16_t fgo_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT fgo_io_init(void) +{ + fgo_io_config_load(&fgo_io_cfg, L".\\segatools.ini"); + + return S_OK; +} + +HRESULT fgo_io_poll(void) +{ + XINPUT_STATE xi; + WORD xb; + + fgo_opbtn = 0; + fgo_gamebtn = 0; + fgo_stick_x = 0; + fgo_stick_y = 0; + + if (GetAsyncKeyState(fgo_io_cfg.vk_test) & 0x8000) { + fgo_opbtn |= FGO_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(fgo_io_cfg.vk_service) & 0x8000) { + fgo_opbtn |= FGO_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(fgo_io_cfg.vk_coin) & 0x8000) { + if (!fgo_io_coin) { + fgo_io_coin = true; + fgo_opbtn |= FGO_IO_OPBTN_COIN; + } + } else { + fgo_io_coin = false; + } + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + if (xi.Gamepad.bLeftTrigger > 64) { + fgo_gamebtn |= FGO_IO_GAMEBTN_SPEED_UP; + } + + if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) { + fgo_gamebtn |= FGO_IO_GAMEBTN_TARGET; + } + + if (xb & XINPUT_GAMEPAD_A) { + fgo_gamebtn |= FGO_IO_GAMEBTN_ATTACK; + } + + if (xb & XINPUT_GAMEPAD_Y) { + fgo_gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASHM; + } + + if (xb & XINPUT_GAMEPAD_LEFT_THUMB) { + fgo_gamebtn |= FGO_IO_GAMEBTN_CAMERA; + } + + float LX = xi.Gamepad.sThumbLX; + float LY = xi.Gamepad.sThumbLY; + + // determine how far the controller is pushed + float magnitude = sqrt(LX*LX + LY*LY); + + // determine the direction the controller is pushed + float normalizedLX = LX / magnitude; + float normalizedLY = LY / magnitude; + + float normalizedMagnitude = 0; + + // check if the controller is outside a circular dead zone + if (magnitude > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + // clip the magnitude at its expected maximum value + if (magnitude > 32767) magnitude = 32767; + + // adjust magnitude relative to the end of the dead zone + magnitude -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + + // optionally normalize the magnitude with respect to its expected range + // giving a magnitude value of 0.0 to 1.0 + normalizedMagnitude = magnitude / (32767 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + } else // if the controller is in the deadzone zero out the magnitude + { + magnitude = 0.0; + normalizedMagnitude = 0.0; + } + + fgo_stick_x = normalizedLX * normalizedMagnitude * 32767; + fgo_stick_y = normalizedLY * normalizedMagnitude * 32767; + + return S_OK; +} + +void fgo_io_get_opbtns(uint8_t *opbtn) +{ + if (opbtn != NULL) { + *opbtn = fgo_opbtn; + } +} + +void fgo_io_get_gamebtns(uint8_t *btn) +{ + if (btn != NULL) { + *btn = fgo_gamebtn; + } +} + +void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y) +{ + if (stick_x != NULL) { + *stick_x = fgo_stick_x; + } + + if (stick_y != NULL) { + *stick_y = fgo_stick_y; + } +} diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h new file mode 100644 index 0000000..f302dfa --- /dev/null +++ b/fgoio/fgoio.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include + +enum { + FGO_IO_OPBTN_TEST = 0x01, + FGO_IO_OPBTN_SERVICE = 0x02, + FGO_IO_OPBTN_COIN = 0x04, +}; + +enum { + FGO_IO_GAMEBTN_SPEED_UP = 0x01, + FGO_IO_GAMEBTN_TARGET = 0x02, + FGO_IO_GAMEBTN_ATTACK = 0x04, + FGO_IO_GAMEBTN_NOBLE_PHANTASHM = 0x08, + FGO_IO_GAMEBTN_CAMERA = 0x10, +}; + +/* Get the version of the Fate Grand Order IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t fgo_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after fgo_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT fgo_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT fgo_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + FGO_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void fgo_io_get_opbtns(uint8_t *opbtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + FGO_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + a left hand side set of inputs and a right hand side set of inputs: the bit + mappings are the same in both cases. + + All buttons are active-high, even though some buttons' electrical signals + on a real cabinet are active-low. + + Minimum API version: 0x0100 */ + +void fgo_io_get_gamebtns(uint8_t *btn); + +/* Get the position of the cabinet stick as of the last poll. The center + position should be equal to or close to 32767. + + Minimum API version: 0x0100 */ + +void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y); diff --git a/fgoio/meson.build b/fgoio/meson.build new file mode 100644 index 0000000..d8a4881 --- /dev/null +++ b/fgoio/meson.build @@ -0,0 +1,16 @@ +fgoio_lib = static_library( + 'fgoio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + dependencies : [ + xinput_lib, + ], + sources : [ + 'fgoio.c', + 'fgoio.h', + 'config.c', + 'config.h', + ], +) diff --git a/hooklib/config.c b/hooklib/config.c index 30f6a4b..584d146 100644 --- a/hooklib/config.c +++ b/hooklib/config.c @@ -21,4 +21,63 @@ void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *fi assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename); + cfg->remap = GetPrivateProfileIntW(L"touch", L"remap", 1, filename); + cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename); +} + +void printer_config_load(struct printer_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 0, filename); + cfg->rotate_180 = GetPrivateProfileIntW(L"printer", L"rotate180", 0, filename); + + GetPrivateProfileStringW( + L"printer", + L"serial_no", + L"5A-A123", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->serial_no, tmpstr, sizeof(cfg->serial_no)); + for (int i = n; i < sizeof(cfg->serial_no); i++) + { + cfg->serial_no[i] = '\0'; + } + + GetPrivateProfileStringW( + L"printer", + L"mainFwPath", + L"DEVICE\\printer_main_fw.bin", + cfg->main_fw_path, + _countof(cfg->main_fw_path), + filename); + + GetPrivateProfileStringW( + L"printer", + L"dspFwPath", + L"DEVICE\\printer_dsp_fw.bin", + cfg->dsp_fw_path, + _countof(cfg->dsp_fw_path), + filename); + + GetPrivateProfileStringW( + L"printer", + L"paramFwPath", + L"DEVICE\\printer_param_fw.bin", + cfg->param_fw_path, + _countof(cfg->param_fw_path), + filename); + + GetPrivateProfileStringW( + L"printer", + L"printerOutPath", + L"DEVICE\\print", + cfg->printer_out_path, + _countof(cfg->printer_out_path), + filename); } diff --git a/hooklib/config.h b/hooklib/config.h index 9763274..9daed18 100644 --- a/hooklib/config.h +++ b/hooklib/config.h @@ -4,6 +4,8 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" +#include "hooklib/printer.h" void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename); void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename); +void printer_config_load(struct printer_config *cfg, const wchar_t *filename); diff --git a/hooklib/meson.build b/hooklib/meson.build index 4f2a703..40fe49d 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -31,5 +31,7 @@ hooklib_lib = static_library( 'spike.h', 'touch.c', 'touch.h', + 'printer.c', + 'printer.h', ], ) diff --git a/hooklib/printer.c b/hooklib/printer.c new file mode 100644 index 0000000..bdc913c --- /dev/null +++ b/hooklib/printer.c @@ -0,0 +1,2380 @@ +/* + Sinfonia CHC-C3XX Printer emulator + + Credits: + + c310emu (rakisaionji) + segatools-kancolle (OLEG) + c310emu (doremi) +*/ + +#include "hooklib/printer.h" + +#include +#include +#include +#include +#include +#include + +#include "hook/table.h" +#include "hooklib/dll.h" +#include "hooklib/uart.h" +#include "util/dprintf.h" +#include "util/dump.h" + +// #define IMAGE_SIZE 0x24FC00 +#define IMAGE_SIZE 0x1F0800 +#define HOLO_SIZE 0xC5400 + +static const int8_t idNumber = 0x01; +static uint64_t serialNo = 0x333231412D4135; + +static uint16_t WIDTH = 0; +static uint16_t HEIGHT = 0; + +static bool rotate180 = false; +static uint8_t cardRFID[0xC] = {0}; +static uint8_t cardDataBuffer[0x20] = {0}; +static bool awaitingCardExit = false; +static wchar_t printer_out_path[MAX_PATH]; + +/* Firmware data */ + +static uint8_t mainFirmware[0x40] = {0}; +static uint8_t dspFirmware[0x40] = {0}; +static uint8_t paramFirmware[0x40] = {0}; + +/* printerInfo variables */ + +static int32_t PAPERINFO[10]; +static int32_t CURVE[3][3]; +static uint8_t POLISH[2]; +static int32_t MTF[9]; + +/* C3xxFWDLusb API hooks */ + +int fwdlusb_open(uint16_t *rResult); +void fwdlusb_close(); +int fwdlusb_listupPrinter(uint8_t *rIdArray); +int fwdlusb_listupPrinterSN(uint64_t *rSerialArray); +int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int fwdlusb_status(uint16_t *rResult); +int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +int fwdlusb_resetPrinter(uint16_t *rResult); +int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); +int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int fwdlusb_MakeThread(uint16_t maxCount); +int fwdlusb_ReleaseThread(uint16_t *rResult); +int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); + +/* C3xxusb API hooks */ + +int chcusb_MakeThread(uint16_t maxCount); +int chcusb_open(uint16_t *rResult); +void chcusb_close(); +int chcusb_ReleaseThread(uint16_t *rResult); +int chcusb_listupPrinter(uint8_t *rIdArray); +int chcusb_listupPrinterSN(uint64_t *rSerialArray); +int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int chcusb_imageformat( + uint16_t format, + uint16_t ncomp, + uint16_t depth, + uint16_t width, + uint16_t height, + uint16_t *rResult); +int chcusb_setmtf(int32_t *mtf); +int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); +int chcusb_setIcctable( + LPCSTR icc1, + LPCSTR icc2, + uint16_t intents, + uint8_t *intoneR, + uint8_t *intoneG, + uint8_t *intoneB, + uint8_t *outtoneR, + uint8_t *outtoneG, + uint8_t *outtoneB, + uint16_t *rResult); +int chcusb_copies(uint16_t copies, uint16_t *rResult); +int chcusb_status(uint16_t *rResult); +int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); +int chcusb_endpage(uint16_t *rResult); +int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); +int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); +int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); +int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int chcusb_blinkLED(uint16_t *rResult); +int chcusb_resetPrinter(uint16_t *rResult); +int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); +int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); +int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); +int chcusb_exitCard(uint16_t *rResult); +int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); +int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); +int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); +int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); +int chcusb_getErrorStatus(uint16_t *rBuffer); +int chcusb_setCutList(uint8_t *rData, uint16_t *rResult); +int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); +int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); +int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); +int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); +int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); + +/* Bitmap writing utils */ + +DWORD WriteDataToBitmapFile( + LPCWSTR lpFilePath, DWORD dwBitCount, + DWORD dwWidth, DWORD dwHeight, + PBYTE pbInput, DWORD cbInput, + PBYTE pbMetadata, DWORD cbMetadata, + bool pFlip); +DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend); + +#define MAX_CARDS 36 + +// big thanks to Coburn and Mitsuhide for helping me figure out this thing + +// request format: +// 0xe0 - sync +// 0x?? - command +// 0x?? - payload length +// ... - payload +// 0x?? - checksum (sum of everything except the sync byte) +// +// response format: +// 0xe0 - sync +// 0x?? - command +// 0x?? - status code +// 0x?? - payload length +// ... - payload +// 0x?? - checksum + +enum { + DECK_CMD_RESET = 0x41, + DECK_CMD_GET_BOOT_FW_VERSION = 0x84, + DECK_CMD_GET_BOARD_INFO = 0x85, + DECK_CMD_INIT_UNK1 = 0x81, + DECK_CMD_GET_APP_FW_VERSION = 0x42, + DECK_CMD_READ_DATA = 0x02, + DECK_CMD_WRITE = 0x03, + DECK_CMD_INIT_UNK2 = 0x04, + DECK_CMD_INIT_UNK3 = 0x05, + DECK_CMD_READ = 0x06 +}; + +enum { + DECK_READ_START = 0x81, + DECK_READ_DATA = 0x82, + DECK_READ_END = 0x83 +}; + +struct deck_hdr { + uint8_t sync; + uint8_t cmd; + uint8_t nbytes; +}; + +struct deck_resp_hdr { + uint8_t sync; + uint8_t cmd; + uint8_t status; + uint8_t nbytes; +}; + +struct deck_resp_get_boot_fw_version { + struct deck_resp_hdr hdr; + uint8_t boot_fw_version; +}; + +struct deck_resp_get_app_fw_version { + struct deck_resp_hdr hdr; + uint8_t app_fw_version; +}; + +struct deck_resp_get_board_info { + struct deck_resp_hdr hdr; + uint8_t board[9]; +}; + +struct deck_resp_read_data { + struct deck_resp_hdr hdr; + uint8_t card_data[32]; +}; + +struct deck_resp_read { + struct deck_resp_hdr hdr; + uint8_t card_data[44]; +}; + +union deck_req_any { + struct deck_hdr hdr; + uint8_t bytes[520]; +}; + +static HRESULT deck_handle_irp(struct irp *irp); +static HRESULT deck_handle_irp_locked(struct irp *irp); +static HRESULT deck_req_dispatch(const union deck_req_any *req); +static HRESULT deck_req_get_boot_fw_version(void); +static HRESULT deck_req_get_app_fw_version(void); +static HRESULT deck_req_get_board_info(void); +static HRESULT deck_req_read(void); +static HRESULT deck_req_read_data(void); +static HRESULT deck_req_write(const uint8_t *req_bytes); +static HRESULT deck_req_nop(uint8_t cmd); +static void deck_read_one(void); + +static HRESULT deck_frame_accept(const struct iobuf *dest); +static void deck_frame_sync(struct iobuf *src); +static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src); +static HRESULT deck_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes); +static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte); + +static CRITICAL_SECTION deck_lock; +static struct uart deck_uart; +static uint8_t deck_written_bytes[1024]; +static uint8_t deck_readable_bytes[1024]; +static uint8_t current_card_idx = 0; +static bool read_pending = false; + +/* C3xxFWDLusb hook tbl. */ + +static const struct hook_symbol C3XXFWDLusb_hooks[] = { + {.name = "fwdlusb_open", + .patch = fwdlusb_open, + .link = NULL}, + {.name = "fwdlusb_close", + .patch = fwdlusb_close, + .link = NULL}, + {.name = "fwdlusb_listupPrinter", + .patch = fwdlusb_listupPrinter, + .link = NULL}, + {.name = "fwdlusb_listupPrinterSN", + .patch = fwdlusb_listupPrinterSN, + .link = NULL}, + {.name = "fwdlusb_selectPrinter", + .patch = fwdlusb_selectPrinter, + .link = NULL}, + {.name = "fwdlusb_selectPrinterSN", + .patch = fwdlusb_selectPrinterSN, + .link = NULL}, + {.name = "fwdlusb_getPrinterInfo", + .patch = fwdlusb_getPrinterInfo, + .link = NULL}, + {.name = "fwdlusb_status", + .patch = fwdlusb_status, + .link = NULL}, + {.name = "fwdlusb_statusAll", + .patch = fwdlusb_statusAll, + .link = NULL}, + {.name = "fwdlusb_resetPrinter", + .patch = fwdlusb_resetPrinter, + .link = NULL}, + {.name = "fwdlusb_updateFirmware", + .patch = fwdlusb_updateFirmware, + .link = NULL}, + {.name = "fwdlusb_getFirmwareInfo", + .patch = fwdlusb_getFirmwareInfo, + .link = NULL}, + {.name = "fwdlusb_MakeThread", + .patch = fwdlusb_MakeThread, + .link = NULL}, + {.name = "fwdlusb_ReleaseThread", + .patch = fwdlusb_ReleaseThread, + .link = NULL}, + {.name = "fwdlusb_AttachThreadCount", + .patch = fwdlusb_AttachThreadCount, + .link = NULL}, + {.name = "fwdlusb_getErrorLog", + .patch = fwdlusb_getErrorLog, + .link = NULL}, +}; + +/* C310A-Busb/C320Ausb/C330Ausb hook tbl. */ + +static const struct hook_symbol C3XXusb_hooks[] = { + {.name = "chcusb_MakeThread", + .patch = chcusb_MakeThread, + .link = NULL}, + {.name = "chcusb_open", + .patch = chcusb_open, + .link = NULL}, + {.name = "chcusb_close", + .patch = chcusb_close, + .link = NULL}, + {.name = "chcusb_ReleaseThread", + .patch = chcusb_ReleaseThread, + .link = NULL}, + {.name = "chcusb_listupPrinter", + .patch = chcusb_listupPrinter, + .link = NULL}, + {.name = "chcusb_listupPrinterSN", + .patch = chcusb_listupPrinterSN, + .link = NULL}, + {.name = "chcusb_selectPrinter", + .patch = chcusb_selectPrinter, + .link = NULL}, + {.name = "chcusb_selectPrinterSN", + .patch = chcusb_selectPrinterSN, + .link = NULL}, + {.name = "chcusb_getPrinterInfo", + .patch = chcusb_getPrinterInfo, + .link = NULL}, + {.name = "chcusb_imageformat", + .patch = chcusb_imageformat, + .link = NULL}, + {.name = "chcusb_setmtf", + .patch = chcusb_setmtf, + .link = NULL}, + {.name = "chcusb_makeGamma", + .patch = chcusb_makeGamma, + .link = NULL}, + {.name = "chcusb_setIcctable", + .patch = chcusb_setIcctable, + .link = NULL}, + {.name = "chcusb_copies", + .patch = chcusb_copies, + .link = NULL}, + {.name = "chcusb_status", + .patch = chcusb_status, + .link = NULL}, + {.name = "chcusb_statusAll", + .patch = chcusb_statusAll, + .link = NULL}, + {.name = "chcusb_startpage", + .patch = chcusb_startpage, + .link = NULL}, + {.name = "chcusb_endpage", + .patch = chcusb_endpage, + .link = NULL}, + {.name = "chcusb_write", + .patch = chcusb_write, + .link = NULL}, + {.name = "chcusb_writeLaminate", + .patch = chcusb_writeLaminate, + .link = NULL}, + {.name = "chcusb_writeHolo", + .patch = chcusb_writeHolo, + .link = NULL}, + {.name = "chcusb_setPrinterInfo", + .patch = chcusb_setPrinterInfo, + .link = NULL}, + {.name = "chcusb_getGamma", + .patch = chcusb_getGamma, + .link = NULL}, + {.name = "chcusb_getMtf", + .patch = chcusb_getMtf, + .link = NULL}, + {.name = "chcusb_cancelCopies", + .patch = chcusb_cancelCopies, + .link = NULL}, + {.name = "chcusb_setPrinterToneCurve", + .patch = chcusb_setPrinterToneCurve, + .link = NULL}, + {.name = "chcusb_getPrinterToneCurve", + .patch = chcusb_getPrinterToneCurve, + .link = NULL}, + {.name = "chcusb_blinkLED", + .patch = chcusb_blinkLED, + .link = NULL}, + {.name = "chcusb_resetPrinter", + .patch = chcusb_resetPrinter, + .link = NULL}, + {.name = "chcusb_AttachThreadCount", + .patch = chcusb_AttachThreadCount, + .link = NULL}, + {.name = "chcusb_getPrintIDStatus", + .patch = chcusb_getPrintIDStatus, + .link = NULL}, + {.name = "chcusb_setPrintStandby", + .patch = chcusb_setPrintStandby, + .link = NULL}, + {.name = "chcusb_testCardFeed", + .patch = chcusb_testCardFeed, + .link = NULL}, + {.name = "chcusb_exitCard", + .patch = chcusb_exitCard, + .link = NULL}, + {.name = "chcusb_getCardRfidTID", + .patch = chcusb_getCardRfidTID, + .link = NULL}, + {.name = "chcusb_commCardRfidReader", + .patch = chcusb_commCardRfidReader, + .link = NULL}, + {.name = "chcusb_updateCardRfidReader", + .patch = chcusb_updateCardRfidReader, + .link = NULL}, + {.name = "chcusb_getErrorLog", + .patch = chcusb_getErrorLog, + .link = NULL}, + {.name = "chcusb_getErrorStatus", + .patch = chcusb_getErrorStatus, + .link = NULL}, + {.name = "chcusb_setCutList", + .patch = chcusb_setCutList, + .link = NULL}, + {.name = "chcusb_setLaminatePattern", + .patch = chcusb_setLaminatePattern, + .link = NULL}, + {.name = "chcusb_color_adjustment", + .patch = chcusb_color_adjustment, + .link = NULL}, + {.name = "chcusb_color_adjustmentEx", + .patch = chcusb_color_adjustmentEx, + .link = NULL}, + {.name = "chcusb_getEEPROM", + .patch = chcusb_getEEPROM, + .link = NULL}, + {.name = "chcusb_setParameter", + .patch = chcusb_setParameter, + .link = NULL}, + {.name = "chcusb_getParameter", + .patch = chcusb_getParameter, + .link = NULL}, + {.name = "chcusb_universal_command", + .patch = chcusb_universal_command, + .link = NULL}, +}; + +/* C300usb hook tbl */ + +static struct hook_symbol C300usb_hooks[] = { + {.name = "chcusb_MakeThread", + .patch = chcusb_MakeThread, + .link = NULL}, + {.name = "chcusb_open", + .patch = chcusb_open, + .link = NULL}, + {.name = "chcusb_close", + .patch = chcusb_close, + .link = NULL}, + {.name = "chcusb_ReleaseThread", + .patch = chcusb_ReleaseThread, + .link = NULL}, + {.name = "chcusb_listupPrinter", + .patch = chcusb_listupPrinter, + .link = NULL}, + {.name = "chcusb_listupPrinterSN", + .patch = chcusb_listupPrinterSN, + .link = NULL}, + {.name = "chcusb_selectPrinter", + .patch = chcusb_selectPrinter, + .link = NULL}, + {.name = "chcusb_selectPrinterSN", + .patch = chcusb_selectPrinterSN, + .link = NULL}, + {.name = "chcusb_getPrinterInfo", + .patch = chcusb_getPrinterInfo, + .link = NULL}, + {.name = "chcusb_imageformat", + .patch = chcusb_imageformat, + .link = NULL}, + {.name = "chcusb_setmtf", + .patch = chcusb_setmtf, + .link = NULL}, + {.name = "chcusb_makeGamma", + .patch = chcusb_makeGamma, + .link = NULL}, + {.name = "chcusb_setIcctable", + .patch = chcusb_setIcctable, + .link = NULL}, + {.name = "chcusb_copies", + .patch = chcusb_copies, + .link = NULL}, + {.name = "chcusb_status", + .patch = chcusb_status, + .link = NULL}, + {.name = "chcusb_statusAll", + .patch = chcusb_statusAll, + .link = NULL}, + {.name = "chcusb_startpage", + .patch = chcusb_startpage, + .link = NULL}, + {.name = "chcusb_endpage", + .patch = chcusb_endpage, + .link = NULL}, + {.name = "chcusb_write", + .patch = chcusb_write, + .link = NULL}, + {.name = "chcusb_writeLaminate", + .patch = chcusb_writeLaminate, + .link = NULL}, + {.name = "chcusb_setPrinterInfo", + .patch = chcusb_setPrinterInfo, + .link = NULL}, + {.name = "chcusb_getGamma", + .patch = chcusb_getGamma, + .link = NULL}, + {.name = "chcusb_getMtf", + .patch = chcusb_getMtf, + .link = NULL}, + {.name = "chcusb_cancelCopies", + .patch = chcusb_cancelCopies, + .link = NULL}, + {.name = "chcusb_setPrinterToneCurve", + .patch = chcusb_setPrinterToneCurve, + .link = NULL}, + {.name = "chcusb_getPrinterToneCurve", + .patch = chcusb_getPrinterToneCurve, + .link = NULL}, + {.name = "chcusb_blinkLED", + .patch = chcusb_blinkLED, + .link = NULL}, + {.name = "chcusb_resetPrinter", + .patch = chcusb_resetPrinter, + .link = NULL}, + {.name = "chcusb_AttachThreadCount", + .patch = chcusb_AttachThreadCount, + .link = NULL}, + {.name = "chcusb_getPrintIDStatus", + .patch = chcusb_getPrintIDStatus, + .link = NULL}, + {.name = "chcusb_setPrintStandby", + .patch = chcusb_setPrintStandby, + .link = NULL}, + {.name = "chcusb_testCardFeed", + .patch = chcusb_testCardFeed, + .link = NULL}, + {.name = "chcusb_setParameter", + .patch = chcusb_setParameter, + .link = NULL}, + {.name = "chcusb_getParameter", + .patch = chcusb_getParameter, + .link = NULL}, + {.name = "chcusb_getErrorStatus", + .patch = chcusb_getErrorStatus, + .link = NULL}, + {.name = "chcusb_setCutList", + .patch = chcusb_setCutList, + .link = NULL}, + {.name = "chcusb_setLaminatePattern", + .patch = chcusb_setLaminatePattern, + .link = NULL}, + {.name = "chcusb_color_adjustment", + .patch = chcusb_color_adjustment, + .link = NULL}, + {.name = "chcusb_color_adjustmentEx", + .patch = chcusb_color_adjustmentEx, + .link = NULL}, + {.name = "chcusb_getEEPROM", + .patch = chcusb_getEEPROM, + .link = NULL}, + {.name = "chcusb_universal_command", + .patch = chcusb_universal_command, + .link = NULL}, +}; + +static struct printer_config printer_config; + +void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self) { + HANDLE fwFile = NULL; + DWORD bytesRead = 0; + + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + /* Set serial and rotate cfg */ + + memcpy(&serialNo, cfg->serial_no, sizeof(serialNo)); + _byteswap_uint64(serialNo); + + rotate180 = cfg->rotate_180; + + memcpy(&printer_config, cfg, sizeof(*cfg)); + hook_table_apply(NULL, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks)); + hook_table_apply(NULL, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(NULL, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(NULL, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(NULL, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(NULL, "C310BFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(NULL, "C320Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(NULL, "C320AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(NULL, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(NULL, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + + if (self != NULL) { + dll_hook_push(self, L"C300usb.dll"); // TODO: This doesn't work. Unity moment + dll_hook_push(self, L"C300FWDLusb.dll"); // TODO: ...and this... + dll_hook_push(self, L"C310Ausb.dll"); + dll_hook_push(self, L"C310Busb.dll"); // TODO: ...and this... + dll_hook_push(self, L"C310FWDLusb.dll"); + dll_hook_push(self, L"C310BFWDLusb.dll"); // TODO: ...aaaand this. + dll_hook_push(self, L"C320Ausb.dll"); + dll_hook_push(self, L"C320AFWDLusb.dll"); + dll_hook_push(self, L"C330Ausb.dll"); + dll_hook_push(self, L"C330AFWDLusb.dll"); + } + + // Load firmware if has previously been written to + fwFile = CreateFileW(cfg->main_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + ReadFile(fwFile, mainFirmware, sizeof(mainFirmware), &bytesRead, NULL); + CloseHandle(fwFile); + } + + fwFile = CreateFileW(cfg->dsp_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + ReadFile(fwFile, dspFirmware, sizeof(dspFirmware), &bytesRead, NULL); + CloseHandle(fwFile); + } + + fwFile = CreateFileW(cfg->param_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + ReadFile(fwFile, paramFirmware, sizeof(dspFirmware), &bytesRead, NULL); + CloseHandle(fwFile); + } + + CreateDirectoryW(cfg->printer_out_path, NULL); + memcpy(printer_out_path, cfg->printer_out_path, MAX_PATH); + + if (rfid_port_no != 0) { + InitializeCriticalSection(&deck_lock); + + uart_init(&deck_uart, rfid_port_no); + deck_uart.written.bytes = deck_written_bytes; + deck_uart.written.nbytes = sizeof(deck_written_bytes); + deck_uart.readable.bytes = deck_readable_bytes; + deck_uart.readable.nbytes = sizeof(deck_readable_bytes); + + dprintf("Printer: RFID: hook enabled.\n"); + + if (FAILED(iohook_push_handler(deck_handle_irp))) { + dprintf("Printer: RFID: failed to hook IRP handler.\n"); + } + } + + dprintf("Printer: hook enabled.\n"); +} + +static void generate_rfid(void) { + for (int i = 0; i < sizeof(cardRFID); i++) + cardRFID[i] = rand(); + + dprintf("Printer: New card RFID:\n"); + dump(cardRFID, sizeof(cardRFID)); +} + +static HRESULT deck_handle_irp(struct irp *irp) { + HRESULT hr; + + assert(irp != NULL); + + if (!uart_match_irp(&deck_uart, irp)) { + return iohook_invoke_next(irp); + } + + EnterCriticalSection(&deck_lock); + hr = deck_handle_irp_locked(irp); + LeaveCriticalSection(&deck_lock); + + return hr; +} + +static HRESULT deck_handle_irp_locked(struct irp *irp) { + uint8_t req[1024]; + struct iobuf req_iobuf; + HRESULT hr; + + if (irp->op == IRP_OP_OPEN) { + dprintf("Printer: RFID: Starting backend\n"); + } + + hr = uart_handle_irp(&deck_uart, irp); + + if (SUCCEEDED(hr) && irp->op == IRP_OP_READ && read_pending == true) { + deck_read_one(); + return S_OK; + } + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { + // if (deck_uart.written.pos != 0) { + // dprintf("Printer: RFID: TX Buffer:\n"); + // dump_iobuf(&deck_uart.written); + // } + + req_iobuf.bytes = req; + req_iobuf.nbytes = sizeof(req); + req_iobuf.pos = 0; + + hr = deck_frame_decode(&req_iobuf, &deck_uart.written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("Printer: RFID: Deframe error: %x, %d %d\n", (int)hr, (int)req_iobuf.nbytes, (int)req_iobuf.pos); + } + + return hr; + } + + // dprintf("Printer: RFID: Deframe Buffer:\n"); + // dump_iobuf(&req_iobuf); + + hr = deck_req_dispatch((const union deck_req_any *)&req); + + if (FAILED(hr)) { + dprintf("Printer: RFID: Processing error: %x\n", (int)hr); + } + + // dprintf("Printer: RFID: Written bytes:\n"); + // dump_iobuf(&deck_uart.readable); + } +} + +static HRESULT deck_req_dispatch(const union deck_req_any *req) { + switch (req->hdr.cmd) { + case DECK_CMD_RESET: + case DECK_CMD_INIT_UNK1: + case DECK_CMD_INIT_UNK2: + case DECK_CMD_INIT_UNK3: + return deck_req_nop(req->hdr.cmd); + + case DECK_CMD_GET_BOOT_FW_VERSION: + return deck_req_get_boot_fw_version(); + + case DECK_CMD_GET_APP_FW_VERSION: + return deck_req_get_app_fw_version(); + + case DECK_CMD_GET_BOARD_INFO: + return deck_req_get_board_info(); + + case DECK_CMD_READ: + return deck_req_read(); + + case DECK_CMD_READ_DATA: + return deck_req_read_data(); + + case DECK_CMD_WRITE: + return deck_req_write(req->bytes); + + default: + dprintf("Printer: RFID: Unhandled command %#02x\n", req->hdr.cmd); + + return S_OK; + } +} + +static HRESULT deck_req_get_boot_fw_version(void) { + struct deck_resp_get_boot_fw_version resp; + + dprintf("Printer: RFID: Get Boot FW Version\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_BOOT_FW_VERSION; + resp.hdr.status = 0; + resp.hdr.nbytes = 1; + resp.boot_fw_version = 0x90; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_get_app_fw_version(void) { + struct deck_resp_get_app_fw_version resp; + + dprintf("Printer: RFID: Get App FW Version\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_APP_FW_VERSION; + resp.hdr.status = 0; + resp.hdr.nbytes = 1; + resp.app_fw_version = 0x90; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_get_board_info(void) { + struct deck_resp_get_board_info resp; + + dprintf("Printer: RFID: Get Board Info\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_GET_BOARD_INFO; + resp.hdr.status = 0; + resp.hdr.nbytes = 9; + memcpy(resp.board, (void *)"837-15347", 9); + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_read(void) { + struct deck_resp_read resp; + + dprintf("Printer: RFID: Read Card\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_READ; + resp.hdr.status = DECK_READ_START; + resp.hdr.nbytes = 0; + + current_card_idx = 0; + read_pending = true; + + return deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); +} + +static HRESULT deck_req_read_data(void) { + struct deck_resp_read_data resp; + + dprintf("Printer: RFID: Read Card Data\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_READ_DATA; + resp.hdr.status = 0; + resp.hdr.nbytes = 32; + memcpy(resp.card_data, cardDataBuffer, 32); + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT deck_req_write(const uint8_t *req_bytes) { + struct deck_resp_hdr resp; + uint8_t off; + + resp.sync = 0xE0; + resp.cmd = DECK_CMD_WRITE; + resp.status = 0; + resp.nbytes = 0; + + off = (req_bytes[5] - 1) * 2; + cardDataBuffer[off] = req_bytes[6]; + cardDataBuffer[off + 1] = req_bytes[7]; + if (req_bytes[5] == 0x10) { + dprintf("Printer: RFID: Card Data Buffer: \n"); + dump(cardDataBuffer, 0x20); + } + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static void deck_read_one(void) { + struct deck_resp_read resp; + + dprintf("Printer: RFID: Read One Card\n"); + + resp.hdr.sync = 0xE0; + resp.hdr.cmd = DECK_CMD_READ; + + if (current_card_idx < 1) { + resp.hdr.status = DECK_READ_DATA; + resp.hdr.nbytes = 44; + memset(resp.card_data, 0, 44); + memcpy(resp.card_data, cardRFID, 0xC); + memcpy(resp.card_data + 0x0C, cardDataBuffer, 0x20); + dump(resp.card_data, 44); + + deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); + current_card_idx++; + } else { + resp.hdr.status = DECK_READ_END; + resp.hdr.nbytes = 0; + deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); + read_pending = false; + } +} + +static HRESULT deck_req_nop(uint8_t cmd) { + struct deck_resp_hdr resp; + + dprintf("Printer: RFID: No-op cmd %#02x\n", cmd); + + resp.sync = 0xE0; + resp.cmd = cmd; + resp.status = 0; + resp.nbytes = 0; + + return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); +} + +static void deck_frame_sync(struct iobuf *src) { + size_t i; + + for (i = 0; i < src->pos && src->bytes[i] != 0xE0; i++) + ; + + src->pos -= i; + memmove(&src->bytes[0], &src->bytes[i], i); +} + +static HRESULT deck_frame_accept(const struct iobuf *dest) { + if (dest->pos < 2 || dest->pos != dest->bytes[2] + 4) { + return S_FALSE; + } + + return S_OK; +} + +static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src) { + uint8_t byte; + bool escape; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(src != NULL); + assert(src->bytes != NULL || src->nbytes == 0); + assert(src->pos <= src->nbytes); + + dest->pos = 0; + escape = false; + + for (i = 0, hr = S_FALSE; i < src->pos && hr == S_FALSE; i++) { + /* Step the FSM to unstuff another byte */ + + byte = src->bytes[i]; + + if (dest->pos >= dest->nbytes) { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } else if (i == 0) { + dest->bytes[dest->pos++] = byte; + } else if (byte == 0xE0) { + hr = E_FAIL; + } else if (byte == 0xD0) { + if (escape) { + hr = E_FAIL; + } + + escape = true; + } else if (escape) { + dest->bytes[dest->pos++] = byte + 1; + escape = false; + } else { + dest->bytes[dest->pos++] = byte; + } + + /* Try to accept the packet we've built up so far */ + + if (SUCCEEDED(hr)) { + hr = deck_frame_accept(dest); + } + } + + /* Handle FSM terminal state */ + + if (hr != S_FALSE) { + /* Frame was either accepted or rejected, remove it from src */ + memmove(&src->bytes[0], &src->bytes[i], src->pos - i); + src->pos -= i; + } + + return hr; +} + +static HRESULT deck_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes) { + const uint8_t *src; + uint8_t checksum; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + assert(nbytes >= 2 && src[0] == 0xE0 && src[3] + 4 == nbytes); + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xE0; + checksum = 0x0; + + for (i = 1; i < nbytes; i++) { + byte = src[i]; + checksum += byte; + + hr = deck_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } + + return deck_frame_encode_byte(dest, checksum); +} + +static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte) { + if (byte == 0xD0 || byte == 0xE0) { + if (dest->pos + 2 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = byte - 1; + } else { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + } + + return S_OK; +} + +// C310FWDLusb stubs + +int fwdlusb_open(uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +void fwdlusb_close() {} + +int fwdlusb_listupPrinter(uint8_t *rIdArray) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + memset(rIdArray, 0xFF, 0x80); + rIdArray[0] = idNumber; + return 1; +} + +int fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + memset(rSerialArray, 0xFF, 0x400); + rSerialArray[0] = serialNo; + return 1; +} + +int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + switch (tagNumber) { + case 0: // getPaperInfo + if (*rLen != 0x67) *rLen = 0x67; + if (rBuffer) memset(rBuffer, 0, *rLen); + return 1; + case 3: // getFirmwareVersion + if (*rLen != 0x99) *rLen = 0x99; + if (rBuffer) { + memset(rBuffer, 0, *rLen); + // bootFirmware + int i = 1; + memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); + // mainFirmware + i += 0x26; + memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); + // printParameterTable + i += 0x26; + memcpy(rBuffer + i, paramFirmware, sizeof(paramFirmware)); + // dspFirmware (C300 only) + i += 0x26; + memcpy(rBuffer + i, dspFirmware, 0x26); + } + return 1; + case 4: // getPrintCountInfo (C300 only) + if (!rBuffer) { + *rLen = 0x1C; + return 1; + } + int32_t bInfoC300[10] = {0}; + uint16_t printCounterC300; + bInfoC300[0] = 22; // printCounter0 + bInfoC300[1] = 23; // printCounter1 + bInfoC300[2] = 33; // feedRollerCount + bInfoC300[3] = 55; // cutterCount + bInfoC300[4] = 88; // headCount + bInfoC300[5] = 999; // ribbonRemain + bInfoC300[6] = 0; // dummy + if (*rLen <= 0x1Cu) { + memcpy(rBuffer, bInfoC300, *rLen); + } else { + bInfoC300[7] = 0; // TODO + if (*rLen > 0x20u) *rLen = 0x20; + memcpy(rBuffer, bInfoC300, *rLen); + } + break; + case 5: // getPrintCountInfo + if (!rBuffer) { + *rLen = 0x28; + return 1; + } + int32_t bInfo[10] = {0}; + bInfo[0] = 22; // printCounter0 + bInfo[1] = 23; // printCounter1 + bInfo[2] = 33; // feedRollerCount + bInfo[3] = 55; // cutterCount + bInfo[4] = 88; // headCount + bInfo[5] = 999; // ribbonRemain + bInfo[6] = 99; // holoHeadCount + if (*rLen <= 0x1Cu) { + memcpy(rBuffer, bInfo, *rLen); + } else { + bInfo[7] = 69; // paperCount + bInfo[8] = 21; // printCounter2 + bInfo[9] = 20; // holoPrintCounter + if (*rLen > 0x28u) *rLen = 0x28; + memcpy(rBuffer, bInfo, *rLen); + } + break; + case 26: // getPrinterSerial + if (*rLen != 8) *rLen = 8; + if (rBuffer) memcpy(rBuffer, &serialNo, 8); + return 1; + default: + dprintf("Printer: %s: Unknown parameter 'tagNumber' value %d.\n", __func__, tagNumber); + break; + } + return 1; +} + +int fwdlusb_status(uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { + *(uint16_t *)(rResultArray + 2 * i) = 0; + } + + return 1; +} + +int fwdlusb_resetPrinter(uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { + int8_t a; + uint32_t b = 0; + for (int32_t i = 0; i < size; ++i) { + if (*(int8_t *)(buffer + i) < 0x30 || *(int8_t *)(buffer + i) > 0x39) { + if (*(int8_t *)(buffer + i) < 0x41 || *(int8_t *)(buffer + i) > 0x46) { + if (*(int8_t *)(buffer + i) < 0x61 || *(int8_t *)(buffer + i) > 0x66) { + return 0; + } + a = *(int8_t *)(buffer + i) - 0x57; + } else { + a = *(int8_t *)(buffer + i) - 0x37; + } + } else { + a = *(int8_t *)(buffer + i) - 0x30; + } + b = a + 0x10 * b; + } + return b; +} + +int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { + DWORD result; + HANDLE fwFile = NULL; + DWORD bytesWritten = 0; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + CloseHandle(hFile); + if (result && read > 0x24) { + uint8_t rBuffer[0x40] = {0}; + + memcpy(rBuffer, buffer + 0x2, 0x8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + *(rBuffer + 0x22) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1A, 0x2); + *(rBuffer + 0x23) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1C, 0x2); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + memcpy(mainFirmware, rBuffer, 0x40); + + fwFile = CreateFileW(printer_config.main_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); + CloseHandle(fwFile); + } + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { + DWORD result; + HANDLE fwFile = NULL; + DWORD bytesWritten = 0; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + CloseHandle(hFile); + if (result && read > 0x24) { + uint8_t rBuffer[0x40] = {0}; + + memcpy(rBuffer, buffer + 0x2, 8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); + memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + memcpy(dspFirmware, rBuffer, 0x40); + + fwFile = CreateFileW(printer_config.dsp_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); + CloseHandle(fwFile); + } + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { + DWORD result; + HANDLE fwFile = NULL; + DWORD bytesWritten = 0; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + CloseHandle(hFile); + if (result && read > 0x24) { + uint8_t rBuffer[0x40] = {0}; + + memcpy(rBuffer, buffer + 0x2, 8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); + memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + memcpy(paramFirmware, rBuffer, 0x40); + + fwFile = CreateFileW(printer_config.param_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (fwFile != NULL) { + WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); + CloseHandle(fwFile); + } + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + if (update == 1) { + return fwdlusb_updateFirmware_main(update, filename, rResult); + } else if (update == 2) { + return fwdlusb_updateFirmware_dsp(update, filename, rResult); + } else if (update == 3) { + return fwdlusb_updateFirmware_param(update, filename, rResult); + } else { + *rResult = 0; + return 1; + } +} + +int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { + DWORD result; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + if (result && read > 0x24) { + memcpy(rBuffer, buffer + 0x2, 0x8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + *(rBuffer + 0x22) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1A, 0x2); + *(rBuffer + 0x23) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1C, 0x2); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { + DWORD result; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + if (result && read > 0x24) { + memcpy(rBuffer, buffer + 0x2, 8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); + memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { + DWORD result; + + if (filename) { + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + { + if (rResult) *rResult = 1005; + result = 0; + } + + DWORD read; + uint8_t buffer[0x40]; + result = ReadFile(hFile, buffer, 0x40, &read, NULL); + if (result && read > 0x24) { + memcpy(rBuffer, buffer + 0x2, 8); + memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); + memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); + memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); + memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); + memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); + + if (rResult) *rResult = 0; + result = 1; + } else { + if (rResult) *rResult = 1005; + result = 0; + } + } else { + if (rResult) *rResult = 1006; + result = 0; + } + + return result; +} + +int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s(update: %d, filename: %s)\n", __func__, update, filename); + if (!rBuffer) { + *rLen = 38; + return 1; + } + if (*rLen > 38) *rLen = 38; + if (update == 1) { + return fwdlusb_getFirmwareInfo_main(filename, rBuffer, rLen, rResult); + } else if (update == 2) { + return fwdlusb_getFirmwareInfo_dsp(filename, rBuffer, rLen, rResult); + } else if (update == 3) { + return fwdlusb_getFirmwareInfo_param(filename, rBuffer, rLen, rResult); + } else { + if (rResult) *rResult = 0; + return 1; + } +} + +int fwdlusb_MakeThread(uint16_t maxCount) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + return 1; +} + +int fwdlusb_ReleaseThread(uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rCount = 0; + *rMaxCount = 1; + return 1; +} + +int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { + dprintf("Printer: C3XXFWDLusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +// C3XXusb stubs + +int chcusb_MakeThread(uint16_t maxCount) { + dprintf("Printer: C3XXusb: %s\n", __func__); + return 1; +} + +int chcusb_open(uint16_t *rResult) { + // Seed random for card id generation + srand(time(NULL)); + generate_rfid(); + + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +void chcusb_close() { + dprintf("Printer: C3XXusb: %s\n", __func__); +} + +int chcusb_ReleaseThread(uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + return 1; +} + +int chcusb_listupPrinter(uint8_t *rIdArray) { + dprintf("Printer: C3XXusb: %s\n", __func__); + memset(rIdArray, 0xFF, 0x80); + rIdArray[0] = idNumber; + return 1; +} + +int chcusb_listupPrinterSN(uint64_t *rSerialArray) { + dprintf("Printer: C3XXusb: %s\n", __func__); + memset(rSerialArray, 0xFF, 0x400); + rSerialArray[0] = serialNo; + return 1; +} + +int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { + // dprintf("Printer: C3XXusb: %s\n", __func__); + + switch (tagNumber) { + // getPaperInfo + case 0: + if (*rLen != 0x67) *rLen = 0x67; + if (rBuffer) memset(rBuffer, 0, *rLen); + break; + + case 3: // getFirmwareVersion + if (*rLen != 0x99) *rLen = 0x99; + if (rBuffer) { + memset(rBuffer, 0, *rLen); + // bootFirmware + int i = 1; + memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); + // mainFirmware + i += 0x26; + memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); + // printParameterTable + i += 0x26; + memcpy(rBuffer + i, paramFirmware, sizeof(paramFirmware)); + // dspFirmware (C300 only) + i += 0x26; + memcpy(rBuffer + i, dspFirmware, 0x26); + } + break; + + case 4: // getPrintCountInfo (C300 only) + if (!rBuffer) { + *rLen = 0x1C; + return 1; + } + int32_t bInfoC300[10] = {0}; + bInfoC300[0] = 22; // printCounter0 + bInfoC300[1] = 23; // printCounter1 + bInfoC300[2] = 33; // feedRollerCount + bInfoC300[3] = 55; // cutterCount + bInfoC300[4] = 88; // headCount + bInfoC300[5] = 999; // ribbonRemain + bInfoC300[6] = 0; // dummy + if (*rLen <= 0x1Cu) { + memcpy(rBuffer, bInfoC300, *rLen); + } else { + bInfoC300[7] = 0; // TODO + if (*rLen > 0x20u) *rLen = 0x20; + memcpy(rBuffer, bInfoC300, *rLen); + } + break; + + case 5: // getPrintCountInfo2 (C310A and later) + if (!rBuffer) { + *rLen = 0x28; + return 1; + } + int32_t bInfo[10] = {0}; + bInfo[0] = 22; // printCounter0 + bInfo[1] = 23; // printCounter1 + bInfo[2] = 33; // feedRollerCount + bInfo[3] = 55; // cutterCount + bInfo[4] = 88; // headCount + bInfo[5] = 999; // ribbonRemain + bInfo[6] = 99; // holoHeadCount + if (*rLen <= 0x1Cu) { + memcpy(rBuffer, bInfo, *rLen); + } else { + bInfo[7] = 69; // paperCount + bInfo[8] = 21; // printCounter2 + bInfo[9] = 20; // holoPrintCounter + if (*rLen > 0x28u) *rLen = 0x28; + memcpy(rBuffer, bInfo, *rLen); + } + break; + + case 6: // pageStatusInfo + *rLen = 32; + if (rBuffer) { + memset(rBuffer, 0, 32); + rBuffer[0] = 88; // holoRemain + rBuffer[1] = 0; + rBuffer[2] = 0; + rBuffer[3] = 0; + } + break; + + case 7: // svc + *rLen = 2; + if (rBuffer) { + memset(rBuffer, 0, 2); + rBuffer[0] = 0; // mainError + rBuffer[1] = 0; // subError + } + break; + + case 8: // printStandby + *rLen = 1; + if (awaitingCardExit) + *rBuffer = 0xF0; + else + *rBuffer = 0; + break; + + case 16: // memoryInfo + *rLen = 18; + if (rBuffer) memset(rBuffer, 0, 18); + break; + + case 20: // printMode + dprintf("Printer: C3xxusb: Unimpl tagNumber 20\n"); + break; + + case 26: // getPrinterSerial + if (*rLen != 8) *rLen = 8; + if (rBuffer) memcpy(rBuffer, &serialNo, 8); + break; + + case 30: // TODO + dprintf("Printer: C3xxusb: Unimpl tagNumber 30\n"); + break; + + case 31: // TODO, possibly CardRFIDCheck? + *rLen = 1; + if (rBuffer) memset(rBuffer, 0, 1); + break; + + case 40: // temperature + *rLen = 10; + if (rBuffer) { + memset(rBuffer, 0, 10); + rBuffer[0] = 1; + rBuffer[1] = 2; + rBuffer[2] = 3; + } + break; + + case 50: // errHistory + *rLen = 61; + if (rBuffer) memset(rBuffer, 0, 61); + break; + + case 60: // getToneTable + *rLen = 6; + if (rBuffer) memset(rBuffer, 0, 6); + break; + + default: + dprintf("Printer: unknown tagNumber, %d", tagNumber); + break; + } + + return 1; +} + +int chcusb_imageformat( + uint16_t format, + uint16_t ncomp, + uint16_t depth, + uint16_t width, + uint16_t height, + uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + WIDTH = width; + HEIGHT = height; + + *rResult = 0; + return 1; +} + +int chcusb_setmtf(int32_t *mtf) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + memcpy(MTF, mtf, sizeof(MTF)); + return 1; +} + +int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + uint8_t tone; + int32_t value; + double power; + + double factor = (double)k / 100.0; + + for (int i = 0; i < 256; ++i) { + power = pow((double)i, factor); + value = (int)(power / pow(255.0, factor) * 255.0); + + if (value > 255) + tone = 255; + if (value >= 0) + tone = value; + else + tone = 0; + + if (intoneR) + *(uint8_t *)(intoneR + i) = tone; + if (intoneG) + *(uint8_t *)(intoneG + i) = tone; + if (intoneB) + *(uint8_t *)(intoneB + i) = tone; + } + + return 1; +} + +int chcusb_setIcctable( + LPCSTR icc1, + LPCSTR icc2, + uint16_t intents, + uint8_t *intoneR, + uint8_t *intoneG, + uint8_t *intoneB, + uint8_t *outtoneR, + uint8_t *outtoneG, + uint8_t *outtoneB, + uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + for (int i = 0; i < 256; ++i) { + intoneR[i] = i; + intoneG[i] = i; + intoneB[i] = i; + outtoneR[i] = i; + outtoneG[i] = i; + outtoneB[i] = i; + } + + *rResult = 0; + return 1; +} + +int chcusb_copies(uint16_t copies, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_status(uint16_t *rResult) { + // dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { + *(uint16_t *)(rResultArray + 2 * i) = 0; + } + + return 1; +} + +int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + *pageId = 1; + *rResult = 0; + return 1; +} + +int chcusb_endpage(uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + awaitingCardExit = true; + + *rResult = 0; + return 1; +} + +int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { + SYSTEMTIME t; + GetLocalTime(&t); + + wchar_t dumpPath[MAX_PATH]; + uint8_t metadata[44]; + swprintf_s( + dumpPath, MAX_PATH, + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d.bmp", + printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + + memcpy(metadata, cardRFID, 12); + memcpy(metadata + 12, cardDataBuffer, 32); + + WriteDataToBitmapFile(dumpPath, 24, WIDTH, HEIGHT, data, *writeSize, metadata, 44, rotate180); + // WriteArrayToFile(dumpPath, data, IMAGE_SIZE, FALSE); + dprintf("Printer: C3XXusb: %s\n", __func__); + dwprintf(L"Printer: File written: %s\n", dumpPath); + + *rResult = 0; + + return 1; +} + +int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { + SYSTEMTIME t; + GetLocalTime(&t); + + char dumpPath[0x80]; + sprintf_s( + dumpPath, 0x80, + "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeLaminate.bin", + t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + + // WriteArrayToFile(dumpPath, data, *writeSize, FALSE); + dprintf("Printer: C3XXusb: %s\n", __func__); + + // *writeSize = written; + *rResult = 0; + + return 1; +} + +int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { + SYSTEMTIME t; + GetLocalTime(&t); + + char dumpPath[0x80]; + sprintf_s( + dumpPath, 0x80, + "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeHolo.bin", + t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + + // WriteArrayToFile(dumpPath, data, HOLO_SIZE, FALSE); + dprintf("Printer: C3XXusb: %s\n", __func__); + + *writeSize = HOLO_SIZE; + *rResult = 0; + + return 1; +} + +int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + switch (tagNumber) { + case 0: // setPaperInfo + memcpy(PAPERINFO, rBuffer, sizeof(PAPERINFO)); + break; + case 20: // setPolishInfo + memcpy(POLISH, rBuffer, sizeof(POLISH)); + break; + default: + break; + } + + *rResult = 0; + return 1; +} + +int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + for (int i = 0; i < 256; ++i) { + r[i] = i; + g[i] = i; + b[i] = i; + } + + *rResult = 0; + return 1; +} + +int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 0; + + DWORD read; + uint8_t buffer[0x40]; + BOOL result = ReadFile(hFile, buffer, 0x40, &read, NULL); + if (!result) return 0; + + int a, c; + int b = 1; + int d = c = 0; + + memset(mtf, 0, sizeof(MTF)); + + for (DWORD i = 0; i < read; i++) { + a = buffer[i] - 0x30; + if (a == -3 && c == 0) { + b = -1; + } else if (a >= 0 && a <= 9) { + mtf[d] = mtf[d] * 10 + a; + c++; + } else if (c > 0) { + mtf[d] *= b; + b = 1; + c = 0; + d++; + } + if (d > 9) break; + } + + *rResult = 0; + return 1; +} + +int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + if ((type > 0 && type < 3) && (number > 0 && number < 3)) { + CURVE[type][number] = *data; + } + *rResult = 0; + return 1; +} + +int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + if ((type > 0 && type < 3) && (number > 0 && number < 3)) { + *data = CURVE[type][number]; + } + *rResult = 0; + return 1; +} + +int chcusb_blinkLED(uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_resetPrinter(uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rCount = 0; + *rMaxCount = 1; + return 1; +} + +int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { + // dprintf("Printer: C3XXusb: %s\n", __func__); + memset(rBuffer, 0, 8); + *((uint16_t *)(rBuffer + 6)) = 2300; + *rResult = 0; + return 1; +} + +int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_exitCard(uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + awaitingCardExit = false; + generate_rfid(); + + *rResult = 0; + return 1; +} + +int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + + memcpy(rCardTID, cardRFID, sizeof(cardRFID)); + *rResult = 2405; + return 1; +} + +int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { + uint8_t off; + + dprintf("Printer: C3XXusb: %s\n", __func__); + // dprintf("Printer: C3XXusb: commCardRfidReader send buffer: \n"); + // dump(sendData, sendSize); + + *rResult = 0; + + switch (sendData[0]) { + case 0x02: + memset(rRecvData, 0, 35); + rRecvData[0] = 2; + rRecvData[2] = 32; + memcpy(rRecvData + 3, cardDataBuffer, 32); + *rRecvSize = 35; + break; + case 0x03: + off = (sendData[4] - 1) * 2; + cardDataBuffer[off] = sendData[5]; + cardDataBuffer[off + 1] = sendData[6]; + if (sendData[4] == 0x10) { + dprintf("Printer: C3XXusb: commCardRfidReader card data buffer: \n"); + dump(cardDataBuffer, 0x20); + } + memset(rRecvData, 0, 3); + rRecvData[0] = 0x03; + *rRecvSize = 3; + break; + case 0x84: + memset(rRecvData, 0, 4); + rRecvData[0] = 0x84; + rRecvData[2] = 1; + rRecvData[3] = 0x90; + *rRecvSize = 4; + break; + case 0x85: + memset(rRecvData, 0, 12); + rRecvData[0] = 0x85; + rRecvData[2] = 9; + memcpy(rRecvData + 3, (void *)"837-15345", 9); + *rRecvSize = 12; + break; + case 0x42: + memset(rRecvData, 0, 4); + rRecvData[0] = 0x42; + rRecvData[2] = 1; + rRecvData[3] = 0x91; + *rRecvSize = 4; + break; + default: + memset(rRecvData, 0, 3); + rRecvData[0] = sendData[0]; + *rRecvSize = 3; + break; + } + + // dprintf("Printer: C3XXusb: commCardRfidReader recv buffer: \n"); + // dump(rRecvData, *rRecvSize); + + return 1; +} + +int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_getErrorStatus(uint16_t *rBuffer) { + dprintf("Printer: C3XXusb: %s\n", __func__); + memset(rBuffer, 0, 0x80); + return 1; +} + +int chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { + dprintf("Printer: C3XXusb: %s\n", __func__); + *rResult = 0; + return 1; +} + +// copy pasted from https://dev.s-ul.net/domeori/c310emu +#define BITMAPHEADERSIZE 0x36 + +DWORD ConvertDataToBitmap( + DWORD dwBitCount, + DWORD dwWidth, DWORD dwHeight, + PBYTE pbInput, DWORD cbInput, + PBYTE pbOutput, DWORD cbOutput, + PDWORD pcbResult, + bool pFlip) { + if (!pbInput || !pbOutput || dwBitCount < 8) return -3; + + if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3; + + PBYTE pBuffer = (PBYTE)malloc(cbInput); + if (!pBuffer) return -2; + + BYTE dwColors = (BYTE)(dwBitCount / 8); + if (!dwColors) return -1; + + UINT16 cbColors; + RGBQUAD pbColors[256]; + + switch (dwBitCount) { + case 1: + cbColors = 1; + break; + case 2: + cbColors = 4; + break; + case 4: + cbColors = 16; + break; + case 8: + cbColors = 256; + break; + default: + cbColors = 0; + break; + } + + if (cbColors) { + BYTE dwStep = (BYTE)(256 / cbColors); + + for (UINT16 i = 0; i < cbColors; ++i) { + pbColors[i].rgbRed = dwStep * i; + pbColors[i].rgbGreen = dwStep * i; + pbColors[i].rgbBlue = dwStep * i; + pbColors[i].rgbReserved = 0; + } + } + + DWORD dwTable = cbColors * sizeof(RGBQUAD); + DWORD dwOffset = BITMAPHEADERSIZE + dwTable; + + // calculate the padded row size, again + DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3; + + BITMAPFILEHEADER bFile = {0}; + BITMAPINFOHEADER bInfo = {0}; + + bFile.bfType = 0x4D42; // MAGIC + bFile.bfSize = dwOffset + cbInput; + bFile.bfOffBits = dwOffset; + + bInfo.biSize = sizeof(BITMAPINFOHEADER); + bInfo.biWidth = dwWidth; + bInfo.biHeight = dwHeight; + bInfo.biPlanes = 1; + bInfo.biBitCount = (WORD)dwBitCount; + bInfo.biCompression = BI_RGB; + bInfo.biSizeImage = cbInput; + + if (cbOutput < bFile.bfSize) return -1; + + // Flip the image (if necessary) and add padding to each row + if (pFlip) { + for (size_t i = 0; i < dwHeight; i++) { + for (size_t j = 0; j < dwWidth; j++) { + for (size_t k = 0; k < dwColors; k++) { + // Calculate the position in the padded buffer + // Make sure to also flip the colors from RGB to BRG + size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1); + size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k; + *(pBuffer + x) = *(pbInput + y); + } + } + } + } else { + for (size_t i = 0; i < dwHeight; i++) { + for (size_t j = 0; j < dwWidth; j++) { + for (size_t k = 0; k < dwColors; k++) { + // Calculate the position in the padded buffer + size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1); + size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k; + *(pBuffer + x) = *(pbInput + y); + } + } + } + } + + memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER)); + memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER)); + if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable); + memcpy(pbOutput + dwOffset, pBuffer, cbInput); + + *pcbResult = bFile.bfSize; + + free(pBuffer); + return 0; +} + +DWORD WriteDataToBitmapFile( + LPCWSTR lpFilePath, DWORD dwBitCount, + DWORD dwWidth, DWORD dwHeight, + PBYTE pbInput, DWORD cbInput, + PBYTE pbMetadata, DWORD cbMetadata, + bool pFlip) { + if (!lpFilePath || !pbInput) return -3; + + HANDLE hFile; + DWORD dwBytesWritten; + + hFile = CreateFileW( + lpFilePath, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, + NULL); + if (hFile == INVALID_HANDLE_VALUE) return -1; + + // calculate the padded row size and padded image size + DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3; + DWORD dwImageSize = dwLineSize * dwHeight; + + DWORD cbResult; + DWORD cbBuffer = dwImageSize + 0x500; + PBYTE pbBuffer = (PBYTE)calloc(cbBuffer, 1); + if (!pbBuffer) return -2; + + if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) { + cbResult = -1; + goto WriteDataToBitmapFile_End; + } + + WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL); + + if (pbMetadata) + WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL); + + CloseHandle(hFile); + + cbResult = dwBytesWritten; + +WriteDataToBitmapFile_End: + free(pbBuffer); + return cbResult; +} + +DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) { +#ifdef NDEBUG + + return nDataSize; + +#else + + HANDLE hFile; + DWORD dwBytesWritten; + DWORD dwDesiredAccess; + DWORD dwCreationDisposition; + + if (isAppend) { + dwDesiredAccess = FILE_APPEND_DATA; + dwCreationDisposition = OPEN_ALWAYS; + } else { + dwDesiredAccess = GENERIC_WRITE; + dwCreationDisposition = CREATE_ALWAYS; + } + + hFile = CreateFileA( + lpOutputFilePath, + dwDesiredAccess, + FILE_SHARE_READ, + NULL, + dwCreationDisposition, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, + NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + + WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL); + CloseHandle(hFile); + + return dwBytesWritten; + +#endif +} diff --git a/hooklib/printer.h b/hooklib/printer.h new file mode 100644 index 0000000..e83ef17 --- /dev/null +++ b/hooklib/printer.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +struct printer_config { + bool enable; + bool rotate_180; + char serial_no[8]; + wchar_t main_fw_path[MAX_PATH]; + wchar_t dsp_fw_path[MAX_PATH]; + wchar_t param_fw_path[MAX_PATH]; + wchar_t printer_out_path[MAX_PATH]; +}; + +void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self); diff --git a/meson.build b/meson.build index 2032f0e..c4936be 100644 --- a/meson.build +++ b/meson.build @@ -65,6 +65,7 @@ subdir('mai2io') subdir('cmio') subdir('mercuryio') subdir('cxbio') +subdir('fgoio') subdir('chunihook') subdir('divahook') @@ -79,3 +80,4 @@ subdir('mai2hook') subdir('cmhook') subdir('mercuryhook') subdir('cxbhook') +subdir('fgohook') From 3cf5cbb793c237573375db09307be2e0e2772d2b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 12 Nov 2023 17:53:14 +0100 Subject: [PATCH 055/204] added LED 15093-06 credits and docs --- chunihook/led1509306.c | 8 +++ chusanhook/led1509306.c | 8 +++ doc/15093-06.txt | 124 ++++++++++++++++++++++++++++++++++++++++ fgohook/led1509306.c | 8 +++ 4 files changed, 148 insertions(+) create mode 100644 doc/15093-06.txt diff --git a/chunihook/led1509306.c b/chunihook/led1509306.c index 16a3b32..47fdd09 100644 --- a/chunihook/led1509306.c +++ b/chunihook/led1509306.c @@ -1,3 +1,11 @@ +/* + SEGA 837-15093-06 LED controller emulator + + Credits: + + somewhatlurker, skogaby +*/ + #include #include diff --git a/chusanhook/led1509306.c b/chusanhook/led1509306.c index c657c84..420c6f5 100644 --- a/chusanhook/led1509306.c +++ b/chusanhook/led1509306.c @@ -1,3 +1,11 @@ +/* + SEGA 837-15093-06 LED controller emulator + + Credits: + + somewhatlurker, skogaby +*/ + #include #include diff --git a/doc/15093-06.txt b/doc/15093-06.txt new file mode 100644 index 0000000..75e3011 --- /dev/null +++ b/doc/15093-06.txt @@ -0,0 +1,124 @@ +Reverse-engineered 15093-06 protocol +(somewhatlurker) + + +The host and device seem to communicate using data frames similar to (but not +the same as) jvs and the slider protocol. + +In general, the host will issue a command to the device and the device will +respond using the same command number. +The response will have source and destination addresses swapped of course. + +The host can request for future packets to not have responses, though this may +only affect certain commands such as LED data. Just something to be aware of +when implementing the system. + + +Basic packet format: `[sync] [dest] [src] [len] [data] [sum]` +sync: 0xe0 +dest: destination address +src: source address +len: length of data +data: payload +sum: sum of all prior bytes except sync + +When the host requests something from/sends something to the board, [data] will +be `[cmd] ...`. +cmd: command number +(followed by arbitrary additional data if applicable) + +When the board responds, [data] will be `[status] [cmd] [report] ...`. +status: status code + (1: Ok, 2: SumError, 3: ParityError, 4: FramingError, 5: OverRunError, + 6: RecvBfOverflow) +cmd: command number (same as the one from request) +report: report status code + (1: Ok, 2: Wait, 3: ReportError, 4: ReportError) +(followed by arbitrary additional data if applicable) + + +Escaping: +Like in JVS, the sync byte and 0xd0 are reserved. To include these in data, send +0xd0 followed by the reserved byte minus 1. (ie. `d0 cf` or `d0 df`) + + +Addresses and game-specific details: +Chunithm uses 2 for the LED boards and 1 for the host. There's two boards +present, but they are differentiated purely by COM port (one COM10, one COM11). +Based on wiring diagrams, I think COM10 should be for the left half of the +marquee display (10 pixels * 5 columns) and the left partition lights (3 pixels). +COM11 should be for the right half (6 columns) and the right partition lights. +The marquee appears to snake strips back and forth (input of first column should +be at the top). + +Ongeki seems to use 1 for the LED board and 2 for the host. It should be on +COM3. +I think the chain is left button (x2), lower left pillar (x7), left ring (x9), +upper left pillar (x7), top edge (x11), upper right pillar (x7), +right ring (x9), lower right pillar (x9), right button (x2). + + +Known Commands: +0xf0: get board info + -- chunithm host sends command with no additional data (`e0 02 01 01 f0 f4`) + -- respond with additional data `[boardno] 0a [chipno] ff [fwver] ...`, + boardno and chipno are strings (seems same as slider protocol) + -- ongeki uses 0a and ff as string terminators, not sure if that's the + intended use though + -- fwver can be found in an update filename (90 for chunithm, a0 for ongeki) + -- there's probably some additional bytes like for slider board info, but + I don't think they're important + -- pad strings with 0x20 (important!) + +0xf2: get firm sum + -- respond with additional data `[sum_upper] [sum_lower]` + -- sum can be found in an update filename (adf7 for chuni, aa53 for ongeki) + +0xf3: get protocol version + -- respond with additional data `[appli_mode] [major] [minor]`, appli_mode + is bool + -- version shouldn't matter much, but I think appli_mode should be 1 + -- try `01 01 04` + +0x11: set timeout + -- host will send with additional data `[timeout_upper] [timeout_lower]` + -- respond with additional data `[timeout_upper] [timeout_lower]` + -- 0 disables timeout + -- presumably this makes the device reset if no data is sent for a certain + time period, or maybe the device sends some kind of heartbeat within this + period + +0x10: reset + -- host will send one additional byte (d9) to choose the reset code/type + -- respond with no additional data + +0xf1: get board status + -- shouldn't be necessary to properly implement this, but if you must... + host sends with additional data `[flagclear]`, + respond with additional data `[boardflag] [uartflag] [cmdflag] [dipsw]` + -- flagclear is a bool that presumably resets error flags + -- flags are bitfields + -- boardflag: `0 0 0 0 [bor] [reset] [timeout] [wdt]` (MSB first) + -- uartflag: `0 0 [txoverflow] [rxoverflow] [overrun] [framing] [parity] [sum]` + -- cmdflag: `0 0 0 0 [exe] [param] [unknown] [busy]` + +0x14: set disable response + -- host will send with additional data `[enable]` + -- respond with additional data `[enable]` + -- it looks like setting enable to true will _disable_ responses + -- I think this makes the device not send responses for future commands + -- it might only affect LED commands + +0x82: set led direct + -- host sends 66*3 bytes for rgb as additional data + -- respond with no additional data + +0x86: set led count + -- host sends additional data `[count]` + -- respond with additional data `[count]` + -- probably just affects the output from the board to LEDs, + neither chuni nor ongeki use this + +0xfd: enter bootloader + -- no real point implementing this, just interesting + -- MCU might be an ATMega 32M1 btw, but I'm not sure \ No newline at end of file diff --git a/fgohook/led1509306.c b/fgohook/led1509306.c index 17f3451..e922738 100644 --- a/fgohook/led1509306.c +++ b/fgohook/led1509306.c @@ -1,3 +1,11 @@ +/* + SEGA 837-15093-06 LED controller emulator + + Credits: + + somewhatlurker, skogaby +*/ + #include #include From 146fac92876cf0b9a6dbc9be90c0596534bb62d3 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 12 Nov 2023 21:16:02 +0100 Subject: [PATCH 056/204] dns: block more All.NET requests --- platform/dns.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/platform/dns.c b/platform/dns.c index e2c5905..f8c2f60 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -40,6 +40,24 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + hr = dns_hook_push(L"op.auth.sys-all.net", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + + hr = dns_hook_push(L"at.auth.sys-all.net", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + + hr = dns_hook_push(L"at.sys-all.net", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + hr = dns_hook_push(L"ib.naominet.jp", cfg->billing); if (FAILED(hr)) { From b9fd59fd70df1bfa7e08b388ebcfe29527c670cc Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 20 Nov 2023 18:04:45 +0100 Subject: [PATCH 057/204] idz: added fullscreen patch by @Felix (again) --- dist/idz/segatools.ini | 11 +++++++++++ idzhook/dllmain.c | 4 ---- idzhook/idzhook.def | 5 +++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 3fae262..c7fa88b 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -47,6 +47,17 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.158.0 +[gfx] +; Enables the graphics hook. This is required for some Initial D Zero versions +; for example v1.31 and v2.11 to run properly in fullscreen. +enable=0 +; Force the game to run windowed. +windowed=0 +; Add a frame to the game window if running windowed. +framed=1 +; Select the monitor to run the game on. (Fullscreen only, 0=primary screen) +monitor=0 + [gpio] ; Emulated Nu DIP switch for Distribution Server setting. ; diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index b358470..10b3ce5 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -45,7 +45,6 @@ static DWORD CALLBACK idz_pre_startup(void) idz_hook_config_load(&idz_hook_cfg, L".\\segatools.ini"); - /* module_path = module_file_name(NULL); if (module_path != NULL) { @@ -64,16 +63,13 @@ static DWORD CALLBACK idz_pre_startup(void) module_path = NULL; } - */ /* Hook Win32 APIs */ serial_hook_init(); - /* gfx_hook_init(&idz_hook_cfg.gfx); gfx_d3d11_hook_init(&idz_hook_cfg.gfx, idz_hook_mod); gfx_dxgi_hook_init(&idz_hook_cfg.gfx, idz_hook_mod); - */ zinput_hook_init(&idz_hook_cfg.zinput); dvd_hook_init(&idz_hook_cfg.dvd, idz_hook_mod); diff --git a/idzhook/idzhook.def b/idzhook/idzhook.def index 486400c..d8db3b0 100644 --- a/idzhook/idzhook.def +++ b/idzhook/idzhook.def @@ -1,6 +1,11 @@ LIBRARY idzhook EXPORTS + CreateDXGIFactory + CreateDXGIFactory1 + CreateDXGIFactory2 + D3D11CreateDevice + D3D11CreateDeviceAndSwapChain aime_io_get_api_version aime_io_init aime_io_led_set_color From d86baab852e74e3c1e68b72619d35568476a6369 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 22 Nov 2023 21:40:10 +0100 Subject: [PATCH 058/204] fgo: working FTDI hook by @OLEG from: https://dev.s-ul.net/OLEG/segatools-kancolle/-/commit/88a0026f0b2fbedf71fcc2b2736d6f8d27a072e2 --- README.md | 17 ++-- dist/fgo/segatools.ini | 7 +- fgohook/config.c | 3 +- fgohook/deck.c | 6 +- fgohook/deck.h | 2 +- fgohook/dllmain.c | 2 - fgohook/ftdi.c | 176 ++++++++++++++++++++++++++++++++++++++++- fgohook/ftdi.h | 1 + hooklib/setupapi.c | 147 ++++++++++++++++++++++++++++++++++ 9 files changed, 341 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7077fde..d24c497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Segatools -Version: `2023-07-14` +Version: `2023-11-22` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. @@ -12,19 +12,22 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo * [Chunithm Star (Plus)](doc/chunihook.md) * [Chunithm Amazon (Plus)](doc/chunihook.md) * [Chunithm Crystal (Plus)](doc/chunihook.md) + * Chunithm SUN * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) - * Initial D The Arcade + * Initial D THE ARCADE * SEGA World Drivers Championship - * SEGA World Drivers Championship 2019 + * up to SEGA World Drivers Championship 2019 +* Fate/Grand Order + * Fate/Grand Order Arcade * ONGEKI - * bright MEMORY + * up to bright MEMORY * maimai DX - * maimai DX FESTiVAL + * up to maimai DX FESTiVAL PLUS * Card Maker - * Card Maker 1.35 + * up to Card Maker 1.35 * Wacca - * Wacca Lilly R (WIP) + * up to WACCA Reverse ## End-users diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 67c0f91..0d99009 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -55,12 +55,13 @@ rotate180=1 ; 837-15345 RFID deck reader emulation setting. enable=1 +[ftdi] +; FTDI serial to usb adapter emulation for CABINET LED. +enable=1 + [ledstrip] ; 837-15093-06 LED strip emulation setting. enable=1 -; FTDI board currently not working properly. Use com0com (Create a virtual pair -; for 21 and 51) or use any USB to Serial Adapter. -port=21 ; ----------------------------------------------------------------------------- ; Input settings diff --git a/fgohook/config.c b/fgohook/config.c index d6971ac..be6bdd0 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -32,6 +32,7 @@ void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"port", 17, filename); } void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) @@ -45,7 +46,7 @@ void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filena memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 21, filename); + cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 17, filename); cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename); cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); diff --git a/fgohook/deck.c b/fgohook/deck.c index e712724..b8e4bed 100644 --- a/fgohook/deck.c +++ b/fgohook/deck.c @@ -129,7 +129,7 @@ static struct card_collection* cards_ptr; static uint8_t current_card_idx = 0; static bool read_pending = false; -HRESULT deck_hook_init(const struct deck_config *cfg, int port) +HRESULT deck_hook_init(const struct deck_config *cfg, unsigned int port_no) { assert(cfg != NULL); @@ -139,7 +139,7 @@ HRESULT deck_hook_init(const struct deck_config *cfg, int port) InitializeCriticalSection(&deck_lock); - uart_init(&deck_uart, port); + uart_init(&deck_uart, port_no); deck_uart.written.bytes = deck_written_bytes; deck_uart.written.nbytes = sizeof(deck_written_bytes); deck_uart.readable.bytes = deck_readable_bytes; @@ -398,6 +398,8 @@ static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src) { assert(src->bytes != NULL || src->nbytes == 0); assert(src->pos <= src->nbytes); + deck_frame_sync(src); + dest->pos = 0; escape = false; diff --git a/fgohook/deck.h b/fgohook/deck.h index 32c1ef9..c8e5f6d 100644 --- a/fgohook/deck.h +++ b/fgohook/deck.h @@ -8,4 +8,4 @@ struct deck_config { bool enable; }; -HRESULT deck_hook_init(const struct deck_config *cfg, int port); +HRESULT deck_hook_init(const struct deck_config *cfg, unsigned int port_no); diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 69269b5..2c3af8e 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -90,13 +90,11 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - /* hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); if (FAILED(hr)) { goto fail; } - */ hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index 50b7d11..bda7507 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -8,15 +8,22 @@ The game queries the presence of the FTDI board itself, followed by a registry check to see which port number is assigned to the FTDI board. If these fail, the "CABINET LED" check on startup will always return "NG". + + Credits: + + OLEG */ #include - +#include +#include #include +#include #include "fgohook/ftdi.h" #include "hook/iohook.h" +#include "hook/table.h" #include "hooklib/setupapi.h" @@ -24,10 +31,97 @@ static struct ftdi_config ftdi_cfg; -static HANDLE ftdi_fd; -HRESULT ftdi_hook_init(const struct ftdi_config *cfg) -{ +static BOOL WINAPI hook_SetupDiGetDeviceRegistryPropertyA( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Property, + uint32_t *PropertyRegDataType, + void *PropertyBuffer, + uint32_t PropertyBufferSize, + uint32_t *RequiredSize +); + +static HKEY WINAPI hook_SetupDiOpenDevRegKey( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Scope, + uint32_t HwProfile, + uint32_t KeyType, + REGSAM samDesired +); + +static LSTATUS WINAPI hook_RegQueryValueExA( + HKEY handle, + const char *name, + void *reserved, + uint32_t *type, + void *bytes, + uint32_t *nbytes); + +static LSTATUS WINAPI hook_RegCloseKey(HKEY handle); + + +static BOOL (WINAPI *next_SetupDiGetDeviceRegistryPropertyA)( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Property, + uint32_t *PropertyRegDataType, + void *PropertyBuffer, + uint32_t PropertyBufferSize, + uint32_t *RequiredSize +); + +static HKEY (WINAPI *next_SetupDiOpenDevRegKey)( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Scope, + uint32_t HwProfile, + uint32_t KeyType, + REGSAM samDesired +); + +static LSTATUS (WINAPI *next_RegQueryValueExA)( + HKEY handle, + const char *name, + void *reserved, + uint32_t *type, + void *bytes, + uint32_t *nbytes); + +static LSTATUS (WINAPI *next_RegCloseKey)(HKEY handle); + + +static const struct hook_symbol setupapi_syms[] = { + { + .name = "SetupDiGetDeviceRegistryPropertyA", + .patch = hook_SetupDiGetDeviceRegistryPropertyA, + .link = (void *) &next_SetupDiGetDeviceRegistryPropertyA, + }, { + .name = "SetupDiOpenDevRegKey", + .patch = hook_SetupDiOpenDevRegKey, + .link = (void *) &next_SetupDiOpenDevRegKey, + } +}; + +static const struct hook_symbol reg_syms[] = { + { + .name = "RegQueryValueExA", + .patch = hook_RegQueryValueExA, + .link = (void *) &next_RegQueryValueExA, + }, { + .name = "RegCloseKey", + .patch = hook_RegCloseKey, + .link = (void *) &next_RegCloseKey, + } +}; + +#define device_fake_key 0xDEADBEEF + +static HANDLE ftdi_fd; +static char port_name[8]; + +HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { HRESULT hr; assert(cfg != NULL); @@ -36,6 +130,18 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) return S_FALSE; } + hook_table_apply( + NULL, + "setupapi.dll", + setupapi_syms, + _countof(setupapi_syms)); + + hook_table_apply( + NULL, + "advapi32.dll", + reg_syms, + _countof(reg_syms)); + memcpy(&ftdi_cfg, cfg, sizeof(*cfg)); hr = iohook_open_nul_fd(&ftdi_fd); @@ -50,6 +156,68 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) return hr; } + sprintf(port_name, "COM%d", cfg->port_no); + dprintf("FTDI: Hook enabled.\n"); return S_OK; } + +static BOOL WINAPI hook_SetupDiGetDeviceRegistryPropertyA( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Property, + uint32_t *PropertyRegDataType, + void *PropertyBuffer, + uint32_t PropertyBufferSize, + uint32_t *RequiredSize +) { + if (!PropertyBuffer || PropertyBufferSize == 0) { + *RequiredSize = 16; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + *PropertyRegDataType = 1; + return TRUE; +} + +static HKEY WINAPI hook_SetupDiOpenDevRegKey( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + uint32_t Scope, + uint32_t HwProfile, + uint32_t KeyType, + REGSAM samDesired +) { + return (HKEY) device_fake_key; +} + +static LSTATUS WINAPI hook_RegCloseKey(HKEY handle) { + if (handle == (HKEY) device_fake_key) + return ERROR_SUCCESS; + + return next_RegCloseKey(handle); +} + +static LSTATUS WINAPI hook_RegQueryValueExA( + HKEY handle, + const char *name, + void *reserved, + uint32_t *type, + void *bytes, + uint32_t *nbytes) { + if (handle == (HKEY) device_fake_key && !strcmp(name, "PortName")) { + strcpy(bytes, port_name); + *nbytes = 5; + *type = 1; + return ERROR_SUCCESS; + } + + return next_RegQueryValueExA( + handle, + name, + reserved, + type, + bytes, + nbytes); +} diff --git a/fgohook/ftdi.h b/fgohook/ftdi.h index c40fb3b..e1cd9d6 100644 --- a/fgohook/ftdi.h +++ b/fgohook/ftdi.h @@ -8,6 +8,7 @@ struct ftdi_config { bool enable; + uint32_t port_no; }; DEFINE_GUID( diff --git a/hooklib/setupapi.c b/hooklib/setupapi.c index edd416a..6f4fbb5 100644 --- a/hooklib/setupapi.c +++ b/hooklib/setupapi.c @@ -16,6 +16,7 @@ struct setupapi_class { const GUID *guid; const wchar_t *path; + char *a_path; HDEVINFO cur_handle; }; @@ -29,6 +30,12 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW( HWND hwndParent, DWORD Flags); +static HDEVINFO WINAPI my_SetupDiGetClassDevsA( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static BOOL WINAPI my_SetupDiEnumDeviceInterfaces( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -44,6 +51,14 @@ static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailW( DWORD *RequiredSize, SP_DEVINFO_DATA *DeviceInfoData); +static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA( + HDEVINFO DeviceInfoSet, + SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData, + SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData, + DWORD DeviceInterfaceDetailDataSize, + DWORD *RequiredSize, + SP_DEVINFO_DATA *DeviceInfoData); + static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); /* Links */ @@ -54,6 +69,12 @@ static HDEVINFO (WINAPI *next_SetupDiGetClassDevsW)( HWND hwndParent, DWORD Flags); +static HDEVINFO (WINAPI *next_SetupDiGetClassDevsA)( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags); + static BOOL (WINAPI *next_SetupDiEnumDeviceInterfaces)( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -69,6 +90,14 @@ static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailW)( DWORD *RequiredSize, SP_DEVINFO_DATA *DeviceInfoData); +static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailA)( + HDEVINFO DeviceInfoSet, + SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData, + SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData, + DWORD DeviceInterfaceDetailDataSize, + DWORD *RequiredSize, + SP_DEVINFO_DATA *DeviceInfoData); + static BOOL (WINAPI *next_SetupDiDestroyDeviceInfoList)(HDEVINFO DeviceInfoSet); /* Hook tbl */ @@ -78,6 +107,10 @@ static const struct hook_symbol setupapi_syms[] = { .name = "SetupDiGetClassDevsW", .patch = my_SetupDiGetClassDevsW, .link = (void *) &next_SetupDiGetClassDevsW, + }, { + .name = "SetupDiGetClassDevsA", + .patch = my_SetupDiGetClassDevsA, + .link = (void *) &next_SetupDiGetClassDevsA, }, { .name = "SetupDiEnumDeviceInterfaces", .patch = my_SetupDiEnumDeviceInterfaces, @@ -86,6 +119,10 @@ static const struct hook_symbol setupapi_syms[] = { .name = "SetupDiGetDeviceInterfaceDetailW", .patch = my_SetupDiGetDeviceInterfaceDetailW, .link = (void *) &next_SetupDiGetDeviceInterfaceDetailW, + }, { + .name = "SetupDiGetDeviceInterfaceDetailA", + .patch = my_SetupDiGetDeviceInterfaceDetailA, + .link = (void *) &next_SetupDiGetDeviceInterfaceDetailA, }, { .name = "SetupDiDestroyDeviceInfoList", .patch = my_SetupDiDestroyDeviceInfoList, @@ -102,6 +139,7 @@ HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path) { struct setupapi_class *class_; struct setupapi_class *new_array; + size_t a_path_len; HRESULT hr; assert(iface_class != NULL); @@ -126,6 +164,11 @@ HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path) class_ = &setupapi_classes[setupapi_nclasses++]; class_->guid = iface_class; class_->path = path; + + a_path_len = wcslen(path) * sizeof(wchar_t) + 1; + class_->a_path = (char*)malloc(a_path_len); + wcstombs(class_->a_path, path, a_path_len); + hr = S_OK; end: @@ -189,6 +232,40 @@ static HDEVINFO WINAPI my_SetupDiGetClassDevsW( return result; } +static HDEVINFO WINAPI my_SetupDiGetClassDevsA( + const GUID *ClassGuid, + char *Enumerator, + HWND hwndParent, + DWORD Flags) +{ + struct setupapi_class *class_; + HDEVINFO result; + size_t i; + + result = next_SetupDiGetClassDevsA( + ClassGuid, + Enumerator, + hwndParent, + Flags); + + if (result == INVALID_HANDLE_VALUE || ClassGuid == NULL) { + return result; + } + + EnterCriticalSection(&setupapi_lock); + + for (i = 0 ; i < setupapi_nclasses ; i++) { + class_ = &setupapi_classes[i]; + if (memcmp(ClassGuid, class_->guid, sizeof(*ClassGuid)) == 0) { + class_->cur_handle = result; + } + } + + LeaveCriticalSection(&setupapi_lock); + + return result; +} + static BOOL WINAPI my_SetupDiEnumDeviceInterfaces( HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA *DeviceInfoData, @@ -322,6 +399,76 @@ pass: DeviceInfoData); } +static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA( + HDEVINFO DeviceInfoSet, + SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData, + SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData, + DWORD DeviceInterfaceDetailDataSize, + DWORD *RequiredSize, + SP_DEVINFO_DATA *DeviceInfoData) +{ + const char *str; + size_t nbytes_str; + size_t nbytes_total; + size_t i; + bool match; + + if (DeviceInfoSet == INVALID_HANDLE_VALUE || DeviceInterfaceData == NULL) { + goto pass; + } + + EnterCriticalSection(&setupapi_lock); + + for (i = 0, match = false; i < setupapi_nclasses && !match; i++) { + if (DeviceInfoSet == setupapi_classes[i].cur_handle && + DeviceInterfaceData->Reserved == (ULONG_PTR) setupapi_classes[i].path) { + str = setupapi_classes[i].a_path; + match = true; + } + } + + LeaveCriticalSection(&setupapi_lock); + + if (!match) { + goto pass; + } + + nbytes_str = strlen(str) + 1; + nbytes_total = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath); + nbytes_total += nbytes_str; + + if (RequiredSize != NULL) { + *RequiredSize = (DWORD) nbytes_total; + } + + if ( DeviceInterfaceDetailData == NULL && + DeviceInterfaceDetailDataSize < nbytes_total) { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + + return FALSE; + } + + if (DeviceInterfaceDetailData->cbSize!=sizeof(*DeviceInterfaceDetailData)) { + SetLastError(ERROR_INVALID_PARAMETER); + + return FALSE; + } + + memcpy(DeviceInterfaceDetailData->DevicePath, str, nbytes_str); + SetLastError(ERROR_SUCCESS); + + return TRUE; + + pass: + return next_SetupDiGetDeviceInterfaceDetailA( + DeviceInfoSet, + DeviceInterfaceData, + DeviceInterfaceDetailData, + DeviceInterfaceDetailDataSize, + RequiredSize, + DeviceInfoData); +} + static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet) { size_t i; From 8b1d0cfefaf8b197bc09f139c8a5f41a3bbfe38e Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sat, 25 Nov 2023 23:00:05 +0100 Subject: [PATCH 059/204] LED board improvements and cleanup --- board/led15093-cmd.h | 222 ++++ .../{led1509306-frame.c => led15093-frame.c} | 50 +- board/led15093-frame.h | 34 + board/led15093.c | 1112 +++++++++++++++++ board/led15093.h | 22 + board/led1509306-cmd.h | 45 - board/led1509306-frame.h | 26 - board/meson.build | 8 +- chunihook/config.c | 56 +- chunihook/config.h | 4 +- chunihook/dllmain.c | 3 +- chunihook/led1509306.c | 385 ------ chunihook/led1509306.h | 15 - chunihook/meson.build | 2 - chusanhook/config.c | 68 +- chusanhook/config.h | 4 +- chusanhook/dllmain.c | 3 +- chusanhook/led1509306.c | 397 ------ chusanhook/meson.build | 2 - dist/chuni/segatools.ini | 4 + dist/chusan/segatools.ini | 39 +- dist/fgo/segatools.ini | 8 +- fgohook/config.c | 57 +- fgohook/config.h | 4 +- fgohook/dllmain.c | 4 +- fgohook/ftdi.c | 8 +- fgohook/ftdi.h | 2 +- fgohook/led1509306.c | 387 ------ fgohook/led1509306.h | 16 - fgohook/meson.build | 2 - 30 files changed, 1610 insertions(+), 1379 deletions(-) create mode 100644 board/led15093-cmd.h rename board/{led1509306-frame.c => led15093-frame.c} (72%) create mode 100644 board/led15093-frame.h create mode 100644 board/led15093.c create mode 100644 board/led15093.h delete mode 100644 board/led1509306-cmd.h delete mode 100644 board/led1509306-frame.h delete mode 100644 chunihook/led1509306.c delete mode 100644 chunihook/led1509306.h delete mode 100644 chusanhook/led1509306.c delete mode 100644 fgohook/led1509306.c delete mode 100644 fgohook/led1509306.h diff --git a/board/led15093-cmd.h b/board/led15093-cmd.h new file mode 100644 index 0000000..5648de6 --- /dev/null +++ b/board/led15093-cmd.h @@ -0,0 +1,222 @@ +#pragma once + +#include "board/led15093-frame.h" + +/* Command IDs */ + +enum { + LED_15093_CMD_RESET = 0x10, + LED_15093_CMD_SET_TIMEOUT = 0x11, + LED_15093_CMD_UNK1 = 0x12, + LED_15093_CMD_SET_DISABLE_RESPONSE = 0x14, + LED_15093_CMD_SET_ID = 0x18, + LED_15093_CMD_CLEAR_ID = 0x19, + LED_15093_CMD_SET_MAX_BRIGHT = 0x3F, // TODO + LED_15093_CMD_UPDATE_LED = 0x80, + LED_15093_CMD_SET_LED = 0x81, + LED_15093_CMD_SET_IMM_LED = 0x82, + LED_15093_CMD_SET_FADE_LED = 0x83, + LED_15093_CMD_SET_FADE_LEVEL = 0x84, + LED_15093_CMD_SET_FADE_SHIFT = 0x85, + LED_15093_CMD_SET_AUTO_SHIFT = 0x86, + LED_15093_CMD_GET_BOARD_INFO = 0xF0, + LED_15093_CMD_GET_BOARD_STATUS = 0xF1, + LED_15093_CMD_GET_FW_SUM = 0xF2, + LED_15093_CMD_GET_PROTOCOL_VER = 0xF3, + LED_15093_CMD_SET_BOOTMODE = 0xFD, + LED_15093_CMD_FW_UPDATE = 0xFE, +}; + +/* Response codes */ + +enum { + LED_15093_STATUS_OK = 0x01, + LED_15093_STATUS_ERR_SUM = 0x02, + LED_15093_STATUS_ERR_PARITY = 0x03, + LED_15093_STATUS_ERR_FRAMING = 0x04, + LED_15093_STATUS_ERR_OVERRUN = 0x05, + LED_15093_STATUS_ERR_BUFFER_OVERFLOW = 0x06, +}; + +enum { + LED_15093_REPORT_OK = 0x01, + LED_15093_REPORT_WAIT = 0x02, + LED_15093_REPORT_ERR1 = 0x03, + LED_15093_REPORT_ERR2 = 0x04, +}; + +/* Status bitmasks */ + +enum { + LED_15093_STATUS_UART_ERR_SUM = 0x01, + LED_15093_STATUS_UART_ERR_PARITY = 0x02, + LED_15093_STATUS_UART_ERR_FRAMING = 0x04, + LED_15093_STATUS_UART_ERR_OVERRUN = 0x08, + LED_15093_STATUS_UART_ERR_BUFFER_OVERFLOW = 0x10, +}; + +enum { + LED_15093_STATUS_BOARD_ERR_WDT = 0x01, + LED_15093_STATUS_BOARD_ERR_TIMEOUT = 0x02, + LED_15093_STATUS_BOARD_ERR_RESET = 0x04, + LED_15093_STATUS_BOARD_ERR_BOR = 0x08, +}; + +enum { + LED_15093_STATUS_CMD_ERR_BUSY = 0x01, + LED_15093_STATUS_CMD_ERR_UNKNOWN = 0x02, + LED_15093_STATUS_CMD_ERR_PARAM = 0x04, + LED_15093_STATUS_CMD_ERR_EXE = 0x08, +}; + +/* Status types for internal use */ + +enum { + LED_15093_STATUS_TYPE_BOARD = 1, + LED_15093_STATUS_TYPE_UART = 2, + LED_15093_STATUS_TYPE_CMD = 3, +}; + +/* Request data structures */ + +struct led15093_req_reset { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t r_type; +}; + +struct led15093_req_set_timeout { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t count; +}; + +struct led15093_req_set_disable_response { + struct led15093_req_hdr hdr; + uint8_t cmd; + bool sw; +}; + +struct led15093_req_set_id { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t id; +}; + +struct led15093_req_set_led { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t data[198]; +}; + +struct led15093_req_set_fade_level { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t depth; + uint8_t cycle; +}; + +struct led15093_req_set_fade_shift { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t target; +}; + +struct led15093_req_set_auto_shift { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t count; + uint8_t target; +}; + +struct led15093_req_get_board_status { + struct led15093_req_hdr hdr; + uint8_t cmd; + bool clear; +}; + +union led15093_req_any { + struct led15093_req_hdr hdr; + struct led15093_req_reset reset; + struct led15093_req_set_timeout set_timeout; + struct led15093_req_set_disable_response set_disable_response; + struct led15093_req_set_id set_id; + struct led15093_req_set_led set_led; + struct led15093_req_set_fade_level set_fade_level; + struct led15093_req_set_fade_shift set_fade_shift; + struct led15093_req_set_auto_shift set_auto_shift; + struct led15093_req_get_board_status get_board_status; + uint8_t payload[256]; +}; + +/* Response data structures */ + +struct led15093_resp_any { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t data[32]; +}; + +struct led15093_resp_timeout { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t count_upper; + uint8_t count_lower; +}; + +struct led15093_resp_fw_sum { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t sum_upper; + uint8_t sum_lower; +}; + +struct led15093_resp_board_info_legacy { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + char board_num[8]; + uint8_t lf; // 0x0A (ASCII LF) + char chip_num[5]; + uint8_t endcode; // Always 0xFF + uint8_t fw_ver; +}; + +struct led15093_resp_board_info { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + char board_num[8]; + uint8_t lf; // 0x0A (ASCII LF) + char chip_num[5]; + uint8_t endcode; // Always 0xFF + uint8_t fw_ver; + uint8_t rx_buf; +}; + +struct led15093_resp_protocol_ver { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t mode; + uint8_t major_ver; + uint8_t minor_ver; +}; + +struct led15093_resp_set_auto_shift { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t count; + uint8_t target; +}; diff --git a/board/led1509306-frame.c b/board/led15093-frame.c similarity index 72% rename from board/led1509306-frame.c rename to board/led15093-frame.c index 8e11e8c..844f4bf 100644 --- a/board/led1509306-frame.c +++ b/board/led15093-frame.c @@ -5,13 +5,13 @@ #include #include -#include "board/led1509306-frame.h" +#include "board/led15093-frame.h" #include "hook/iobuf.h" -static void led1509306_frame_sync(struct iobuf *src); -static HRESULT led1509306_frame_accept(const struct iobuf *dest); -static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte); +static void led15093_frame_sync(struct iobuf *src); +static HRESULT led15093_frame_accept(const struct iobuf *dest); +static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte); /* Frame structure: @@ -34,17 +34,17 @@ static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte); 0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */ -static void led1509306_frame_sync(struct iobuf *src) +static void led15093_frame_sync(struct iobuf *src) { size_t i; - for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++); + for (i = 0 ; i < src->pos && src->bytes[i] != LED_15093_FRAME_SYNC ; i++); src->pos -= i; memmove(&src->bytes[0], &src->bytes[i], i); } -static HRESULT led1509306_frame_accept(const struct iobuf *dest) +static HRESULT led15093_frame_accept(const struct iobuf *dest) { uint8_t checksum; size_t i; @@ -58,9 +58,9 @@ static HRESULT led1509306_frame_accept(const struct iobuf *dest) for (i = 1 ; i < dest->pos - 1 ; i++) { checksum += dest->bytes[i]; } - - //dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]); - + + // dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]); + if (checksum != dest->bytes[dest->pos - 1]) { return HRESULT_FROM_WIN32(ERROR_CRC); } @@ -68,7 +68,7 @@ static HRESULT led1509306_frame_accept(const struct iobuf *dest) return S_OK; } -HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) +HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src) { uint8_t byte; bool escape; @@ -82,7 +82,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) assert(src->bytes != NULL || src->nbytes == 0); assert(src->pos <= src->nbytes); - led1509306_frame_sync(src); + led15093_frame_sync(src); dest->pos = 0; escape = false; @@ -96,9 +96,9 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } else if (i == 0) { dest->bytes[dest->pos++] = byte; - } else if (byte == 0xE0) { + } else if (byte == LED_15093_FRAME_SYNC) { hr = E_FAIL; - } else if (byte == 0xD0) { + } else if (byte == LED_15093_FRAME_ESC) { if (escape) { hr = E_FAIL; } @@ -114,7 +114,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) /* Try to accept the packet we've built up so far */ if (SUCCEEDED(hr)) { - hr = led1509306_frame_accept(dest); + hr = led15093_frame_accept(dest); } } @@ -129,7 +129,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) return hr; } -HRESULT led1509306_frame_encode( +HRESULT led15093_frame_encode( struct iobuf *dest, const void *ptr, size_t nbytes) @@ -147,22 +147,24 @@ HRESULT led1509306_frame_encode( src = ptr; - assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes); + assert(nbytes >= 3 && + src[0] == LED_15093_FRAME_SYNC && + src[3] + 4 == nbytes); if (dest->pos >= dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } - dest->bytes[dest->pos++] = 0xE0; + dest->bytes[dest->pos++] = LED_15093_FRAME_SYNC; checksum = 0; - // dprintf("%02x ", 0xe0); + // dprintf("%02x ", LED_15093_FRAME_SYNC); for (i = 1 ; i < nbytes ; i++) { byte = src[i]; checksum += byte; // dprintf("%02x ", byte); - hr = led1509306_frame_encode_byte(dest, byte); + hr = led15093_frame_encode_byte(dest, byte); if (FAILED(hr)) { return hr; @@ -170,17 +172,17 @@ HRESULT led1509306_frame_encode( } // dprintf("%02x \n", checksum); - return led1509306_frame_encode_byte(dest, checksum); + return led15093_frame_encode_byte(dest, checksum); } -static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte) +static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte) { - if (byte == 0xE0 || byte == 0xD0) { + if (byte == LED_15093_FRAME_SYNC || byte == LED_15093_FRAME_ESC) { if (dest->pos + 2 > dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } - dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = LED_15093_FRAME_ESC; dest->bytes[dest->pos++] = byte - 1; } else { if (dest->pos + 1 > dest->nbytes) { diff --git a/board/led15093-frame.h b/board/led15093-frame.h new file mode 100644 index 0000000..2311eb6 --- /dev/null +++ b/board/led15093-frame.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + LED_15093_FRAME_SYNC = 0xE0, + LED_15093_FRAME_ESC = 0xD0, +}; + +struct led15093_req_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +struct led15093_resp_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src); + +HRESULT led15093_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/led15093.c b/board/led15093.c new file mode 100644 index 0000000..c00e39f --- /dev/null +++ b/board/led15093.c @@ -0,0 +1,1112 @@ +/* + SEGA 837-15093-XX LED Controller Board emulator + + Supported variants: + + 837-15093 + 837-15093-01 + 837-15093-04 + 837-15093-05 + 837-15093-06 + + Credits: + 837-15093-XX LED Controller Board emulator (emihiok) + 837-15093-06 LED Controller Board emulator (somewhatlurker, skogaby) +*/ + +#include + +#include +#include +#include +#include +#include + +#include "board/led15093-cmd.h" +#include "board/led15093-frame.h" + +#include "board/led15093.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/str.h" +#include "util/dump.h" + +#define led15093_nboards 2 +#define led15093_nnodes 1 + +#define led15093_led_count_max 66 + +typedef struct { + uint8_t boardadr; + uint8_t boardstatus[4]; + uint8_t fade_depth; + uint8_t fade_cycle; + uint8_t led[led15093_led_count_max][3]; + uint8_t led_bright[led15093_led_count_max][3]; + uint8_t led_count; + uint8_t status_code; + uint8_t report_code; + bool enable_bootloader; + bool enable_response; +} _led15093_per_node_vars; + +typedef struct { + CRITICAL_SECTION lock; + bool started; + HRESULT start_hr; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + _led15093_per_node_vars per_node_vars[led15093_nnodes]; +} _led15093_per_board_vars; + +_led15093_per_board_vars led15093_per_board_vars[led15093_nboards]; + +static HRESULT led15093_handle_irp(struct irp *irp); +static HRESULT led15093_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led15093_req_dispatch(int board, const union led15093_req_any *req); +static HRESULT led15093_req_reset(int board, const struct led15093_req_reset *req); +static HRESULT led15093_req_set_timeout(int board, const struct led15093_req_set_timeout *req); +static HRESULT led15093_req_set_response(int board, const struct led15093_req_set_disable_response *req); +static HRESULT led15093_req_set_id(int board, const struct led15093_req_set_id *req); +static HRESULT led15093_req_clear_id(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_max_bright(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_update_led(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_fade_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_fade_level(int board, const struct led15093_req_set_fade_level *req); +static HRESULT led15093_req_set_fade_shift(int board, const struct led15093_req_set_fade_shift *req); +static HRESULT led15093_req_set_auto_shift(int board, const struct led15093_req_set_auto_shift *req); +static HRESULT led15093_req_get_board_info(int board, const union led15093_req_any *req); +static HRESULT led15093_req_get_board_status(int board, const struct led15093_req_get_board_status *req); +static HRESULT led15093_req_get_fw_sum(int board, const union led15093_req_any *req); +static HRESULT led15093_req_get_protocol_ver(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_bootmode(int board, const union led15093_req_any *req); +static HRESULT led15093_req_fw_update(int board, const union led15093_req_any *req); + +static void led15093_set_status(int board, int id, uint8_t type, uint8_t status); +static void led15093_set_report(int board, int id, uint8_t report); +static void led15093_clear_status(int board, int id); +static void led15093_clear_report(int board, int id); + +static char led15093_board_num[8]; +static char led15093_chip_num[5]; +static char led15093_boot_chip_num[5]; +static uint8_t led15093_fw_ver; +static uint16_t led15093_fw_sum; +static uint8_t led15093_host_adr = 255; + +HRESULT led15093_hook_init( + const struct led15093_config *cfg, + unsigned int port_no_0, + unsigned int port_no_1) +{ + assert(cfg != NULL); + unsigned int port_no[2] = {port_no_0, port_no_1}; + + if (!cfg->enable) { + return S_FALSE; + } + + for (int i = 0; i < led15093_nboards; i++) { + if (cfg->port_no[i] != 0) { + port_no[i] = cfg->port_no[i]; + } + } + + memcpy(led15093_board_num, cfg->board_number, sizeof(led15093_board_num)); + memcpy(led15093_chip_num, cfg->chip_number, sizeof(led15093_chip_num)); + memcpy(led15093_boot_chip_num, cfg->boot_chip_number, sizeof(led15093_boot_chip_num)); + led15093_fw_ver = cfg->fw_ver; + led15093_fw_sum = cfg->fw_sum; + + for (int i = 0; i < led15093_nboards; i++) + { + _led15093_per_board_vars *vb = &led15093_per_board_vars[i]; + + InitializeCriticalSection(&vb->lock); + + if (port_no[i] == 0) { + continue; + } + + uart_init(&vb->boarduart, port_no[i]); + if (cfg->high_baudrate) { + vb->boarduart.baud.BaudRate = 460800; + } else { + vb->boarduart.baud.BaudRate = 115200; + } + vb->boarduart.written.bytes = vb->written_bytes; + vb->boarduart.written.nbytes = sizeof(vb->written_bytes); + vb->boarduart.readable.bytes = vb->readable_bytes; + vb->boarduart.readable.nbytes = sizeof(vb->readable_bytes); + + for (int j = 0; j < led15093_nnodes; j++) + { + _led15093_per_node_vars *vn = &vb->per_node_vars[j]; + + memset(vn->led, 0, sizeof(vn->led)); + memset(vn->led_bright, 0x3F, sizeof(vn->led_bright)); + vn->led_count = led15093_led_count_max; + vn->fade_depth = 32; + vn->fade_cycle = 8; + led15093_clear_status(i, 1 + j); + led15093_clear_report(i, 1 + j); + vn->boardstatus[3] = 1; // DIPSW1 ON + vn->boardadr = 1 + j; + vn->enable_bootloader = false; + vn->enable_response = true; + } + } + + dprintf("LED 15093: hook enabled.\n"); + + return iohook_push_handler(led15093_handle_irp); +} + +static HRESULT led15093_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led15093_nboards; i++) + { + _led15093_per_board_vars *v = &led15093_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led15093_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) +{ + union led15093_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + _led15093_per_board_vars *v = &led15093_per_board_vars[board]; + struct uart *boarduart = &led15093_per_board_vars[board].boarduart; + + /* + if (irp->op == IRP_OP_OPEN) { + // Unfortunately the LED board UART gets opened and closed repeatedly + + if (!v->started) { + dprintf("LED 15093: Starting LED backend\n"); + // hr = fgo_dll.led_init(); + hr = S_OK; + + v->started = true; + v->start_hr = hr; + + if (FAILED(hr)) { + dprintf("LED 15093: Backend error, LED board disconnected: " + "%x\n", + (int) hr); + + return hr; + } + } else { + hr = v->start_hr; + + if (FAILED(hr)) { + return hr; + } + } + } + */ + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led15093_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (hr == HRESULT_FROM_WIN32(ERROR_CRC)) { + led15093_set_status( + board, + 2, + LED_15093_STATUS_TYPE_UART, + LED_15093_STATUS_UART_ERR_SUM); + } + + if (FAILED(hr)) { + dprintf("LED 15093: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led15093_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("LED 15093: Processing error: %x\n", (int) hr); + } + + /* TODO: We should wait for a get board status request with a clear flag, + instead of doing this here. */ + led15093_clear_status(board, req.hdr.dest_adr); + led15093_clear_report(board, req.hdr.dest_adr); + } +} + +static HRESULT led15093_req_dispatch(int board, const union led15093_req_any *req) +{ + switch (req->payload[4]) { + case LED_15093_CMD_RESET: + return led15093_req_reset(board, &req->reset); + + case LED_15093_CMD_SET_TIMEOUT: + return led15093_req_set_timeout(board, &req->set_timeout); + + case LED_15093_CMD_SET_DISABLE_RESPONSE: + return led15093_req_set_response(board, &req->set_disable_response); + + case LED_15093_CMD_SET_ID: + return led15093_req_set_id(board, &req->set_id); + + case LED_15093_CMD_CLEAR_ID: + return led15093_req_clear_id(board, req); + + case LED_15093_CMD_SET_MAX_BRIGHT: + return led15093_req_set_max_bright(board, &req->set_led); + + case LED_15093_CMD_UPDATE_LED: + return led15093_req_update_led(board, req); + + case LED_15093_CMD_SET_LED: + return led15093_req_set_led(board, &req->set_led); + + case LED_15093_CMD_SET_IMM_LED: + // case LED_15093_CMD_SET_IMM_LED_LEGACY: + return led15093_req_set_imm_led(board, &req->set_led); + + case LED_15093_CMD_SET_FADE_LED: + return led15093_req_set_fade_led(board, &req->set_led); + + case LED_15093_CMD_SET_FADE_LEVEL: + return led15093_req_set_fade_level(board, &req->set_fade_level); + + case LED_15093_CMD_SET_FADE_SHIFT: + return led15093_req_set_fade_shift(board, &req->set_fade_shift); + + case LED_15093_CMD_SET_AUTO_SHIFT: + return led15093_req_set_auto_shift(board, &req->set_auto_shift); + + case LED_15093_CMD_GET_BOARD_INFO: + return led15093_req_get_board_info(board, req); + + case LED_15093_CMD_GET_BOARD_STATUS: + return led15093_req_get_board_status(board, &req->get_board_status); + + case LED_15093_CMD_GET_FW_SUM: + return led15093_req_get_fw_sum(board, req); + + case LED_15093_CMD_GET_PROTOCOL_VER: + return led15093_req_get_protocol_ver(board, req); + + case LED_15093_CMD_SET_BOOTMODE: + return led15093_req_set_bootmode(board, req); + + case LED_15093_CMD_FW_UPDATE: + return led15093_req_fw_update(board, req); + + default: + dprintf("LED 15093: Unhandled command %02x\n", req->payload[4]); + led15093_set_report( + board, + req->hdr.dest_adr, + LED_15093_REPORT_ERR2); + + return S_OK; + } +} + +static HRESULT led15093_req_reset(int board, const struct led15093_req_reset *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Reset (board %d, node %d, type %02x)\n", + board, req->hdr.dest_adr, req->r_type); + + if (req->r_type != 0xd9) + dprintf("LED 15093: Warning -- Unknown reset type %02x\n", req->r_type); + + /* A dest_adr of 0 means that this message is addressed to all nodes */ + if (req->hdr.dest_adr == 0) { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].enable_bootloader = false; + led15093_per_board_vars[board].per_node_vars[i].enable_response = true; + } + } else { + v->enable_bootloader = false; + v->enable_response = true; + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_RESET; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_timeout(int board, const struct led15093_req_set_timeout *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set timeout (board %u, count %u)\n", board, req->count); + + struct led15093_resp_timeout resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_TIMEOUT; + resp.report = v->report_code; + + resp.count_upper = (req->count >> 8) & 0xff; + resp.count_lower = req->count & 0xff; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_response(int board, const struct led15093_req_set_disable_response *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + if (req->hdr.nbytes > 1) { + dprintf("LED 15093: Set LED response setting (board %d, node %d, SW %d)\n", + board, req->hdr.dest_adr, req->sw); + v->enable_response = !req->sw; + } else { + dprintf("LED 15093: Check LED response setting (board %d, node %d)\n", + board, req->hdr.dest_adr); + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_DISABLE_RESPONSE; + resp.report = v->report_code; + + resp.data[0] = !v->enable_response; + + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_id(int board, const struct led15093_req_set_id *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set ID (board %d, requested node ID %d)\n", + board, req->id); + + if (req->id == 0 || req->id > 8) { + dprintf("LED 15093: Error -- Invalid node ID requested: %d\n", + req->id); + led15093_set_status( + board, + v->boardadr, + LED_15093_STATUS_TYPE_CMD, + LED_15093_STATUS_CMD_ERR_PARAM); + + return HRESULT_FROM_WIN32(ERROR_BAD_UNIT); + } + + /* A dest_adr of 0 means that this message is addressed to any unassigned + node..? */ + if (req->hdr.dest_adr == 0) { + bool slot_found = false; + + for (int i = 0; i < led15093_nnodes && slot_found == false; i++) { + if (led15093_per_board_vars[board].per_node_vars[i].boardadr == 0) { + led15093_per_board_vars[board].per_node_vars[i].boardadr = req->id; + slot_found = true; + } + } + + if (!slot_found) { + dprintf("LED 15093: Warning -- Unable to assign requested node " + "%d, all slots full\n", req->hdr.dest_adr); + } + } else { + /* Overwrite current ID. Probably no use case for this but we do it + anyway */ + v->boardadr = req->id; + } + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_ID; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_clear_id(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Clear ID (board %d, node %d)\n", + board, req->hdr.dest_adr); + + /* A dest_adr of 0 means that this message is addressed to all nodes */ + if (req->hdr.dest_adr == 0) { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].boardadr = 0; + } + } else { + /* Overwrite current ID. Probably no use case for this but we do it + anyway */ + v->boardadr = 0; + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_CLEAR_ID; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_max_bright(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set maximum LED brightness (board %d, node %d)\n", + board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + /* 15093 equivalent of 15070's "set DC data". 63 (0x3F) is, again, the + default. */ + + memcpy(v->led_bright, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_max_bright((const uint8_t*)&v->led_bright); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_MAX_BRIGHT; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + + +static HRESULT led15093_req_update_led(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Update LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_UPDATE_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set and immediately draw LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + if (req->cmd == LED_15093_CMD_SET_IMM_LED) { + resp.cmd = LED_15093_CMD_SET_IMM_LED; + } + // else { + // resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY; + // } + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set and fade LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_fade( + // (const uint8_t*)v->led, + // v->fade_depth, + // v->fade_cycle); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_level(int board, const struct led15093_req_set_fade_level *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set fade level (board %d, node %d, depth %d, cycle %d)\n", + board, req->hdr.dest_adr, req->depth, req->cycle); + + v->fade_depth = req->depth; + v->fade_cycle = req->cycle; + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_LEVEL; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_shift(int board, const struct led15093_req_set_fade_shift *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set fade shift (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_SHIFT; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_auto_shift(int board, const struct led15093_req_set_auto_shift *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set auto shift (board %d, node %d)\n", + board, req->hdr.dest_adr); + + /* There's actually a lot of conflicting info about this command... It + seems they changed the arguments between the -04 and -05 board variants, + and also changed the command ID from 0x87 to 0x86. + + Fortunately, only the -05 variant actually uses this in any shipping + game, so we don't need to implement support for the legacy command + version. */ + + v->led_count = req->count; + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_set_auto_shift resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_AUTO_SHIFT; + resp.report = v->report_code; + + resp.count = v->led_count; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_board_info(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get board info (board %d, node %d)\n", + board, req->hdr.dest_adr); + + if (str_eq(led15093_board_num, "15093")) { + struct led15093_resp_board_info_legacy resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 7 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_INFO; + resp.report = v->report_code; + + memcpy(resp.board_num, led15093_board_num, sizeof(resp.board_num)); + resp.endcode = 0xff; + resp.fw_ver = led15093_fw_ver; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); + } else { + struct led15093_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 18 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_INFO; + resp.report = v->report_code; + + memcpy(resp.board_num, led15093_board_num, sizeof(resp.board_num)); + resp.lf = 0x0a; + if (v->enable_bootloader) { + memcpy(resp.chip_num, led15093_boot_chip_num, sizeof(resp.chip_num)); + } else { + memcpy(resp.chip_num, led15093_chip_num, sizeof(resp.chip_num)); + } + resp.endcode = 0xff; + resp.fw_ver = led15093_fw_ver; + resp.rx_buf = 204; // Must be 204 regardless of active LED count + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); + } +} + +static HRESULT led15093_req_get_board_status(int board, const struct led15093_req_get_board_status *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get board status (board %d, node %d, clear %d)\n", + board, req->hdr.dest_adr, req->clear); + + if (req->clear) { + led15093_clear_status(board, req->hdr.dest_adr); + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = (v->enable_bootloader) ? (3 + 3) : (4 + 3); + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_STATUS; + resp.report = v->report_code; + + if (v->enable_bootloader) { + resp.data[0] = v->boardstatus[0]; // Board flags + resp.data[1] = v->boardstatus[1]; // UART flags + resp.data[2] = v->boardstatus[2]; // Command flags + } else { + resp.data[0] = v->boardstatus[0]; // Board flags + resp.data[1] = v->boardstatus[1]; // UART flags + resp.data[2] = v->boardstatus[2]; // Command flags + resp.data[3] = v->boardstatus[3]; // DIPSW + } + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_fw_sum(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get firmware checksum (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_fw_sum resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_FW_SUM; + resp.report = v->report_code; + + resp.sum_upper = (led15093_fw_sum >> 8) & 0xff; + resp.sum_lower = led15093_fw_sum & 0xff; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_protocol_ver(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get protocol version (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_protocol_ver resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_PROTOCOL_VER; + resp.report = v->report_code; + + if (v->enable_bootloader) { + resp.mode = 0; // BOOT mode + resp.major_ver = 1; + resp.minor_ver = 1; + } else { + resp.mode = 1; // APPLI mode + resp.major_ver = 1; + resp.minor_ver = 4; + } + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_bootmode(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set bootmode (board %d, node %d)\n", + board, req->hdr.dest_adr); + + v->enable_bootloader = true; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_BOOTMODE; + resp.report = v->report_code; + + resp.data[0] = 1; // IDK but this seems to fix test mode????? + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_fw_update(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Firmware update (UNIMPLEMENTED) (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_FW_UPDATE; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static void led15093_set_status(int board, int id, uint8_t type, uint8_t status) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + + if (type == LED_15093_STATUS_TYPE_BOARD) { + /* Set board flag */ + v->boardstatus[0] |= status; + } else if (type == LED_15093_STATUS_TYPE_UART) { + /* Set UART flag */ + v->boardstatus[1] |= status; + /* Set response status code */ + switch (status) { + case LED_15093_STATUS_UART_ERR_SUM: + v->status_code = LED_15093_STATUS_ERR_SUM; + break; + case LED_15093_STATUS_UART_ERR_PARITY: + v->status_code = LED_15093_STATUS_ERR_PARITY; + break; + case LED_15093_STATUS_UART_ERR_FRAMING: + v->status_code = LED_15093_STATUS_ERR_FRAMING; + break; + case LED_15093_STATUS_ERR_OVERRUN: + v->status_code = LED_15093_STATUS_ERR_OVERRUN; + break; + case LED_15093_STATUS_ERR_BUFFER_OVERFLOW: + v->status_code = LED_15093_STATUS_ERR_BUFFER_OVERFLOW; + break; + default: + break; + } + } else if (type == LED_15093_STATUS_TYPE_CMD) { + /* Set command flag */ + v->boardstatus[2] |= status; + } +} + +static void led15093_set_report(int board, int id, uint8_t report) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + v->report_code = report; +} + +static void led15093_clear_status(int board, int id) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + if (id == 0) + { + for (int i = 0; i < led15093_nnodes; i++) { + for (int j = 0; j < (_countof(v->boardstatus) - 1); j++) { + led15093_per_board_vars[board].per_node_vars[i].boardstatus[j] = 0; + } + + led15093_per_board_vars[board].per_node_vars[i].status_code = LED_15093_STATUS_OK; + } + } + else + { + v->boardstatus[0] = 0; // Board flags + v->boardstatus[1] = 0; // UART flags + v->boardstatus[2] = 0; // Command flags + + v->status_code = LED_15093_STATUS_OK; + } +} + +static void led15093_clear_report(int board, int id) +{ + if (id == 0) + { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].report_code = LED_15093_REPORT_OK; + } + } + else + { + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + v->report_code = LED_15093_STATUS_OK; + } +} diff --git a/board/led15093.h b/board/led15093.h new file mode 100644 index 0000000..ae4c27c --- /dev/null +++ b/board/led15093.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include +#include + +struct led15093_config { + bool enable; + bool high_baudrate; + unsigned int port_no[2]; + char board_number[8]; + char chip_number[5]; + char boot_chip_number[5]; + uint8_t fw_ver; + uint16_t fw_sum; +}; + +HRESULT led15093_hook_init( + const struct led15093_config *cfg, + unsigned int port_no_0, + unsigned int port_no_1); diff --git a/board/led1509306-cmd.h b/board/led1509306-cmd.h deleted file mode 100644 index 78019dc..0000000 --- a/board/led1509306-cmd.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "board/led1509306-frame.h" - -enum { - LED_15093_06_CMD_RESET = 0x10, - LED_15093_06_CMD_SET_TIMEOUT = 0x11, - LED_15093_06_CMD_SET_DISABLE_RESPONSE = 0x14, - LED_15093_06_CMD_SET_LED = 0x82, - LED_15093_06_CMD_SET_LED_COUNT = 0x86, - LED_15093_06_CMD_BOARD_INFO = 0xF0, - LED_15093_06_CMD_BOARD_STATUS = 0xF1, - LED_15093_06_CMD_FW_SUM = 0xF2, - LED_15093_06_CMD_PROTOCOL_VER = 0xF3, - LED_15093_06_CMD_BOOTLOADER = 0xFD, -}; - -struct led1509306_req_any { - struct led1509306_hdr hdr; - uint8_t cmd; - uint8_t payload[256]; -}; - -struct led1509306_resp_any { - struct led1509306_hdr hdr; - uint8_t status; - uint8_t cmd; - uint8_t report; - uint8_t data[32]; -}; - -struct led1509306_resp_board_info { - struct led1509306_hdr hdr; - uint8_t status; - uint8_t cmd; - uint8_t report; - struct { - char board_num[8]; - uint8_t _0a; - char chip_num[5]; - uint8_t _ff; - uint8_t fw_ver; - // may be some more data after this that isn't checked - } data; -}; \ No newline at end of file diff --git a/board/led1509306-frame.h b/board/led1509306-frame.h deleted file mode 100644 index a39493e..0000000 --- a/board/led1509306-frame.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "hook/iobuf.h" - -enum { - LED_15093_06_FRAME_SYNC = 0xE0, -}; - -struct led1509306_hdr { - uint8_t sync; - uint8_t dest_adr; - uint8_t src_adr; - uint8_t nbytes; -}; - -HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src); - -HRESULT led1509306_frame_encode( - struct iobuf *dest, - const void *ptr, - size_t nbytes); diff --git a/board/meson.build b/board/meson.build index df6ce92..b0dd300 100644 --- a/board/meson.build +++ b/board/meson.build @@ -20,9 +20,11 @@ board_lib = static_library( 'io3.h', 'io4.c', 'io4.h', - 'led1509306-cmd.h', - 'led1509306-frame.c', - 'led1509306-frame.h', + 'led15093-cmd.h', + 'led15093-frame.c', + 'led15093-frame.h', + 'led15093.c', + 'led15093.h', 'sg-cmd.c', 'sg-cmd.h', 'sg-frame.c', diff --git a/chunihook/config.c b/chunihook/config.c index afc7fae..92e99de 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -43,33 +43,65 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); wchar_t tmpstr[16]; - + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + tmpstr, + _countof(tmpstr), + filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); for (int i = n; i < sizeof(cfg->board_number); i++) { cfg->board_number[i] = ' '; } - - GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710 ", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } void chuni_hook_config_load( @@ -87,5 +119,5 @@ void chuni_hook_config_load( gfx_config_load(&cfg->gfx, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); } diff --git a/chunihook/config.h b/chunihook/config.h index d7a392b..8902b85 100644 --- a/chunihook/config.h +++ b/chunihook/config.h @@ -6,10 +6,10 @@ #include "amex/amex.h" #include "board/sg-reader.h" +#include "board/led15093.h" #include "chunihook/chuni-dll.h" #include "chunihook/slider.h" -#include "chunihook/led1509306.h" #include "gfxhook/gfx.h" @@ -22,7 +22,7 @@ struct chuni_hook_config { struct gfx_config gfx; struct chuni_dll_config dll; struct slider_config slider; - struct led1509306_config led1509306; + struct led15093_config led15093; }; void chuni_dll_config_load( diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 5303378..bd68994 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -9,7 +9,6 @@ #include "chunihook/config.h" #include "chunihook/jvs.h" #include "chunihook/slider.h" -#include "chunihook/led1509306.h" #include "chuniio/chuniio.h" @@ -97,7 +96,7 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = led1509306_hook_init(&chuni_hook_cfg.led1509306); + hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 11); if (FAILED(hr)) { goto fail; diff --git a/chunihook/led1509306.c b/chunihook/led1509306.c deleted file mode 100644 index 47fdd09..0000000 --- a/chunihook/led1509306.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "chunihook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, 10 + i); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/chunihook/led1509306.h b/chunihook/led1509306.h deleted file mode 100644 index 15c7c3e..0000000 --- a/chunihook/led1509306.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#include - -struct led1509306_config { - bool enable; - char board_number[8]; - char chip_number[5]; - uint8_t fw_ver; - uint16_t fw_sum; -}; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/chunihook/meson.build b/chunihook/meson.build index b4c464d..3f4a35d 100644 --- a/chunihook/meson.build +++ b/chunihook/meson.build @@ -30,7 +30,5 @@ shared_library( 'jvs.h', 'slider.c', 'slider.h', - 'led1509306.c', - 'led1509306.h', ], ) diff --git a/chusanhook/config.c b/chusanhook/config.c index 7b290f3..f585926 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -71,34 +71,76 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); wchar_t tmpstr[16]; - + bool cvt_port; + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->cvt_port = GetPrivateProfileIntW(L"ledstrip", L"cvt_port", 0, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cvt_port = GetPrivateProfileIntW(L"led15093", L"cvtPort", 0, filename); + + if (!cvt_port) { + // SP mode: COM20, COM21 + cfg->port_no[0] = 20; + cfg->port_no[1] = 21; + } else { + // CVT mode: COM2, COM3 + cfg->port_no[0] = 2; + cfg->port_no[1] = 3; + } + + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + tmpstr, + _countof(tmpstr), + filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); for (int i = n; i < sizeof(cfg->board_number); i++) { cfg->board_number[i] = ' '; } - - GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710 ", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } @@ -118,5 +160,5 @@ void chusan_hook_config_load( gfx_config_load(&cfg->gfx, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); } diff --git a/chusanhook/config.h b/chusanhook/config.h index 856112b..48fb696 100644 --- a/chusanhook/config.h +++ b/chusanhook/config.h @@ -3,6 +3,7 @@ #include #include "board/config.h" +#include "board/led15093.h" #include "hooklib/dvd.h" @@ -12,7 +13,6 @@ #include "chusanhook/chuni-dll.h" #include "chusanhook/slider.h" -#include "chusanhook/led1509306.h" struct chusan_hook_config { struct platform_config platform; @@ -22,7 +22,7 @@ struct chusan_hook_config { struct gfx_config gfx; struct chuni_dll_config dll; struct slider_config slider; - struct led1509306_config led1509306; + struct led15093_config led15093; }; void chuni_dll_config_load( diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 4b23983..8522f67 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -11,7 +11,6 @@ #include "chusanhook/config.h" #include "chusanhook/io4.h" #include "chusanhook/slider.h" -#include "chusanhook/led1509306.h" #include "chuniio/chuniio.h" @@ -100,7 +99,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - hr = led1509306_hook_init(&chusan_hook_cfg.led1509306); + hr = led15093_hook_init(&chusan_hook_cfg.led15093, 20, 21); if (FAILED(hr)) { goto fail; diff --git a/chusanhook/led1509306.c b/chusanhook/led1509306.c deleted file mode 100644 index 420c6f5..0000000 --- a/chusanhook/led1509306.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "chusanhook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - int com_ports[2]; - - if (!cfg->cvt_port) { - // SP mode: COM20, COM21 - com_ports[0] = 20; - com_ports[1] = 21; - } else { - // CVT mode: COM2, COM3 - com_ports[0] = 2; - com_ports[1] = 3; - } - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, com_ports[i]); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/chusanhook/meson.build b/chusanhook/meson.build index 02c82b0..69250bb 100644 --- a/chusanhook/meson.build +++ b/chusanhook/meson.build @@ -28,7 +28,5 @@ shared_library( 'io4.h', 'slider.c', 'slider.h', - 'led1509306.c', - 'led1509306.h', ], ) diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 7385546..7724c30 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -38,6 +38,10 @@ monitor=0 ; Leave empty if you want to use Segatools built-in keyboard input. path= +[led15093] +; 837-15093-06 LED strip emulation setting. +enable=1 + [chuniio] ; To use a custom Chunithm IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index b1da417..dc6e2ae 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -44,7 +44,7 @@ enable=1 ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 -; Monitor type: 0 = 120FPS, 1 = 60FPS +; Monitor type: 0 = 120FPS (SP), 1 = 60FPS (CVT) dipsw2=1 ; Aime reader hardware type: 0 = SP, 1 = CVT dipsw3=1 @@ -57,6 +57,18 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +[led15093] +; 837-15093-06 LED strip emulation setting. +enable=1 +; Set to 1 if running game in 60FPS (CVT) mode. +cvtPort=0 + +[chuniio] +; Uncomment this if you have custom chuniio implementation. +; x86 chuniio to path32, x64 to path64. Both are necessary. +;path32= +;path64= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -79,18 +91,12 @@ coin=0x33 ; Set to 0 for enable separate ir control. Deafult is space key. ir=0x20 -[io4] -enable=1 - -[ledstrip] -; Set to 1 if running game in CVT mode. -cvt_port=0 - -[chuniio] -; Uncomment this if you have custom chuniio implementation. -; x86 chuniio to path32, x64 to path64. Both are necessary. -;path32= -;path64= +[ir] +; Uncomment and complete the following sequence of settings to configure a +; custom ir-cappable controller if you have one. +;ir6=0x53 +; ... etc ... +;ir1=0x53 [slider] ; Enable slider emulation. If you have real AC slider, set this to 0. @@ -116,10 +122,3 @@ cvt_port=0 ; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. ; eg. COM5 ;ledport= - -[ir] -; Uncomment and complete the following sequence of settings to configure a -; custom ir-cappable controller if you have one. -;ir6=0x53 -; ... etc ... -;ir1=0x53 \ No newline at end of file diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 0d99009..18e2bbb 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -58,10 +58,14 @@ enable=1 [ftdi] ; FTDI serial to usb adapter emulation for CABINET LED. enable=1 +; COM port number where the LED board is connected to. +portNo=17 -[ledstrip] -; 837-15093-06 LED strip emulation setting. +[led15093] +; 837-15093-06 LED board emulation setting. enable=1 +; COM port number for the first LED board. Has to be the same as the FTDI port. +portNo0=17 ; ----------------------------------------------------------------------------- ; Input settings diff --git a/fgohook/config.c b/fgohook/config.c index be6bdd0..3253568 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -32,10 +32,10 @@ void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"port", 17, filename); + cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"portNo", 0, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); @@ -44,25 +44,56 @@ void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filena memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 17, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xaa53, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + tmpstr, + _countof(tmpstr), + filename); + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); for (int i = n; i < sizeof(cfg->board_number); i++) { cfg->board_number[i] = ' '; } - - GetPrivateProfileStringW(L"ledstrip", L"chip_number", L"6710A", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710A", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } void fgo_deck_config_load( @@ -90,6 +121,6 @@ void fgo_hook_config_load( printer_config_load(&cfg->printer, filename); fgo_deck_config_load(&cfg->deck, filename); ftdi_config_load(&cfg->ftdi, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); fgo_dll_config_load(&cfg->dll, filename); } diff --git a/fgohook/config.h b/fgohook/config.h index a2cad3b..59b48ee 100644 --- a/fgohook/config.h +++ b/fgohook/config.h @@ -3,6 +3,7 @@ #include #include "board/config.h" +#include "board/led15093.h" #include "hooklib/dvd.h" #include "hooklib/touch.h" @@ -10,7 +11,6 @@ #include "fgohook/deck.h" #include "fgohook/ftdi.h" -#include "fgohook/led1509306.h" #include "fgohook/fgo-dll.h" #include "platform/config.h" @@ -24,7 +24,7 @@ struct fgo_hook_config { struct printer_config printer; struct deck_config deck; struct ftdi_config ftdi; - struct led1509306_config led1509306; + struct led15093_config led15093; struct fgo_dll_config dll; }; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 2c3af8e..4f71216 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -90,13 +90,13 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); + hr = ftdi_hook_init(&fgo_hook_cfg.ftdi, 17); if (FAILED(hr)) { goto fail; } - hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); + hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 0); if (FAILED(hr)) { goto fail; diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index bda7507..91aea04 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -121,7 +121,7 @@ static const struct hook_symbol reg_syms[] = { static HANDLE ftdi_fd; static char port_name[8]; -HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { +HRESULT ftdi_hook_init(const struct ftdi_config *cfg, unsigned int port_no) { HRESULT hr; assert(cfg != NULL); @@ -130,6 +130,10 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { return S_FALSE; } + if (cfg->port_no != 0) { + port_no = cfg->port_no; + } + hook_table_apply( NULL, "setupapi.dll", @@ -156,7 +160,7 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { return hr; } - sprintf(port_name, "COM%d", cfg->port_no); + sprintf(port_name, "COM%d", port_no); dprintf("FTDI: Hook enabled.\n"); return S_OK; diff --git a/fgohook/ftdi.h b/fgohook/ftdi.h index e1cd9d6..18e5d73 100644 --- a/fgohook/ftdi.h +++ b/fgohook/ftdi.h @@ -18,4 +18,4 @@ DEFINE_GUID( 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73); -HRESULT ftdi_hook_init(const struct ftdi_config *cfg); +HRESULT ftdi_hook_init(const struct ftdi_config *cfg, unsigned int port_no); diff --git a/fgohook/led1509306.c b/fgohook/led1509306.c deleted file mode 100644 index e922738..0000000 --- a/fgohook/led1509306.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "fgohook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, cfg->port_no + i); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - dprintf("LED Strip: hook enabled.\n"); - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/fgohook/led1509306.h b/fgohook/led1509306.h deleted file mode 100644 index f4b3260..0000000 --- a/fgohook/led1509306.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include - -struct led1509306_config { - bool enable; - unsigned int port_no; - char board_number[8]; - char chip_number[5]; - uint8_t fw_ver; - uint16_t fw_sum; -}; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/fgohook/meson.build b/fgohook/meson.build index 11737b2..2e9772f 100644 --- a/fgohook/meson.build +++ b/fgohook/meson.build @@ -30,7 +30,5 @@ shared_library( 'deck.h', 'ftdi.c', 'ftdi.h', - 'led1509306.c', - 'led1509306.h', ], ) From 4dcf01f6433fed99e6d6f82e8f1b673fcf021986 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Mon, 27 Nov 2023 23:23:00 -0500 Subject: [PATCH 060/204] carol: somewhat-working touch board?? --- carolhook/dllmain.c | 5 ++++ carolhook/touch.c | 69 +++++++++++++++++++++++++----------------- carolhook/touch.h | 19 ++++++++---- carolio/carolio.c | 52 ++++++++++++++++++++++++++++---- carolio/carolio.h | 2 +- hooklib/cursor.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ hooklib/cursor.h | 3 ++ hooklib/meson.build | 2 ++ 8 files changed, 186 insertions(+), 39 deletions(-) create mode 100644 hooklib/cursor.c create mode 100644 hooklib/cursor.h diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index eca445b..6ff4c9f 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -20,6 +20,7 @@ #include "hooklib/serial.h" #include "hooklib/spike.h" #include "hooklib/createprocess.h" +#include "hooklib/cursor.h" #include "platform/platform.h" @@ -44,6 +45,8 @@ static DWORD CALLBACK carol_pre_startup(void) HMODULE dbghelp; dprintf("--- Begin carol_pre_startup ---\n"); + if ( !SetProcessDPIAware() ) + dprintf("Failed to set process DPI awareness level!\n"); /* Pin the D3D shader compiler. This makes startup much faster. */ @@ -65,6 +68,8 @@ static DWORD CALLBACK carol_pre_startup(void) dprintf("Failed to load debug helper library!\n"); } + cursor_hook_init(); + /* Config load */ carol_hook_config_load(&carol_hook_cfg, L".\\segatools.ini"); diff --git a/carolhook/touch.c b/carolhook/touch.c index 46527b8..ba61e42 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -8,13 +8,15 @@ #include "carolhook/carol-dll.h" #include "carolhook/touch.h" +#include "hook/table.h" + #include "hooklib/uart.h" #include "util/dprintf.h" #include "util/dump.h" /** - * CMDS for M3 EX series + * CMDS for touch thing * CX -> Calibrate Extend, preform callibration * MS -> Mode Stream, enters stream mode * R -> Reset, resets the device @@ -32,7 +34,8 @@ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf); static HRESULT handle_touch_ack_cmd(const struct touch_req *req); static HRESULT handle_touch_name_cmd(const struct touch_req *req); static HRESULT handle_touch_id_cmd(const struct touch_req *req); -static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y); +static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req); +static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y); static CRITICAL_SECTION touch_lock; static struct uart touch_uart; @@ -40,8 +43,10 @@ static uint8_t touch_written_bytes[528]; static uint8_t touch_readable_bytes[528]; static bool should_stream = false; static bool last_pressed; -static uint16_t last_x; -static uint16_t last_y; +static uint8_t last_x1; +static uint8_t last_x2; +static uint8_t last_y1; +static uint8_t last_y2; HRESULT touch_hook_init(const struct touch_config *cfg) @@ -91,6 +96,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) if (irp->op == IRP_OP_OPEN) { dprintf("Touchscreen: Starting backend DLL\n"); hr = carol_dll.touch_init(); + carol_dll.touch_start(touch_scan_auto); if (FAILED(hr)) { dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr); @@ -123,7 +129,9 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } else if (!strcmp("OI", (char *)req.cmd)) { hr = handle_touch_id_cmd(&req); - //carol_dll.touch_start(touch_scan_auto); + } + else if (!strcmp("UT", (char *)req.cmd)) { + hr = handle_touch_unit_type_cmd(&req); } else if (!strcmp("NM", (char *)req.cmd)) { hr = handle_touch_name_cmd(&req); @@ -150,16 +158,22 @@ static HRESULT handle_touch_ack_cmd(const struct touch_req *req) static HRESULT handle_touch_name_cmd(const struct touch_req *req) { dprintf("Touch: Get Name\n"); - return iobuf_write(&touch_uart.readable, "\001EX1234 EX1234\015", 15); + return iobuf_write(&touch_uart.readable, "\001AD1000\015", 15); } static HRESULT handle_touch_id_cmd(const struct touch_req *req) { dprintf("Touch: Get ID\n"); - return iobuf_write(&touch_uart.readable, "\001EX1234\015", 8); + return iobuf_write(&touch_uart.readable, "\001AD1000\015", 8); } -static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y) +static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req) +{ + dprintf("Touch: Get Unit Type\n"); + return iobuf_write(&touch_uart.readable, "\001AD****00\015", 8); +} + +static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y) { struct touch_auto_resp resp; uint16_t tmp_x; @@ -167,34 +181,37 @@ static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const bool flg = false; memset(&resp, 0, sizeof(resp)); - resp.rep_id = 0x17; - resp.touches[0].status = 0x04; - resp.count = 1; + resp.touches[0].status |= 1 << 7; if (is_pressed) { - resp.touches[0].status = 0x07; + resp.touches[0].status |= (1 << 7) | (1 << 6); resp.touches[0].touch_id = 1; tmp_x = mouse_x & 0x7FFF; tmp_y = mouse_y & 0x7FFF; - // flip - resp.touches[0].x = (tmp_x << 8) | (tmp_x >> 8); - resp.touches[0].y = (tmp_y << 8) | (tmp_y >> 8); + resp.touches[0].x1 = tmp_x & 0x7F; + resp.touches[0].x2 = (tmp_x >> 7) & 0x7F; + resp.touches[0].y1 = tmp_y & 0x7F; + resp.touches[0].y2 = (tmp_y >> 7) & 0x7F; - flg = resp.touches[0].x != last_x || resp.touches[0].y != last_y; + flg = resp.touches[0].x1 != last_x1 || resp.touches[0].x2 != last_x2 || resp.touches[0].y1 != last_y1 || resp.touches[0].y2 != last_y2; #if 1 if (flg) - dprintf("Touch: Mouse down! x %04X y: %04X\n", resp.touches[0].x, resp.touches[0].y); + dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2); #endif - last_x = resp.touches[0].x; - last_y = resp.touches[0].y; + last_x1 = resp.touches[0].x1; + last_x2 = resp.touches[0].x2; + last_y1 = resp.touches[0].y1; + last_y2 = resp.touches[0].y2; } else if (last_pressed) { - resp.touches[0].x = last_x; - resp.touches[0].y = last_y; + resp.touches[0].x1 = last_x1; + resp.touches[0].x2 = last_x2; + resp.touches[0].y1 = last_y1; + resp.touches[0].y2 = last_y2; } last_pressed = is_pressed; @@ -203,11 +220,9 @@ static void touch_scan_auto(const bool is_pressed, const uint32_t mouse_x, const iobuf_write(&touch_uart.readable, &resp, sizeof(resp)); LeaveCriticalSection(&touch_lock); -#if 1 - //if (flg) { - dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos); - dump_iobuf(&touch_uart.readable); - //} +#if 0 + dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos); + dump_iobuf(&touch_uart.readable); #endif } @@ -235,4 +250,4 @@ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) } return S_OK; -} \ No newline at end of file +} diff --git a/carolhook/touch.h b/carolhook/touch.h index a815cd1..bc621d6 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -8,6 +8,9 @@ struct touch_config { bool enable; + unsigned int port_no; + char board_id[7]; + char unit_type[9]; }; // Always starts with 0x01, always ends with 0x0D @@ -20,17 +23,21 @@ struct touch_req { struct touch_report { uint8_t status; + uint8_t x1; + uint8_t x2; + uint8_t y1; + uint8_t y2; uint8_t touch_id; - uint16_t x; - uint16_t y; }; struct touch_auto_resp { - uint8_t rep_id; struct touch_report touches[10]; - uint8_t count; - uint16_t scan_time; - //uint8_t padding[456]; +}; + +enum { + TOUCH_MODE_STREAM = 0x01, + TOUCH_MODE_DOWN_UP = 0x02, + TOUCH_MODE_INACTIVE = 0x03, }; #pragma pack(pop) diff --git a/carolio/carolio.c b/carolio/carolio.c index 3f4339b..5368da6 100644 --- a/carolio/carolio.c +++ b/carolio/carolio.c @@ -7,6 +7,7 @@ #include "carolio/carolio.h" #include "carolio/config.h" +#include "util/dprintf.h" static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx); @@ -15,6 +16,7 @@ static uint16_t carol_io_coins; static struct carol_io_config carol_io_cfg; static bool carol_io_touch_stop_flag; static HANDLE carol_io_touch_thread; +static bool carol_io_window_focus = false; uint16_t carol_io_get_api_version(void) { @@ -110,22 +112,62 @@ void carol_io_touch_stop() carol_io_touch_stop_flag = true; } +void check_fg_wind(void) +{ + HWND hwnd = GetForegroundWindow(); + wchar_t window_class[MAX_PATH]; + + /* Unlike every other game, we can't use GetWindowText here. Why? + + From MSDN: + + "If the window does not have a caption, the return value is a null + string. This behavior is by design. It allows applications to call + GetWindowText without becoming unresponsive if the process that owns + the target window is not responding. However, if the target window + is not responding and it belongs to the calling application, + GetWindowText will cause the calling application to become + unresponsive." + + Great, thanks Microsoft, very cool. Luckily Carol sets its class + name to the window title too so we can use that. */ + + GetClassNameW(hwnd, window_class, MAX_PATH); + + if (wcscmp(window_class, L"WONDER Master")) { + if (carol_io_window_focus) { + dprintf("Carol IO: Window focus lost\n"); + carol_io_window_focus = false; + } + } else if (!carol_io_window_focus) { + dprintf("Carol IO: Window focus regained\n"); + carol_io_window_focus = true; + } +} + static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx) { carol_io_touch_callback_t callback; bool mouse_is_down = false; - uint32_t mX = 0; - uint32_t mY = 0; + uint16_t mX = 0; + uint16_t mY = 0; POINT lpPoint; + HWND hwnd; callback = ctx; while (!carol_io_touch_stop_flag) { + check_fg_wind(); if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) { mouse_is_down = true; - if (GetCursorPos(&lpPoint)) { - mX = lpPoint.x; - mY = lpPoint.y; + if (GetCursorPos(&lpPoint)) { + hwnd = GetForegroundWindow(); + if (ScreenToClient(hwnd, &lpPoint)) { + if (lpPoint.x < 0) lpPoint.x = 0; + if (lpPoint.y < 0) lpPoint.y = 0; + mX = (uint16_t)lpPoint.x; + mY = (uint16_t)lpPoint.y; + } } } else { mouse_is_down = false; diff --git a/carolio/carolio.h b/carolio/carolio.h index 6c85e3d..8b2b308 100644 --- a/carolio/carolio.h +++ b/carolio/carolio.h @@ -5,7 +5,7 @@ #include #include -typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint32_t mouse_x, const uint32_t mouse_y); +typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y); /* Get the version of the Project carol IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is diff --git a/hooklib/cursor.c b/hooklib/cursor.c new file mode 100644 index 0000000..8c66412 --- /dev/null +++ b/hooklib/cursor.c @@ -0,0 +1,73 @@ +#include + +#include +#include +#include +#include + +#include "hook/table.h" +#include "util/dprintf.h" + +static HCURSOR my_SetCursor(HCURSOR hCursor); +static HCURSOR (*next_SetCursor)(HCURSOR hCursor); +static BOOL my_SetCursorPos(int x, int y); +static BOOL my_SetPhysicalCursorPos(int x, int y); +static int my_ShowCursor(BOOL bShow); + +static const struct hook_symbol cursor_syms[] = { + { + .name = "SetCursor", + .patch = my_SetCursor, + .link = (void **) &next_SetCursor + },/*{ + .name = "SetCursorPos", + .patch = my_SetCursorPos, + },*/ { + .name = "SetPhysicalCursorPos", + .patch = my_SetPhysicalCursorPos + }, /*{ + .name = "ShowCursor", + .patch = my_ShowCursor + }*/ +}; + +void cursor_hook_init() +{ + hook_table_apply( + NULL, + "user32.dll", + cursor_syms, + _countof(cursor_syms)); + + dprintf("Cursor: Init\n"); +} + +static BOOL my_SetCursorPos(int x, int y) +{ + dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y); + return true; +} + +static BOOL my_SetPhysicalCursorPos(int x, int y) +{ + dprintf("my_SetPhysicalCursorPos Hit! x %d y %d\n", x, y); + return true; +} + +static int my_ShowCursor(BOOL bShow) +{ + dprintf("my_ShowCursor Hit!\n"); + return 0; +} + +static HCURSOR my_SetCursor(HCURSOR hCursor) +{ + dprintf("my_SetCursor Hit!\n"); + HCURSOR fake_cursor; + + if ( hCursor ) + return next_SetCursor(hCursor); + fake_cursor = LoadCursorA(0, (LPCSTR)0x7F00); + next_SetCursor(fake_cursor); + return 0; +} diff --git a/hooklib/cursor.h b/hooklib/cursor.h new file mode 100644 index 0000000..de0461a --- /dev/null +++ b/hooklib/cursor.h @@ -0,0 +1,3 @@ +#pragma once + +void cursor_hook_init(); \ No newline at end of file diff --git a/hooklib/meson.build b/hooklib/meson.build index 4a381b4..4ff4734 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -7,6 +7,8 @@ hooklib_lib = static_library( capnhook.get_variable('hook_dep'), ], sources : [ + 'cursor.c', + 'cursor.h', 'config.c', 'config.h', 'createprocess.c', From 8c12853051fe6a676b0db78b23422249959867d5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 30 Nov 2023 00:02:00 +0100 Subject: [PATCH 061/204] cm: disabled coin selector AS6DB --- Package.mk | 1 + dist/cm/config_hook.json | 9 +++++++++ dist/cm/start.bat | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 dist/cm/config_hook.json diff --git a/Package.mk b/Package.mk index 6ccc6d0..750f072 100644 --- a/Package.mk +++ b/Package.mk @@ -194,6 +194,7 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/cmhook/cmhook.dll \ + $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ $(DIST_DIR)/cm/start.bat \ $(BUILD_DIR_ZIP)/cm diff --git a/dist/cm/config_hook.json b/dist/cm/config_hook.json new file mode 100644 index 0000000..5723db7 --- /dev/null +++ b/dist/cm/config_hook.json @@ -0,0 +1,9 @@ +{ + "credit" : + { + "coin_selector_AS6DB" : + { + "enable" : false + } + } +} diff --git a/dist/cm/start.bat b/dist/cm/start.bat index 865498b..b17a6a1 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json +start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 From 793417e8911e2701707012c3c22cfcbd2df72e96 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 3 Dec 2023 18:45:42 +0100 Subject: [PATCH 062/204] added new aime card reader generation - Added new aime generation: 837-15286 and 837-15396 - New config setting `[aime] gen=3` for 837-15396 - Updated LED information for card reader - Updated all games with the needed reader generation? --- Package.mk | 1 - board/config.c | 1 + board/sg-led-cmd.h | 2 +- board/sg-led.c | 16 ++++++++++++---- board/sg-led.h | 2 ++ board/sg-nfc-cmd.h | 1 + board/sg-nfc.c | 27 +++++++++++++++++++++++---- board/sg-nfc.h | 2 ++ board/sg-reader.c | 15 +++++++++++++-- board/sg-reader.h | 2 ++ chunihook/dllmain.c | 2 +- chusanhook/dllmain.c | 3 +-- cmhook/dllmain.c | 2 +- cxbhook/dllmain.c | 2 +- dist/fgo/config_hook.json | 12 ------------ dist/idac/config_hook.json | 9 --------- divahook/dllmain.c | 2 +- doc/config/common.md | 11 +++++++++++ fgohook/dllmain.c | 4 ++-- idachook/dllmain.c | 2 +- idzhook/dllmain.c | 2 +- idzio/dllmain.c | 2 +- mai2hook/dllmain.c | 2 +- mercuryhook/dllmain.c | 2 +- swdchook/dllmain.c | 2 +- 25 files changed, 81 insertions(+), 47 deletions(-) delete mode 100644 dist/fgo/config_hook.json diff --git a/Package.mk b/Package.mk index 750f072..ac567a6 100644 --- a/Package.mk +++ b/Package.mk @@ -79,7 +79,6 @@ $(BUILD_DIR_ZIP)/fgo.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/fgohook/fgohook.dll \ - $(DIST_DIR)/fgo/config_hook.json \ $(DIST_DIR)/fgo/segatools.ini \ $(DIST_DIR)/fgo/start.bat \ $(BUILD_DIR_ZIP)/fgo diff --git a/board/config.c b/board/config.c index 9d015e9..3ffa6ab 100644 --- a/board/config.c +++ b/board/config.c @@ -31,6 +31,7 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highbaud", 1, filename); + cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename); } void io4_config_load(struct io4_config *cfg, const wchar_t *filename) diff --git a/board/sg-led-cmd.h b/board/sg-led-cmd.h index f74505b..cd4bcc6 100644 --- a/board/sg-led-cmd.h +++ b/board/sg-led-cmd.h @@ -17,7 +17,7 @@ struct sg_led_res_reset { struct sg_led_res_get_info { struct sg_res_header res; - uint8_t payload[9]; + char payload[12]; }; struct sg_led_req_set_color { diff --git a/board/sg-led.c b/board/sg-led.c index 855e36b..cd09c14 100644 --- a/board/sg-led.c +++ b/board/sg-led.c @@ -27,14 +27,18 @@ static HRESULT sg_led_cmd_set_color( const struct sg_led *led, const struct sg_led_req_set_color *req); -static const uint8_t sg_led_info[] = { - '1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12, +const char *sg_led_info[] = { + "15084\xFF\x10\x00\x12", + "000-00000\xFF\x11\x40", + // maybe the same? + "000-00000\xFF\x11\x40" }; void sg_led_init( struct sg_led *led, uint8_t addr, const struct sg_led_ops *ops, + unsigned int gen, void *ctx) { assert(led != NULL); @@ -43,6 +47,7 @@ void sg_led_init( led->ops = ops; led->ops_ctx = ctx; led->addr = addr; + led->gen = gen; } void sg_led_transact( @@ -150,8 +155,11 @@ static HRESULT sg_led_cmd_get_info( struct sg_led_res_get_info *res) { sg_led_dprintf(led, "Get info\n"); - sg_res_init(&res->res, req, sizeof(res->payload)); - memcpy(res->payload, sg_led_info, sizeof(sg_led_info)); + + unsigned int len = strlen(sg_led_info[led->gen - 1]); + + sg_res_init(&res->res, req, len); + memcpy(res->payload, sg_led_info[led->gen - 1], len); return S_OK; } diff --git a/board/sg-led.h b/board/sg-led.h index de3caa6..eaa8d16 100644 --- a/board/sg-led.h +++ b/board/sg-led.h @@ -15,12 +15,14 @@ struct sg_led { const struct sg_led_ops *ops; void *ops_ctx; uint8_t addr; + unsigned int gen; }; void sg_led_init( struct sg_led *led, uint8_t addr, const struct sg_led_ops *ops, + unsigned int gen, void *ctx); void sg_led_transact( diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index b6754c2..c44586a 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -15,6 +15,7 @@ enum { SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ + SG_NFC_CMD_SEND_HEX_DATA = 0x61, SG_NFC_CMD_RESET = 0x62, SG_NFC_CMD_FELICA_ENCAP = 0x71, }; diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 2db684d..c519358 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -65,10 +65,23 @@ static HRESULT sg_nfc_cmd_dummy( const struct sg_req_header *req, struct sg_res_header *res); +static const char *hw_version[] = { + "TN32MSEC003S H/W Ver3.0", + "837-15286", + "837-15396" +}; + +static const char *fw_version[] = { + "TN32MSEC003S F/W Ver1.2", + "\x94", + "\x94" +}; + void sg_nfc_init( struct sg_nfc *nfc, uint8_t addr, const struct sg_nfc_ops *ops, + unsigned int gen, void *ops_ctx) { assert(nfc != NULL); @@ -77,6 +90,7 @@ void sg_nfc_init( nfc->ops = ops; nfc->ops_ctx = ops_ctx; nfc->addr = addr; + nfc->gen = gen; } #ifdef NDEBUG @@ -176,6 +190,7 @@ static HRESULT sg_nfc_dispatch( case SG_NFC_CMD_MIFARE_SET_KEY_BANA: case SG_NFC_CMD_RADIO_ON: case SG_NFC_CMD_RADIO_OFF: + case SG_NFC_CMD_SEND_HEX_DATA: // TODO: implement? return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); default: @@ -202,9 +217,11 @@ static HRESULT sg_nfc_cmd_get_fw_version( const struct sg_req_header *req, struct sg_nfc_res_get_fw_version *res) { + unsigned int len = strlen(fw_version[nfc->gen - 1]); + /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, sizeof(res->version)); - memcpy(res->version, "TN32MSEC003S F/W Ver1.2E", sizeof(res->version)); + sg_res_init(&res->res, req, len); + memcpy(res->version, fw_version[nfc->gen - 1], len); return S_OK; } @@ -214,9 +231,11 @@ static HRESULT sg_nfc_cmd_get_hw_version( const struct sg_req_header *req, struct sg_nfc_res_get_hw_version *res) { + unsigned int len = strlen(hw_version[nfc->gen - 1]); + /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, sizeof(res->version)); - memcpy(res->version, "TN32MSEC003S H/W Ver3.0J", sizeof(res->version)); + sg_res_init(&res->res, req, len); + memcpy(res->version, hw_version[nfc->gen - 1], len); return S_OK; } diff --git a/board/sg-nfc.h b/board/sg-nfc.h index 5562b2b..3c8eb49 100644 --- a/board/sg-nfc.h +++ b/board/sg-nfc.h @@ -22,6 +22,7 @@ struct sg_nfc { const struct sg_nfc_ops *ops; void *ops_ctx; uint8_t addr; + unsigned int gen; struct felica felica; struct mifare mifare; }; @@ -30,6 +31,7 @@ void sg_nfc_init( struct sg_nfc *nfc, uint8_t addr, const struct sg_nfc_ops *ops, + unsigned int gen, void *ops_ctx); void sg_nfc_transact( diff --git a/board/sg-reader.c b/board/sg-reader.c index e8fbfba..24df4df 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -48,6 +48,7 @@ static struct sg_led sg_reader_led; HRESULT sg_reader_hook_init( const struct aime_config *cfg, unsigned int port_no, + unsigned int gen, HINSTANCE self) { HRESULT hr; @@ -65,8 +66,18 @@ HRESULT sg_reader_hook_init( return hr; } - sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL); - sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL); + if (cfg->gen != 0) { + gen = cfg->gen; + } + + if (gen < 1 || gen > 3) { + dprintf("NFC Assembly: Invalid reader generation: %u\n", gen); + + return E_INVALIDARG; + } + + sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL); + sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL); InitializeCriticalSection(&sg_reader_lock); diff --git a/board/sg-reader.h b/board/sg-reader.h index b9f19c5..01eb0b3 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -10,9 +10,11 @@ struct aime_config { struct aime_dll_config dll; bool enable; bool high_baudrate; + unsigned int gen; }; HRESULT sg_reader_hook_init( const struct aime_config *cfg, unsigned int port_no, + unsigned int gen, HINSTANCE self); diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index bd68994..7035943 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -102,7 +102,7 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, chuni_hook_mod); + hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 8522f67..3375158 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -105,8 +105,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - - hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, chusan_hook_mod); + hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, dipsw[2] ? 2 : 3, chusan_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 9fd12cd..72587ad 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -54,7 +54,7 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, cm_hook_mod); + hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/cxbhook/dllmain.c b/cxbhook/dllmain.c index b9c3056..ba0bb7b 100644 --- a/cxbhook/dllmain.c +++ b/cxbhook/dllmain.c @@ -91,7 +91,7 @@ static DWORD CALLBACK cxb_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&cxb_hook_cfg.aime, 12, cxb_hook_mod); + hr = sg_reader_hook_init(&cxb_hook_cfg.aime, 12, 1, cxb_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/dist/fgo/config_hook.json b/dist/fgo/config_hook.json deleted file mode 100644 index cc1ab5d..0000000 --- a/dist/fgo/config_hook.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "aime" : - { - "firmware_path" : - [ - "am\\aime_firm\\update_15396_6728_94.bin", - "am\\aime_firm\\TN32MSEC003S_V12.hex", - "am\\aime_firm\\837-15286-P_LPC1112_NFC_RW_LED_BD_0x92.bin" - ], - "high_baudrate" : true - } -} diff --git a/dist/idac/config_hook.json b/dist/idac/config_hook.json index 12fae62..3758b3d 100644 --- a/dist/idac/config_hook.json +++ b/dist/idac/config_hook.json @@ -1,13 +1,4 @@ { - "aime" : - { - "firmware_path" : - [ - ".\\aime_firm\\TN32MSEC003S_V12.hex", - ".\\aime_firm\\update_15396_6728_94.bin" - ], - "high_baudrate" : true - }, "network" : { "property" : diff --git a/divahook/dllmain.c b/divahook/dllmain.c index fb3c678..8bd13de 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -62,7 +62,7 @@ static DWORD CALLBACK diva_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&diva_hook_cfg.aime, 10, diva_hook_mod); + hr = sg_reader_hook_init(&diva_hook_cfg.aime, 10, 1, diva_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/doc/config/common.md b/doc/config/common.md index 9648386..fb82131 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -38,6 +38,17 @@ Default: `1` Enables the high baudrate of the Aime card reader to be 115200 (instead of 38400). This is required for some games (e.g. Chunithm) but not others (e.g. WACCA). +### `gen` + +Default: `1` + +Changes the Aime card reader generation, this will also change the LED info +provided for the game. + +- `1`: TN32MSEC003S H/W Ver3.0 / TN32MSEC003S F/W Ver1.2 +- `2`: 837-15286 / 94 +- `3`: 837-15396 / 94 + ### `aimePath` Default: `DEVICE\aime.txt` diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 4f71216..6dc722c 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -60,7 +60,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&fgo_hook_cfg.aime, 3, fgo_hook_mod); + hr = sg_reader_hook_init(&fgo_hook_cfg.aime, 3, 3, fgo_hook_mod); if (FAILED(hr)) { goto fail; @@ -102,7 +102,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = createprocess_push_hook_a("am/amdaemon.exe", "inject -d -k fgohook.dll ", " -c config_hook.json", false); + hr = createprocess_push_hook_a("am/amdaemon.exe", "inject -d -k fgohook.dll ", "", false); if (FAILED(hr)) { goto fail; diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 5d6f695..500e9c5 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -53,7 +53,7 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, idac_hook_mod); + hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index 10b3ce5..82ae124 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -97,7 +97,7 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&idz_hook_cfg.aime, 10, idz_hook_mod); + hr = sg_reader_hook_init(&idz_hook_cfg.aime, 10, 1, idz_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/idzio/dllmain.c b/idzio/dllmain.c index 278c8c2..ad94747 100644 --- a/idzio/dllmain.c +++ b/idzio/dllmain.c @@ -111,7 +111,7 @@ void idz_io_jvs_read_coin_counter(uint16_t *out) /* Coin counter is not backend-specific */ - if ( idz_io_cfg.vk_coin && + if (idz_io_cfg.vk_coin && (GetAsyncKeyState(idz_io_cfg.vk_coin) & 0x8000)) { if (!idz_io_coin) { idz_io_coin = true; diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 3232d6c..220e213 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -51,7 +51,7 @@ static DWORD CALLBACK mai2_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, mai2_hook_mod); + hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, 1, mai2_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index f3df2a7..bcec31f 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -58,7 +58,7 @@ static DWORD CALLBACK mercury_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&mercury_hook_cfg.aime, 1, mercury_hook_mod); + hr = sg_reader_hook_init(&mercury_hook_cfg.aime, 1, 1, mercury_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index d3e09b0..b33c711 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -54,7 +54,7 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, swdc_hook_mod); + hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, 3, swdc_hook_mod); if (FAILED(hr)) { goto fail; From 3dd6054a1ee77dcff31ad2cd2baa653cef192644 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 3 Dec 2023 21:34:38 +0100 Subject: [PATCH 063/204] chusan, fgo, mu3: fixed LED 15093 board --- board/led15093.c | 31 +++++++++++++------------------ board/led15093.h | 9 ++++----- carolhook/dllmain.c | 2 +- chunihook/config.c | 3 +-- chunihook/dllmain.c | 2 +- chusanhook/config.c | 34 +++++++++++----------------------- chusanhook/dllmain.c | 28 +++++++++++++++++++++++++++- dist/chusan/segatools.ini | 7 +++---- dist/fgo/segatools.ini | 4 ++-- fgohook/config.c | 5 ++--- fgohook/dllmain.c | 2 +- hooklib/printer.c | 6 +++--- mu3hook/config.h | 2 ++ mu3hook/dllmain.c | 8 +++++++- platform/dipsw.c | 5 ++--- 15 files changed, 80 insertions(+), 68 deletions(-) diff --git a/board/led15093.c b/board/led15093.c index c00e39f..c18b1b0 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -24,7 +24,6 @@ #include "board/led15093-cmd.h" #include "board/led15093-frame.h" - #include "board/led15093.h" #include "hook/iobuf.h" @@ -101,43 +100,39 @@ static char led15093_chip_num[5]; static char led15093_boot_chip_num[5]; static uint8_t led15093_fw_ver; static uint16_t led15093_fw_sum; -static uint8_t led15093_host_adr = 255; +static uint8_t led15093_board_adr = 1; +static uint8_t led15093_host_adr = 1; -HRESULT led15093_hook_init( - const struct led15093_config *cfg, - unsigned int port_no_0, - unsigned int port_no_1) +HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, + unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) { + assert(cfg != NULL); - unsigned int port_no[2] = {port_no_0, port_no_1}; if (!cfg->enable) { return S_FALSE; } - for (int i = 0; i < led15093_nboards; i++) { - if (cfg->port_no[i] != 0) { - port_no[i] = cfg->port_no[i]; - } + if (cfg->port_no != 0) { + first_port = cfg->port_no; } + led15093_board_adr = board_adr; + led15093_host_adr = host_adr; + memcpy(led15093_board_num, cfg->board_number, sizeof(led15093_board_num)); memcpy(led15093_chip_num, cfg->chip_number, sizeof(led15093_chip_num)); memcpy(led15093_boot_chip_num, cfg->boot_chip_number, sizeof(led15093_boot_chip_num)); led15093_fw_ver = cfg->fw_ver; led15093_fw_sum = cfg->fw_sum; - for (int i = 0; i < led15093_nboards; i++) + for (int i = 0; i < num_boards; i++) { _led15093_per_board_vars *vb = &led15093_per_board_vars[i]; InitializeCriticalSection(&vb->lock); - if (port_no[i] == 0) { - continue; - } - - uart_init(&vb->boarduart, port_no[i]); + uart_init(&vb->boarduart, first_port + i); if (cfg->high_baudrate) { vb->boarduart.baud.BaudRate = 460800; } else { @@ -160,7 +155,7 @@ HRESULT led15093_hook_init( led15093_clear_status(i, 1 + j); led15093_clear_report(i, 1 + j); vn->boardstatus[3] = 1; // DIPSW1 ON - vn->boardadr = 1 + j; + vn->boardadr = led15093_board_adr + j; vn->enable_bootloader = false; vn->enable_response = true; } diff --git a/board/led15093.h b/board/led15093.h index ae4c27c..4e1b7f4 100644 --- a/board/led15093.h +++ b/board/led15093.h @@ -8,7 +8,7 @@ struct led15093_config { bool enable; bool high_baudrate; - unsigned int port_no[2]; + unsigned int port_no; char board_number[8]; char chip_number[5]; char boot_chip_number[5]; @@ -16,7 +16,6 @@ struct led15093_config { uint16_t fw_sum; }; -HRESULT led15093_hook_init( - const struct led15093_config *cfg, - unsigned int port_no_0, - unsigned int port_no_1); +HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, + unsigned int num_boards, uint8_t board_adr, uint8_t host_adr); + diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 6ff4c9f..3e86f6d 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -102,7 +102,7 @@ static DWORD CALLBACK carol_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&carol_hook_cfg.aime, 10, carol_hook_mod); + hr = sg_reader_hook_init(&carol_hook_cfg.aime, 10, 1, carol_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/chunihook/config.c b/chunihook/config.c index 92e99de..99b9c3a 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -55,8 +55,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); - cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no = 0; cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 7035943..d598672 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -96,7 +96,7 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 11); + hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 2, 2, 1); if (FAILED(hr)) { goto fail; diff --git a/chusanhook/config.c b/chusanhook/config.c index f585926..f3ff50e 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -14,20 +14,20 @@ // Check windows #if _WIN32 || _WIN64 - #if _WIN64 - #define ENV64BIT - #else - #define ENV32BIT - #endif + #if _WIN64 + #define ENV64BIT + #else + #define ENV32BIT + #endif #endif // Check GCC #if __GNUC__ - #if __x86_64__ || __ppc64__ - #define ENV64BIT - #else - #define ENV32BIT - #endif + #if __x86_64__ || __ppc64__ + #define ENV64BIT + #else + #define ENV32BIT + #endif #endif void chuni_dll_config_load( @@ -84,18 +84,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cvt_port = GetPrivateProfileIntW(L"led15093", L"cvtPort", 0, filename); - - if (!cvt_port) { - // SP mode: COM20, COM21 - cfg->port_no[0] = 20; - cfg->port_no[1] = 21; - } else { - // CVT mode: COM2, COM3 - cfg->port_no[0] = 2; - cfg->port_no[1] = 3; - } - + cfg->port_no = 0; cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); @@ -143,7 +132,6 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) } } - void chusan_hook_config_load( struct chusan_hook_config *cfg, const wchar_t *filename) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 3375158..cd66dbd 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -99,7 +99,33 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - hr = led15093_hook_init(&chusan_hook_cfg.led15093, 20, 21); + bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0]; + + if (dipsw[1] != dipsw[2]) { + dprintf("DipSw: DipSw2 and 3 must be set to the same value!\n"); + goto fail; + } + + for (int i = 0; i < 3; i++) { + switch (i) { + case 0: + dprintf("DipSw: NetInstall: %s\n", dipsw[0] ? "Server" : "Client"); + break; + + case 1: + dprintf("DipSw: Monitor Type: %dFPS\n", dipsw[1] ? 60 : 120); + break; + + case 2: + dprintf("DipSw: Aime Reader: %s\n", dipsw[2] ? "CVT" : "SP"); + + break; + } + } + + unsigned int first_port = dipsw[1] ? 2 : 20; + + hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1); if (FAILED(hr)) { goto fail; diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index dc6e2ae..df17ac3 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -46,22 +46,21 @@ enable=1 dipsw1=1 ; Monitor type: 0 = 120FPS (SP), 1 = 60FPS (CVT) dipsw2=1 -; Aime reader hardware type: 0 = SP, 1 = CVT +; Aime reader hardware type: 0 = SP, 1 = CVT. Both dipsw2 and dipsw3 must be +; the same value. dipsw3=1 [gfx] ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. -framed=1 +framed=0 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 [led15093] ; 837-15093-06 LED strip emulation setting. enable=1 -; Set to 1 if running game in 60FPS (CVT) mode. -cvtPort=0 [chuniio] ; Uncomment this if you have custom chuniio implementation. diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 18e2bbb..d106aaf 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -64,8 +64,8 @@ portNo=17 [led15093] ; 837-15093-06 LED board emulation setting. enable=1 -; COM port number for the first LED board. Has to be the same as the FTDI port. -portNo0=17 +; COM port number for the LED board. Has to be the same as the FTDI port. +portNo=17 ; ----------------------------------------------------------------------------- ; Input settings diff --git a/fgohook/config.c b/fgohook/config.c index 3253568..4b05e97 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -47,11 +47,10 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); - cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xaa53, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); GetPrivateProfileStringW( L"led15093", diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 6dc722c..fcac111 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -96,7 +96,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 0); + hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 1, 1, 2); if (FAILED(hr)) { goto fail; diff --git a/hooklib/printer.c b/hooklib/printer.c index bdc913c..1ef5a0c 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -1042,7 +1042,7 @@ static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte) { return S_OK; } -// C310FWDLusb stubs +// C3XXFWDLusb stubs int fwdlusb_open(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); @@ -1674,7 +1674,7 @@ int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) break; case 20: // printMode - dprintf("Printer: C3xxusb: Unimpl tagNumber 20\n"); + dprintf("Printer: C3XXusb: Unimpl tagNumber 20\n"); break; case 26: // getPrinterSerial @@ -1683,7 +1683,7 @@ int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) break; case 30: // TODO - dprintf("Printer: C3xxusb: Unimpl tagNumber 30\n"); + dprintf("Printer: C3XXusb: Unimpl tagNumber 30\n"); break; case 31: // TODO, possibly CardRFIDCheck? diff --git a/mu3hook/config.h b/mu3hook/config.h index 58af239..1273983 100644 --- a/mu3hook/config.h +++ b/mu3hook/config.h @@ -3,6 +3,7 @@ #include #include "board/config.h" +#include "board/led15093.h" #include "gfxhook/gfx.h" @@ -18,6 +19,7 @@ struct mu3_hook_config { struct dvd_config dvd; struct io4_config io4; struct gfx_config gfx; + struct led15093_config led15093; struct mu3_dll_config dll; }; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index dd01104..b867345 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -61,7 +61,13 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, mu3_hook_mod); + hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2); + + if (FAILED(hr)) { + return hr; + } + + hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/platform/dipsw.c b/platform/dipsw.c index ee6dd91..b9caf44 100644 --- a/platform/dipsw.c +++ b/platform/dipsw.c @@ -74,7 +74,7 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) if (f == NULL) { - dprintf("First run detected, DipSw settings can only be applied AFTER the first run\n"); + dprintf("DipSw: First run detected, DipSw settings can only be applied AFTER the first run\n"); return; } @@ -84,7 +84,7 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) if (file_size != 0x6000) { - dprintf("Invalid sysfile.dat file size\n"); + dprintf("DipSw: Invalid sysfile.dat file size\n"); fclose(f); return; @@ -94,7 +94,6 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) fread(dip_switches.data, 1, file_size, f); fclose(f); - // memcpy(dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); memcpy(&dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); } From 4ffcf25555abff9d9ed28164e278774c1e775975 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 3 Dec 2023 22:22:17 +0100 Subject: [PATCH 064/204] added freeplay setting to ALLS games --- Package.mk | 1 - dist/chusan/segatools.ini | 5 +++ dist/idac/segatools.ini | 5 +++ dist/mai2/segatools.ini | 5 +++ dist/mercury/segatools.ini | 46 ++++++++++++++++++++-------- dist/mu3/segatools.ini | 9 ++++++ dist/swdc/config_hook.json | 10 ------ dist/swdc/segatools.ini | 9 ++++++ dist/swdc/start.bat | 2 +- platform/config.c | 1 + platform/dipsw.c | 62 ++++++++++++++++++++++++++++---------- platform/dipsw.h | 1 + 12 files changed, 116 insertions(+), 40 deletions(-) delete mode 100644 dist/swdc/config_hook.json diff --git a/Package.mk b/Package.mk index ac567a6..438421e 100644 --- a/Package.mk +++ b/Package.mk @@ -110,7 +110,6 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/swdchook/swdchook.dll \ - $(DIST_DIR)/swdc/config_hook.json \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/start.bat \ $(BUILD_DIR_ZIP)/swdc diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index df17ac3..1631b35 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -41,6 +41,11 @@ subnet=192.168.100.0 ; ALLS DIP switches. enable=1 +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 22a0568..830f78b 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -42,6 +42,11 @@ region=4 ; ALLS DIP switches. enable=1 +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + ; If multiple machines are present on the same LAN then set this to 1 on ; exactly one machine and set this to 0 on all others. dipsw1=1 diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 148d852..f3dc0d8 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -34,6 +34,11 @@ subnet=192.168.100.0 ; ALLS DIP switches. enable=1 +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index f231c66..80816b4 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -12,14 +12,6 @@ option=option ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 -[ds] -; Region code on the emulated AMEX board DS EEPROM. -; 1: Japan -; 4: Export (some UI elements in English) -; -; NOTE: Changing this setting causes a factory reset. -region=1 - [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. ; SEGA games are somewhat picky about their LAN environment, so leaving this @@ -35,12 +27,42 @@ subnet=192.168.174.0 [gfx] enable=1 +[gpio] +; ALLS DIP switches. +enable=1 + +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 1 on exactly one machine and set this to 0 on all others. +dipsw1=1 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io4] -; Input API selection for JVS input emulator. -test=0x2D -service=0x2E -coin=0x24 +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 + +; Volume up virtual-key code. Default is the "UP" key. volup=0x26 +; Volume down virtual-key code. Default is the "DOWN" key. voldown=0x28 ; Hooks related to the touch boards diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 0ec7dd4..83fe03b 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -34,6 +34,11 @@ subnet=192.168.162.0 ; ALLS DIP switches. enable=1 +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 @@ -41,6 +46,10 @@ dipsw1=1 [gfx] enable=1 +[led15093] +; 837-15093-06 LED board emulation setting. +enable=1 + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/swdc/config_hook.json b/dist/swdc/config_hook.json deleted file mode 100644 index d0d8767..0000000 --- a/dist/swdc/config_hook.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "aime" : - { - "firmware_path" : - [ - ".\\aime_firm\\TN32MSEC003S_V12.hex", - ".\\aime_firm\\update_15396_6728_94.bin" - ] - } -} diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 7f030d0..f3867a7 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -40,6 +40,15 @@ path= ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= +[gpio] +; ALLS DIP switches. +enable=1 + +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index 020c27f..c5e7733 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -5,7 +5,7 @@ pushd %~dp0 rem Matching Server start /min ..\..\..\Tools\tdrserver.exe REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json -start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json config_hook.json +start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED diff --git a/platform/config.c b/platform/config.c index 8e71847..05f1a0b 100644 --- a/platform/config.c +++ b/platform/config.c @@ -330,6 +330,7 @@ void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 0, filename); + cfg->freeplay = GetPrivateProfileIntW(L"gpio", L"freeplay", 0, filename); wcscpy_s(name, _countof(name), L"dipsw0"); diff --git a/platform/dipsw.c b/platform/dipsw.c index b9caf44..22b88ed 100644 --- a/platform/dipsw.c +++ b/platform/dipsw.c @@ -19,20 +19,29 @@ typedef struct { uint32_t checksum; - char padding_1[4]; + char padding[6]; + uint8_t freeplay; + char data[DATA_SIZE - 2]; +} CreditBlock; + +typedef struct +{ + uint32_t checksum; + char padding[4]; uint8_t dip_switches; char data[DATA_SIZE]; } DipSwitchBlock; typedef struct { + CreditBlock credit_block; DipSwitchBlock dip_switch_block; char *data; -} DipSwitches; +} SystemInfo; #pragma pack(pop) -static DipSwitches dip_switches; +static SystemInfo system_info; static struct dipsw_config dipsw_config; static struct vfs_config vfs_config; @@ -90,16 +99,21 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) return; } - dip_switches.data = malloc(file_size); - fread(dip_switches.data, 1, file_size, f); + system_info.data = malloc(file_size); + fread(system_info.data, 1, file_size, f); fclose(f); - memcpy(&dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); + // copy the credit_block and dip_switch_block from the sysfile.dat + memcpy(&system_info.credit_block, system_info.data, BLOCK_SIZE); + memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE); } static void dipsw_save_sysfile(const wchar_t *sys_file) { + char block[BLOCK_SIZE]; uint8_t dipsw = 0; + uint8_t freeplay = 0; + // open the sysfile.dat for writing in bytes mode FILE *f = _wfopen(sys_file, L"rb+"); @@ -119,33 +133,49 @@ static void dipsw_save_sysfile(const wchar_t *sys_file) } } - dip_switches.dip_switch_block.dip_switches = dipsw; + if (dipsw_config.freeplay) + { + // print that freeplay is enabled + dprintf("DipSw: Freeplay enabled\n"); + freeplay = 1; + } + + // set the new credit block + system_info.credit_block.freeplay = freeplay; + // set the new dip_switch_block + system_info.dip_switch_block.dip_switches = dipsw; // calculate the new checksum, skip the old crc32 value // which is at the beginning of the block, thats's why the +4 // conver the struct to chars in order for the crc32 calculation to work - dip_switches.dip_switch_block.checksum = crc32( - (char *)&dip_switches.dip_switch_block + 4, BLOCK_SIZE - 4, 0); + system_info.credit_block.checksum = crc32( + (char *)&system_info.credit_block + 4, BLOCK_SIZE - 4, 0); + system_info.dip_switch_block.checksum = crc32( + (char *)&system_info.dip_switch_block + 4, BLOCK_SIZE - 4, 0); + + // build the new credit block + memcpy(block, (char *)&system_info.credit_block, BLOCK_SIZE); + + memcpy(system_info.data, block, BLOCK_SIZE); + memcpy(system_info.data + 0x3000, block, BLOCK_SIZE); // build the new dip switch block - char block[BLOCK_SIZE]; - memcpy(block, (char *)&dip_switches.dip_switch_block, BLOCK_SIZE); + memcpy(block, (char *)&system_info.dip_switch_block, BLOCK_SIZE); - // replace the old block with the new one - memcpy(dip_switches.data + 0x2800, block, BLOCK_SIZE); - memcpy(dip_switches.data + 0x5800, block, BLOCK_SIZE); + memcpy(system_info.data + 0x2800, block, BLOCK_SIZE); + memcpy(system_info.data + 0x5800, block, BLOCK_SIZE); // print the dip_switch_block in hex /* dprintf("DipSw Block: "); for (size_t i = 0; i < BLOCK_SIZE; i++) { - dprintf("%02X ", ((uint8_t *)&dip_switches.dip_switch_block)[i]); + dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]); } dprintf("\n"); */ - fwrite(dip_switches.data, 1, 0x6000, f); + fwrite(system_info.data, 1, 0x6000, f); fclose(f); } diff --git a/platform/dipsw.h b/platform/dipsw.h index a4bfdb2..336b0d7 100644 --- a/platform/dipsw.h +++ b/platform/dipsw.h @@ -9,6 +9,7 @@ struct dipsw_config { bool enable; + bool freeplay; bool dipsw[8]; }; From 72db08ac938c4746d57b26e9987d9eedea33970e Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 11 Dec 2023 19:18:25 +0100 Subject: [PATCH 065/204] idz, idac, swdc: added FFB centering spring feature --- dist/idac/segatools.ini | 7 ++++++- dist/idz/segatools.ini | 5 +++++ dist/swdc/segatools.ini | 5 +++++ idacio/config.c | 8 ++++++++ idacio/config.h | 3 +++ idacio/di-dev.c | 30 ++++++++++++++++++------------ idacio/di-dev.h | 2 +- idacio/di.c | 15 ++++++++++++++- idzio/config.c | 7 +++++++ idzio/config.h | 3 +++ idzio/di-dev.c | 30 ++++++++++++++++++------------ idzio/di-dev.h | 2 +- idzio/di.c | 15 ++++++++++++++- swdcio/config.c | 8 ++++++++ swdcio/config.h | 3 +++ swdcio/di-dev.c | 30 ++++++++++++++++++------------ swdcio/di-dev.h | 2 +- swdcio/di.c | 15 ++++++++++++++- 18 files changed, 147 insertions(+), 43 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 830f78b..bf9bafc 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -29,7 +29,7 @@ enable=1 ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. Set it to your LAN's subnet if you ; want to play head-to-head using netenv=1. -subnet=192.168.100.0 +subnet=192.168.158.0 ; Override the keychip's region code. Most games seem to pay attention to the ; DS EEPROM region code and not the keychip region code, and this seems to be @@ -174,3 +174,8 @@ gear6=18 ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 reverseBrakeAxis=0 + +; Force feedback settings. +; Strength of the force feedback spring effect in percent. Possible values +; are 0-100. +centerSpringStrength=30 diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index c7fa88b..e7b0701 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -173,3 +173,8 @@ gear6=18 ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 reverseBrakeAxis=0 + +; Force feedback settings. +; Strength of the force feedback spring effect in percent. Possible values +; are 0-100. +centerSpringStrength=30 diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index f3867a7..fb93e50 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -133,3 +133,8 @@ wheelGreen=10 ; (Needed when using DirectInput for the Dualshock 4 for example) reverseAccelAxis=0 reverseBrakeAxis=0 + +; Force feedback settings. +; Strength of the force feedback spring effect in percent. Possible values +; are 0-100. +centerSpringStrength=30 diff --git a/idacio/config.c b/idacio/config.c index f6ed605..2daeb8f 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -79,6 +79,14 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename) cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename); } + // FFB configuration + + cfg->center_spring_strength = GetPrivateProfileIntW( + L"dinput", + L"centerSpringStrength", + 30, + filename); + } void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) diff --git a/idacio/config.h b/idacio/config.h index ec91ce6..bbf568d 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -23,6 +23,9 @@ struct idac_di_config { uint8_t gear[6]; bool reverse_brake_axis; bool reverse_accel_axis; + + // FFB configuration + uint16_t center_spring_strength; }; struct idac_xi_config { diff --git a/idacio/di-dev.c b/idacio/di-dev.c index c77584b..62cab2f 100644 --- a/idacio/di-dev.c +++ b/idacio/di-dev.c @@ -44,7 +44,8 @@ HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) return hr; } -void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +void idac_di_dev_start_fx( + IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) { /* Set up force-feedback on devices that support it. This is just a stub for the time being, since we don't yet know how the serial port force @@ -67,7 +68,7 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) DWORD axis; LONG direction; DIEFFECT fx; - DICONSTANTFORCE cf; + DICONDITION cond; HRESULT hr; assert(dev != NULL); @@ -77,11 +78,17 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + // Auto-centering effect axis = DIJOFS_X; direction = 0; - memset(&cf, 0, sizeof(cf)); - cf.lMagnitude = 0; + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = strength; + cond.lNegativeCoefficient = strength; + cond.dwPositiveSaturation = strength; // For FG920? + cond.dwNegativeSaturation = strength; // For FG920? + cond.lDeadBand = 0; memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); @@ -93,20 +100,19 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) fx.cAxes = 1; fx.rgdwAxes = &axis; fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cf); - fx.lpvTypeSpecificParams = &cf; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; hr = IDirectInputDevice8_CreateEffect( dev, - &GUID_ConstantForce, + &GUID_Spring, &fx, &obj, NULL); if (FAILED(hr)) { - dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", (int) hr); - return; } @@ -114,15 +120,15 @@ void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) if (FAILED(hr)) { IDirectInputEffect_Release(obj); - dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", (int) hr); - return; } *out = obj; - dprintf("DirectInput: Force feedback initialized and set to zero\n"); + dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", + strength / 100); } HRESULT idac_di_dev_poll( diff --git a/idacio/di-dev.h b/idacio/di-dev.h index efbe39e..b1559e3 100644 --- a/idacio/di-dev.h +++ b/idacio/di-dev.h @@ -11,7 +11,7 @@ union idac_di_state { }; HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT idac_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, diff --git a/idacio/di.c b/idacio/di.c index 75e2c50..55018e8 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -75,6 +75,7 @@ static uint8_t idac_di_gear[6]; static bool idac_di_use_pedals; static bool idac_di_reverse_brake_axis; static bool idac_di_reverse_accel_axis; +static uint16_t idac_di_center_spring_strength; HRESULT idac_di_init( const struct idac_di_config *cfg, @@ -173,7 +174,9 @@ HRESULT idac_di_init( return hr; } - idac_di_dev_start_fx(idac_di_dev, &idac_di_fx); + // Convert the strength from 0-100 to 0-10000 for DirectInput + idac_di_dev_start_fx(idac_di_dev, &idac_di_fx, + idac_di_center_spring_strength * 100); if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( @@ -364,6 +367,16 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) idac_di_gear[i] = cfg->gear[i]; } + // FFB configuration + + if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { + dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + + return E_INVALIDARG; + } + + idac_di_center_spring_strength = cfg->center_spring_strength; + return S_OK; } diff --git a/idzio/config.c b/idzio/config.c index 25b188d..2a6e083 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -76,7 +76,14 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename) swprintf_s(key, _countof(key), L"gear%i", i + 1); cfg->gear[i] = GetPrivateProfileIntW(L"dinput", key, i + 1, filename); } + + // FFB configuration + cfg->center_spring_strength = GetPrivateProfileIntW( + L"dinput", + L"centerSpringStrength", + 30, + filename); } void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) diff --git a/idzio/config.h b/idzio/config.h index 6b4cd20..155f797 100644 --- a/idzio/config.h +++ b/idzio/config.h @@ -21,6 +21,9 @@ struct idz_di_config { uint8_t gear[6]; bool reverse_brake_axis; bool reverse_accel_axis; + + // FFB configuration + uint16_t center_spring_strength; }; struct idz_xi_config { diff --git a/idzio/di-dev.c b/idzio/di-dev.c index 6f66bf0..26cf6e3 100644 --- a/idzio/di-dev.c +++ b/idzio/di-dev.c @@ -44,7 +44,8 @@ HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) return hr; } -void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +void idz_di_dev_start_fx( + IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) { /* Set up force-feedback on devices that support it. This is just a stub for the time being, since we don't yet know how the serial port force @@ -67,7 +68,7 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) DWORD axis; LONG direction; DIEFFECT fx; - DICONSTANTFORCE cf; + DICONDITION cond; HRESULT hr; assert(dev != NULL); @@ -77,11 +78,17 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + // Auto-centering effect axis = DIJOFS_X; direction = 0; - memset(&cf, 0, sizeof(cf)); - cf.lMagnitude = 0; + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = strength; + cond.lNegativeCoefficient = strength; + cond.dwPositiveSaturation = strength; // For FG920? + cond.dwNegativeSaturation = strength; // For FG920? + cond.lDeadBand = 0; memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); @@ -93,20 +100,19 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) fx.cAxes = 1; fx.rgdwAxes = &axis; fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cf); - fx.lpvTypeSpecificParams = &cf; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; hr = IDirectInputDevice8_CreateEffect( dev, - &GUID_ConstantForce, + &GUID_Spring, &fx, &obj, NULL); if (FAILED(hr)) { - dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", (int) hr); - return; } @@ -114,15 +120,15 @@ void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) if (FAILED(hr)) { IDirectInputEffect_Release(obj); - dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", (int) hr); - return; } *out = obj; - dprintf("DirectInput: Force feedback initialized and set to zero\n"); + dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", + strength / 100); } HRESULT idz_di_dev_poll( diff --git a/idzio/di-dev.h b/idzio/di-dev.h index 9c8b2d2..9b3d03f 100644 --- a/idzio/di-dev.h +++ b/idzio/di-dev.h @@ -11,7 +11,7 @@ union idz_di_state { }; HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT idz_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, diff --git a/idzio/di.c b/idzio/di.c index 5d0a454..e0cb4c6 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -73,6 +73,7 @@ static uint8_t idz_di_gear[6]; static bool idz_di_use_pedals; static bool idz_di_reverse_brake_axis; static bool idz_di_reverse_accel_axis; +static uint16_t idz_di_center_spring_strength; HRESULT idz_di_init( const struct idz_di_config *cfg, @@ -171,7 +172,9 @@ HRESULT idz_di_init( return hr; } - idz_di_dev_start_fx(idz_di_dev, &idz_di_fx); + // Convert the strength from 0-100 to 0-10000 for DirectInput + idz_di_dev_start_fx(idz_di_dev, &idz_di_fx, + idz_di_center_spring_strength * 100); if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( @@ -346,6 +349,16 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) idz_di_gear[i] = cfg->gear[i]; } + // FFB configuration + + if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { + dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + + return E_INVALIDARG; + } + + idz_di_center_spring_strength = cfg->center_spring_strength; + return S_OK; } diff --git a/swdcio/config.c b/swdcio/config.c index 0dce00e..4208c76 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -67,6 +67,14 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename) L"reverseAccelAxis", 0, filename); + + // FFB configuration + + cfg->center_spring_strength = GetPrivateProfileIntW( + L"dinput", + L"centerSpringStrength", + 30, + filename); } void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) diff --git a/swdcio/config.h b/swdcio/config.h index d6f9667..ba3240c 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -19,6 +19,9 @@ struct swdc_di_config { uint8_t wheel_yellow; bool reverse_brake_axis; bool reverse_accel_axis; + + // FFB configuration + uint16_t center_spring_strength; }; struct swdc_xi_config { diff --git a/swdcio/di-dev.c b/swdcio/di-dev.c index 116e529..254596a 100644 --- a/swdcio/di-dev.c +++ b/swdcio/di-dev.c @@ -44,7 +44,8 @@ HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) return hr; } -void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +void swdc_di_dev_start_fx( + IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) { /* Set up force-feedback on devices that support it. This is just a stub for the time being, since we don't yet know how the serial port force @@ -67,7 +68,7 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) DWORD axis; LONG direction; DIEFFECT fx; - DICONSTANTFORCE cf; + DICONDITION cond; HRESULT hr; assert(dev != NULL); @@ -77,11 +78,17 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + // Auto-centering effect axis = DIJOFS_X; direction = 0; - memset(&cf, 0, sizeof(cf)); - cf.lMagnitude = 0; + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = strength; + cond.lNegativeCoefficient = strength; + cond.dwPositiveSaturation = strength; // For FG920? + cond.dwNegativeSaturation = strength; // For FG920? + cond.lDeadBand = 0; memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); @@ -93,20 +100,19 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) fx.cAxes = 1; fx.rgdwAxes = &axis; fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cf); - fx.lpvTypeSpecificParams = &cf; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; hr = IDirectInputDevice8_CreateEffect( dev, - &GUID_ConstantForce, + &GUID_Spring, &fx, &obj, NULL); if (FAILED(hr)) { - dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", (int) hr); - return; } @@ -114,15 +120,15 @@ void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) if (FAILED(hr)) { IDirectInputEffect_Release(obj); - dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", (int) hr); - return; } *out = obj; - dprintf("DirectInput: Force feedback initialized and set to zero\n"); + dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", + strength / 100); } HRESULT swdc_di_dev_poll( diff --git a/swdcio/di-dev.h b/swdcio/di-dev.h index 82ceef0..06ac036 100644 --- a/swdcio/di-dev.h +++ b/swdcio/di-dev.h @@ -11,7 +11,7 @@ union swdc_di_state { }; HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT swdc_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, diff --git a/swdcio/di.c b/swdcio/di.c index 35c6463..09f25d0 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -70,6 +70,7 @@ static uint8_t swdc_di_wheel_yellow; static bool swdc_di_use_pedals; static bool swdc_di_reverse_brake_axis; static bool swdc_di_reverse_accel_axis; +static uint16_t swdc_di_center_spring_strength; HRESULT swdc_di_init( const struct swdc_di_config *cfg, @@ -168,7 +169,9 @@ HRESULT swdc_di_init( return hr; } - swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx); + // Convert the strength from 0-100 to 0-10000 for DirectInput + swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx, + swdc_di_center_spring_strength * 100); if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( @@ -320,6 +323,16 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) swdc_di_reverse_brake_axis = cfg->reverse_brake_axis; swdc_di_reverse_accel_axis = cfg->reverse_accel_axis; + // FFB configuration + + if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { + dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + + return E_INVALIDARG; + } + + swdc_di_center_spring_strength = cfg->center_spring_strength; + return S_OK; } From 1cbc33d97d86bd686cb01887edacd5b7600a0bce Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 17 Dec 2023 09:26:30 +0100 Subject: [PATCH 066/204] chuasn: fixed coin insert for custom chuniio --- chuniio/chuniio.c | 11 +---------- chusanhook/io4.c | 5 ++--- dist/chusan/segatools.ini | 4 ++-- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 86938be..5df741f 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -38,7 +38,7 @@ void chuni_io_jvs_read_coin_counter(uint16_t *out) return; } - if (GetAsyncKeyState(chuni_io_cfg.vk_coin)) { + if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) { if (!chuni_io_coin) { chuni_io_coin = true; chuni_io_coins++; @@ -62,15 +62,6 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) *opbtn |= CHUNI_IO_OPBTN_SERVICE; } - if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) { - if (!chuni_io_coin) { - chuni_io_coin = true; - *opbtn |= CHUNI_IO_OPBTN_COIN; - } - } else { - chuni_io_coin = false; - } - if (chuni_io_cfg.vk_ir_emu) { // Use emulated AIR if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) { diff --git a/chusanhook/io4.c b/chusanhook/io4.c index 2495369..c7f8265 100644 --- a/chusanhook/io4.c +++ b/chusanhook/io4.c @@ -73,6 +73,7 @@ static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) beams = 0; chuni_dll.jvs_poll(&opbtn, &beams); + chuni_dll.jvs_read_coin_counter(&coins); if (chuni_dll.api_version >= 0x0101) { // Use correct mapping @@ -90,9 +91,7 @@ static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) state->buttons[0] |= IO4_BUTTON_SERVICE; } - if (opbtn & CHUNI_IO_OPBTN_COIN) { - coins++; - } + // Update the coin counter with the value from jvs_read_coin_counter state->chutes[0] = coins << 8; for (i = 0; i < 6; i++) { diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 1631b35..df9419f 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -18,7 +18,7 @@ aimePath=DEVICE\aime.txt [aimeio] ; x64 aimeio dll path. ; Uncomment this if you have custom aime implementation. -;path64= +;path= [dns] ; Insert the hostname or IP address of the server you wish to use here. @@ -35,7 +35,7 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.100.0 +subnet=192.168.139.0 [gpio] ; ALLS DIP switches. From ad154a83e5b361ed9605c82991a5967d267c60b1 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 17 Dec 2023 19:43:00 +0100 Subject: [PATCH 067/204] chusan: fixed dipsw settings, added aimeio DLL loading --- board/aime-dll.h | 1 + board/config.c | 43 ++++++++++++++++++++++++++++++++++++++- chusanhook/config.c | 3 +++ chusanhook/dllmain.c | 20 ++++++++++-------- dist/chusan/segatools.ini | 10 ++++----- 5 files changed, 63 insertions(+), 14 deletions(-) diff --git a/board/aime-dll.h b/board/aime-dll.h index 354516b..75dba9e 100644 --- a/board/aime-dll.h +++ b/board/aime-dll.h @@ -18,6 +18,7 @@ struct aime_dll { struct aime_dll_config { wchar_t path[MAX_PATH]; + bool path64; }; extern struct aime_dll aime_dll; diff --git a/board/config.c b/board/config.c index 3ffa6ab..bbbf074 100644 --- a/board/config.c +++ b/board/config.c @@ -9,18 +9,59 @@ #include "board/config.h" #include "board/sg-reader.h" +#include "util/dprintf.h" + +// Check windows +#if _WIN32 || _WIN64 + #if _WIN64 + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +// Check GCC +#if __GNUC__ + #if __x86_64__ || __ppc64__ + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( + // Workaround for x64/x86 external IO dlls + // path32 for 32bit, path64 for 64bit + // for else.. is that possible? idk + + if (cfg->path64) { + #if defined(ENV32BIT) + // Always empty, due to amdaemon being 64 bit in 32 bit mode + memset(cfg->path, 0, sizeof(cfg->path)); + #elif defined(ENV64BIT) + GetPrivateProfileStringW( + L"aimeio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); + #else + #error "Unknown environment" + #endif + } else { + GetPrivateProfileStringW( L"aimeio", L"path", L"", cfg->path, _countof(cfg->path), filename); + } } void aime_config_load(struct aime_config *cfg, const wchar_t *filename) diff --git a/chusanhook/config.c b/chusanhook/config.c index f3ff50e..0361e98 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -141,6 +141,9 @@ void chusan_hook_config_load( memset(cfg, 0, sizeof(*cfg)); + // Force load the 64bit Aime DLL instead of the 32bit one + cfg->aime.dll.path64 = true; + platform_config_load(&cfg->platform, filename); aime_config_load(&cfg->aime, filename); dvd_config_load(&cfg->dvd, filename); diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index cd66dbd..61c7f47 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -100,11 +100,7 @@ static DWORD CALLBACK chusan_pre_startup(void) } bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0]; - - if (dipsw[1] != dipsw[2]) { - dprintf("DipSw: DipSw2 and 3 must be set to the same value!\n"); - goto fail; - } + bool *is_sp = dipsw + 2; for (int i = 0; i < 3; i++) { switch (i) { @@ -117,13 +113,21 @@ static DWORD CALLBACK chusan_pre_startup(void) break; case 2: - dprintf("DipSw: Aime Reader: %s\n", dipsw[2] ? "CVT" : "SP"); + dprintf("DipSw: Cab Type: %s\n", is_sp ? "SP" : "CVT"); break; } } - unsigned int first_port = dipsw[1] ? 2 : 20; + unsigned int first_port = is_sp ? 20 : 2; + + if (is_sp) { + hr = vfd_hook_init(2); + + if (FAILED(hr)) { + goto fail; + } + } hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1); @@ -131,7 +135,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, dipsw[2] ? 2 : 3, chusan_hook_mod); + hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_sp ? 3: 2, chusan_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index df9419f..44d1a96 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -16,8 +16,8 @@ aimePath=DEVICE\aime.txt ;highbaud=1 [aimeio] -; x64 aimeio dll path. -; Uncomment this if you have custom aime implementation. +; Uncomment this if you have custom (x64) aime implementation. +; Leave empty if you want to use Segatools built-in keyboard input. ;path= [dns] @@ -49,10 +49,10 @@ freeplay=0 ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 -; Monitor type: 0 = 120FPS (SP), 1 = 60FPS (CVT) +; Monitor type: 0 = 120FPS, 1 = 60FPS dipsw2=1 -; Aime reader hardware type: 0 = SP, 1 = CVT. Both dipsw2 and dipsw3 must be -; the same value. +; Cab type: 0 = SP, 1 = CVT. SP will enable VFD and eMoney. This setting will switch +; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well. dipsw3=1 [gfx] From ed042176d7ec21c8e1af7f7a5cd6e906689b8f8c Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 17 Dec 2023 20:17:26 +0100 Subject: [PATCH 068/204] chusan: ledport changed to COM5, fixes VFD --- chuniio/config.c | 2 +- dist/chuni/segatools.ini | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/chuniio/config.c b/chuniio/config.c index 580a056..07d78ad 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -57,7 +57,7 @@ void chuni_io_config_load( filename); } - GetPrivateProfileStringW(L"slider", L"ledport", L"COM2", port_input, 6, filename); + GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename); wcsncpy(cfg->led_com, L"\\\\.\\", 4); wcsncat_s(cfg->led_com, 11, port_input, 6); } diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 7724c30..ba75d61 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -82,3 +82,7 @@ coin=0x33 ;cell31=0x53 ;cell30=0x53 ; ... etc ... + +; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. +; eg. COM5 +;ledport= From 8ebdf67d6e06fae3d613fdf60265c8311f3de077 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 19 Dec 2023 12:43:26 +0100 Subject: [PATCH 069/204] chuni/chusan: added LED output to DLLs (will break most DLLs) Credits: somewhatlurker, skogaby https://dev.s-ul.net/skogaby/segatools/-/blob/ongeki-15093/ --- board/led15093.c | 31 +++++++- board/led15093.h | 7 +- chunihook/chuni-dll.c | 6 ++ chunihook/chuni-dll.h | 2 + chunihook/chunihook.def | 2 + chunihook/dllmain.c | 4 +- chuniio/chuniio.c | 84 ++++++-------------- chuniio/chuniio.h | 18 +++++ chuniio/config.c | 23 +++++- chuniio/config.h | 13 +++- chuniio/leddata.h | 22 ++++++ chuniio/ledoutput.c | 133 +++++++++++++++++++++++++++++++ chuniio/ledoutput.h | 19 +++++ chuniio/meson.build | 7 ++ chuniio/pipeimpl.c | 160 ++++++++++++++++++++++++++++++++++++++ chuniio/pipeimpl.h | 14 ++++ chuniio/serialimpl.c | 99 +++++++++++++++++++++++ chuniio/serialimpl.h | 15 ++++ chusanhook/chuni-dll.c | 6 ++ chusanhook/chuni-dll.h | 2 + chusanhook/chusanhook.def | 2 + chusanhook/dllmain.c | 3 +- chusanhook/led1509306.h | 16 ---- dist/chuni/segatools.ini | 71 ++++++++++++++--- dist/chusan/segatools.ini | 45 ++++++++++- fgohook/dllmain.c | 4 +- fgohook/fgo-dll.c | 6 ++ fgohook/fgo-dll.h | 2 + fgohook/fgohook.def | 2 + fgoio/fgoio.c | 10 +++ fgoio/fgoio.h | 15 ++++ mu3hook/config.h | 4 +- mu3hook/dllmain.c | 3 + 33 files changed, 743 insertions(+), 107 deletions(-) create mode 100644 chuniio/leddata.h create mode 100644 chuniio/ledoutput.c create mode 100644 chuniio/ledoutput.h create mode 100644 chuniio/pipeimpl.c create mode 100644 chuniio/pipeimpl.h create mode 100644 chuniio/serialimpl.c create mode 100644 chuniio/serialimpl.h delete mode 100644 chusanhook/led1509306.h diff --git a/board/led15093.c b/board/led15093.c index c18b1b0..4224303 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -103,11 +103,16 @@ static uint16_t led15093_fw_sum; static uint8_t led15093_board_adr = 1; static uint8_t led15093_host_adr = 1; -HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, - unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) +static io_led_init_t led_init; +static io_led_set_leds_t set_leds; + +HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, + io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) { assert(cfg != NULL); + assert(_led_init != NULL); + assert(_set_leds != NULL); if (!cfg->enable) { return S_FALSE; @@ -117,6 +122,8 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first first_port = cfg->port_no; } + led_init = _led_init; + set_leds = _set_leds; led15093_board_adr = board_adr; led15093_host_adr = host_adr; @@ -207,9 +214,9 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) if (!v->started) { dprintf("LED 15093: Starting LED backend\n"); - // hr = fgo_dll.led_init(); - hr = S_OK; + hr = led_init(); + // hr = S_OK; v->started = true; v->start_hr = hr; @@ -229,6 +236,19 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) } } */ + + if (irp->op == IRP_OP_OPEN) { + dprintf("LED 15093: Starting backend DLL\n"); + int res = led_init(); + + if (res != 0) { + dprintf("LED 15093: Backend error, LED board disconnected: " + "%d\n", + res); + + return E_FAIL; + } + } hr = uart_handle_irp(boarduart, irp); @@ -624,6 +644,9 @@ static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led memcpy(v->led, req->data, req->hdr.nbytes - 1); + // Return the current LED data, remove const qualifier + set_leds(board, (uint8_t *) req->data); + if (!v->enable_response) return S_OK; diff --git a/board/led15093.h b/board/led15093.h index 4e1b7f4..ff2f612 100644 --- a/board/led15093.h +++ b/board/led15093.h @@ -16,6 +16,9 @@ struct led15093_config { uint16_t fw_sum; }; -HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, - unsigned int num_boards, uint8_t board_adr, uint8_t host_adr); +typedef int (*io_led_init_t)(); +typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb); + +HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, + io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr); diff --git a/chunihook/chuni-dll.c b/chunihook/chuni-dll.c index c98a9de..72393e9 100644 --- a/chunihook/chuni-dll.c +++ b/chunihook/chuni-dll.c @@ -30,6 +30,12 @@ const struct dll_bind_sym chuni_dll_syms[] = { }, { .sym = "chuni_io_slider_set_leds", .off = offsetof(struct chuni_dll, slider_set_leds), + }, { + .sym = "chuni_io_led_init", + .off = offsetof(struct chuni_dll, led_init), + }, { + .sym = "chuni_io_led_set_colors", + .off = offsetof(struct chuni_dll, led_set_leds), } }; diff --git a/chunihook/chuni-dll.h b/chunihook/chuni-dll.h index ecd88ee..034b204 100644 --- a/chunihook/chuni-dll.h +++ b/chunihook/chuni-dll.h @@ -13,6 +13,8 @@ struct chuni_dll { void (*slider_start)(chuni_io_slider_callback_t callback); void (*slider_stop)(void); void (*slider_set_leds)(const uint8_t *rgb); + int (*led_init)(); + void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; struct chuni_dll_config { diff --git a/chunihook/chunihook.def b/chunihook/chunihook.def index 2a90ab6..517a10b 100644 --- a/chunihook/chunihook.def +++ b/chunihook/chunihook.def @@ -20,3 +20,5 @@ EXPORTS chuni_io_slider_set_leds chuni_io_slider_start chuni_io_slider_stop + chuni_io_led_init + chuni_io_led_set_colors diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index d598672..69cf559 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -4,6 +4,7 @@ #include "amex/amex.h" +#include "board/led15093.h" #include "board/sg-reader.h" #include "chunihook/config.h" @@ -96,7 +97,8 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 2, 2, 1); + hr = led15093_hook_init(&chuni_hook_cfg.led15093, + chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1); if (FAILED(hr)) { goto fail; diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 5df741f..32481f1 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -7,6 +7,7 @@ #include "chuniio/chuniio.h" #include "chuniio/config.h" +#include "chuniio/ledoutput.h" #include "util/dprintf.h" @@ -18,7 +19,6 @@ static uint8_t chuni_io_hand_pos; static HANDLE chuni_io_slider_thread; static bool chuni_io_slider_stop_flag; static struct chuni_io_config chuni_io_cfg; -static HANDLE chuni_io_slider_led_port; uint16_t chuni_io_get_api_version(void) { @@ -28,7 +28,17 @@ uint16_t chuni_io_get_api_version(void) HRESULT chuni_io_jvs_init(void) { chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini"); - + + led_init_mutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (led_init_mutex == NULL) + { + return E_FAIL; + } + return S_OK; } @@ -93,7 +103,7 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) HRESULT chuni_io_slider_init(void) { - return S_OK; + return led_output_init(&chuni_io_cfg); // because of slider LEDs } void chuni_io_slider_start(chuni_io_slider_callback_t callback) @@ -111,39 +121,6 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback) callback, 0, NULL); - - chuni_io_slider_led_port = CreateFileW(chuni_io_cfg.led_com, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL); - - if (chuni_io_slider_led_port == INVALID_HANDLE_VALUE) - dprintf("Chunithm LEDs: Failed to open COM port (Attempted on %S)\n", chuni_io_cfg.led_com); - else - dprintf("Chunithm LEDs: COM Port Success!\n"); - - DCB dcb_serial_params = { 0 }; - dcb_serial_params.DCBlength = sizeof(dcb_serial_params); - status = GetCommState(chuni_io_slider_led_port, &dcb_serial_params); - - dcb_serial_params.BaudRate = CBR_115200; // Setting BaudRate = 115200 - dcb_serial_params.ByteSize = 8; // Setting ByteSize = 8 - dcb_serial_params.StopBits = ONESTOPBIT;// Setting StopBits = 1 - dcb_serial_params.Parity = NOPARITY; // Setting Parity = None - SetCommState(chuni_io_slider_led_port, &dcb_serial_params); - - COMMTIMEOUTS timeouts = { 0 }; - timeouts.ReadIntervalTimeout = 50; // in milliseconds - timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds - timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds - timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds - timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds - - SetCommTimeouts(chuni_io_slider_led_port, &timeouts); - } void chuni_io_slider_stop(void) @@ -158,34 +135,11 @@ void chuni_io_slider_stop(void) CloseHandle(chuni_io_slider_thread); chuni_io_slider_thread = NULL; chuni_io_slider_stop_flag = false; - - dprintf("Chunithm LEDs: Closing COM port\n"); - CloseHandle(chuni_io_slider_led_port); } void chuni_io_slider_set_leds(const uint8_t *rgb) { - if (chuni_io_slider_led_port != INVALID_HANDLE_VALUE) - { - char led_buffer[100]; - DWORD bytes_to_write; // No of bytes to write into the port - DWORD bytes_written = 0; // No of bytes written to the port - bytes_to_write = sizeof(led_buffer); - BOOL status; - - led_buffer[0] = 0xAA; - led_buffer[1] = 0xAA; - memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96); - led_buffer[98] = 0xDD; - led_buffer[99] = 0xDD; - - status = WriteFile(chuni_io_slider_led_port, // Handle to the Serial port - led_buffer, // Data to be written to the port - bytes_to_write, //No of bytes to write - &bytes_written, //Bytes written - NULL); - } - + led_output_update(2, rgb); } static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) @@ -211,3 +165,13 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) return 0; } + +int chuni_io_led_init() +{ + return led_output_init(&chuni_io_cfg); +} + +void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb) +{ + led_output_update(board, rgb); +} diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index 08a30ca..5fc7ebe 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -145,3 +145,21 @@ void chuni_io_slider_stop(void); Minimum API version: 0x0100 */ void chuni_io_slider_set_leds(const uint8_t *rgb); + +/* Initialize LED emulation. This function will be called before any + other chuni_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. */ + +int chuni_io_led_init(); + +/* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198 + bytes. The majority of these are for the marquee display, but the final + LEDs are for the side partitions. + + Chunithm uses two chains/boards. One is on the left side and one on the + right side of the cab. Exact layout is TBD. */ + +void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb); diff --git a/chuniio/config.c b/chuniio/config.c index 07d78ad..0ce06a2 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -57,7 +57,24 @@ void chuni_io_config_load( filename); } - GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename); - wcsncpy(cfg->led_com, L"\\\\.\\", 4); - wcsncat_s(cfg->led_com, 11, port_input, 6); + cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename); + cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename); + + cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename); + cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename); + + cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename); + + GetPrivateProfileStringW( + L"led", + L"serialPort", + L"COM5", + port_input, + 6, + filename); + + // Sanitize the output path. If it's a serial COM port, it needs to be prefixed + // with `\\.\`. + wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4); + wcsncat_s(cfg->led_serial_port, 11, port_input, 6); } diff --git a/chuniio/config.h b/chuniio/config.h index b615804..fc8884c 100644 --- a/chuniio/config.h +++ b/chuniio/config.h @@ -10,7 +10,18 @@ struct chuni_io_config { uint8_t vk_ir_emu; uint8_t vk_ir[6]; uint8_t vk_cell[32]; - wchar_t led_com[12]; + + // Which ways to output LED information are enabled + bool led_output_pipe; + bool led_output_serial; + + bool slider_led_output_pipe; + bool slider_led_output_serial; + + // The name of a COM port to output LED data on, in serial mode + wchar_t led_serial_port[12]; + int32_t led_serial_baud; + }; void chuni_io_config_load( diff --git a/chuniio/leddata.h b/chuniio/leddata.h new file mode 100644 index 0000000..0764c9f --- /dev/null +++ b/chuniio/leddata.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#define LED_PACKET_FRAMING 0xE0 +#define LED_PACKET_ESCAPE 0xD0 +#define LED_NUM_MAX 66 +#define LED_BOARDS_TOTAL 3 +#define LED_OUTPUT_HEADER_SIZE 2 +#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped +#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX + +// This struct is used to send data related to the slider and billboard LEDs +struct _chuni_led_data_buf_t { + byte framing; // Sync byte + uint8_t board; // LED output the data is for (0-1: billboard, 2: slider) + byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs + byte data_len; // How many bytes to output from the buffer +}; + +static byte chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3}; \ No newline at end of file diff --git a/chuniio/ledoutput.c b/chuniio/ledoutput.c new file mode 100644 index 0000000..84509bc --- /dev/null +++ b/chuniio/ledoutput.c @@ -0,0 +1,133 @@ +#include + +#include +#include +#include + +#include "chuniio/config.h" +#include "chuniio/leddata.h" +#include "chuniio/ledoutput.h" +#include "chuniio/pipeimpl.h" +#include "chuniio/serialimpl.h" + +static struct _chuni_led_data_buf_t led_unescaped_buf[LED_BOARDS_TOTAL]; +static struct _chuni_led_data_buf_t led_escaped_buf[LED_BOARDS_TOTAL]; + +static bool led_output_is_init = false; +static struct chuni_io_config* config; +static bool any_outputs_enabled; + +HANDLE led_init_mutex; + +int led_output_init(struct chuni_io_config* const cfg) +{ + DWORD dwWaitResult = WaitForSingleObject(led_init_mutex, INFINITE); + if (dwWaitResult == WAIT_FAILED) + { + // return HRESULT_FROM_WIN32(GetLastError()); + return 1; + } + else if (dwWaitResult != WAIT_OBJECT_0) + { + // return E_FAIL; + return 1; + } + + if (!led_output_is_init) + { + config = cfg; + + // Setup the framing bytes for the packets + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + led_unescaped_buf[i].framing = LED_PACKET_FRAMING; + led_unescaped_buf[i].board = i; + led_unescaped_buf[i].data_len = chuni_led_board_data_lens[i]; + + led_escaped_buf[i].framing = LED_PACKET_FRAMING; + led_escaped_buf[i].board = i; + led_escaped_buf[i].data_len = chuni_led_board_data_lens[i]; + } + + any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe + || config->led_output_serial || config->slider_led_output_serial; + + if (config->led_output_pipe || config->slider_led_output_pipe) + { + led_pipe_init(); // don't really care about errors here tbh + } + + if (config->led_output_serial || config->slider_led_output_serial) + { + led_serial_init(config->led_serial_port, config->led_serial_baud); + } + } + + led_output_is_init = true; + + ReleaseMutex(led_init_mutex); + // return S_OK; + return 0; +} + +struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unescaped) +{ + struct _chuni_led_data_buf_t* out_struct = &led_escaped_buf[unescaped->board]; + + byte* in_buf = unescaped->data; + byte* out_buf = out_struct->data; + int i = 0; + int o = 0; + + while (i < unescaped->data_len) + { + byte b = in_buf[i++]; + if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE) + { + out_buf[o++] = LED_PACKET_ESCAPE; + b--; + } + out_buf[o++] = b; + } + + out_struct->data_len = o; + + return out_struct; +} + +void led_output_update(uint8_t board, const byte* rgb) +{ + if (board < 0 || board > 2 || !any_outputs_enabled) + { + return; + } + + memcpy(led_unescaped_buf[board].data, rgb, led_unescaped_buf[board].data_len); + struct _chuni_led_data_buf_t* escaped_data = escape_led_data(&led_unescaped_buf[board]); + + if (board < 2) + { + // billboard + if (config->led_output_pipe) + { + led_pipe_update(escaped_data); + } + + if (config->led_output_serial) + { + led_serial_update(escaped_data); + } + } + else + { + // slider + if (config->slider_led_output_pipe) + { + led_pipe_update(escaped_data); + } + + if (config->slider_led_output_serial) + { + led_serial_update(escaped_data); + } + } +} diff --git a/chuniio/ledoutput.h b/chuniio/ledoutput.h new file mode 100644 index 0000000..82e54b1 --- /dev/null +++ b/chuniio/ledoutput.h @@ -0,0 +1,19 @@ +/* + LED output functions + + Credits: + somewhatlurker, skogaby +*/ + +#pragma once + +#include + +#include +#include + +#include "chuniio/config.h" + +extern HANDLE led_init_mutex; +int led_output_init(struct chuni_io_config* const cfg); +void led_output_update(uint8_t board, const byte* rgb); diff --git a/chuniio/meson.build b/chuniio/meson.build index 9e61229..fabf499 100644 --- a/chuniio/meson.build +++ b/chuniio/meson.build @@ -9,5 +9,12 @@ chuniio_lib = static_library( 'chuniio.h', 'config.c', 'config.h', + 'leddata.h', + 'ledoutput.c', + 'ledoutput.h', + 'pipeimpl.c', + 'pipeimpl.h', + 'serialimpl.c', + 'serialimpl.h' ], ) diff --git a/chuniio/pipeimpl.c b/chuniio/pipeimpl.c new file mode 100644 index 0000000..972d84d --- /dev/null +++ b/chuniio/pipeimpl.c @@ -0,0 +1,160 @@ +#include + +#include +#include +#include + +#include "chuniio/leddata.h" +#include "chuniio/pipeimpl.h" + +static bool pipe_update[LED_BOARDS_TOTAL]; + +// incoming data is copied into these to ensure it isn't written during output +static struct _chuni_led_data_buf_t pipe_write_buf[LED_BOARDS_TOTAL]; +static HANDLE pipe_write_mutex; + +static HRESULT pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize) +{ + *hPipe = INVALID_HANDLE_VALUE; + + *hPipe = CreateNamedPipeW( + lpszPipename, // pipe name + PIPE_ACCESS_OUTBOUND, // read/write access + PIPE_TYPE_BYTE | // byte type pipe + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + dwBufSize, // output buffer size + 0, // input buffer size + 0, // client time-out + NULL); // default security attribute + + if (*hPipe == INVALID_HANDLE_VALUE) + { + return E_FAIL; + } + + return S_OK; +} + +static HRESULT pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize) +{ + DWORD cbWritten = 0; + + bool fSuccess = WriteFile( + hPipe, + lpBuffer, + dwSize, + &cbWritten, + NULL); + + if (!fSuccess || cbWritten != dwSize) + { + DWORD last_err = GetLastError(); + return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL; + } + + return S_OK; +} + +static unsigned int __stdcall chuni_io_led_pipe_thread_proc(void *ctx) +{ + HANDLE hPipe; + LPCWSTR lpszPipename = L"\\\\.\\pipe\\chuni_led"; + + while (true) + { + hPipe = INVALID_HANDLE_VALUE; + + if (pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK) + { + continue; + } + + // wait for a connection to the pipe + bool fConnected = ConnectNamedPipe(hPipe, NULL) ? + true : (GetLastError() == ERROR_PIPE_CONNECTED); + + while (fConnected) + { + if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0) + { + continue; + } + + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + if (pipe_update[i]) + { + HRESULT result = pipe_write( + hPipe, + &pipe_write_buf[i], + LED_OUTPUT_HEADER_SIZE + pipe_write_buf[i].data_len); + + if (result != S_OK) + { + //if (result == E_ABORT) + //{ + fConnected = false; + //} + break; + } + + pipe_update[i] = false; + } + } + + ReleaseMutex(pipe_write_mutex); + } + + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + CloseHandle(hPipe); + } + + return 0; +} + +HRESULT led_pipe_init() +{ + pipe_write_mutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (pipe_write_mutex == NULL) + { + return E_FAIL; + } + + // clear out update bools + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + pipe_update[i] = false; + } + + _beginthreadex( + NULL, + 0, + chuni_io_led_pipe_thread_proc, + 0, + 0, + NULL); + + return S_OK; +} + +void led_pipe_update(struct _chuni_led_data_buf_t* data) +{ + if (data->board > 2) + { + return; + } + + if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0) + { + return; + } + + memcpy(&pipe_write_buf[data->board], data, sizeof(struct _chuni_led_data_buf_t)); + pipe_update[data->board] = true; + + ReleaseMutex(pipe_write_mutex); +} diff --git a/chuniio/pipeimpl.h b/chuniio/pipeimpl.h new file mode 100644 index 0000000..4f7a268 --- /dev/null +++ b/chuniio/pipeimpl.h @@ -0,0 +1,14 @@ +/* + Pipe implementation for chuniio + + Credits: + somewhatlurker, skogaby +*/ +#pragma once + +#include + +#include "chuniio/leddata.h" + +HRESULT led_pipe_init(); +void led_pipe_update(struct _chuni_led_data_buf_t* data); diff --git a/chuniio/serialimpl.c b/chuniio/serialimpl.c new file mode 100644 index 0000000..57ebb7f --- /dev/null +++ b/chuniio/serialimpl.c @@ -0,0 +1,99 @@ +#include + +#include +#include +#include + +#include "chuniio/leddata.h" +#include "chuniio/serialimpl.h" +#include "util/dprintf.h" + +static HANDLE serial_port; +static HANDLE serial_write_mutex; + +HRESULT led_serial_init(wchar_t led_com[12], DWORD baud) +{ + // Setup the serial communications + BOOL status; + + serial_port = CreateFileW(led_com, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (serial_port == INVALID_HANDLE_VALUE) + dprintf("Chunithm Serial LEDs: Failed to open COM port (Attempted on %S)\n", led_com); + else + dprintf("Chunithm Serial LEDs: COM port success!\n"); + + DCB dcb_serial_params = { 0 }; + dcb_serial_params.DCBlength = sizeof(dcb_serial_params); + status = GetCommState(serial_port, &dcb_serial_params); + + dcb_serial_params.BaudRate = baud; + dcb_serial_params.ByteSize = 8; + dcb_serial_params.StopBits = ONESTOPBIT; + dcb_serial_params.Parity = NOPARITY; + SetCommState(serial_port, &dcb_serial_params); + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + SetCommTimeouts(serial_port, &timeouts); + + if (!status) + { + return E_FAIL; + } + + serial_write_mutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (serial_write_mutex == NULL) + { + return E_FAIL; + } + + return S_OK; +} + +void led_serial_update(struct _chuni_led_data_buf_t* data) +{ + if (data->board > 2) + { + return; + } + + if (WaitForSingleObject(serial_write_mutex, INFINITE) != WAIT_OBJECT_0) + { + return; + } + + BOOL status = true; + DWORD bytes_written = 0; + + if (serial_port != INVALID_HANDLE_VALUE) { + status = WriteFile( + serial_port, + data, + LED_OUTPUT_HEADER_SIZE + data->data_len, + &bytes_written, + NULL); + } + + if (!status) { + DWORD last_err = GetLastError(); + // dprintf("Chunithm Serial LEDs: Serial port write failed -- %d\n", last_err); + } + + ReleaseMutex(serial_write_mutex); +} diff --git a/chuniio/serialimpl.h b/chuniio/serialimpl.h new file mode 100644 index 0000000..f8f276b --- /dev/null +++ b/chuniio/serialimpl.h @@ -0,0 +1,15 @@ +/* + Serial LED implementation for chuniio + + Credits: + somewhatlurker, skogaby +*/ + +#pragma once + +#include + +#include "chuniio/leddata.h" + +HRESULT led_serial_init(wchar_t led_com[12], DWORD baud); +void led_serial_update(struct _chuni_led_data_buf_t* data); diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c index c946043..3a100ac 100644 --- a/chusanhook/chuni-dll.c +++ b/chusanhook/chuni-dll.c @@ -30,6 +30,12 @@ const struct dll_bind_sym chuni_dll_syms[] = { }, { .sym = "chuni_io_slider_set_leds", .off = offsetof(struct chuni_dll, slider_set_leds), + }, { + .sym = "chuni_io_led_init", + .off = offsetof(struct chuni_dll, led_init), + }, { + .sym = "chuni_io_led_set_colors", + .off = offsetof(struct chuni_dll, led_set_leds), } }; diff --git a/chusanhook/chuni-dll.h b/chusanhook/chuni-dll.h index ecd88ee..034b204 100644 --- a/chusanhook/chuni-dll.h +++ b/chusanhook/chuni-dll.h @@ -13,6 +13,8 @@ struct chuni_dll { void (*slider_start)(chuni_io_slider_callback_t callback); void (*slider_stop)(void); void (*slider_set_leds)(const uint8_t *rgb); + int (*led_init)(); + void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; struct chuni_dll_config { diff --git a/chusanhook/chusanhook.def b/chusanhook/chusanhook.def index 5039c7d..66ae5ec 100644 --- a/chusanhook/chusanhook.def +++ b/chusanhook/chusanhook.def @@ -20,3 +20,5 @@ EXPORTS chuni_io_slider_set_leds chuni_io_slider_start chuni_io_slider_stop + chuni_io_led_init + chuni_io_led_set_colors diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 61c7f47..ee8bc77 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -129,7 +129,8 @@ static DWORD CALLBACK chusan_pre_startup(void) } } - hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1); + hr = led15093_hook_init(&chusan_hook_cfg.led15093, + chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1); if (FAILED(hr)) { goto fail; diff --git a/chusanhook/led1509306.h b/chusanhook/led1509306.h deleted file mode 100644 index 03dc62a..0000000 --- a/chusanhook/led1509306.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include - -struct led1509306_config { - bool enable; - bool cvt_port; - char board_number[8]; - char chip_number[5]; - uint8_t fw_ver; - uint16_t fw_sum; -}; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg); diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index ba75d61..57524f8 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -38,15 +38,52 @@ monitor=0 ; Leave empty if you want to use Segatools built-in keyboard input. path= -[led15093] -; 837-15093-06 LED strip emulation setting. -enable=1 - [chuniio] ; To use a custom Chunithm IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. path= +[led15093] +; Enable emulation of the 15093-06 controlled lights, which handle the air tower +; RGBs and the rear LED panel (billboard) on the cabinet. +enable=1 + +[led] +; Output billboard LED strip data to a named pipe called "\\.\pipe\chuni_ledstrip" +cabLedOutputPipe=1 +; Output billboard LED strip data to serial +cabLedOutputSerial=0 + +; Output slider LED data to the named pipe +controllerLedOutputPipe=1 +; Output slider LED data to the serial port +controllerLedOutputSerial=0 + +; Serial port to send data to if using serial output. Default is COM5. +;serialPort=COM5 +; Baud rate for serial data +;serialBaud=921600 + +; Data output a sequence of bytes, with JVS-like framing. +; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere, +; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore +; it and use the next sent byte plus one instead. +; +; After the sync is one byte for the board number that was updated, followed by +; the red, green and blue values for each LED. +; +; Board 0 has 53 LEDs: +; [0]-[49]: snakes through left half of billboard (first column starts at top) +; [50]-[52]: left side partition LEDs +; +; Board 1 has 63 LEDs: +; [0]-[59]: right half of billboard (first column starts at bottom) +; [60]-[62]: right side partition LEDs +; +; Board 2 is the slider and has 31 LEDs: +; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers + + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -66,6 +103,20 @@ test=0x31 service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. coin=0x33 +; Set to 0 for enable separate ir control. Deafult is space key. +ir=0x20 + +[ir] +; Uncomment and complete the following sequence of settings to configure a +; custom ir-cappable controller if you have one. +;ir6=0x53 +; ... etc ... +;ir1=0x53 + +[slider] +; Enable slider emulation. If you have real AC slider, set this to 0. +; Slider serial port must be COM1. +;enable=1 ; Key bindings for each of the 32 touch cells. The default key map, depicted ; in left-to-right order, is as follows: @@ -77,12 +128,8 @@ coin=0x33 ; ; Uncomment and complete the following sequence of settings to configure a ; custom high-precision touch strip controller if you have one. -[slider] -;cell32=0x53 -;cell31=0x53 -;cell30=0x53 +;cell1=0x53 +;cell2=0x53 ; ... etc ... - -; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. -; eg. COM5 -;ledport= +;cell31=0x53 +;cell32=0x53 diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 44d1a96..45e2df9 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -63,16 +63,53 @@ framed=0 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 -[led15093] -; 837-15093-06 LED strip emulation setting. -enable=1 - [chuniio] ; Uncomment this if you have custom chuniio implementation. ; x86 chuniio to path32, x64 to path64. Both are necessary. ;path32= ;path64= +[led15093] +; Enable emulation of the 15093-06 controlled lights, which handle the air tower +; RGBs and the rear LED panel (billboard) on the cabinet. +enable=1 + +[led] +; Output billboard LED strip data to a named pipe called "\\.\pipe\chuni_led" +cabLedOutputPipe=1 +; Output billboard LED strip data to serial +cabLedOutputSerial=0 + +; Output slider LED data to the named pipe +controllerLedOutputPipe=1 +; Output slider LED data to the serial port +controllerLedOutputSerial=0 + +; Serial port to send data to if using serial output. Default is COM5. +;serialPort=COM5 +; Baud rate for serial data +;serialBaud=921600 + +; Data output a sequence of bytes, with JVS-like framing. +; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere, +; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore +; it and use the next sent byte plus one instead. +; +; After the sync is one byte for the board number that was updated, followed by +; the red, green and blue values for each LED. +; +; Board 0 has 53 LEDs: +; [0]-[49]: snakes through left half of billboard (first column starts at top) +; [50]-[52]: left side partition LEDs +; +; Board 1 has 63 LEDs: +; [0]-[59]: right half of billboard (first column starts at bottom) +; [60]-[62]: right side partition LEDs +; +; Board 2 is the slider and has 31 LEDs: +; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers + + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index fcac111..2e8619e 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -3,6 +3,7 @@ #include #include "board/io4.h" +#include "board/led15093.h" #include "board/sg-reader.h" #include "board/vfd.h" @@ -96,7 +97,8 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 1, 1, 2); + hr = led15093_hook_init(&fgo_hook_cfg.led15093, + fgo_dll.led_init, fgo_dll.led_set_leds, 17, 1, 1, 2); if (FAILED(hr)) { goto fail; diff --git a/fgohook/fgo-dll.c b/fgohook/fgo-dll.c index 2f4ef7d..dce25ab 100644 --- a/fgohook/fgo-dll.c +++ b/fgohook/fgo-dll.c @@ -24,6 +24,12 @@ const struct dll_bind_sym fgo_dll_syms[] = { }, { .sym = "fgo_io_get_analogs", .off = offsetof(struct fgo_dll, get_analogs), + }, { + .sym = "fgo_io_led_init", + .off = offsetof(struct fgo_dll, led_init), + }, { + .sym = "fgo_io_led_set_leds", + .off = offsetof(struct fgo_dll, led_set_leds), } }; diff --git a/fgohook/fgo-dll.h b/fgohook/fgo-dll.h index 41d6e92..05dd997 100644 --- a/fgohook/fgo-dll.h +++ b/fgohook/fgo-dll.h @@ -11,6 +11,8 @@ struct fgo_dll { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint8_t *gamebtn); void (*get_analogs)(int16_t *stick_x, int16_t *stick_y); + int (*led_init)(); + void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; struct fgo_dll_config { diff --git a/fgohook/fgohook.def b/fgohook/fgohook.def index 04bf2f0..2f4c1c6 100644 --- a/fgohook/fgohook.def +++ b/fgohook/fgohook.def @@ -17,6 +17,8 @@ EXPORTS fgo_io_get_opbtns fgo_io_init fgo_io_poll + fgo_io_led_init + fgo_io_led_set_leds fwdlusb_open fwdlusb_close fwdlusb_listupPrinter diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index c6bd88f..5ffbd72 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -139,3 +139,13 @@ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y) *stick_y = fgo_stick_y; } } + +int fgo_io_led_init() +{ + return 0; +} + +void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb) +{ + return; +} \ No newline at end of file diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h index f302dfa..6e526f5 100644 --- a/fgoio/fgoio.h +++ b/fgoio/fgoio.h @@ -69,3 +69,18 @@ void fgo_io_get_gamebtns(uint8_t *btn); Minimum API version: 0x0100 */ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y); + +/* Initialize LED emulation. This function will be called before any + other fgo_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. */ + +int fgo_io_led_init(); + +/* Update the RGB LEDs. + + Exact layout is TBD. */ + +void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb); diff --git a/mu3hook/config.h b/mu3hook/config.h index 1273983..623397c 100644 --- a/mu3hook/config.h +++ b/mu3hook/config.h @@ -3,7 +3,7 @@ #include #include "board/config.h" -#include "board/led15093.h" +// #include "board/led15093.h" #include "gfxhook/gfx.h" @@ -19,7 +19,7 @@ struct mu3_hook_config { struct dvd_config dvd; struct io4_config io4; struct gfx_config gfx; - struct led15093_config led15093; + // struct led15093_config led15093; struct mu3_dll_config dll; }; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index b867345..c27fd4d 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -61,11 +61,14 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } + /* + // Does not work, Unity moment hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2); if (FAILED(hr)) { return hr; } + */ hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod); From 3bf223c04eb901725333d60408bfcc8343ec8ebe Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 19 Dec 2023 13:45:06 +0100 Subject: [PATCH 070/204] chusan: fixed SP/CVT switching --- chusanhook/dllmain.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index ee8bc77..1e3ee2c 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -100,7 +100,7 @@ static DWORD CALLBACK chusan_pre_startup(void) } bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0]; - bool *is_sp = dipsw + 2; + bool is_cvt = dipsw[2]; for (int i = 0; i < 3; i++) { switch (i) { @@ -113,15 +113,15 @@ static DWORD CALLBACK chusan_pre_startup(void) break; case 2: - dprintf("DipSw: Cab Type: %s\n", is_sp ? "SP" : "CVT"); + dprintf("DipSw: Cab Type: %s\n", is_cvt ? "CVT" : "SP"); break; } } - unsigned int first_port = is_sp ? 20 : 2; + unsigned int first_port = is_cvt ? 2 : 20; - if (is_sp) { + if (!is_cvt) { hr = vfd_hook_init(2); if (FAILED(hr)) { @@ -136,7 +136,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_sp ? 3: 2, chusan_hook_mod); + hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod); if (FAILED(hr)) { goto fail; From ac9b889d71481273605686a349e4ee4898b2e28b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 19 Dec 2023 14:40:02 +0100 Subject: [PATCH 071/204] chusan/chuni: tower LEDs added --- board/led15093.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/board/led15093.c b/board/led15093.c index 4224303..cb3cd2e 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -644,9 +644,6 @@ static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led memcpy(v->led, req->data, req->hdr.nbytes - 1); - // Return the current LED data, remove const qualifier - set_leds(board, (uint8_t *) req->data); - if (!v->enable_response) return S_OK; @@ -680,8 +677,20 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set return E_INVALIDARG; } - memcpy(v->led, req->data, req->hdr.nbytes - 1); + /* + if (board == 0) { + dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0x96], req->data[0x97], req->data[0x98]); + } + else if (board == 1) + { + dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0xb4], req->data[0xb5], req->data[0xb6]); + } + */ + // Return the current LED data, remove const qualifier + set_leds(board, (uint8_t *) req->data); + + memcpy(v->led, req->data, req->hdr.nbytes - 1); // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); if (!v->enable_response) From d4372fa5c2bc8077205ff06e2b2a06338a25bcc5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 21 Dec 2023 00:45:41 +0100 Subject: [PATCH 072/204] chuniio: use HRESULT instead of int for chuni_io_led_init() --- board/led15093.c | 24 +++++++++++++++++------- board/led15093.h | 2 +- chunihook/chuni-dll.h | 2 +- chuniio/chuniio.c | 2 +- chuniio/chuniio.h | 2 +- chuniio/ledoutput.c | 14 +++++++------- chuniio/ledoutput.h | 2 +- chusanhook/chuni-dll.h | 2 +- fgohook/fgo-dll.h | 2 +- fgoio/fgoio.c | 5 +++-- fgoio/fgoio.h | 2 +- 11 files changed, 35 insertions(+), 24 deletions(-) diff --git a/board/led15093.c b/board/led15093.c index cb3cd2e..606ce27 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -239,15 +239,25 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) if (irp->op == IRP_OP_OPEN) { dprintf("LED 15093: Starting backend DLL\n"); - int res = led_init(); + // int res = led_init(); + hr = led_init(); + + /* + if (res != 0) { + dprintf("LED 15093: Backend error, LED board disconnected: " + "%d\n", + res); - if (res != 0) { - dprintf("LED 15093: Backend error, LED board disconnected: " - "%d\n", - res); + return E_FAIL; + } + */ + if (FAILED(hr)) { + dprintf("LED 15093: Backend error, LED board disconnected: " + "%x\n", + (int) hr); - return E_FAIL; - } + return hr; + } } hr = uart_handle_irp(boarduart, irp); diff --git a/board/led15093.h b/board/led15093.h index ff2f612..869a11b 100644 --- a/board/led15093.h +++ b/board/led15093.h @@ -16,7 +16,7 @@ struct led15093_config { uint16_t fw_sum; }; -typedef int (*io_led_init_t)(); +typedef HRESULT (*io_led_init_t)(void); typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb); HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, diff --git a/chunihook/chuni-dll.h b/chunihook/chuni-dll.h index 034b204..8341b48 100644 --- a/chunihook/chuni-dll.h +++ b/chunihook/chuni-dll.h @@ -13,7 +13,7 @@ struct chuni_dll { void (*slider_start)(chuni_io_slider_callback_t callback); void (*slider_stop)(void); void (*slider_set_leds)(const uint8_t *rgb); - int (*led_init)(); + HRESULT (*led_init)(void); void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 32481f1..95a52d7 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -166,7 +166,7 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) return 0; } -int chuni_io_led_init() +HRESULT chuni_io_led_init(void) { return led_output_init(&chuni_io_cfg); } diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index 5fc7ebe..1ecba4a 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -153,7 +153,7 @@ void chuni_io_slider_set_leds(const uint8_t *rgb); overlap with each other. Ensuring synchronization inside your IO DLL is your responsibility. */ -int chuni_io_led_init(); +HRESULT chuni_io_led_init(void); /* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198 bytes. The majority of these are for the marquee display, but the final diff --git a/chuniio/ledoutput.c b/chuniio/ledoutput.c index 84509bc..ab0187f 100644 --- a/chuniio/ledoutput.c +++ b/chuniio/ledoutput.c @@ -19,18 +19,18 @@ static bool any_outputs_enabled; HANDLE led_init_mutex; -int led_output_init(struct chuni_io_config* const cfg) +HRESULT led_output_init(struct chuni_io_config* const cfg) { DWORD dwWaitResult = WaitForSingleObject(led_init_mutex, INFINITE); if (dwWaitResult == WAIT_FAILED) { - // return HRESULT_FROM_WIN32(GetLastError()); - return 1; + return HRESULT_FROM_WIN32(GetLastError()); + // return 1; } else if (dwWaitResult != WAIT_OBJECT_0) { - // return E_FAIL; - return 1; + return E_FAIL; + // return 1; } if (!led_output_is_init) @@ -65,8 +65,8 @@ int led_output_init(struct chuni_io_config* const cfg) led_output_is_init = true; ReleaseMutex(led_init_mutex); - // return S_OK; - return 0; + return S_OK; + // return 0; } struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unescaped) diff --git a/chuniio/ledoutput.h b/chuniio/ledoutput.h index 82e54b1..33a4180 100644 --- a/chuniio/ledoutput.h +++ b/chuniio/ledoutput.h @@ -15,5 +15,5 @@ #include "chuniio/config.h" extern HANDLE led_init_mutex; -int led_output_init(struct chuni_io_config* const cfg); +HRESULT led_output_init(struct chuni_io_config* const cfg); void led_output_update(uint8_t board, const byte* rgb); diff --git a/chusanhook/chuni-dll.h b/chusanhook/chuni-dll.h index 034b204..8341b48 100644 --- a/chusanhook/chuni-dll.h +++ b/chusanhook/chuni-dll.h @@ -13,7 +13,7 @@ struct chuni_dll { void (*slider_start)(chuni_io_slider_callback_t callback); void (*slider_stop)(void); void (*slider_set_leds)(const uint8_t *rgb); - int (*led_init)(); + HRESULT (*led_init)(void); void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; diff --git a/fgohook/fgo-dll.h b/fgohook/fgo-dll.h index 05dd997..22bf02d 100644 --- a/fgohook/fgo-dll.h +++ b/fgohook/fgo-dll.h @@ -11,7 +11,7 @@ struct fgo_dll { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint8_t *gamebtn); void (*get_analogs)(int16_t *stick_x, int16_t *stick_y); - int (*led_init)(); + HRESULT (*led_init)(); void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index 5ffbd72..95c86d9 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -140,9 +140,10 @@ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y) } } -int fgo_io_led_init() +HRESULT fgo_io_led_init(void) { - return 0; + // return 0; + return S_OK; } void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb) diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h index 6e526f5..5a815a7 100644 --- a/fgoio/fgoio.h +++ b/fgoio/fgoio.h @@ -77,7 +77,7 @@ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y); overlap with each other. Ensuring synchronization inside your IO DLL is your responsibility. */ -int fgo_io_led_init(); +HRESULT fgo_io_led_init(void); /* Update the RGB LEDs. From ee414d122bb343315268970c457b3d736e337683 Mon Sep 17 00:00:00 2001 From: CrazyRedMachine Date: Sun, 24 Dec 2023 08:10:29 -0500 Subject: [PATCH 073/204] Include chu2to3 engine --- chunihook/dllmain.c | 13 +- chuniio/chu2to3.c | 357 ++++++++++++++++++++++++++++++++++++++ chuniio/chu2to3.h | 26 +++ chuniio/chuniio.h | 22 ++- chuniio/meson.build | 2 + chusanhook/chuni-dll.c | 88 ++++++++-- chusanhook/chuni-dll.h | 1 + chusanhook/chusanhook.def | 10 ++ chusanhook/config.c | 31 ++-- chusanhook/dllmain.c | 13 +- dist/chusan/segatools.ini | 6 +- 11 files changed, 532 insertions(+), 37 deletions(-) create mode 100644 chuniio/chu2to3.c create mode 100644 chuniio/chu2to3.h diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 69cf559..1a3fb57 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -97,11 +97,16 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = led15093_hook_init(&chuni_hook_cfg.led15093, - chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1); + if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL ) + { + dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n"); + } else { + hr = led15093_hook_init(&chuni_hook_cfg.led15093, + chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1); - if (FAILED(hr)) { - goto fail; + if (FAILED(hr)) { + goto fail; + } } hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod); diff --git a/chuniio/chu2to3.c b/chuniio/chu2to3.c new file mode 100644 index 0000000..3569426 --- /dev/null +++ b/chuniio/chu2to3.c @@ -0,0 +1,357 @@ +#include + +#include +#include +#include +#include + +#include "chuniio/chu2to3.h" +#include "util/dprintf.h" + +// Check windows +#if _WIN32 || _WIN64 + #if _WIN64 + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +// Check GCC +#if __GNUC__ + #if __x86_64__ || __ppc64__ + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +/* chuniio.dll dynamic loading */ +HMODULE hinstLib; +typedef uint16_t (*chuni_io_get_api_version_t)(void); +typedef HRESULT (*chuni_io_jvs_init_t)(void); +typedef void (*chuni_io_jvs_poll_t)(uint8_t*, uint8_t*); +typedef void (*chuni_io_jvs_read_coin_counter_t)(uint16_t *); +typedef HRESULT (*chuni_io_slider_init_t)(void); +typedef void (*chuni_io_slider_set_leds_t)(const uint8_t *); +typedef void (*chuni_io_slider_start_t)(chuni_io_slider_callback_t); +typedef void (*chuni_io_slider_stop_t)(void); +typedef HRESULT (*chuni_io_led_init_t)(void); +typedef void (*chuni_io_led_set_colors_t)(uint8_t, uint8_t *); + +chuni_io_get_api_version_t _chuni_io_get_api_version; +chuni_io_jvs_init_t _chuni_io_jvs_init; +chuni_io_jvs_poll_t _chuni_io_jvs_poll; +chuni_io_jvs_read_coin_counter_t _chuni_io_jvs_read_coin_counter; +chuni_io_slider_init_t _chuni_io_slider_init; +chuni_io_slider_set_leds_t _chuni_io_slider_set_leds; +chuni_io_slider_start_t _chuni_io_slider_start; +chuni_io_slider_stop_t _chuni_io_slider_stop; +chuni_io_led_init_t _chuni_io_led_init; +chuni_io_led_set_colors_t _chuni_io_led_set_colors; + +/* SHMEM Handling */ +#define BUF_SIZE 1024 +#define SHMEM_WRITE(buf, size) CopyMemory((PVOID)g_pBuf, buf, size) +#define SHMEM_READ(buf, size) CopyMemory(buf,(PVOID)g_pBuf, size) +TCHAR g_shmem_name[]=TEXT("Local\\Chu2to3Shmem"); +HANDLE g_hMapFile; +LPVOID g_pBuf; + +#pragma pack(1) +typedef struct shared_data_s { + uint16_t coin_counter; + uint8_t opbtn; + uint8_t beams; + uint16_t version; +} shared_data_t; + +shared_data_t g_shared_data; + +bool shmem_create() +{ + g_hMapFile = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + BUF_SIZE, // maximum object size (low-order DWORD) + g_shmem_name); // name of mapping object + + if (g_hMapFile == NULL) + { + dprintf("shmem_create : Could not create file mapping object (%d).\n", + GetLastError()); + return 0; + } + g_pBuf = MapViewOfFile(g_hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + BUF_SIZE); + + if (g_pBuf == NULL) + { + dprintf("shmem_create : Could not map view of file (%d).\n", + GetLastError()); + + CloseHandle(g_hMapFile); + + return 0; + } + + return 1; +} + +bool shmem_load() +{ + g_hMapFile = OpenFileMapping( + FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + g_shmem_name); // name of mapping object + + if (g_hMapFile == NULL) + { + dprintf("shmem_load : Could not open file mapping object (%d).\n", GetLastError()); + return 0; + } + + g_pBuf = MapViewOfFile(g_hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + BUF_SIZE); + + if (g_pBuf == NULL) + { + dprintf("shmem_load : Could not map view of file (%d).\n", GetLastError()); + CloseHandle(g_hMapFile); + return 0; + } + + dprintf("shmem_load : shmem loaded succesfully.\n"); + return 1; +} + +void shmem_free() +{ + UnmapViewOfFile(g_pBuf); + CloseHandle(g_hMapFile); +} + +/* jvs polling thread (to forward info to x64 dll) */ +static HANDLE jvs_poll_thread; +static bool jvs_poll_stop_flag; + +static unsigned int __stdcall jvs_poll_thread_proc(void *ctx) +{ + while (1) { + _chuni_io_jvs_read_coin_counter(&g_shared_data.coin_counter); + g_shared_data.opbtn = 0; + _chuni_io_jvs_poll(&g_shared_data.opbtn, &g_shared_data.beams); + SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t)); + Sleep(1); + } + + return 0; +} + +uint16_t chu2to3_load_dll(wchar_t *dllname) +{ + #if defined(ENV64BIT) + /* x64 must just open the shmem and do nothing else */ + int errcount = 0; + while (!shmem_load()) + { + if (errcount >= 10) + return -1; + Sleep(5000); + errcount++; + } + Sleep(1000); + return S_OK; + #endif + + /* this is the first function called so let's setup the chuniio forwarding */ + hinstLib = LoadLibraryW(dllname); + if (hinstLib == NULL) { + dprintf("ERROR: unable to load %S (error %d)\n",dllname, GetLastError()); + return -1; + } + + _chuni_io_get_api_version = (chuni_io_get_api_version_t)GetProcAddress(hinstLib, "chuni_io_get_api_version"); + _chuni_io_jvs_init = (chuni_io_jvs_init_t)GetProcAddress(hinstLib, "chuni_io_jvs_init"); + _chuni_io_jvs_poll = (chuni_io_jvs_poll_t)GetProcAddress(hinstLib, "chuni_io_jvs_poll"); + _chuni_io_jvs_read_coin_counter = (chuni_io_jvs_read_coin_counter_t)GetProcAddress(hinstLib, "chuni_io_jvs_read_coin_counter"); + _chuni_io_slider_init = (chuni_io_slider_init_t)GetProcAddress(hinstLib, "chuni_io_slider_init"); + _chuni_io_slider_set_leds = (chuni_io_slider_set_leds_t)GetProcAddress(hinstLib, "chuni_io_slider_set_leds"); + _chuni_io_slider_start = (chuni_io_slider_start_t)GetProcAddress(hinstLib, "chuni_io_slider_start"); + _chuni_io_slider_stop = (chuni_io_slider_stop_t)GetProcAddress(hinstLib, "chuni_io_slider_stop"); + _chuni_io_led_init = (chuni_io_led_init_t)GetProcAddress(hinstLib, "chuni_io_led_init"); + _chuni_io_led_set_colors = (chuni_io_led_set_colors_t)GetProcAddress(hinstLib, "chuni_io_led_set_colors"); + + /* x86 has to create the shmem */ + if (!shmem_create()) + { + return -1; + } + + return 0; +} + +/* chuniio exports */ +uint16_t chu2to3_io_get_api_version(void) +{ + #if defined(ENV64BIT) + /* This might be called too soon so let's make sure x86 has time to write to the shmem */ + SHMEM_READ(&g_shared_data, sizeof(shared_data_t)); + int errcount = 0; + while (g_shared_data.version == 0) + { + if (errcount >= 3) + { + dprintf("CHU2TO3 X64: Couldn't retrieve api version from shmem, assuming 0x0100\n"); + return 0x0100; + } + Sleep(5000); + errcount++; + SHMEM_READ(&g_shared_data, sizeof(shared_data_t)); + } + dprintf("CHU2TO3 X64: api version is %04X\n", g_shared_data.version); + return g_shared_data.version; + #endif + + if ( _chuni_io_get_api_version == NULL ) + { + g_shared_data.version = 0x0100; + } + else + { + g_shared_data.version = _chuni_io_get_api_version(); + } + dprintf("CHU2TO3: api version is %04X\n", g_shared_data.version); + + SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t)); + + return g_shared_data.version; +} + +HRESULT chu2to3_io_jvs_init(void) +{ + #if defined(ENV64BIT) + /* x86 only */ + return S_OK; + #endif + + _chuni_io_jvs_init(); + + /* start jvs poll thread now that jvs_init is done */ + if (jvs_poll_thread != NULL) { + return S_OK; + } + + jvs_poll_thread = (HANDLE) _beginthreadex(NULL, + 0, + jvs_poll_thread_proc, + NULL, + 0, + NULL); + return S_OK; +} + +void chu2to3_io_jvs_read_coin_counter(uint16_t *out) +{ + #if defined(ENV32BIT) + /* x86 can perform the call and update shmem (although this call never happens) */ + _chuni_io_jvs_read_coin_counter(&g_shared_data.coin_counter); + SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t)); + return; + #endif + + /* x64 must read value from shmem and update arg */ + SHMEM_READ(&g_shared_data, sizeof(shared_data_t)); + if (out == NULL) { + return; + } + *out = g_shared_data.coin_counter; +} + +void chu2to3_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) +{ + #if defined(ENV32BIT) + /* x86 can perform the call and update shmem (although this call never happens) */ + _chuni_io_jvs_poll(&g_shared_data.opbtn, &g_shared_data.beams); + SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t)); + return; + #endif + + /* x64 must read value from shmem and update args */ + SHMEM_READ(&g_shared_data, sizeof(shared_data_t)); + *opbtn = g_shared_data.opbtn; + *beams = g_shared_data.beams; +} + +HRESULT chu2to3_io_slider_init(void) +{ + #if defined(ENV64BIT) + /* x86 only */ + return S_OK; + #endif + + return _chuni_io_slider_init(); +} + +void chu2to3_io_slider_start(chuni_io_slider_callback_t callback) +{ + #if defined(ENV64BIT) + /* x86 only */ + return; + #endif + + _chuni_io_slider_start(callback); +} + +void chu2to3_io_slider_stop(void) +{ + #if defined(ENV64BIT) + /* x86 only */ + return; + #endif + + _chuni_io_slider_stop(); +} + +void chu2to3_io_slider_set_leds(const uint8_t *rgb) +{ + #if defined(ENV64BIT) + /* x86 only */ + return; + #endif + + _chuni_io_slider_set_leds(rgb); +} + +HRESULT chu2to3_io_led_init(void) +{ + #if defined(ENV64BIT) + /* x86 only */ + return S_OK; + #endif + + if (_chuni_io_led_init != NULL) + return _chuni_io_led_init(); + return S_OK; +} + +void chu2to3_io_led_set_colors(uint8_t board, uint8_t *rgb) +{ + #if defined(ENV64BIT) + /* x86 only */ + return; + #endif + + if (_chuni_io_led_set_colors != NULL) + { + _chuni_io_led_set_colors(board, rgb); + } +} diff --git a/chuniio/chu2to3.h b/chuniio/chu2to3.h new file mode 100644 index 0000000..bdbab77 --- /dev/null +++ b/chuniio/chu2to3.h @@ -0,0 +1,26 @@ +#pragma once + +/* + CHU2TO3 CUSTOM IO API + + This dll just mirrors chuniio dll binds but with a dynamic library loading and + a SHMEM system to let a single 32bit dll talk with x86 and x64 processes at once +*/ + +#include + +#include +#include + +uint16_t chu2to3_io_get_api_version(void); +HRESULT chu2to3_io_jvs_init(void); +void chu2to3_io_jvs_poll(uint8_t *opbtn, uint8_t *beams); +void chu2to3_io_jvs_read_coin_counter(uint16_t *total); +HRESULT chu2to3_io_slider_init(void); +typedef void (*chuni_io_slider_callback_t)(const uint8_t *state); +void chu2to3_io_slider_start(chuni_io_slider_callback_t callback); +void chu2to3_io_slider_stop(void); +void chu2to3_io_slider_set_leds(const uint8_t *rgb); +HRESULT chu2to3_io_led_init(void); +void chu2to3_io_led_set_colors(uint8_t board, uint8_t *rgb); +uint16_t chu2to3_load_dll(wchar_t *dllname); \ No newline at end of file diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index 1ecba4a..e149a52 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -8,6 +8,7 @@ - 0x0100: Initial API version (assumed if chuni_io_get_api_version is not exported) - 0x0101: Fix IR beam mappings + - 0x0102: Add air tower led and billboard support */ #include @@ -151,15 +152,24 @@ void chuni_io_slider_set_leds(const uint8_t *rgb); All subsequent calls may originate from arbitrary threads and some may overlap with each other. Ensuring synchronization inside your IO DLL is - your responsibility. */ + your responsibility. + + Minimum API version: 0x0102 */ HRESULT chuni_io_led_init(void); -/* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198 - bytes. The majority of these are for the marquee display, but the final - LEDs are for the side partitions. +/* Update the RGB LEDs. rgb is a pointer to an array of up to 63 * 3 = 189 bytes. + + Chunithm uses two chains/boards with WS2811 protocol (each logical led corresponds to 3 physical leds). + board 0 is on the left side and board 1 on the right side of the cab + + left side has 5*10 rgb values for the billboard, followed by 3 rgb values for the air tower + right side has 6*10 rgb values for the billboard, followed by 3 rgb values for the air tower - Chunithm uses two chains/boards. One is on the left side and one on the - right side of the cab. Exact layout is TBD. */ + Each rgb value is comprised of 3 bytes in R,G,B order + + NOTE: billboard strips have alternating direction (bottom to top, top to bottom, ...) + + Minimum API version: 0x0102 */ void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb); diff --git a/chuniio/meson.build b/chuniio/meson.build index fabf499..864aa87 100644 --- a/chuniio/meson.build +++ b/chuniio/meson.build @@ -5,6 +5,8 @@ chuniio_lib = static_library( implicit_include_directories : false, c_pch : '../precompiled.h', sources : [ + 'chu2to3.c', + 'chu2to3.h', 'chuniio.c', 'chuniio.h', 'config.c', diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c index 3a100ac..23bd311 100644 --- a/chusanhook/chuni-dll.c +++ b/chusanhook/chuni-dll.c @@ -39,6 +39,50 @@ const struct dll_bind_sym chuni_dll_syms[] = { } }; +const struct dll_bind_sym chu2to3_dll_syms[] = { + { + .sym = "chu2to3_io_jvs_init", + .off = offsetof(struct chuni_dll, jvs_init), + }, { + .sym = "chu2to3_io_jvs_poll", + .off = offsetof(struct chuni_dll, jvs_poll), + }, { + .sym = "chu2to3_io_jvs_read_coin_counter", + .off = offsetof(struct chuni_dll, jvs_read_coin_counter), + }, { + .sym = "chu2to3_io_slider_init", + .off = offsetof(struct chuni_dll, slider_init), + }, { + .sym = "chu2to3_io_slider_start", + .off = offsetof(struct chuni_dll, slider_start), + }, { + .sym = "chu2to3_io_slider_stop", + .off = offsetof(struct chuni_dll, slider_stop), + }, { + .sym = "chu2to3_io_slider_set_leds", + .off = offsetof(struct chuni_dll, slider_set_leds), + }, { + .sym = "chu2to3_io_led_init", + .off = offsetof(struct chuni_dll, led_init), + }, { + .sym = "chu2to3_io_led_set_colors", + .off = offsetof(struct chuni_dll, led_set_leds), + } +}; + +/* Helper function to determine upon dll_bind failure whether the required functions were found + NOTE: relies on symbols order declared above */ +static HRESULT has_enough_symbols(uint16_t version, uint8_t count) +{ + if ( version <= 0x0101 && count == 7 ) + return S_OK; + + if ( version >= 0x0102 && count == 9 ) + return S_OK; + + return E_FAIL; +} + struct chuni_dll chuni_dll; // Copypasta DLL binding and diagnostic message boilerplate. @@ -58,7 +102,12 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) assert(cfg != NULL); assert(self != NULL); - if (cfg->path[0] != L'\0') { + owned = NULL; + src = self; + + if (cfg->chu2to3) { + dprintf("Chunithm IO: using chu2to3 engine for IO DLL: %S\n", cfg->path); + } else if (cfg->path[0] != L'\0') { owned = LoadLibraryW(cfg->path); if (owned == NULL) { @@ -72,12 +121,18 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path); src = owned; - } else { - owned = NULL; - src = self; } - get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version"); + if (cfg->chu2to3) { + if (chu2to3_load_dll(cfg->path) != 0) + dprintf("Could not init chu2to3 engine\n"); + + get_api_version = (void *) GetProcAddress(src, "chu2to3_io_get_api_version"); + } + else + { + get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version"); + } if (get_api_version != NULL) { chuni_dll.api_version = get_api_version(); @@ -97,17 +152,26 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) goto end; } - sym = chuni_dll_syms; + sym = cfg->chu2to3 ? chu2to3_dll_syms : chuni_dll_syms; + const struct dll_bind_sym *init_sym = &sym[0]; + hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms)); if (FAILED(hr)) { if (src != self) { - dprintf("Chunithm IO: Custom IO DLL does not provide function " - "\"%s\". Please contact your IO DLL's developer for " - "further assistance.\n", - sym->sym); - - goto end; + // Might still be ok depending on external dll API version + int bind_count = sym - init_sym; + if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK ) + { + hr = S_OK; + } else { + dprintf("Chunithm IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + dprintf("imported %d symbols\n",bind_count); + goto end; + } } else { dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); } diff --git a/chusanhook/chuni-dll.h b/chusanhook/chuni-dll.h index 8341b48..bfc415c 100644 --- a/chusanhook/chuni-dll.h +++ b/chusanhook/chuni-dll.h @@ -19,6 +19,7 @@ struct chuni_dll { struct chuni_dll_config { wchar_t path[MAX_PATH]; + uint8_t chu2to3; }; extern struct chuni_dll chuni_dll; diff --git a/chusanhook/chusanhook.def b/chusanhook/chusanhook.def index 66ae5ec..ea786f5 100644 --- a/chusanhook/chusanhook.def +++ b/chusanhook/chusanhook.def @@ -22,3 +22,13 @@ EXPORTS chuni_io_slider_stop chuni_io_led_init chuni_io_led_set_colors + chu2to3_io_get_api_version + chu2to3_io_jvs_init + chu2to3_io_jvs_poll + chu2to3_io_jvs_read_coin_counter + chu2to3_io_slider_init + chu2to3_io_slider_set_leds + chu2to3_io_slider_start + chu2to3_io_slider_stop + chu2to3_io_led_init + chu2to3_io_led_set_colors diff --git a/chusanhook/config.c b/chusanhook/config.c index 0361e98..d71ad71 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -39,16 +39,27 @@ void chuni_dll_config_load( // Workaround for x64/x86 external IO dlls // path32 for 32bit, path64 for 64bit - // for else.. is that possible? idk + // path for 32bit only dlls (internal chu2to3 engine) - #if defined(ENV32BIT) - GetPrivateProfileStringW( - L"chuniio", - L"path32", - L"", - cfg->path, - _countof(cfg->path), - filename); + GetPrivateProfileStringW( + L"chuniio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); + if (cfg->path[0] != L'\0') { + cfg->chu2to3 = 1; + } else { + cfg->chu2to3 = 0; + #if defined(ENV32BIT) + GetPrivateProfileStringW( + L"chuniio", + L"path32", + L"", + cfg->path, + _countof(cfg->path), + filename); #elif defined(ENV64BIT) GetPrivateProfileStringW( L"chuniio", @@ -60,7 +71,7 @@ void chuni_dll_config_load( #else #error "Unknown environment" #endif - + } } void slider_config_load(struct slider_config *cfg, const wchar_t *filename) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 1e3ee2c..e8fce32 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -129,11 +129,16 @@ static DWORD CALLBACK chusan_pre_startup(void) } } - hr = led15093_hook_init(&chusan_hook_cfg.led15093, - chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1); + if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL ) + { + dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n"); + } else { + hr = led15093_hook_init(&chusan_hook_cfg.led15093, + chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1); - if (FAILED(hr)) { - goto fail; + if (FAILED(hr)) { + goto fail; + } } hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod); diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 45e2df9..3531bdf 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -64,7 +64,11 @@ framed=0 monitor=0 [chuniio] -; Uncomment this if you have custom chuniio implementation. +; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL. +; (will use chu2to3 engine internally) +;path= + +; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs. ; x86 chuniio to path32, x64 to path64. Both are necessary. ;path32= ;path64= From b38dea23ac9c27436daa9abd8680dc76f3940a60 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 25 Dec 2023 15:03:44 +0100 Subject: [PATCH 074/204] chu2to3: fixed docker compilation, bugfixes --- chuniio/chu2to3.c | 13 +++++++------ chuniio/chu2to3.h | 2 +- chuniio/chuniio.c | 2 +- chusanhook/chuni-dll.c | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/chuniio/chu2to3.c b/chuniio/chu2to3.c index 3569426..550583b 100644 --- a/chuniio/chu2to3.c +++ b/chuniio/chu2to3.c @@ -80,7 +80,7 @@ bool shmem_create() if (g_hMapFile == NULL) { - dprintf("shmem_create : Could not create file mapping object (%d).\n", + dprintf("shmem_create : Could not create file mapping object (%ld).\n", GetLastError()); return 0; } @@ -92,7 +92,7 @@ bool shmem_create() if (g_pBuf == NULL) { - dprintf("shmem_create : Could not map view of file (%d).\n", + dprintf("shmem_create : Could not map view of file (%ld).\n", GetLastError()); CloseHandle(g_hMapFile); @@ -112,7 +112,7 @@ bool shmem_load() if (g_hMapFile == NULL) { - dprintf("shmem_load : Could not open file mapping object (%d).\n", GetLastError()); + dprintf("shmem_load : Could not open file mapping object (%ld).\n", GetLastError()); return 0; } @@ -124,7 +124,7 @@ bool shmem_load() if (g_pBuf == NULL) { - dprintf("shmem_load : Could not map view of file (%d).\n", GetLastError()); + dprintf("shmem_load : Could not map view of file (%ld).\n", GetLastError()); CloseHandle(g_hMapFile); return 0; } @@ -148,6 +148,7 @@ static unsigned int __stdcall jvs_poll_thread_proc(void *ctx) while (1) { _chuni_io_jvs_read_coin_counter(&g_shared_data.coin_counter); g_shared_data.opbtn = 0; + g_shared_data.beams = 0; _chuni_io_jvs_poll(&g_shared_data.opbtn, &g_shared_data.beams); SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t)); Sleep(1); @@ -156,7 +157,7 @@ static unsigned int __stdcall jvs_poll_thread_proc(void *ctx) return 0; } -uint16_t chu2to3_load_dll(wchar_t *dllname) +uint16_t chu2to3_load_dll(const wchar_t *dllname) { #if defined(ENV64BIT) /* x64 must just open the shmem and do nothing else */ @@ -175,7 +176,7 @@ uint16_t chu2to3_load_dll(wchar_t *dllname) /* this is the first function called so let's setup the chuniio forwarding */ hinstLib = LoadLibraryW(dllname); if (hinstLib == NULL) { - dprintf("ERROR: unable to load %S (error %d)\n",dllname, GetLastError()); + dprintf("ERROR: unable to load %S (error %ld)\n",dllname, GetLastError()); return -1; } diff --git a/chuniio/chu2to3.h b/chuniio/chu2to3.h index bdbab77..de6e711 100644 --- a/chuniio/chu2to3.h +++ b/chuniio/chu2to3.h @@ -23,4 +23,4 @@ void chu2to3_io_slider_stop(void); void chu2to3_io_slider_set_leds(const uint8_t *rgb); HRESULT chu2to3_io_led_init(void); void chu2to3_io_led_set_colors(uint8_t board, uint8_t *rgb); -uint16_t chu2to3_load_dll(wchar_t *dllname); \ No newline at end of file +uint16_t chu2to3_load_dll(const wchar_t *dllname); diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 95a52d7..c5d81e5 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -22,7 +22,7 @@ static struct chuni_io_config chuni_io_cfg; uint16_t chuni_io_get_api_version(void) { - return 0x0101; + return 0x0102; } HRESULT chuni_io_jvs_init(void) diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c index 23bd311..e02b60b 100644 --- a/chusanhook/chuni-dll.c +++ b/chusanhook/chuni-dll.c @@ -3,6 +3,7 @@ #include #include +#include "chuniio/chu2to3.h" #include "chusanhook/chuni-dll.h" #include "util/dll-bind.h" From f5f275c8e9e6144e75a6c9a63932160e123bee6b Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 25 Dec 2023 15:12:25 +0100 Subject: [PATCH 075/204] chuniio: fixed individual IR notes --- chuniio/chuniio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index c5d81e5..27fe7b0 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -91,12 +91,12 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) } } else { // Use actual AIR - // IR format is beams[5:0] = {b5,b6,b3,b4,b1,b2}; - for (i = 0 ; i < 3 ; i++) { - if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2]) & 0x8000) - *beams |= (1 << (i*2+1)); - if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2+1]) & 0x8000) - *beams |= (1 << (i*2)); + for (i = 0; i < 6; i++) { + if(GetAsyncKeyState(chuni_io_cfg.vk_ir[i]) & 0x8000) { + *beams |= (1 << i); + } else { + *beams &= ~(1 << i); + } } } } From f4a3a5f78d91d3764c5caf58cd8202cda4738957 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 25 Dec 2023 15:55:43 +0100 Subject: [PATCH 076/204] optimized meson.build to decrease filesize --- meson.build | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index c4936be..a0db24a 100644 --- a/meson.build +++ b/meson.build @@ -17,11 +17,13 @@ add_project_arguments( language: 'c', ) -# Use get_argument_syntax() instead once Meson 0.49.0 releases -if meson.get_compiler('c').get_id() != 'msvc' +cc = meson.get_compiler('c') + +if cc.get_id() != 'msvc' add_project_arguments( '-ffunction-sections', '-fdata-sections', + '-flto', # Enable Link-Time Optimization language: 'c', ) @@ -30,11 +32,12 @@ if meson.get_compiler('c').get_id() != 'msvc' '-Wl,--exclude-all-symbols', '-Wl,--gc-sections', '-static-libgcc', + '-flto', # Enable Link-Time Optimization + '-Wl,-s', # Strip debug symbols language: 'c', ) endif -cc = meson.get_compiler('c') shlwapi_lib = cc.find_library('shlwapi') dinput8_lib = cc.find_library('dinput8') dxguid_lib = cc.find_library('dxguid') From 926493290b089df3abe7dde9203daa91d0174907 Mon Sep 17 00:00:00 2001 From: CrazyRedMachine Date: Tue, 26 Dec 2023 06:25:26 -0500 Subject: [PATCH 077/204] fix chunihook --- chunihook/chuni-dll.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/chunihook/chuni-dll.c b/chunihook/chuni-dll.c index 72393e9..5867f66 100644 --- a/chunihook/chuni-dll.c +++ b/chunihook/chuni-dll.c @@ -39,6 +39,19 @@ const struct dll_bind_sym chuni_dll_syms[] = { } }; +/* Helper function to determine upon dll_bind failure whether the required functions were found + NOTE: relies on symbols order declared above */ +static HRESULT has_enough_symbols(uint16_t version, uint8_t count) +{ + if ( version <= 0x0101 && count == 7 ) + return S_OK; + + if ( version >= 0x0102 && count == 9 ) + return S_OK; + + return E_FAIL; +} + struct chuni_dll chuni_dll; // Copypasta DLL binding and diagnostic message boilerplate. @@ -98,16 +111,24 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) } sym = chuni_dll_syms; + const struct dll_bind_sym *init_sym = &sym[0]; hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms)); if (FAILED(hr)) { if (src != self) { - dprintf("Chunithm IO: Custom IO DLL does not provide function " - "\"%s\". Please contact your IO DLL's developer for " - "further assistance.\n", - sym->sym); + // Might still be ok depending on external dll API version + int bind_count = sym - init_sym; + if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK ) + { + hr = S_OK; + } else { + dprintf("Chunithm IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); - goto end; + goto end; + } } else { dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); } From d0165b1eb0d9b1808502e0e1c5c5b47c66b71577 Mon Sep 17 00:00:00 2001 From: beerpsi Date: Mon, 8 Jan 2024 01:33:40 +0700 Subject: [PATCH 078/204] fix(netenv): Print IP addresses properly --- platform/netenv.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/platform/netenv.c b/platform/netenv.c index 37a9eae..951c4b0 100644 --- a/platform/netenv.c +++ b/platform/netenv.c @@ -1,5 +1,4 @@ #include -#include #include #include @@ -372,9 +371,12 @@ static uint32_t WINAPI hook_GetBestRoute( return ERROR_INVALID_PARAMETER; } - dprintf("Netenv: GetBestRoute ip4 %x -> ip4 %x\n", - (int) _byteswap_ulong(src_ip), - (int) _byteswap_ulong(dest_ip)); + uint32_t src_addr = _byteswap_ulong(src_ip); + uint32_t dest_addr = _byteswap_ulong(dest_ip); + + dprintf("Netenv: GetBestRoute ip4 %u.%u.%u.%u -> ip4 %u.%u.%u.%u\n", + (src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff, + (dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff); memset(route, 0, sizeof(*route)); @@ -469,8 +471,10 @@ static uint32_t WINAPI hook_IcmpSendEcho2( return 0; } - dprintf("Netenv: Virtualized ICMP Ping to ip4 %x\n", - (int) _byteswap_ulong(DestinationAddress)); + uint32_t addr = _byteswap_ulong(DestinationAddress); + + dprintf("Netenv: Virtualized ICMP Ping to ip4 %u.%u.%u.%u\n", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); pong = (ICMP_ECHO_REPLY *) ReplyBuffer; memset(pong, 0, sizeof(*pong)); From 0affc96e3e2c043c01a094be7a1e04d65d25a964 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 16 Jan 2024 17:54:06 +0100 Subject: [PATCH 079/204] small optimizations --- board/config.c | 2 +- chunihook/config.c | 2 +- chusanhook/config.c | 2 +- dist/chusan/segatools.ini | 6 +++++- dist/fgo/segatools.ini | 1 - doc/config/common.md | 2 +- fgohook/config.c | 2 +- fgohook/fgo-dll.h | 2 +- fgoio/fgoio.c | 1 - idachook/idac-dll.c | 3 --- idachook/idac-dll.h | 1 - idachook/io4.c | 8 -------- idacio/idacio.def | 1 - idacio/idacio.h | 9 +-------- 14 files changed, 12 insertions(+), 30 deletions(-) diff --git a/board/config.c b/board/config.c index bbbf074..9fefd4c 100644 --- a/board/config.c +++ b/board/config.c @@ -71,7 +71,7 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); - cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highbaud", 1, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename); cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename); } diff --git a/chunihook/config.c b/chunihook/config.c index 99b9c3a..dd1497d 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -56,7 +56,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); cfg->port_no = 0; - cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); diff --git a/chusanhook/config.c b/chusanhook/config.c index d71ad71..3796f69 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -96,7 +96,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); cfg->port_no = 0; - cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 3531bdf..926a6fe 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -13,7 +13,7 @@ appdata= enable=1 aimePath=DEVICE\aime.txt ; Enable high baud rate. -;highbaud=1 +;highBaud=1 [aimeio] ; Uncomment this if you have custom (x64) aime implementation. @@ -30,6 +30,10 @@ default=127.0.0.1 ; Chunithm is extremely picky about its LAN environment, so leaving this ; setting enabled is strongly recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index d106aaf..08218a2 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -23,7 +23,6 @@ default=127.0.0.1 ; SEGA games are somewhat picky about their LAN environment, so leaving this ; setting enabled is recommended. enable=1 - ; The final octet of the local host's IP address on the virtualized subnet (so, ; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the ; local host's virtualized LAN IP is `192.168.32.11`). diff --git a/doc/config/common.md b/doc/config/common.md index fb82131..56283b5 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -31,7 +31,7 @@ Default: `1` Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime reader (COM port number varies by game). -### `highbaud` +### `highBaud` Default: `1` diff --git a/fgohook/config.c b/fgohook/config.c index 4b05e97..24b5825 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -48,7 +48,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); - cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); diff --git a/fgohook/fgo-dll.h b/fgohook/fgo-dll.h index 22bf02d..b7e4f3d 100644 --- a/fgohook/fgo-dll.h +++ b/fgohook/fgo-dll.h @@ -11,7 +11,7 @@ struct fgo_dll { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint8_t *gamebtn); void (*get_analogs)(int16_t *stick_x, int16_t *stick_y); - HRESULT (*led_init)(); + HRESULT (*led_init)(void); void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index 95c86d9..d9aeed1 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -142,7 +142,6 @@ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y) HRESULT fgo_io_led_init(void) { - // return 0; return S_OK; } diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c index 03a6a3e..b463a6d 100644 --- a/idachook/idac-dll.c +++ b/idachook/idac-dll.c @@ -12,9 +12,6 @@ const struct dll_bind_sym idac_dll_syms[] = { { .sym = "idac_io_init", .off = offsetof(struct idac_dll, init), - }, { - .sym = "idac_io_poll", - .off = offsetof(struct idac_dll, poll), }, { .sym = "idac_io_get_opbtns", .off = offsetof(struct idac_dll, get_opbtns), diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h index 7db5639..cc4a492 100644 --- a/idachook/idac-dll.h +++ b/idachook/idac-dll.h @@ -7,7 +7,6 @@ struct idac_dll { uint16_t api_version; HRESULT (*init)(void); - HRESULT (*poll)(void); void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint8_t *gamebtn); void (*get_shifter)(uint8_t *gear); diff --git a/idachook/io4.c b/idachook/io4.c index 3d2eec5..b5e13be 100644 --- a/idachook/io4.c +++ b/idachook/io4.c @@ -57,7 +57,6 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) struct idac_io_analog_state analog_state; HRESULT hr; - assert(idac_dll.poll != NULL); assert(idac_dll.get_opbtns != NULL); assert(idac_dll.get_gamebtns != NULL); assert(idac_dll.get_analogs != NULL); @@ -65,13 +64,6 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) memset(state, 0, sizeof(*state)); memset(&analog_state, 0, sizeof(analog_state)); - - hr = idac_dll.poll(); - - if (FAILED(hr)) { - return hr; - } - opbtn = 0; gamebtn = 0; gear = 0; diff --git a/idacio/idacio.def b/idacio/idacio.def index 18839b2..e888510 100644 --- a/idacio/idacio.def +++ b/idacio/idacio.def @@ -2,7 +2,6 @@ LIBRARY idacio EXPORTS idac_io_init - idac_io_poll idac_io_get_opbtns idac_io_get_gamebtns idac_io_get_shifter diff --git a/idacio/idacio.h b/idacio/idacio.h index c0e743e..04c1b10 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -56,13 +56,6 @@ uint16_t idac_io_get_api_version(void); HRESULT idac_io_init(void); -/* Send any queued outputs (of which there are currently none, though this may - change in subsequent API versions) and retrieve any new inputs. - - Minimum API version: 0x0100 */ - -HRESULT idac_io_poll(void); - /* Get the state of the cabinet's operator buttons as of the last poll. See IDAC_IO_OPBTN enum above: this contains bit mask definitions for button states returned in *opbtn. All buttons are active-high. @@ -93,7 +86,7 @@ void idac_io_get_analogs(struct idac_io_analog_state *out); /* Poll the current position of the six-speed shifter and return it via the gear out parameter. Valid values are 0 for neutral and 1-6 for gears 1-6. - idzhook internally translates this gear position value into the correct + idachook internally translates this gear position value into the correct combination of Gear Left, Gear Right, Gear Up, Gear Down buttons that the game will then interpret as the current position of the gear lever. From cc0b6b0953e268fe29365ed11bc2079786e2a9d6 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 16 Jan 2024 17:56:24 +0100 Subject: [PATCH 080/204] swdc: fixed steering wheel buttons, improved start.bat --- Package.mk | 1 + dist/swdc/config_hook.json | 6 + dist/swdc/segatools.ini | 2 +- dist/swdc/start.bat | 36 +++++- swdchook/dllmain.c | 18 +-- swdchook/io4.c | 65 ++++++++--- swdchook/swdc-dll.c | 3 - swdchook/swdc-dll.h | 1 - swdchook/swdchook.def | 1 - swdchook/zinput.c | 220 +++++++++++++++++++++++++++++-------- swdchook/zinput.h | 2 +- swdcio/di.c | 3 - swdcio/swdcio.def | 1 - swdcio/swdcio.h | 13 +-- 14 files changed, 280 insertions(+), 92 deletions(-) create mode 100644 dist/swdc/config_hook.json diff --git a/Package.mk b/Package.mk index 438421e..55ae693 100644 --- a/Package.mk +++ b/Package.mk @@ -111,6 +111,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/swdchook/swdchook.dll \ $(DIST_DIR)/swdc/segatools.ini \ + $(DIST_DIR)/swdc/config_hook.json \ $(DIST_DIR)/swdc/start.bat \ $(BUILD_DIR_ZIP)/swdc $(V)cp pki/billing.pub \ diff --git a/dist/swdc/config_hook.json b/dist/swdc/config_hook.json new file mode 100644 index 0000000..6c33540 --- /dev/null +++ b/dist/swdc/config_hook.json @@ -0,0 +1,6 @@ +{ + "emoney" : + { + "enable" : false + } +} diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index fb93e50..4e88bf3 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -6,7 +6,7 @@ option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. -appdata= +appdata=appdata [aime] ; Controls emulation of the Aime card reader assembly. diff --git a/dist/swdc/start.bat b/dist/swdc/start.bat index c5e7733..a44605b 100644 --- a/dist/swdc/start.bat +++ b/dist/swdc/start.bat @@ -2,12 +2,36 @@ pushd %~dp0 -rem Matching Server -start /min ..\..\..\Tools\tdrserver.exe -REM start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanClient.json config_MiniCabinet.json config_hook.json -start /min inject -d -k swdchook.dll amdaemon.exe -c config.json config_LanServer.json config_MiniCabinet.json -REM Valid -launch parameters are "PC", "Cabinet" and "MiniCabinet -inject -d -k swdchook.dll ..\Todoroki\Binaries\Win64\Todoroki-Win64-Shipping.exe -launch=MiniCabinet -ABSLOG="..\..\..\..\..\Userdata\Todoroki.log" -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +REM Root directory +set ROOT_DIR=WindowsNoEditor + +rem Matching Server paths +set MATCHING_SERVER_FILE_NAME=tdrserver.exe +set MATCHING_SERVER_PATH=..\Tools\%MATCHING_SERVER_FILE_NAME% + +rem AM Daemon paths +set DAEMON_DIR=%ROOT_DIR%\AMDaemon +set DAEMON_CONFIG_PATH=%DAEMON_DIR%\config.json +rem Make sure to use appdata=appdata in segatools.ini +set DAEMON_CHECK_LAN_SERVER_PATH=appdata\SDDS\LanServer.dat + +rem Check if LanServer.dat is present +if exist "%DAEMON_CHECK_LAN_SERVER_PATH%" ( + set DAEMON_LAN_CONFIG_PATH=%DAEMON_DIR%\config_LanServer.json + + start "matching_server" /min %MATCHING_SERVER_PATH% +) else ( + set DAEMON_LAN_CONFIG_PATH=%DAEMON_DIR%\config_LanClient.json +) + +start "AM Daemon" /min inject -d -k swdchook.dll "%DAEMON_DIR%\amdaemon.exe" -c %DAEMON_CONFIG_PATH% -c %DAEMON_LAN_CONFIG_PATH% config_hook.json + +REM Launch Todoroki +set APP_EXE_DIR=WindowsNoEditor\Todoroki\Binaries\Win64 +set APP_EXE_PATH=%APP_EXE_DIR%\Todoroki-Win64-Shipping.exe + +REM Valid -launch parameters are "Cabinet" or "MiniCabinet" +inject -d -k swdchook.dll "%APP_EXE_PATH%" -launch="MiniCabinet" -ABSLOG="..\Userdata\Todoroki.log" -UserDir="..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 taskkill /f /im tdrserver.exe > nul 2>&1 diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index b33c711..e5a47d2 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -16,7 +16,6 @@ #include "swdchook/config.h" #include "swdchook/swdc-dll.h" #include "swdchook/io4.h" -#include "swdchook/zinput.h" #include "platform/platform.h" @@ -39,7 +38,6 @@ static DWORD CALLBACK swdc_pre_startup(void) /* Hook Win32 APIs */ serial_hook_init(); - zinput_hook_init(&swdc_hook_cfg.zinput, swdc_hook_mod); dvd_hook_init(&swdc_hook_cfg.dvd, swdc_hook_mod); /* Initialize emulation hooks */ @@ -54,6 +52,12 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } + hr = swdc_dll_init(&swdc_hook_cfg.dll, swdc_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + hr = sg_reader_hook_init(&swdc_hook_cfg.aime, 3, 3, swdc_hook_mod); if (FAILED(hr)) { @@ -66,18 +70,16 @@ static DWORD CALLBACK swdc_pre_startup(void) return hr; } - hr = swdc_dll_init(&swdc_hook_cfg.dll, swdc_hook_mod); - - if (FAILED(hr)) { - goto fail; - } - hr = swdc_io4_hook_init(&swdc_hook_cfg.io4); if (FAILED(hr)) { goto fail; } + /* Hook external DLL APIs */ + + zinput_hook_init(&swdc_hook_cfg.zinput); + /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); diff --git a/swdchook/io4.c b/swdchook/io4.c index 10736ef..be2749e 100644 --- a/swdchook/io4.c +++ b/swdchook/io4.c @@ -6,9 +6,13 @@ #include "board/io4.h" +#include "util/dprintf.h" + #include "swdchook/swdc-dll.h" -#include "util/dprintf.h" +static HANDLE mmf; +static HRESULT init_mmf(void); +static void swdc_set_gamebtns(uint16_t value); static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state); static uint16_t coins; @@ -17,8 +21,7 @@ static const struct io4_ops swdc_io4_ops = { .poll = swdc_io4_poll, }; -HRESULT swdc_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT swdc_io4_hook_init(const struct io4_config *cfg) { HRESULT hr; assert(swdc_dll.init != NULL); @@ -29,30 +32,54 @@ HRESULT swdc_io4_hook_init(const struct io4_config *cfg) return hr; } + hr = init_mmf(); + + if (FAILED(hr)) { + return hr; + } + return swdc_dll.init(); } -static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) -{ +// Function to initialize the memory-mapped file +static HRESULT init_mmf(void) { + mmf = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, "SWDCButton"); + if (mmf == NULL) { + return S_FALSE; + } + + swdc_set_gamebtns(0); + + return S_OK; +} + +void swdc_set_gamebtns(uint16_t value) { + // WaitForSingleObject(mutex, INFINITE); + + // Update the memory-mapped file + LPVOID mmf_view = MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, 2); + if (mmf_view != NULL) { + uint16_t* ptr = (uint16_t*)mmf_view; + *ptr = value; + + UnmapViewOfFile(mmf_view); + } + + // ReleaseMutex(mutex); +} + +static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { uint8_t opbtn; uint16_t gamebtn; struct swdc_io_analog_state analog_state; HRESULT hr; - assert(swdc_dll.poll != NULL); assert(swdc_dll.get_opbtns != NULL); assert(swdc_dll.get_gamebtns != NULL); assert(swdc_dll.get_analogs != NULL); memset(state, 0, sizeof(*state)); memset(&analog_state, 0, sizeof(analog_state)); - - hr = swdc_dll.poll(); - - if (FAILED(hr)) { - return hr; - } - opbtn = 0; gamebtn = 0; @@ -99,7 +126,17 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) state->buttons[0] |= 1 << 2; } - /* Update steering wheel buttons */ +/* + Update steering wheel buttons + + Those are connected to the SEGA838-15415 INDICATOR BD MAIN + USB board which is not emulated for now. So those buttons + are hooked to the built-in XInput support. +*/ + + /* Instead update gamebtns for the file mapping */ + + swdc_set_gamebtns(gamebtn); if (gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) { state->buttons[1] |= 1 << 15; diff --git a/swdchook/swdc-dll.c b/swdchook/swdc-dll.c index 47120ee..80d4526 100644 --- a/swdchook/swdc-dll.c +++ b/swdchook/swdc-dll.c @@ -12,9 +12,6 @@ const struct dll_bind_sym swdc_dll_syms[] = { { .sym = "swdc_io_init", .off = offsetof(struct swdc_dll, init), - }, { - .sym = "swdc_io_poll", - .off = offsetof(struct swdc_dll, poll), }, { .sym = "swdc_io_get_opbtns", .off = offsetof(struct swdc_dll, get_opbtns), diff --git a/swdchook/swdc-dll.h b/swdchook/swdc-dll.h index 8e13a2c..87781c8 100644 --- a/swdchook/swdc-dll.h +++ b/swdchook/swdc-dll.h @@ -7,7 +7,6 @@ struct swdc_dll { uint16_t api_version; HRESULT (*init)(void); - HRESULT (*poll)(void); void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint16_t *gamebtn); void (*get_analogs)(struct swdc_io_analog_state *out); diff --git a/swdchook/swdchook.def b/swdchook/swdchook.def index 37b47bd..160cb7d 100644 --- a/swdchook/swdchook.def +++ b/swdchook/swdchook.def @@ -13,7 +13,6 @@ EXPORTS amDllVideoSetResolution @3 swdc_io_get_api_version swdc_io_init - swdc_io_poll swdc_io_get_opbtns swdc_io_get_gamebtns swdc_io_get_analogs diff --git a/swdchook/zinput.c b/swdchook/zinput.c index 264102b..5a14800 100644 --- a/swdchook/zinput.c +++ b/swdchook/zinput.c @@ -1,31 +1,61 @@ #include -#include +#include #include +#include #include +#include +#include + +#include "board/io4.h" + +#include "hook/table.h" +#include "util/dprintf.h" +#include "util/lib.h" #include "swdchook/config.h" #include "swdchook/zinput.h" -#include "hook/table.h" +static struct zinput_config zinput_config; +static bool zinput_hook_initted; +static bool zinput_controller_init = false; -#include "util/dprintf.h" +static HRESULT init_mmf(void); +static HANDLE mmf; +static uint16_t* swdc_gamebtn; + +/* Hooked functions */ DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState); +DWORD WINAPI hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration); +// Not needed for now? +DWORD WINAPI hook_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities); -static const struct hook_symbol zinput_hook_syms[] = { +// Yup SEGA imports XInput functions via ordinal. FUN! +static struct hook_symbol zinput_hook_syms[] = { { - .name = "XInputGetState", - .patch = hook_XInputGetState, - .link = NULL + .name = "XInputGetState", + .ordinal = 0x0002, + .patch = hook_XInputGetState, + .link = NULL + }, { + .name = "XInputSetState", + .ordinal = 0x0003, + .patch = hook_XInputSetState, + .link = NULL + }, { + // Not needed for now? + .name = "XInputGetCapabilities", + .patch = hook_XInputGetCapabilities, + .link = NULL }, }; -static struct zinput_config zinput_config; -static bool zinput_hook_initted; - -void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self) +void zinput_hook_init(struct zinput_config *cfg) { + wchar_t *module_path; + wchar_t *file_name; + assert(cfg != NULL); if (!cfg->enable) { @@ -36,45 +66,149 @@ void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self) return; } - memcpy(&zinput_config, cfg, sizeof(*cfg)); - hook_table_apply( - NULL, - "XINPUT9_1_0.dll", - zinput_hook_syms, - _countof(zinput_hook_syms)); + module_path = module_file_name(NULL); + + if (module_path != NULL) { + file_name = PathFindFileNameW(module_path); + + free(module_path); + module_path = NULL; + + _wcslwr(file_name); + + if (wcsstr(file_name, L"amdaemon") != NULL) { + // dprintf("Executable filename contains 'amdaemon', disabling zinput\n"); + return; + } + } hook_table_apply( - NULL, - "XINPUT1_1.dll", - zinput_hook_syms, - _countof(zinput_hook_syms)); - - hook_table_apply( - NULL, - "XINPUT1_2.dll", - zinput_hook_syms, - _countof(zinput_hook_syms)); - - hook_table_apply( - NULL, - "XINPUT1_3.dll", - zinput_hook_syms, - _countof(zinput_hook_syms)); - - hook_table_apply( - NULL, - "XINPUT1_4.dll", - zinput_hook_syms, - _countof(zinput_hook_syms)); + NULL, + "XINPUT1_3.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + if (FAILED(init_mmf())) { + return; + } zinput_hook_initted = true; - dprintf("ZInput: Blocking built-in XInput support\n"); + dprintf("ZInput: Hooking built-in XInput support\n"); } -DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) -{ +bool zinput_connect_controller(bool enable) { + zinput_controller_init = enable; + dprintf("zinput_connect_controller\n"); + return true; +} + +static HRESULT init_mmf(void) { + // Create or open memory-mapped file + mmf = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, "SWDCButton"); + if (mmf == NULL) { + return S_FALSE; + } + + // Map the memory-mapped file + swdc_gamebtn = (uint16_t*)MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, 2); + + return S_OK; +} + +DWORD WINAPI hook_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities) { + // dprintf("ZInput: XInputGetCapabilities hook hit\n"); + + if (!zinput_controller_init) { + zinput_connect_controller(true); + } + + if (dwFlags > XINPUT_FLAG_GAMEPAD) { + return ERROR_BAD_ARGUMENTS; + } + + if (zinput_controller_init && dwUserIndex == 0) { + pCapabilities->Flags = XINPUT_CAPS_VOICE_SUPPORTED; + pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD; + pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD; + + pCapabilities->Gamepad.wButtons = 0xF3FF; + + pCapabilities->Gamepad.bLeftTrigger = 0xFF; + pCapabilities->Gamepad.bRightTrigger = 0xFF; + + pCapabilities->Gamepad.sThumbLX = (SHORT)0xFFC0; + pCapabilities->Gamepad.sThumbLY = (SHORT)0xFFC0; + pCapabilities->Gamepad.sThumbRX = (SHORT)0xFFC0; + pCapabilities->Gamepad.sThumbRY = (SHORT)0xFFC0; + + pCapabilities->Vibration.wLeftMotorSpeed = 0xFF; + pCapabilities->Vibration.wRightMotorSpeed = 0xFF; + + return ERROR_SUCCESS; + } else { + return ERROR_DEVICE_NOT_CONNECTED; + } +} + +DWORD WINAPI hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) { // dprintf("ZInput: XInputGetState hook hit\n"); - return ERROR_SUCCESS; + if (!zinput_controller_init) { + zinput_connect_controller(true); + } + + if (zinput_controller_init && dwUserIndex == 0) { + XINPUT_GAMEPAD gamepad_state = {0}; + gamepad_state.wButtons = 0; + + /* Read filemapping for for the gamebtns */ + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_LEFT) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + } + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + } + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_BLUE) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_X; + } + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_RED) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_B; + } + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_GREEN) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_A; + } + + if (*swdc_gamebtn & SWDC_IO_GAMEBTN_STEERING_YELLOW) { + gamepad_state.wButtons |= XINPUT_GAMEPAD_Y; + } + if (pState->dwPacketNumber == UINT_MAX) + pState->dwPacketNumber = 0; + else + pState->dwPacketNumber++; + + pState->Gamepad = gamepad_state; + return ERROR_SUCCESS; + } else { + return ERROR_DEVICE_NOT_CONNECTED; + } +} + +DWORD WINAPI hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration) { + // dprintf("ZInput: XInputSetState hook hit\n"); + + if (!zinput_controller_init) { + zinput_connect_controller(true); + } + + if (zinput_controller_init && dwUserIndex == 0) { + return ERROR_SUCCESS; + } else { + return ERROR_DEVICE_NOT_CONNECTED; + } } diff --git a/swdchook/zinput.h b/swdchook/zinput.h index ee3e6ad..dc883dc 100644 --- a/swdchook/zinput.h +++ b/swdchook/zinput.h @@ -8,4 +8,4 @@ struct zinput_config { bool enable; }; -void zinput_hook_init(struct zinput_config *cfg, HINSTANCE self); +void zinput_hook_init(struct zinput_config *cfg); diff --git a/swdcio/di.c b/swdcio/di.c index 09f25d0..da6e4b5 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -28,9 +28,6 @@ static BOOL CALLBACK swdc_di_enum_callback( static BOOL CALLBACK swdc_di_enum_callback_pedals( const DIDEVICEINSTANCEW *dev, void *ctx); -static BOOL CALLBACK swdc_di_enum_callback_shifter( - const DIDEVICEINSTANCEW *dev, - void *ctx); static void swdc_di_get_buttons(uint16_t *gamebtn_out); static uint8_t swdc_di_decode_pov(DWORD pov); static void swdc_di_get_analogs(struct swdc_io_analog_state *out); diff --git a/swdcio/swdcio.def b/swdcio/swdcio.def index c2cb0ce..ca63aca 100644 --- a/swdcio/swdcio.def +++ b/swdcio/swdcio.def @@ -2,7 +2,6 @@ LIBRARY swdcio EXPORTS swdc_io_init - swdc_io_poll swdc_io_get_opbtns swdc_io_get_gamebtns swdc_io_get_analogs diff --git a/swdcio/swdcio.h b/swdcio/swdcio.h index 5ce593c..7155273 100644 --- a/swdcio/swdcio.h +++ b/swdcio/swdcio.h @@ -55,7 +55,7 @@ struct swdc_io_analog_state { uint16_t swdc_io_get_api_version(void); /* Initialize the IO DLL. This is the second function that will be called on - your DLL, after mu3_io_get_api_version. + your DLL, after SWDC_io_get_api_version. All subsequent calls to this API may originate from arbitrary threads. @@ -63,15 +63,8 @@ uint16_t swdc_io_get_api_version(void); HRESULT swdc_io_init(void); -/* Send any queued outputs (of which there are currently none, though this may - change in subsequent API versions) and retrieve any new inputs. - - Minimum API version: 0x0100 */ - -HRESULT swdc_io_poll(void); - /* Get the state of the cabinet's operator buttons as of the last poll. See - MU3_IO_OPBTN enum above: this contains bit mask definitions for button + SWDC_IO_OPBTN enum above: this contains bit mask definitions for button states returned in *opbtn. All buttons are active-high. Minimum API version: 0x0100 */ @@ -79,7 +72,7 @@ HRESULT swdc_io_poll(void); void swdc_io_get_opbtns(uint8_t *opbtn); /* Get the state of the cabinet's gameplay buttons as of the last poll. See - MU3_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into + SWDC_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into a left hand side set of inputs and a right hand side set of inputs: the bit mappings are the same in both cases. From cadf20040c7fb872d072dc51ed2b54fbbd83b3f2 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 17 Jan 2024 15:52:41 +0100 Subject: [PATCH 081/204] swdc: fixed dinput buttons --- swdchook/io4.c | 2 +- swdcio/di.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swdchook/io4.c b/swdchook/io4.c index be2749e..d9f2198 100644 --- a/swdchook/io4.c +++ b/swdchook/io4.c @@ -129,7 +129,7 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { /* Update steering wheel buttons - Those are connected to the SEGA838-15415 INDICATOR BD MAIN + Those are connected to the SEGA 838-15415 INDICATOR BD MAIN USB board which is not emulated for now. So those buttons are hooked to the built-in XInput support. */ diff --git a/swdcio/di.c b/swdcio/di.c index da6e4b5..7639a4e 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -408,7 +408,7 @@ static BOOL CALLBACK swdc_di_enum_callback_pedals( static void swdc_di_get_buttons(uint16_t *gamebtn_out) { union swdc_di_state state; - uint8_t gamebtn; + uint16_t gamebtn; HRESULT hr; assert(gamebtn_out != NULL); From dae301841145c0c91bec55f8d02781f28b4be837 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sat, 27 Jan 2024 23:10:59 +0100 Subject: [PATCH 082/204] doc: added develop dongle hint --- doc/config/common.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/config/common.md b/doc/config/common.md index 56283b5..7249d49 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -396,8 +396,8 @@ is an issue. Billing types are: Default: `0x64` An 8-bit bitfield of unclear meaning. The least significant bit indicates a -developer dongle, I think? Changing this doesn't seem to have any effect on -anything other than Project DIVA. +developer dongle. Changing this doesn't seem to have any effect on +anything other than SEGA AM2 games. Other values observed in the wild: From 451a7ec49d6eab979a026e0ba0156862dc9e5b11 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 6 Feb 2024 12:34:11 +0100 Subject: [PATCH 083/204] added VFD toggle to config --- board/config.c | 9 +++++++++ board/config.h | 2 ++ board/vfd.c | 10 +++++++++- board/vfd.h | 7 ++++++- chusanhook/config.c | 1 + chusanhook/config.h | 1 + chusanhook/dllmain.c | 2 +- cmhook/config.c | 1 + cmhook/config.h | 1 + cmhook/dllmain.c | 2 +- dist/chusan/segatools.ini | 8 +++++++- dist/cm/segatools.ini | 8 +++++++- dist/fgo/segatools.ini | 8 +++++++- dist/mai2/segatools.ini | 8 +++++++- dist/mercury/segatools.ini | 11 +++++++++++ dist/mu3/segatools.ini | 8 +++++++- dist/swdc/segatools.ini | 8 +++++++- doc/config/common.md | 11 +++++++++++ fgohook/config.c | 1 + fgohook/config.h | 1 + fgohook/dllmain.c | 2 +- mai2hook/config.c | 1 + mai2hook/config.h | 1 + mai2hook/dllmain.c | 2 +- mercuryhook/config.c | 1 + mercuryhook/config.h | 1 + mercuryhook/dllmain.c | 2 +- mu3hook/config.c | 1 + mu3hook/config.h | 1 + mu3hook/dllmain.c | 2 +- swdchook/config.c | 1 + swdchook/config.h | 1 + swdchook/dllmain.c | 2 +- 33 files changed, 111 insertions(+), 15 deletions(-) diff --git a/board/config.c b/board/config.c index 9fefd4c..9b69b42 100644 --- a/board/config.c +++ b/board/config.c @@ -8,6 +8,7 @@ #include "board/aime-dll.h" #include "board/config.h" #include "board/sg-reader.h" +#include "board/vfd.h" #include "util/dprintf.h" @@ -82,3 +83,11 @@ void io4_config_load(struct io4_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename); } + +void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename); +} diff --git a/board/config.h b/board/config.h index f436a82..37b5b14 100644 --- a/board/config.h +++ b/board/config.h @@ -5,6 +5,8 @@ #include "board/io4.h" #include "board/sg-reader.h" +#include "board/vfd.h" void aime_config_load(struct aime_config *cfg, const wchar_t *filename); void io4_config_load(struct io4_config *cfg, const wchar_t *filename); +void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename); diff --git a/board/vfd.c b/board/vfd.c index 081a8d8..0442439 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -27,14 +27,22 @@ static struct uart vfd_uart; static uint8_t vfd_written[512]; static uint8_t vfd_readable[512]; -HRESULT vfd_hook_init(unsigned int port_no) +HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no) { + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + uart_init(&vfd_uart, port_no); vfd_uart.written.bytes = vfd_written; vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.readable.bytes = vfd_readable; vfd_uart.readable.nbytes = sizeof(vfd_readable); + dprintf("VFD: hook enabled.\n"); + return iohook_push_handler(vfd_handle_irp); } diff --git a/board/vfd.h b/board/vfd.h index 01cd82e..e37386f 100644 --- a/board/vfd.h +++ b/board/vfd.h @@ -2,4 +2,9 @@ #include -HRESULT vfd_hook_init(unsigned int port_no); +struct vfd_config { + bool enable; +}; + + +HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no); diff --git a/chusanhook/config.c b/chusanhook/config.c index 3796f69..fa6f19f 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -160,6 +160,7 @@ void chusan_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); gfx_config_load(&cfg->gfx, filename); + vfd_config_load(&cfg->vfd, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); led15093_config_load(&cfg->led15093, filename); diff --git a/chusanhook/config.h b/chusanhook/config.h index 48fb696..e877be5 100644 --- a/chusanhook/config.h +++ b/chusanhook/config.h @@ -20,6 +20,7 @@ struct chusan_hook_config { struct dvd_config dvd; struct io4_config io4; struct gfx_config gfx; + struct vfd_config vfd; struct chuni_dll_config dll; struct slider_config slider; struct led15093_config led15093; diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index e8fce32..136db03 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -122,7 +122,7 @@ static DWORD CALLBACK chusan_pre_startup(void) unsigned int first_port = is_cvt ? 2 : 20; if (!is_cvt) { - hr = vfd_hook_init(2); + hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/cmhook/config.c b/cmhook/config.c index 64cbbb2..fd9186c 100644 --- a/cmhook/config.c +++ b/cmhook/config.c @@ -37,6 +37,7 @@ void cm_hook_config_load( aime_config_load(&cfg->aime, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); cm_dll_config_load(&cfg->dll, filename); } diff --git a/cmhook/config.h b/cmhook/config.h index c79f47a..cf39c70 100644 --- a/cmhook/config.h +++ b/cmhook/config.h @@ -16,6 +16,7 @@ struct cm_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct vfd_config vfd; struct cm_dll_config dll; struct touch_screen_config touch; }; diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 72587ad..0e12adb 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -60,7 +60,7 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&cm_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 926a6fe..f6959d3 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -9,12 +9,18 @@ option= appdata= [aime] -; Enable aime reader emulation. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt ; Enable high baud rate. ;highBaud=1 +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [aimeio] ; Uncomment this if you have custom (x64) aime implementation. ; Leave empty if you want to use Segatools built-in keyboard input. diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 93b2151..9ca7041 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -9,10 +9,16 @@ option= appdata= [aime] -; Enable aime reader emulation. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 08218a2..4d83225 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -9,10 +9,16 @@ option= appdata= [aime] -; Controls emulation of the Aime card reader assembly. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index f3dc0d8..d8ad3d2 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -9,10 +9,16 @@ option= appdata= [aime] -; Enable aime reader emulation. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 80816b4..5a7cfa3 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -7,6 +7,17 @@ amfs=amfs appdata=appdata option=option +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 83fe03b..a6e68fa 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -9,10 +9,16 @@ option= appdata= [aime] -; Controls emulation of the Aime card reader assembly. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 4e88bf3..7b64550 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -9,10 +9,16 @@ option= appdata=appdata [aime] -; Controls emulation of the Aime card reader assembly. +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. enable=1 aimePath=DEVICE\aime.txt +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. diff --git a/doc/config/common.md b/doc/config/common.md index 7249d49..23be911 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -84,6 +84,17 @@ emulates an IC card in its proximity. A variety of different IC cards can be emulated; the exact choice of card that is emulated depends on the presence or absence of the configured card ID files. +## `[vfd]` + +Controls emulation of the VFD GP1232A02A FUTABA assembly. + +### `enable` + +Default: `1` + +Enable VFD emulation (currently just stubbed). Disable to use a real VFD +GP1232A02A FUTABA assembly (COM port number varies by game). + ## `[amvideo]` Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is diff --git a/fgohook/config.c b/fgohook/config.c index 24b5825..5442b32 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -116,6 +116,7 @@ void fgo_hook_config_load( aime_config_load(&cfg->aime, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); printer_config_load(&cfg->printer, filename); fgo_deck_config_load(&cfg->deck, filename); diff --git a/fgohook/config.h b/fgohook/config.h index 59b48ee..ffffc25 100644 --- a/fgohook/config.h +++ b/fgohook/config.h @@ -20,6 +20,7 @@ struct fgo_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct vfd_config vfd; struct touch_screen_config touch; struct printer_config printer; struct deck_config deck; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 2e8619e..43ac26e 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -67,7 +67,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = vfd_hook_init(1); + hr = vfd_hook_init(&fgo_hook_cfg.vfd, 1); if (FAILED(hr)) { goto fail; diff --git a/mai2hook/config.c b/mai2hook/config.c index 87615e9..86b9764 100644 --- a/mai2hook/config.c +++ b/mai2hook/config.c @@ -37,5 +37,6 @@ void mai2_hook_config_load( aime_config_load(&cfg->aime, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + vfd_config_load(&cfg->vfd, filename); mai2_dll_config_load(&cfg->dll, filename); } diff --git a/mai2hook/config.h b/mai2hook/config.h index 3b7fc22..2def3a7 100644 --- a/mai2hook/config.h +++ b/mai2hook/config.h @@ -15,6 +15,7 @@ struct mai2_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct vfd_config vfd; struct mai2_dll_config dll; }; diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 220e213..5d53368 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -57,7 +57,7 @@ static DWORD CALLBACK mai2_pre_startup(void) goto fail; } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&mai2_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/mercuryhook/config.c b/mercuryhook/config.c index f087942..4038129 100644 --- a/mercuryhook/config.c +++ b/mercuryhook/config.c @@ -68,6 +68,7 @@ void mercury_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); gfx_config_load(&cfg->gfx, filename); + vfd_config_load(&cfg->vfd, filename); mercury_dll_config_load(&cfg->dll, filename); touch_config_load(&cfg->touch, filename); elisabeth_config_load(&cfg->elisabeth, filename); diff --git a/mercuryhook/config.h b/mercuryhook/config.h index d5bf463..2105704 100644 --- a/mercuryhook/config.h +++ b/mercuryhook/config.h @@ -19,6 +19,7 @@ struct mercury_hook_config { struct dvd_config dvd; struct io4_config io4; struct gfx_config gfx; + struct vfd_config vfd; struct mercury_dll_config dll; struct touch_config touch; struct elisabeth_config elisabeth; diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index bcec31f..06b62ad 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -64,7 +64,7 @@ static DWORD CALLBACK mercury_pre_startup(void) goto fail; } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&mercury_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/mu3hook/config.c b/mu3hook/config.c index 6e3991d..bb51103 100644 --- a/mu3hook/config.c +++ b/mu3hook/config.c @@ -40,5 +40,6 @@ void mu3_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); gfx_config_load(&cfg->gfx, filename); + vfd_config_load(&cfg->vfd, filename); mu3_dll_config_load(&cfg->dll, filename); } diff --git a/mu3hook/config.h b/mu3hook/config.h index 623397c..f1b2cdf 100644 --- a/mu3hook/config.h +++ b/mu3hook/config.h @@ -20,6 +20,7 @@ struct mu3_hook_config { struct io4_config io4; struct gfx_config gfx; // struct led15093_config led15093; + struct vfd_config vfd; struct mu3_dll_config dll; }; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index c27fd4d..3f940dd 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -76,7 +76,7 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&mu3_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/swdchook/config.c b/swdchook/config.c index ba4d34a..4513fd8 100644 --- a/swdchook/config.c +++ b/swdchook/config.c @@ -42,6 +42,7 @@ void swdc_hook_config_load( zinput_config_load(&cfg->zinput, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + vfd_config_load(&cfg->vfd, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/swdchook/config.h b/swdchook/config.h index 5237b9f..587ab66 100644 --- a/swdchook/config.h +++ b/swdchook/config.h @@ -17,6 +17,7 @@ struct swdc_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct vfd_config vfd; struct swdc_dll_config dll; struct zinput_config zinput; }; diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index e5a47d2..9806123 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -64,7 +64,7 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } - hr = vfd_hook_init(4); + hr = vfd_hook_init(&swdc_hook_cfg.vfd, 4); if (FAILED(hr)) { return hr; From 3e9303e04385b196bcae566edc1cb71288ad6fbf Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 6 Feb 2024 12:34:39 +0100 Subject: [PATCH 084/204] fgo: ups forgot to add it to Package.mk --- Package.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.mk b/Package.mk index 55ae693..0b60a36 100644 --- a/Package.mk +++ b/Package.mk @@ -225,6 +225,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/mu3.zip \ $(BUILD_DIR_ZIP)/mai2.zip \ $(BUILD_DIR_ZIP)/cm.zip \ + $(BUILD_DIR_ZIP)/fgo.zip \ CHANGELOG.md \ README.md \ From 56e971c6a43dffd8c482b80d248c8895202b3c38 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 6 Feb 2024 13:01:26 +0100 Subject: [PATCH 085/204] changed default operator buttons to F1, F2 and F3 and fixed subnets --- carolio/config.c | 6 +++--- chuniio/config.c | 6 +++--- cmio/config.c | 6 +++--- dist/carol/segatools.ini | 24 ++++++++++++++++++------ dist/chuni/segatools.ini | 16 ++++++++++------ dist/chusan/segatools.ini | 12 ++++++------ dist/cm/segatools.ini | 13 +++++++------ dist/cxb/segatools.ini | 14 +++++++------- dist/diva/segatools.ini | 28 +++++++++++++++++++++++++++- dist/fgo/segatools.ini | 2 +- dist/idac/segatools.ini | 12 ++++++------ dist/idz/segatools.ini | 13 ++++++------- dist/mai2/segatools.ini | 14 +++++++------- dist/mercury/segatools.ini | 12 ++++++------ dist/mu3/segatools.ini | 27 +++++++++++++-------------- dist/swdc/segatools.ini | 18 +++++++++++------- divaio/config.c | 6 +++--- fgoio/config.c | 6 +++--- idacio/config.c | 6 +++--- idzio/config.c | 7 ++++--- mai2io/config.c | 6 +++--- mercuryio/config.c | 10 +++++----- mu3io/config.c | 6 +++--- swdcio/config.c | 6 +++--- 24 files changed, 161 insertions(+), 115 deletions(-) diff --git a/carolio/config.c b/carolio/config.c index 151e909..fba56ad 100644 --- a/carolio/config.c +++ b/carolio/config.c @@ -14,7 +14,7 @@ void carol_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename); } diff --git a/chuniio/config.c b/chuniio/config.c index 0ce06a2..c41ae99 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -34,9 +34,9 @@ void chuni_io_config_load( assert(filename != NULL); // Technically it's io4 but leave this for compatibility with old configs. - cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename); cfg->vk_ir_emu = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename); for (i = 0 ; i < 6 ; i++) { diff --git a/cmio/config.c b/cmio/config.c index 4c37f96..452f3b3 100644 --- a/cmio/config.c +++ b/cmio/config.c @@ -16,7 +16,7 @@ void cm_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); } diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index d43cfe0..a73747f 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -39,10 +39,22 @@ monitor=0 ; Leave empty if you want to use Segatools built-in keyboard input. path= +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + [io3] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 \ No newline at end of file diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 57524f8..69bc339 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -18,6 +18,10 @@ default=127.0.0.1 ; Chunithm is extremely picky about its LAN environment, so leaving this ; setting enabled is strongly recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. @@ -97,12 +101,12 @@ controllerLedOutputSerial=0 ; world. An improved solution will be provided later. [io3] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Set to 0 for enable separate ir control. Deafult is space key. ir=0x20 diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index f6959d3..72e3fd4 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -137,12 +137,12 @@ controllerLedOutputSerial=0 ; world. An improved solution will be provided later. [io3] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Set to 0 for enable separate ir control. Deafult is space key. ir=0x20 diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 9ca7041..0eb44bf 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -48,6 +48,7 @@ dipsw1=0 ; Enable/Disable WinTouch emulation enable=0 + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -61,9 +62,9 @@ enable=0 ; world. An improved solution will be provided later. [io4] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index e0491ff..6caf61d 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -24,7 +24,7 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.100.0 +subnet=192.168.150.0 billingCa=../DEVICE/ca.crt billingPub=../DEVICE/billing.pub billingType=2 @@ -61,12 +61,12 @@ enable=1 [revio] ; Enable emulation of the rev IO board enabe=1 -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Menu up key. Default is up arrow. up=0x26 ; Menu down key. Default is down arrow. diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index e2608c0..5735503 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -8,6 +8,12 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -26,7 +32,27 @@ dipsw1=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.150.0 +subnet=192.168.78.0 + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io3] +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 [slider] cell1=0x51 diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 4d83225..3404d65 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -38,7 +38,7 @@ addrSuffix=11 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.172.0 +subnet=192.168.167.0 [touch] ; WinTouch emulation setting. diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index bf9bafc..4143aa7 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -82,12 +82,12 @@ path= ; world. An improved solution will be provided later. [io4] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index e7b0701..68cdae0 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -34,7 +34,6 @@ region=4 ; SEGA games are somewhat picky about their LAN environment, so leaving this ; setting enabled is recommended. enable=1 - ; The final octet of the local host's IP address on the virtualized subnet ; (so, if the keychip subnet is 192.168.32.0 and this value is set to 11, ; then the local host's virtualized LAN IP is 192.168.32.11). @@ -88,12 +87,12 @@ path= ; world. An improved solution will be provided later. [io3] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Input API selection for JVS input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index d8ad3d2..9cd0baa 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -34,7 +34,7 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.100.0 +subnet=192.168.172.0 [gpio] ; ALLS DIP switches. @@ -62,12 +62,12 @@ dipsw1=1 ; world. An improved solution will be provided later. [io4] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Key bindings for buttons around screen. The default key map, depicted ; in clockwise order, is as follows: diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 5a7cfa3..2586c9c 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -64,12 +64,12 @@ dipsw1=1 ; world. An improved solution will be provided later. [io4] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Volume up virtual-key code. Default is the "UP" key. volup=0x26 diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index a6e68fa..5464257 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -69,28 +69,27 @@ enable=1 ; world. An improved solution will be provided later. [io4] -; Input API selection for JVS input emulator. -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Set "1" to enable mouse lever emulation, "0" to use XInput mouse=1 ; Keyboard input bindings left1=0x41 ; A -left2=0x53 ; S -left3=0x44 ; D +left2=0x53 ; S +left3=0x44 ; D -leftSide=0x01 ; Mouse Left -rightSide=0x02 ; Mouse Right +leftSide=0x01 ; Mouse Left +rightSide=0x02 ; Mouse Right right1=0x4A ; J right1=0x4B ; K -right3=0x4C ; L +right3=0x4C ; L -leftMenu=0x55 ; U -rightMenu=0x4F ; O +leftMenu=0x55 ; U +rightMenu=0x4F ; O diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 7b64550..ef182cc 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -29,12 +29,16 @@ default=127.0.0.1 ; SEGA games are somewhat picky about their LAN environment, so leaving this ; setting enabled is recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; You must set this to your LAN's IP subnet, and that subnet must start with 192.168, ; in order to find the MAIN cabinet. -subnet=192.168.100.0 +subnet=192.168.160.0 [aimeio] ; To use a custom card reader IO DLL enter its path here. @@ -68,12 +72,12 @@ freeplay=0 ; world. An improved solution will be provided later. [io4] -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; Input API selection for IO4 input emulator. ; Set "xinput" to use a gamepad and "dinput" to use a steering wheel. diff --git a/divaio/config.c b/divaio/config.c index 886277e..110392e 100644 --- a/divaio/config.c +++ b/divaio/config.c @@ -27,9 +27,9 @@ void diva_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename); for (i = 0 ; i < _countof(cfg->vk_buttons) ; i++) { swprintf_s(key, _countof(key), L"key%i", i + 1); diff --git a/fgoio/config.c b/fgoio/config.c index 7f1f5e4..6270391 100644 --- a/fgoio/config.c +++ b/fgoio/config.c @@ -14,7 +14,7 @@ void fgo_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); } diff --git a/idacio/config.c b/idacio/config.c index 2daeb8f..6bf6996 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -124,9 +124,9 @@ void idac_io_config_load(struct idac_io_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 128, filename); GetPrivateProfileStringW( diff --git a/idzio/config.c b/idzio/config.c index 2a6e083..aec8261 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -121,9 +121,10 @@ void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + /* Technically it's io4 */ + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename); cfg->restrict_ = GetPrivateProfileIntW(L"io3", L"restrict", 97, filename); GetPrivateProfileStringW( diff --git a/mai2io/config.c b/mai2io/config.c index 75e842a..619b0ef 100644 --- a/mai2io/config.c +++ b/mai2io/config.c @@ -24,9 +24,9 @@ void mai2_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); for (i = 0 ; i < 9 ; i++) { swprintf_s(key, _countof(key), L"1p_btn%i", i + 1); diff --git a/mercuryio/config.c b/mercuryio/config.c index f3c8e54..853ed29 100644 --- a/mercuryio/config.c +++ b/mercuryio/config.c @@ -27,11 +27,11 @@ void mercury_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", 0x2D, filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", 0x2E, filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", 0x24, filename); - cfg->vk_vol_up = GetPrivateProfileIntW(L"io4", L"volup", 0x26, filename); - cfg->vk_vol_down = GetPrivateProfileIntW(L"io4", L"voldown", 0x28, filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); + cfg->vk_vol_up = GetPrivateProfileIntW(L"io4", L"volup", VK_UP, filename); + cfg->vk_vol_down = GetPrivateProfileIntW(L"io4", L"voldown", VK_DOWN, filename); for (i = 0 ; i < 240 ; i++) { swprintf_s(key, _countof(key), L"cell%i", i + 1); diff --git a/mu3io/config.c b/mu3io/config.c index b47a4dc..612c860 100644 --- a/mu3io/config.c +++ b/mu3io/config.c @@ -14,9 +14,9 @@ void mu3_io_config_load( assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); cfg->use_mouse = GetPrivateProfileIntW(L"io4", L"mouse", 0, filename); diff --git a/swdcio/config.c b/swdcio/config.c index 4208c76..131b403 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -112,9 +112,9 @@ void swdc_io_config_load(struct swdc_io_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); - cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); - cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); cfg->restrict_ = GetPrivateProfileIntW(L"io4", L"restrict", 128, filename); GetPrivateProfileStringW( From e40e1dffe3e41e928862f16e32e89d8f23ea63d8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 21 Feb 2024 21:58:44 +0100 Subject: [PATCH 086/204] improved all `segatools.ini` configs --- dist/carol/segatools.ini | 47 +++++++++++++++++-- dist/chuni/segatools.ini | 34 ++++++++++++++ dist/chusan/segatools.ini | 36 +++++++++++++-- dist/cm/segatools.ini | 28 ++++++++++++ dist/cxb/segatools.ini | 86 +++++++++++++++++++++++++++-------- dist/diva/segatools.ini | 34 ++++++++++++++ dist/fgo/segatools.ini | 93 ++++++++++++++++++++++++++++++++------ dist/idac/segatools.ini | 40 +++++++++++++++- dist/idz/segatools.ini | 66 +++++++++++++++++++++------ dist/mai2/segatools.ini | 36 ++++++++++++++- dist/mercury/segatools.ini | 71 +++++++++++++++++++++-------- dist/mu3/segatools.ini | 52 +++++++++++++++++++-- dist/swdc/segatools.ini | 56 +++++++++++++++++++---- fgoio/fgoio.c | 4 +- segatools.md | 2 +- 15 files changed, 594 insertions(+), 91 deletions(-) diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index a73747f..e79cf13 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -1,23 +1,56 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains Axxx directories) +; Insert the path to the game Option directory here (contains MOV1, PAR0, +; PAR1, RES0 and RES1 directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 [netenv] -; Simulate an ideal LAN environment. +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; Chunithm is extremely picky about its LAN environment, so leaving this +; setting enabled is strongly recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- [gpio] +; Emulated Nu DIP switch for Distribution Server setting. +; +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. dipsw1=1 [keychip] @@ -26,6 +59,10 @@ dipsw1=1 ; that subnet must start with 192.168. subnet=192.168.126.0 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + [gfx] ; Force the game to run windowed. windowed=1 @@ -34,6 +71,10 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. @@ -57,4 +98,4 @@ test=0x70 ; Service button virtual-key code. Default is the F2 key. service=0x71 ; Keyboard button to increment coin counter. Default is the F3 key. -coin=0x72 \ No newline at end of file +coin=0x72 diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 69bc339..5497643 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,20 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -23,12 +41,20 @@ enable=1 ; local host's virtualized LAN IP is `192.168.32.11`). addrSuffix=11 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. subnet=192.168.139.0 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + [gfx] ; Force the game to run windowed. windowed=1 @@ -37,6 +63,10 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. @@ -47,6 +77,10 @@ path= ; Leave empty if you want to use Segatools built-in keyboard input. path= +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + [led15093] ; Enable emulation of the 15093-06 controlled lights, which handle the air tower ; RGBs and the rear LED panel (billboard) on the cabinet. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 72e3fd4..a5e3d51 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -21,10 +29,9 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -[aimeio] -; Uncomment this if you have custom (x64) aime implementation. -; Leave empty if you want to use Segatools built-in keyboard input. -;path= +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- [dns] ; Insert the hostname or IP address of the server you wish to use here. @@ -41,6 +48,10 @@ enable=1 ; local host's virtualized LAN IP is `192.168.32.11`). addrSuffix=11 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and @@ -65,6 +76,10 @@ dipsw2=1 ; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well. dipsw3=1 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + [gfx] ; Force the game to run windowed. windowed=1 @@ -73,6 +88,15 @@ framed=0 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL (x64) enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + [chuniio] ; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL. ; (will use chu2to3 engine internally) @@ -83,6 +107,10 @@ monitor=0 ;path32= ;path64= +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + [led15093] ; Enable emulation of the 15093-06 controlled lights, which handle the air tower ; RGBs and the rear LED panel (billboard) on the cabinet. diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 0eb44bf..37f5708 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -19,6 +27,10 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -30,6 +42,10 @@ default=127.0.0.1 ; setting enabled is recommended. enable=1 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and @@ -44,10 +60,22 @@ enable=1 ; this to 0 on exactly one machine and set this to 1 on all others. dipsw1=0 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + [touch] ; Enable/Disable WinTouch emulation enable=0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= ; ----------------------------------------------------------------------------- ; Input settings diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 6caf61d..984f609 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Make sure theses are full paths and not relative or you will have a bad time ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) @@ -9,6 +13,27 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + +[aime] +; Aime reader emulation +; CXB is stupid, so we have to make the paths go back one +enable=1 +aimePath=../DEVICE/aime.txt +felicaPath=../DEVICE/felica.txt + +[led] +; Emulation for the LED board. Currently it's just dummy responses, +; but if somebody wants to make their keyboard or whatever light +; up with the game they can +enable=1 + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -20,6 +45,10 @@ default=127.0.0.1 ; setting enabled is strongly recommended. enable=1 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and @@ -29,21 +58,6 @@ billingCa=../DEVICE/ca.crt billingPub=../DEVICE/billing.pub billingType=2 -[gfx] -; Force the game to run windowed. -windowed=1 -; Add a frame to the game window if running windowed. -framed=1 -; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) -monitor=0 - -[aime] -; Aime reader emulation -; CXB is stupid, so we have to make the paths go back one -enable=1 -aimePath=../DEVICE/aime.txt -felicaPath=../DEVICE/felica.txt - [eeprom] ; See above path=../DEVICE/eeprom.bin @@ -52,11 +66,43 @@ path=../DEVICE/eeprom.bin ; See above path=../DEVICE/sram.bin -[led] -; Emulation for the LED board. Currently it's just dummy responses, -; but if somebody wants to make their keyboard or whatever light -; up with the game they can -enable=1 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[gfx] +; Force the game to run windowed. +windowed=1 +; Add a frame to the game window if running windowed. +framed=1 +; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) +monitor=0 + +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[cxbio] +; To use a custom crossbeats REV. DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. [revio] ; Enable emulation of the rev IO board diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index 5735503..000f5c8 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,12 +12,20 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. enable=1 aimePath=DEVICE\aime.txt +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -25,7 +37,15 @@ default=127.0.0.1 ; setting enabled is strongly recommended. enable=1 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [gpio] +; Emulated Nu DIP switch for Distribution Server setting. +; +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. dipsw1=1 [keychip] @@ -34,6 +54,20 @@ dipsw1=1 ; that subnet must start with 192.168. subnet=192.168.78.0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[divaio] +; To use a custom Project DIVA Arcade IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in gamepad/wheel input. +path= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 3404d65..7ffbd80 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -19,6 +27,26 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +[deckReader] +; 837-15345 RFID deck reader emulation setting. +enable=1 + +[ftdi] +; FTDI serial to usb adapter emulation for CABINET LED. +enable=1 +; COM port number where the LED board is connected to. +portNo=17 + +[led15093] +; 837-15093-06 LED board emulation setting. +enable=1 +; COM port number for the LED board. Has to be the same as the FTDI port. +portNo=17 + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -34,12 +62,29 @@ enable=1 ; local host's virtualized LAN IP is `192.168.32.11`). addrSuffix=11 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. subnet=192.168.167.0 +[gpio] +; ALLS DIP switches. +enable=1 + +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + [touch] ; WinTouch emulation setting. enable=1 @@ -56,21 +101,19 @@ printerOutPath="DEVICE\print" ; Rotate all printed images by 180 degrees. rotate180=1 -[deckReader] -; 837-15345 RFID deck reader emulation setting. -enable=1 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- -[ftdi] -; FTDI serial to usb adapter emulation for CABINET LED. -enable=1 -; COM port number where the LED board is connected to. -portNo=17 +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= -[led15093] -; 837-15093-06 LED board emulation setting. -enable=1 -; COM port number for the LED board. Has to be the same as the FTDI port. -portNo=17 +[fgoio] +; To use a custom Fate/Grand Order Arcade IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in gamepad input. +path= ; ----------------------------------------------------------------------------- ; Input settings @@ -92,3 +135,27 @@ test=0x31 service=0x32 ; Keyboard button to increment coin counter. Default is the 3 key. coin=0x33 + +; .·:'''''''''''''''''''''''''''''''''''''''''''''':·. +; : : ______ / \ [] : : +; : : | | _____ \ / Coin : : +; : : |______| { (0) } /--\ Attack. : : +; : : DECK \ / / \ : : +; : : | | > < : : +; : : | | \ / ___ : : +; : : | | \--/ | | : : +; : : JOY Noble. | | : : +; : : |___| : : +; : : AIME. : : +; '·:..............................................:·' +; +; Only XInput is currently supported. + +; Controller Button +; ------------------------------------------------------- +; Left Stick Joystick +; Left Stick Click Reset Camera +; Left Trigger Dash +; Left Shoulder Switch Target +; A/B Attack +; X/Y Noble Phantasm diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 4143aa7..8ed90a2 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -1,18 +1,30 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains OPxx directories) +; Insert the path to the game Option directory here (contains MVxx directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Controls emulation of the Aime card reader assembly. enable=1 aimePath=DEVICE\aime.txt +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -24,6 +36,10 @@ default=127.0.0.1 ; setting enabled is recommended. enable=1 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and @@ -59,13 +75,17 @@ dipsw3=0 dipsw4=0 dipsw5=0 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. path= [idacio] -; To use a custom Initial D The Arcade IO DLL enter its path here. +; To use a custom Initial D THE ARCADE IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= @@ -106,6 +126,22 @@ mode=xinput restrict=128 [xinput] +; XInput bindings +; +; Left Stick Steering +; Right Stick (Steering) when "singleStickSteering" is disabled +; Left Trigger Brake +; Right Trigger Accelerator +; Left Stick Click Left (used for Time Up) +; Right Stick Click Right (used for Time Up) +; Left Shoulder Shift Down +; Right Shoulder Shift Up +; Start/A Start +; Back/B View Change +; X Shift Up +; Y Shift Down +; D-Pad D-Pad + ; Left and right thumbsticks are mapped to left and right dpad buttons. ; Press both thumbsticks to trigger "Time Up" and exit the course. ; Automatically reset the simulated shifter to Neutral when XInput Start is diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 68cdae0..c37bab6 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Controls emulation of the Aime card reader assembly. enable=1 @@ -16,19 +24,15 @@ aimePath=DEVICE\aime.txt felicaGen=0 aimeGen=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 -[ds] -; Region code on the emulated AMEX board DS EEPROM. -; 1: Japan -; 4: Export (some UI elements in English) -; -; NOTE: Changing this setting causes a factory reset. -region=4 - [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. ; SEGA games are somewhat picky about their LAN environment, so leaving this @@ -40,12 +44,35 @@ enable=1 ; Needed for in store battle, one needs to set it to 12. ;addrSuffix=12 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. subnet=192.168.158.0 +[ds] +; Region code on the emulated AMEX board DS EEPROM. +; 1: Japan +; 4: Export (some UI elements in English) +; +; NOTE: Changing this setting causes a factory reset. +region=4 + +[gpio] +; Emulated Nu DIP switch for Distribution Server setting. +; +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. +dipsw1=1 + +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + [gfx] ; Enables the graphics hook. This is required for some Initial D Zero versions ; for example v1.31 and v2.11 to run properly in fullscreen. @@ -57,12 +84,9 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0=primary screen) monitor=0 -[gpio] -; Emulated Nu DIP switch for Distribution Server setting. -; -; If multiple machines are present on the same LAN then set this to 1 on -; exactly one machine and set this to 0 on all others. -dipsw1=1 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- [aimeio] ; To use a custom card reader IO DLL enter its path here. @@ -111,6 +135,20 @@ mode=xinput restrict=97 [xinput] +; XInput bindings +; +; Left Stick Steering +; Right Stick (Steering) when "singleStickSteering" is disabled +; Left Trigger Brake +; Right Trigger Accelerator +; Left Shoulder Shift Down +; Right Shoulder Shift Up +; Start/A Start +; Back/B View Change +; X Shift Up +; Y Shift Down +; D-Pad D-Pad + ; Automatically reset the simulated shifter to Neutral when XInput Start is ; pressed (e.g. when navigating menus between races). autoNeutral=1 diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 9cd0baa..3aa8758 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -1,13 +1,21 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains Axxx, Bxxx directories) +; Insert the path to the game Option directory here (contains Axxx directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -19,6 +27,10 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -29,6 +41,14 @@ default=127.0.0.1 ; SEGA games are somewhat picky about its LAN environment, so leaving this ; setting enabled is recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. @@ -49,6 +69,20 @@ freeplay=0 ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[mai2io] +; To use a custom maimai DX IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 2586c9c..a31abd7 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -1,11 +1,20 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) -amfs=amfs +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. -appdata=appdata -option=option +appdata= + +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime @@ -18,6 +27,10 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -28,6 +41,14 @@ default=127.0.0.1 ; SEGA games are somewhat picky about their LAN environment, so leaving this ; setting enabled is recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. @@ -35,9 +56,6 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.174.0 -[gfx] -enable=1 - [gpio] ; ALLS DIP switches. enable=1 @@ -51,6 +69,35 @@ freeplay=0 ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + +[gfx] +enable=1 + +; Hooks related to the touch boards +[touch] +enable=1 + +; Hooks related to the LED board (codenamed Elisabeth) +[elisabeth] +enable=1 + +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[mercuryio] +; To use a custom WACCA IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -75,15 +122,3 @@ coin=0x72 volup=0x26 ; Volume down virtual-key code. Default is the "DOWN" key. voldown=0x28 - -; Hooks related to the touch boards -[touch] -enable=1 - -; Hooks related to the LED board (codenamed Elisabeth) -[elisabeth] -enable=1 - -;[mercuryio] -; Use mercuryio.dll -;path=mercuryio.dll diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 5464257..6cdad24 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -1,3 +1,7 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= @@ -8,6 +12,10 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -19,6 +27,10 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -30,6 +42,10 @@ default=127.0.0.1 ; setting enabled is recommended. enable=1 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and @@ -49,12 +65,26 @@ freeplay=0 ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + [gfx] enable=1 -[led15093] -; 837-15093-06 LED board emulation setting. -enable=1 +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[fgoio] +; To use a custom O.N.G.E.K.I. IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +path= ; ----------------------------------------------------------------------------- ; Input settings @@ -79,6 +109,22 @@ coin=0x72 ; Set "1" to enable mouse lever emulation, "0" to use XInput mouse=1 +; XInput input bindings +; +; Left Stick Lever +; Left Trigger Lever (move to the left) +; Right Trigger Lever (move to the right) +; Left Left red button +; Up Left green button +; Right Left blue button +; Left Shoulder Left side button +; Right Shoulder Right side button +; X Right red button +; Y Right green button +; A Right blue button +; Back Left menu button +; Start Right menu button + ; Keyboard input bindings left1=0x41 ; A left2=0x53 ; S diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index ef182cc..47e2bcb 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -1,13 +1,21 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains OPxx directories) +; Insert the path to the game Option directory here (contains Axxx directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. ; NOTE: This has nothing to do with Windows %APPDATA%. appdata=appdata +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + [aime] ; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime ; reader. @@ -19,6 +27,10 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -34,12 +46,29 @@ enable=1 ; local host's virtualized LAN IP is `192.168.32.11`). addrSuffix=11 +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; You must set this to your LAN's IP subnet, and that subnet must start with 192.168, ; in order to find the MAIN cabinet. subnet=192.168.160.0 +[gpio] +; ALLS DIP switches. +enable=1 + +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0´ + +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. @@ -50,15 +79,6 @@ path= ; Leave empty if you want to use Segatools built-in gamepad/wheel input. path= -[gpio] -; ALLS DIP switches. -enable=1 - -; Enable freeplay mode. This will disable the coin slot and set the game to -; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not -; allow you to start a game in freeplay mode. -freeplay=0 - ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -96,6 +116,22 @@ mode=xinput restrict=128 [xinput] +; XInput bindings +; +; Left Stick Steering +; Right Stick (Steering) when "singleStickSteering" is disabled +; Left Trigger Brake +; Right Trigger Accelerator +; Left Shoulder Left Paddle +; Right Shoulder Right Paddle +; Start Start +; Back View Change +; A Green (Wheel) +; B Red (Wheel) +; X Blue (Wheel) +; Y Yellow (Wheel) +; D-Pad D-Pad + ; Use the left thumbstick for steering instead of both on XInput Controllers. ; Not recommended as it will not give you the precision needed for this game. singleStickSteering=1 diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index d9aeed1..ff3e953 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -67,11 +67,11 @@ HRESULT fgo_io_poll(void) fgo_gamebtn |= FGO_IO_GAMEBTN_TARGET; } - if (xb & XINPUT_GAMEPAD_A) { + if (xb & XINPUT_GAMEPAD_A || xb & XINPUT_GAMEPAD_B) { fgo_gamebtn |= FGO_IO_GAMEBTN_ATTACK; } - if (xb & XINPUT_GAMEPAD_Y) { + if (xb & XINPUT_GAMEPAD_Y || xb & XINPUT_GAMEPAD_X) { fgo_gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASHM; } diff --git a/segatools.md b/segatools.md index 4dcaf43..51b97e0 100644 --- a/segatools.md +++ b/segatools.md @@ -283,7 +283,7 @@ Enable keychip emulation. Disable to use a real keychip. Default: `A69E-01A88888888` Keychip serial number. Keychip serials observed in the wild follow this -pattern: `A6xE-01Ayyyyyyyy`. +pattern: `A\d{2}(E01|X20)[ABCDU]\d{8}`. ### `gameId` From ae199502e89110ed34f116699470b9bda55ad3a4 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 22 Feb 2024 12:02:32 +0100 Subject: [PATCH 087/204] fixed amfs/appdata redirects --- aimeio/aimeio.c | 2 +- platform/vfs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index fa0db03..93f3ebf 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -68,7 +68,7 @@ static void aime_io_config_read( cfg->felica_path, _countof(cfg->felica_path), filename); - dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError()); + // dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError()); cfg->felica_gen = GetPrivateProfileIntW( L"aime", diff --git a/platform/vfs.c b/platform/vfs.c index e19b046..60e4d4f 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -466,10 +466,10 @@ static HRESULT vfs_path_hook_option( static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) { - return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); // seems to be busted? + return reg_hook_read_wstr(bytes, nbytes, L"E:\\"); } static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) { - return reg_hook_read_wstr(bytes, nbytes, vfs_config.appdata); + return reg_hook_read_wstr(bytes, nbytes, L"Y:\\"); } From ca36a879cb3c7f720d1067b726ecdb4425d23b62 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 22 Feb 2024 12:12:29 +0100 Subject: [PATCH 088/204] updated README and added "AM Daemon" window name --- README.md | 28 +++++++++++++--------------- dist/chusan/start.bat | 3 ++- dist/cm/start.bat | 2 +- dist/fgo/segatools.ini | 16 ++++++++-------- dist/idac/start.bat | 2 +- dist/mai2/start.bat | 2 +- dist/mercury/start.bat | 4 ++-- dist/mu3/start.bat | 2 +- dist/swdc/segatools.ini | 2 +- 9 files changed, 30 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d24c497..50a2e73 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,31 @@ # Segatools -Version: `2023-11-22` +Version: `2024-02-22` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. ## List of supported games -* Chunithm - * [Chunithm (Plus)](doc/chunihook.md) - * [Chunithm Air (Plus)](doc/chunihook.md) - * [Chunithm Star (Plus)](doc/chunihook.md) - * [Chunithm Amazon (Plus)](doc/chunihook.md) - * [Chunithm Crystal (Plus)](doc/chunihook.md) - * Chunithm SUN +* CHUNITHM + * up to [CHUNITHM PARADISE LOST](doc/chunihook.md) + * starting from CHUNITHM NEW!! * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) * Initial D THE ARCADE +* Hatsune Miku: Project DIVA Arcade + * up to Future Tone * SEGA World Drivers Championship - * up to SEGA World Drivers Championship 2019 + * SEGA World Drivers Championship 2019 * Fate/Grand Order * Fate/Grand Order Arcade -* ONGEKI - * up to bright MEMORY +* O.N.G.E.K.I. + * starting from O.N.G.E.K.I. * maimai DX - * up to maimai DX FESTiVAL PLUS + * starting from maimai DX * Card Maker - * up to Card Maker 1.35 -* Wacca - * up to WACCA Reverse + * starting from Card Maker +* WACCA + * starting from WACCA ## End-users diff --git a/dist/chusan/start.bat b/dist/chusan/start.bat index 78de368..bf3f195 100644 --- a/dist/chusan/start.bat +++ b/dist/chusan/start.bat @@ -2,8 +2,9 @@ pushd %~dp0 -start /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json +start "AM Daemon" /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json inject_x86 -d -k chusanhook_x86.dll chusanApp.exe + taskkill /f /im amdaemon.exe > nul 2>&1 echo. diff --git a/dist/cm/start.bat b/dist/cm/start.bat index b17a6a1..570fb9c 100644 --- a/dist/cm/start.bat +++ b/dist/cm/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json +start "AM Daemon" /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 7ffbd80..2afe1fe 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -129,12 +129,12 @@ path= [io4] ; Input API selection for JVS input emulator. -; Test button virtual-key code. Default is the 1 key. -test=0x31 -; Service button virtual-key code. Default is the 2 key. -service=0x32 -; Keyboard button to increment coin counter. Default is the 3 key. -coin=0x33 +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 ; .·:'''''''''''''''''''''''''''''''''''''''''''''':·. ; : : ______ / \ [] : : @@ -151,8 +151,8 @@ coin=0x33 ; ; Only XInput is currently supported. -; Controller Button -; ------------------------------------------------------- +; XInput bindings +; ; Left Stick Joystick ; Left Stick Click Reset Camera ; Left Trigger Dash diff --git a/dist/idac/start.bat b/dist/idac/start.bat index fb40211..ac77096 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -39,7 +39,7 @@ config_seat_single_ex.json ^ config_seat_single_jp.json ^ config_hook.json -start /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG% +start "AM Daemon" /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG% inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mai2/start.bat b/dist/mai2/start.bat index a89a1d5..88cc551 100644 --- a/dist/mai2/start.bat +++ b/dist/mai2/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mercury/start.bat b/dist/mercury/start.bat index c00f2ea..a9a3f22 100644 --- a/dist/mercury/start.bat +++ b/dist/mercury/start.bat @@ -4,10 +4,10 @@ pushd %~dp0 taskkill /f /im amdaemon.exe > nul 2>&1 REM USA -REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json +start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json REM JP -start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json +start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/mu3/start.bat b/dist/mu3/start.bat index 8058daf..743a3df 100644 --- a/dist/mu3/start.bat +++ b/dist/mu3/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json +start "AM Daemon" /min inject -d -k mu3hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json inject -d -k mu3hook.dll mu3 -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 taskkill /f /im amdaemon.exe > nul 2>&1 diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 47e2bcb..71de4e3 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -63,7 +63,7 @@ enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to ; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not ; allow you to start a game in freeplay mode. -freeplay=0´ +freeplay=0 ; ----------------------------------------------------------------------------- ; Custom IO settings From 629ded40186650cbfdebae1b799af55da0b68d81 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 25 Feb 2024 19:03:05 +0100 Subject: [PATCH 089/204] added AimePay, E-MONEY DNS redirects --- hooklib/dns.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ platform/dns.c | 20 ++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/hooklib/dns.c b/hooklib/dns.c index aac90ce..7dd6d0b 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,12 @@ static int WSAAPI hook_getaddrinfo( const char *pServiceName, const ADDRINFOA *pHints, ADDRINFOA **ppResult); + +static HINTERNET WINAPI hook_WinHttpConnect( + HINTERNET hSession, + const wchar_t *pwszServerName, + INTERNET_PORT nServerPort, + DWORD dwReserved); /* Link pointers */ @@ -95,6 +102,12 @@ static int (WSAAPI *next_getaddrinfo)( const ADDRINFOA *pHints, ADDRINFOA **ppResult); +static HINTERNET (WINAPI *next_WinHttpConnect)( + HINTERNET hSession, + const wchar_t *pwszServerName, + INTERNET_PORT nServerPort, + DWORD dwReserved); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -120,6 +133,14 @@ static const struct hook_symbol dns_hook_syms_ws2[] = { } }; +static const struct hook_symbol dns_hook_syms_winhttp[] = { + { + .name = "WinHttpConnect", + .patch = hook_WinHttpConnect, + .link = (void **) &next_WinHttpConnect, + } +}; + static bool dns_hook_initted; static CRITICAL_SECTION dns_hook_lock; static struct dns_hook_entry *dns_hook_entries; @@ -145,6 +166,12 @@ static void dns_hook_init(void) "ws2_32.dll", dns_hook_syms_ws2, _countof(dns_hook_syms_ws2)); + + hook_table_apply( + NULL, + "winhttp.dll", + dns_hook_syms_winhttp, + _countof(dns_hook_syms_winhttp)); } HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src) @@ -460,3 +487,38 @@ end: return result; } + +static HINTERNET WINAPI hook_WinHttpConnect( + HINTERNET hSession, + const wchar_t *pwszServerName, + INTERNET_PORT nServerPort, + DWORD dwReserved) +{ + const struct dns_hook_entry *pos; + size_t i; + + if (pwszServerName == NULL) { + return NULL; + } + + EnterCriticalSection(&dns_hook_lock); + + for (i = 0 ; i < dns_hook_nentries ; i++) { + pos = &dns_hook_entries[i]; + + if (_wcsicmp(pwszServerName, pos->from) == 0) { + if(pos->to == NULL) { + LeaveCriticalSection(&dns_hook_lock); + return NULL; + } + + pwszServerName = pos->to; + + break; + } + } + + LeaveCriticalSection(&dns_hook_lock); + + return next_WinHttpConnect(hSession, pwszServerName, nServerPort, dwReserved); +} diff --git a/platform/dns.c b/platform/dns.c index f8c2f60..d6d37a7 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -82,6 +82,26 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + // AimePay + hr = dns_hook_push(L"api-aime.am-all.net", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + + // E-MONEY + hr = dns_hook_push(L"tasms-api-basis.thincacloud.com", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + + hr = dns_hook_push(L"shop.tfps.thincacloud.com", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + // if your ISP resolves bad domains, it will kill the network. These 2 // *cannot* resolve From f57086994641f9d934bf58d60624fc968c481821 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 27 Feb 2024 16:49:27 +0100 Subject: [PATCH 090/204] fixed AMFS path redirect with no E:/ drive present --- README.md | 2 +- platform/vfs.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 50a2e73..a754a74 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Segatools -Version: `2024-02-22` +Version: `2024-02-27` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. diff --git a/platform/vfs.c b/platform/vfs.c index 60e4d4f..c44bbb0 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -277,11 +277,12 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) const wchar_t *redir; size_t required; size_t redir_len; + size_t src_len; assert(src != NULL); assert(count != NULL); - if (src[0] == L'\0' || src[1] != L':' || !path_is_separator_w(src[2])) { + if (src[0] == L'\0' || src[1] != L':') { return S_FALSE; } @@ -304,10 +305,15 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) return S_FALSE; } + /* GetFileAttributesW would request the src "E:", so fix the src_len in + in order to redirect the drive letter successfully */ + + src_len = path_is_separator_w(src[2]) ? 3 : 2; + /* Cut off \, replace with redir path, count NUL terminator */ redir_len = wcslen(redir); - required = wcslen(src) - 3 + redir_len + 1; + required = wcslen(src) - src_len + redir_len + 1; if (dest != NULL) { if (required > *count) { @@ -315,7 +321,7 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) } wcscpy_s(dest, *count, redir); - wcscpy_s(dest + redir_len, *count - redir_len, src + 3); + wcscpy_s(dest + redir_len, *count - redir_len, src + src_len); } *count = required; From 9c66488906f4ebbbb1beb9070734a39be123c689 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 27 Feb 2024 16:54:12 +0100 Subject: [PATCH 091/204] added Move/Replace/Delete hooks - fixes FGO not correctly switching `START UP MODE` - fixes SWDC not correctly switching `CABINET SETTING` --- hooklib/path.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) diff --git a/hooklib/path.c b/hooklib/path.c index 1d1d4d2..82f97e2 100644 --- a/hooklib/path.c +++ b/hooklib/path.c @@ -101,6 +101,40 @@ static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath); static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath); +static BOOL WINAPI hook_MoveFileA( + const char *lpExistingFileName, + const char *lpNewFileName); + +static BOOL WINAPI hook_MoveFileW( + const wchar_t *lpExistingFileName, + const wchar_t *lpNewFileName); + +static BOOL WINAPI hook_MoveFileExA( + const char *lpExistingFileName, + const char *lpNewFileName, + uint32_t dwFlags); + + +static BOOL WINAPI hook_ReplaceFileA( + const char *lpReplacedFileName, + const char *lpReplacementFileName, + const char *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved); + +static BOOL WINAPI hook_ReplaceFileW( + const wchar_t *lpReplacedFileName, + const wchar_t *lpReplacementFileName, + const wchar_t *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved); + +static BOOL WINAPI hook_DeleteFileA(const char *lpFileName); + +static BOOL WINAPI hook_DeleteFileW(const wchar_t *lpFileName); + /* Link pointers */ static BOOL (WINAPI *next_CreateDirectoryA)( @@ -185,6 +219,39 @@ static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath); static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath); +static BOOL (WINAPI *next_MoveFileA)( + const char *lpExistingFileName, + const char *lpNewFileName); + +static BOOL (WINAPI *next_MoveFileW)( + const wchar_t *lpExistingFileName, + const wchar_t *lpNewFileName); + +static BOOL (WINAPI *next_MoveFileExA)( + const char *lpExistingFileName, + const char *lpNewFileName, + uint32_t dwFlags); + +static BOOL (WINAPI *next_ReplaceFileA)( + const char *lpReplacedFileName, + const char *lpReplacementFileName, + const char *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved); + +static BOOL (WINAPI *next_ReplaceFileW)( + const wchar_t *lpReplacedFileName, + const wchar_t *lpReplacementFileName, + const wchar_t *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved); + +static BOOL (WINAPI *next_DeleteFileA)(const char *lpFileName); + +static BOOL (WINAPI *next_DeleteFileW)(const wchar_t *lpFileName); + /* Hook table */ static const struct hook_symbol path_hook_syms[] = { @@ -260,6 +327,34 @@ static const struct hook_symbol path_hook_syms[] = { .name = "PathFileExistsW", .patch = hook_PathFileExistsW, .link = (void **) &next_PathFileExistsW, + }, { + .name = "MoveFileA", + .patch = hook_MoveFileA, + .link = (void **) &next_MoveFileA, + }, { + .name = "MoveFileW", + .patch = hook_MoveFileW, + .link = (void **) &next_MoveFileW, + }, { + .name = "MoveFileExA", + .patch = hook_MoveFileExA, + .link = (void **) &next_MoveFileExA, + }, { + .name = "ReplaceFileA", + .patch = hook_ReplaceFileA, + .link = (void **) &next_ReplaceFileA, + }, { + .name = "ReplaceFileW", + .patch = hook_ReplaceFileW, + .link = (void **) &next_ReplaceFileW, + }, { + .name = "DeleteFileA", + .patch = hook_DeleteFileA, + .link = (void **) &next_DeleteFileA, + }, { + .name = "DeleteFileW", + .patch = hook_DeleteFileW, + .link = (void **) &next_DeleteFileW, } }; @@ -906,3 +1001,213 @@ static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath) return ok; } + +static BOOL WINAPI hook_MoveFileA( + const char *lpExistingFileName, + const char *lpNewFileName) +{ + char *oldTrans; + char *newTrans; + BOOL ok; + + ok = path_transform_a(&oldTrans, lpExistingFileName); + + if (!ok) { + return FALSE; + } + + ok = path_transform_a(&newTrans, lpNewFileName); + + if (!ok) { + free(oldTrans); + + return FALSE; + } + + ok = next_MoveFileA( + oldTrans ? oldTrans : lpExistingFileName, + newTrans ? newTrans : lpNewFileName); + + free(oldTrans); + free(newTrans); + + return ok; +} + +static BOOL WINAPI hook_MoveFileW( + const wchar_t *lpExistingFileName, + const wchar_t *lpNewFileName) +{ + wchar_t *oldTrans; + wchar_t *newTrans; + BOOL ok; + + ok = path_transform_w(&oldTrans, lpExistingFileName); + + if (!ok) { + return FALSE; + } + + ok = path_transform_w(&newTrans, lpNewFileName); + + if (!ok) { + free(oldTrans); + + return FALSE; + } + + ok = next_MoveFileW( + oldTrans ? oldTrans : lpExistingFileName, + newTrans ? newTrans : lpNewFileName); + + free(oldTrans); + free(newTrans); + + return ok; +} + +static BOOL WINAPI hook_MoveFileExA( + const char *lpExistingFileName, + const char *lpNewFileName, + uint32_t dwFlags) +{ + char *oldTrans; + char *newTrans; + BOOL ok; + + ok = path_transform_a(&oldTrans, lpExistingFileName); + + if (!ok) { + return FALSE; + } + + ok = path_transform_a(&newTrans, lpNewFileName); + + if (!ok) { + free(oldTrans); + + return FALSE; + } + + ok = next_MoveFileExA( + oldTrans ? oldTrans : lpExistingFileName, + newTrans ? newTrans : lpNewFileName, + dwFlags); + + free(oldTrans); + free(newTrans); + + return ok; +} + +static BOOL WINAPI hook_ReplaceFileA( + const char *lpReplacedFileName, + const char *lpReplacementFileName, + const char *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved) +{ + char *oldTrans; + char *newTrans; + BOOL ok; + + ok = path_transform_a(&oldTrans, lpReplacedFileName); + + if (!ok) { + return FALSE; + } + + ok = path_transform_a(&newTrans, lpReplacementFileName); + + if (!ok) { + free(oldTrans); + + return FALSE; + } + + ok = next_ReplaceFileA( + oldTrans ? oldTrans : lpReplacedFileName, + newTrans ? newTrans : lpReplacementFileName, + lpBackupFileName, + dwReplaceFlags, + lpExclude, + lpReserved); + + free(oldTrans); + free(newTrans); + + return ok; +} + +static BOOL WINAPI hook_ReplaceFileW( + const wchar_t *lpReplacedFileName, + const wchar_t *lpReplacementFileName, + const wchar_t *lpBackupFileName, + uint32_t dwReplaceFlags, + void *lpExclude, + void *lpReserved) +{ + wchar_t *oldTrans; + wchar_t *newTrans; + BOOL ok; + + ok = path_transform_w(&oldTrans, lpReplacedFileName); + + if (!ok) { + return FALSE; + } + + ok = path_transform_w(&newTrans, lpReplacementFileName); + + if (!ok) { + free(oldTrans); + + return FALSE; + } + + ok = next_ReplaceFileW( + oldTrans ? oldTrans : lpReplacedFileName, + newTrans ? newTrans : lpReplacementFileName, + lpBackupFileName, + dwReplaceFlags, + lpExclude, + lpReserved); + + free(oldTrans); + free(newTrans); + + return ok; +} + +static BOOL WINAPI hook_DeleteFileA(const char *lpFileName) +{ + char *trans; + BOOL ok; + + ok = path_transform_a(&trans, lpFileName); + + if (!ok) { + return FALSE; + } + + ok = next_DeleteFileA(trans ? trans: lpFileName); + + return ok; +} + +static BOOL WINAPI hook_DeleteFileW(const wchar_t *lpFileName) +{ + wchar_t *trans; + BOOL ok; + + ok = path_transform_w(&trans, lpFileName); + + if (!ok) { + return FALSE; + } + + ok = next_DeleteFileW(trans ? trans: lpFileName); + + return ok; +} From 2590e749ca5a3670180e108176aa80eaa0e7c4b6 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 7 Mar 2024 15:46:43 +0100 Subject: [PATCH 092/204] config bugfixes --- dist/mai2/start.bat | 3 ++- dist/mu3/segatools.ini | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dist/mai2/start.bat b/dist/mai2/start.bat index 88cc551..e7c6d9a 100644 --- a/dist/mai2/start.bat +++ b/dist/mai2/start.bat @@ -3,7 +3,8 @@ pushd %~dp0 start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json -inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 +inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 -popupwindow -screen-width 2160 -screen-height 1920 -silent-crashes + taskkill /f /im amdaemon.exe > nul 2>&1 echo. diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 6cdad24..ac897df 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -81,7 +81,7 @@ enable=1 ; Leave empty if you want to use Segatools built-in keyboard input. path= -[fgoio] +[mu3io] ; To use a custom O.N.G.E.K.I. IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. path= From 097b74d8493602f11a638becf93412b00cf6fbb8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 13 Mar 2024 17:51:58 +0100 Subject: [PATCH 093/204] cxb: server support added, bugfixes, thanks @Midorica --- README.md | 6 ++-- aimeio/aimeio.c | 1 - cxbhook/revio.c | 4 +-- dist/cxb/segatools.ini | 9 ++++-- doc/config/common.md | 25 +++++++++++++++- hooklib/dns.c | 67 +++++++++++++++++++++++++++++++++++++++++- idachook/idachook.def | 1 - idacio/xi.c | 4 --- platform/config.c | 8 +++++ platform/dns.c | 7 +++++ platform/dns.h | 1 + platform/nusec.c | 32 ++++++++++---------- 12 files changed, 135 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index a754a74..4e4e0e3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Segatools -Version: `2024-02-27` +Version: `2024-03-13` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. @@ -8,7 +8,9 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo * CHUNITHM * up to [CHUNITHM PARADISE LOST](doc/chunihook.md) - * starting from CHUNITHM NEW!! + * starting from CHUNITHM NEW!! +* crossbeats REV. + * up to crossbeats REV. SUNRISE * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) * Initial D THE ARCADE diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index 93f3ebf..17de30e 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -68,7 +68,6 @@ static void aime_io_config_read( cfg->felica_path, _countof(cfg->felica_path), filename); - // dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError()); cfg->felica_gen = GetPrivateProfileIntW( L"aime", diff --git a/cxbhook/revio.c b/cxbhook/revio.c index e72158d..15e2260 100644 --- a/cxbhook/revio.c +++ b/cxbhook/revio.c @@ -154,7 +154,7 @@ static int my_cCommIo_GetTrigger() out &= ~last_triggers; - dprintf("Revio: GetTrigger %X\n", out); + // dprintf("Revio: GetTrigger %X\n", out); last_triggers = out; return out; } @@ -188,7 +188,7 @@ static int my_cCommIo_GetRelease() out &= ~btns; - dprintf("Revio: GetRelease %X\n", out); + // dprintf("Revio: GetRelease %X\n", out); last_triggers = btns; return out; } diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 984f609..40f0ad6 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -19,10 +19,10 @@ appdata= [aime] ; Aime reader emulation -; CXB is stupid, so we have to make the paths go back one enable=1 +; CXB is stupid, so we have to make the paths go back two directories. This +; will load the file from "resource\DEVICE\aime.txt". aimePath=../DEVICE/aime.txt -felicaPath=../DEVICE/felica.txt [led] ; Emulation for the LED board. Currently it's just dummy responses, @@ -39,6 +39,10 @@ enable=1 ; Note that 127.0.0.1, localhost etc are specifically rejected. default=127.0.0.1 +; Set the title server hostname or IP address here, as the title server +; is hardcoded in the game. +title=https://127.0.0.1:9002 + [netenv] ; Simulate an ideal LAN environment. This may interfere with head-to-head play. ; Crossbeats is extremely picky about its LAN environment, so leaving this @@ -113,6 +117,7 @@ test=0x70 service=0x71 ; Keyboard button to increment coin counter. Default is the F3 key. coin=0x72 + ; Menu up key. Default is up arrow. up=0x26 ; Menu down key. Default is down arrow. diff --git a/doc/config/common.md b/doc/config/common.md index 23be911..59ec2e1 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -153,6 +153,13 @@ setting. Also, loopback addresses are specifically checked for and rejected by the games themselves; this needs to be a LAN or WAN IP (or a hostname that resolves to one). +### `title` + +Default: `title` + +Leave it as `title` to use the title server returned by ALL.Net. Rewrites +the title server hostname for certain games, such as crossbeats REV. + ### `router` Default: Empty string (i.e. use value from `default` setting) @@ -388,13 +395,29 @@ Bit values are: - 3: EXP: Export (for Asian markets) - 4: CHS: China (Simplified Chinese?) +### `billingCa` + +Default: `DEVICE\\ca.crt` + +Set the billing certificate path. This has to match the one used for the +SSL billing server. The DER certificate must fit in 1024 bytes so it must be +small. + +### `billingPub` + +Default: `DEVICE\\billing.pub` + +Set the actual keychip RSA public key path. This public key has to match the +private key `billing.key` of the billing server in order to decrypt/encrypt +the billing transactions. + ### `billingType` Default: `1` Set the billing "type" for the keychip. The type determins what kind of revenue share, if any, the game maker has with SEGA. Some games may be picky and require types other -then 1 (ex. Crossbeats requires billing type 2), so this option is provided if this +then 1 (ex. crossbeats REV. requires billing type 2), so this option is provided if this is an issue. Billing types are: - 0: No billing? diff --git a/hooklib/dns.c b/hooklib/dns.c index 7dd6d0b..e8b0e69 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -13,6 +13,8 @@ #include "hook/hr.h" #include "hook/table.h" +#include "util/dprintf.h" + #include "hooklib/dns.h" /* Latest w32headers does not include DnsQueryEx, so we'll have to "polyfill" @@ -66,13 +68,19 @@ static int WSAAPI hook_getaddrinfo( const char *pServiceName, const ADDRINFOA *pHints, ADDRINFOA **ppResult); - + static HINTERNET WINAPI hook_WinHttpConnect( HINTERNET hSession, const wchar_t *pwszServerName, INTERNET_PORT nServerPort, DWORD dwReserved); +static bool WINAPI hook_WinHttpCrackUrl( + const wchar_t *pwszUrl, + DWORD dwUrlLength, + DWORD dwFlags, + LPURL_COMPONENTS lpUrlComponents); + /* Link pointers */ static DNS_STATUS (WINAPI *next_DnsQuery_A)( @@ -108,6 +116,12 @@ static HINTERNET (WINAPI *next_WinHttpConnect)( INTERNET_PORT nServerPort, DWORD dwReserved); +static bool (WINAPI *next_WinHttpCrackUrl)( + const wchar_t *pwszUrl, + DWORD dwUrlLength, + DWORD dwFlags, + LPURL_COMPONENTS lpUrlComponents); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -138,13 +152,19 @@ static const struct hook_symbol dns_hook_syms_winhttp[] = { .name = "WinHttpConnect", .patch = hook_WinHttpConnect, .link = (void **) &next_WinHttpConnect, + }, { + .name = "WinHttpCrackUrl", + .patch = hook_WinHttpCrackUrl, + .link = (void **) &next_WinHttpCrackUrl, } + }; static bool dns_hook_initted; static CRITICAL_SECTION dns_hook_lock; static struct dns_hook_entry *dns_hook_entries; static size_t dns_hook_nentries; +static char received_title_url[255]; static void dns_hook_init(void) { @@ -522,3 +542,48 @@ static HINTERNET WINAPI hook_WinHttpConnect( return next_WinHttpConnect(hSession, pwszServerName, nServerPort, dwReserved); } + +// Hook to replace CXB title url +static bool WINAPI hook_WinHttpCrackUrl( + const wchar_t *pwszUrl, + DWORD dwUrlLength, + DWORD dwFlags, + LPURL_COMPONENTS lpUrlComponents) +{ + const struct dns_hook_entry *pos; + size_t i; + + EnterCriticalSection(&dns_hook_lock); + + for (i = 0 ; i < dns_hook_nentries ; i++) { + pos = &dns_hook_entries[i]; + + if (_wcsicmp(pwszUrl, pos->from) == 0) { + wchar_t* toAddr = pos->to; + wchar_t titleBuffer[255]; + + if(wcscmp(toAddr, L"title") == 0) { + size_t wstr_c; + mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url)); + toAddr = titleBuffer; + } + + bool result = next_WinHttpCrackUrl( + toAddr, + wcslen(toAddr), + dwFlags, + lpUrlComponents + ); + LeaveCriticalSection(&dns_hook_lock); + return result; + } + } + + LeaveCriticalSection(&dns_hook_lock); + return next_WinHttpCrackUrl( + pwszUrl, + dwUrlLength, + dwFlags, + lpUrlComponents + ); +} diff --git a/idachook/idachook.def b/idachook/idachook.def index 4c944fd..a8b05b5 100644 --- a/idachook/idachook.def +++ b/idachook/idachook.def @@ -13,7 +13,6 @@ EXPORTS amDllVideoSetResolution @3 idac_io_get_api_version idac_io_init - idac_io_poll idac_io_get_opbtns idac_io_get_gamebtns idac_io_get_shifter diff --git a/idacio/xi.c b/idacio/xi.c index 3b912fc..c924153 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -52,10 +52,6 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back return S_OK; } -HRESULT idac_io_poll(void) { - return S_OK; -} - static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg) { /* Deadzones check */ if (cfg->left_stick_deadzone > 32767 || cfg->left_stick_deadzone < 0) { diff --git a/platform/config.c b/platform/config.c index 05f1a0b..fd48a3e 100644 --- a/platform/config.c +++ b/platform/config.c @@ -113,6 +113,14 @@ void dns_config_load(struct dns_config *cfg, const wchar_t *filename) cfg->aimedb, _countof(cfg->aimedb), filename); + + GetPrivateProfileStringW( + L"dns", + L"title", + L"title", + cfg->title, + _countof(cfg->title), + filename); } void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename) diff --git a/platform/dns.c b/platform/dns.c index d6d37a7..a658b58 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -82,6 +82,13 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + // croosbeats REV. + hr = dns_hook_push(L"https://rev-ent.ac.capcom.jp:443", cfg->title); + + if (FAILED(hr)) { + return hr; + } + // AimePay hr = dns_hook_push(L"api-aime.am-all.net", cfg->startup); diff --git a/platform/dns.h b/platform/dns.h index 416fe73..e822ff3 100644 --- a/platform/dns.h +++ b/platform/dns.h @@ -11,6 +11,7 @@ struct dns_config { wchar_t startup[128]; wchar_t billing[128]; wchar_t aimedb[128]; + wchar_t title[128]; }; HRESULT dns_platform_hook_init(const struct dns_config *cfg); diff --git a/platform/nusec.c b/platform/nusec.c index 6094408..a82a99f 100644 --- a/platform/nusec.c +++ b/platform/nusec.c @@ -14,22 +14,22 @@ #include "util/str.h" enum { - NUSEC_IOCTL_PING = 0x22A114, - NUSEC_IOCTL_ERASE_TRACE_LOG = 0x22E188, - NUSEC_IOCTL_TD_ERASE_USED = 0x22E18C, - NUSEC_IOCTL_ADD_PLAY_COUNT = 0x22E154, - NUSEC_IOCTL_GET_BILLING_CA_CERT = 0x22E1C4, - NUSEC_IOCTL_GET_BILLING_PUBKEY = 0x22E1C8, - NUSEC_IOCTL_GET_NEARFULL = 0x22E20C, - NUSEC_IOCTL_GET_NVRAM_AVAILABLE = 0x22E19C, - NUSEC_IOCTL_GET_NVRAM_GEOMETRY = 0x22E24C, - NUSEC_IOCTL_GET_PLAY_COUNT = 0x22E150, - NUSEC_IOCTL_GET_PLAY_LIMIT = 0x22E204, - NUSEC_IOCTL_GET_TRACE_LOG_DATA = 0x22E194, - NUSEC_IOCTL_GET_TRACE_LOG_STATE = 0x22E198, - NUSEC_IOCTL_PUT_NEARFULL = 0x22E210, - NUSEC_IOCTL_PUT_PLAY_LIMIT = 0x22E208, - NUSEC_IOCTL_PUT_TRACE_LOG_DATA = 0x22E190, + NUSEC_IOCTL_PING = CTL_CODE(0x22, 0x845, METHOD_BUFFERED, FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_PLAY_COUNT = CTL_CODE(0x22, 0x854, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_ADD_PLAY_COUNT = CTL_CODE(0x22, 0x855, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_ERASE_TRACE_LOG = CTL_CODE(0x22, 0x862, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_TD_ERASE_USED = CTL_CODE(0x22, 0x863, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_PUT_TRACE_LOG_DATA = CTL_CODE(0x22, 0x864, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_TRACE_LOG_DATA = CTL_CODE(0x22, 0x865, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_TRACE_LOG_STATE = CTL_CODE(0x22, 0x866, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_NVRAM_AVAILABLE = CTL_CODE(0x22, 0x867, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_BILLING_CA_CERT = CTL_CODE(0x22, 0x871, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_BILLING_PUBKEY = CTL_CODE(0x22, 0x872, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_PLAY_LIMIT = CTL_CODE(0x22, 0x881, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_PUT_PLAY_LIMIT = CTL_CODE(0x22, 0x882, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_NEARFULL = CTL_CODE(0x22, 0x883, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_PUT_NEARFULL = CTL_CODE(0x22, 0x884, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + NUSEC_IOCTL_GET_NVRAM_GEOMETRY = CTL_CODE(0x22, 0x893, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), }; struct nusec_log_record { From 774a639bb7236d2ecac0d698aa630b1deb18bf00 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 14 Mar 2024 00:14:51 +0100 Subject: [PATCH 094/204] cxb: fixed configs --- cxbhook/config.c | 21 +++++++++++++++------ cxbhook/config.h | 3 --- cxbhook/dllmain.c | 7 ------- cxbhook/led.c | 8 +++++++- cxbhook/meson.build | 2 -- cxbhook/network.c | 13 ------------- cxbhook/network.h | 13 ------------- cxbhook/revio.c | 8 +++++++- dist/cxb/segatools.ini | 2 +- platform/dns.c | 2 +- 10 files changed, 31 insertions(+), 48 deletions(-) delete mode 100644 cxbhook/network.c delete mode 100644 cxbhook/network.h diff --git a/cxbhook/config.c b/cxbhook/config.c index 9a513d1..c83694d 100644 --- a/cxbhook/config.c +++ b/cxbhook/config.c @@ -23,22 +23,32 @@ void cxb_dll_config_load( struct cxb_dll_config *cfg, const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + GetPrivateProfileStringW( + L"cxbio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); } void revio_config_load(struct revio_config *cfg, const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); -} - -void network_config_load(struct network_config *cfg, const wchar_t *filename) -{ - + cfg->enable = GetPrivateProfileIntW(L"revio", L"enable", 1, filename); } void led_config_load(struct led_config *cfg, const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + cfg->enable = GetPrivateProfileIntW(L"led", L"enable", 1, filename); } void cxb_hook_config_load( @@ -56,6 +66,5 @@ void cxb_hook_config_load( gfx_config_load(&cfg->gfx, filename); cxb_dll_config_load(&cfg->dll, filename); revio_config_load(&cfg->revio, filename); - network_config_load(&cfg->network, filename); led_config_load(&cfg->led, filename); } \ No newline at end of file diff --git a/cxbhook/config.h b/cxbhook/config.h index f2bb8ca..4c7d3af 100644 --- a/cxbhook/config.h +++ b/cxbhook/config.h @@ -10,7 +10,6 @@ #include "cxbhook/cxb-dll.h" #include "cxbhook/revio.h" #include "cxbhook/led.h" -#include "cxbhook/network.h" #include "gfxhook/gfx.h" @@ -23,7 +22,6 @@ struct cxb_hook_config { struct gfx_config gfx; struct cxb_dll_config dll; struct revio_config revio; - struct network_config network; struct led_config led; }; @@ -32,7 +30,6 @@ void cxb_dll_config_load( const wchar_t *filename); void revio_config_load(struct revio_config *cfg, const wchar_t *filename); -void network_config_load(struct network_config *cfg, const wchar_t *filename); void led_config_load(struct led_config *cfg, const wchar_t *filename); void cxb_hook_config_load( diff --git a/cxbhook/dllmain.c b/cxbhook/dllmain.c index ba0bb7b..18aaa7f 100644 --- a/cxbhook/dllmain.c +++ b/cxbhook/dllmain.c @@ -9,7 +9,6 @@ #include "cxbhook/config.h" #include "cxbhook/revio.h" #include "cxbhook/led.h" -#include "cxbhook/network.h" #include "cxbio/cxbio.h" @@ -103,12 +102,6 @@ static DWORD CALLBACK cxb_pre_startup(void) goto fail; } - hr = network_hook_init(&cxb_hook_cfg.network); - - if (FAILED(hr)) { - goto fail; - } - hr = led_hook_init(&cxb_hook_cfg.led); if (FAILED(hr)) { diff --git a/cxbhook/led.c b/cxbhook/led.c index 39d6d4f..be3f26f 100644 --- a/cxbhook/led.c +++ b/cxbhook/led.c @@ -49,7 +49,13 @@ static struct hook_symbol lamp_syms[] = { HRESULT led_hook_init(struct led_config *cfg) { - dprintf("LED: Init\n"); + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + dprintf("LED: Hook enabled.\n"); return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms)); } diff --git a/cxbhook/meson.build b/cxbhook/meson.build index 1c23a00..68f8f76 100644 --- a/cxbhook/meson.build +++ b/cxbhook/meson.build @@ -30,7 +30,5 @@ shared_library( 'revio.h', 'led.c', 'led.h', - 'network.c', - 'network.h', ], ) diff --git a/cxbhook/network.c b/cxbhook/network.c deleted file mode 100644 index e9a832a..0000000 --- a/cxbhook/network.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include - -#include "cxbhook/network.h" - -#include "util/dprintf.h" - -HRESULT network_hook_init(struct network_config *cfg) -{ - dprintf("Network: Init\n"); - return S_OK; -} \ No newline at end of file diff --git a/cxbhook/network.h b/cxbhook/network.h deleted file mode 100644 index a2ae7ce..0000000 --- a/cxbhook/network.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include -#include - -struct network_config { - bool enable; - bool disable_ssl; - char title_server[PATH_MAX]; -}; - -HRESULT network_hook_init(struct network_config *cfg); \ No newline at end of file diff --git a/cxbhook/revio.c b/cxbhook/revio.c index 15e2260..601c75a 100644 --- a/cxbhook/revio.c +++ b/cxbhook/revio.c @@ -82,7 +82,13 @@ static struct hook_symbol revio_syms[] = { HRESULT revio_hook_init(struct revio_config *cfg) { - dprintf("Revio: Init\n"); + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + dprintf("Revio: Hook enabled.\n"); return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms)); } diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 40f0ad6..6d9e5e0 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -110,7 +110,7 @@ path= [revio] ; Enable emulation of the rev IO board -enabe=1 +enable=1 ; Test button virtual-key code. Default is the F1 key. test=0x70 ; Service button virtual-key code. Default is the F2 key. diff --git a/platform/dns.c b/platform/dns.c index a658b58..692ee13 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -82,7 +82,7 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } - // croosbeats REV. + // crossbeats REV. hr = dns_hook_push(L"https://rev-ent.ac.capcom.jp:443", cfg->title); if (FAILED(hr)) { From 47a65e5e51635e2eeb9fd238decf56c2222231c2 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 17 Mar 2024 14:19:56 +0100 Subject: [PATCH 095/204] fixed aime LED firmware --- board/sg-cmd.h | 7 +++++++ board/sg-led.c | 14 +++++++------- board/sg-nfc.c | 28 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/board/sg-cmd.h b/board/sg-cmd.h index 685377f..73029ec 100644 --- a/board/sg-cmd.h +++ b/board/sg-cmd.h @@ -25,6 +25,13 @@ struct sg_res_header { uint8_t payload_len; }; +/* struct to save the version string with its length + to fix NUL terminator issues */ +struct version_info { + const char *version; + uint8_t length; +}; + typedef HRESULT (*sg_dispatch_fn_t)( void *ctx, const void *req, diff --git a/board/sg-led.c b/board/sg-led.c index cd09c14..47f97c2 100644 --- a/board/sg-led.c +++ b/board/sg-led.c @@ -27,11 +27,11 @@ static HRESULT sg_led_cmd_set_color( const struct sg_led *led, const struct sg_led_req_set_color *req); -const char *sg_led_info[] = { - "15084\xFF\x10\x00\x12", - "000-00000\xFF\x11\x40", +static const struct version_info led_version[] = { + {"15084\xFF\x10\x00\x12", 9}, + {"000-00000\xFF\x11\x40", 12}, // maybe the same? - "000-00000\xFF\x11\x40" + {"000-00000\xFF\x11\x40", 12} }; void sg_led_init( @@ -156,10 +156,10 @@ static HRESULT sg_led_cmd_get_info( { sg_led_dprintf(led, "Get info\n"); - unsigned int len = strlen(sg_led_info[led->gen - 1]); + const struct version_info *fw = &led_version[led->gen - 1]; - sg_res_init(&res->res, req, len); - memcpy(res->payload, sg_led_info[led->gen - 1], len); + sg_res_init(&res->res, req, fw->length); + memcpy(res->payload, fw->version, fw->length); return S_OK; } diff --git a/board/sg-nfc.c b/board/sg-nfc.c index c519358..8f7c9bd 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -65,16 +65,16 @@ static HRESULT sg_nfc_cmd_dummy( const struct sg_req_header *req, struct sg_res_header *res); -static const char *hw_version[] = { - "TN32MSEC003S H/W Ver3.0", - "837-15286", - "837-15396" +static const struct version_info hw_version[] = { + {"TN32MSEC003S H/W Ver3.0", 23}, + {"837-15286", 9}, + {"837-15396", 9} }; -static const char *fw_version[] = { - "TN32MSEC003S F/W Ver1.2", - "\x94", - "\x94" +static const struct version_info fw_version[] = { + {"TN32MSEC003S F/W Ver1.2", 23}, + {"\x94", 1}, + {"\x94", 1} }; void sg_nfc_init( @@ -217,11 +217,11 @@ static HRESULT sg_nfc_cmd_get_fw_version( const struct sg_req_header *req, struct sg_nfc_res_get_fw_version *res) { - unsigned int len = strlen(fw_version[nfc->gen - 1]); + const struct version_info *fw = &fw_version[nfc->gen - 1]; /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, len); - memcpy(res->version, fw_version[nfc->gen - 1], len); + sg_res_init(&res->res, req, fw->length); + memcpy(res->version, fw->version, fw->length); return S_OK; } @@ -231,11 +231,11 @@ static HRESULT sg_nfc_cmd_get_hw_version( const struct sg_req_header *req, struct sg_nfc_res_get_hw_version *res) { - unsigned int len = strlen(hw_version[nfc->gen - 1]); + const struct version_info *hw = &hw_version[nfc->gen - 1]; /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, len); - memcpy(res->version, hw_version[nfc->gen - 1], len); + sg_res_init(&res->res, req, hw->length); + memcpy(res->version, hw->version, hw->length); return S_OK; } From 4041844ea997bc3c73d13721b7fe2fb43e493520 Mon Sep 17 00:00:00 2001 From: beerpsi Date: Mon, 15 Apr 2024 19:30:28 +0000 Subject: [PATCH 096/204] mai2/mu3/cm: Integrate UnityDoorstop with segatools (#11) [UnityDoorstop](https://github.com/NeighTools/UnityDoorstop) is a tool to execute managed code (.NET DLLs) before Unity does, useful for modding frameworks such as BepInEx. This PR integrates parts of its code into segatools, so loading BepInEx is as simple as adding 2 lines to `segatools.ini`: ```ini [unity] targetAssembly=BepInEx\core\BepInEx.Preloader.dll ``` This PR also factors out the Unity path redirection hooks to its own module. Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/11 Co-authored-by: beerpsi Co-committed-by: beerpsi --- cmhook/config.c | 1 + cmhook/config.h | 3 + cmhook/dllmain.c | 5 +- cmhook/meson.build | 3 +- cmhook/unity.c | 95 --------------- cmhook/unity.h | 3 - dist/cm/segatools.ini | 5 + dist/mai2/segatools.ini | 9 ++ dist/mu3/segatools.ini | 5 + mai2hook/config.c | 1 + mai2hook/config.h | 3 + mai2hook/dllmain.c | 5 +- mai2hook/meson.build | 3 +- mai2hook/unity.h | 3 - meson.build | 2 + mu3hook/config.c | 1 + mu3hook/config.h | 3 + mu3hook/dllmain.c | 7 +- mu3hook/meson.build | 3 +- mu3hook/unity.c | 95 --------------- mu3hook/unity.h | 3 - unityhook/config.c | 14 +++ unityhook/config.h | 12 ++ unityhook/doorstop.c | 173 +++++++++++++++++++++++++++ unityhook/doorstop.h | 5 + mai2hook/unity.c => unityhook/hook.c | 59 +++++---- unityhook/hook.h | 7 ++ unityhook/meson.build | 20 ++++ unityhook/mono.h | 100 ++++++++++++++++ unityhook/util.h | 20 ++++ 30 files changed, 436 insertions(+), 232 deletions(-) delete mode 100644 cmhook/unity.c delete mode 100644 cmhook/unity.h delete mode 100644 mai2hook/unity.h delete mode 100644 mu3hook/unity.c delete mode 100644 mu3hook/unity.h create mode 100644 unityhook/config.c create mode 100644 unityhook/config.h create mode 100644 unityhook/doorstop.c create mode 100644 unityhook/doorstop.h rename mai2hook/unity.c => unityhook/hook.c (70%) create mode 100644 unityhook/hook.h create mode 100644 unityhook/meson.build create mode 100644 unityhook/mono.h create mode 100644 unityhook/util.h diff --git a/cmhook/config.c b/cmhook/config.c index fd9186c..4c0a808 100644 --- a/cmhook/config.c +++ b/cmhook/config.c @@ -40,4 +40,5 @@ void cm_hook_config_load( vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); cm_dll_config_load(&cfg->dll, filename); + unity_config_load(&cfg->unity, filename); } diff --git a/cmhook/config.h b/cmhook/config.h index cf39c70..a840358 100644 --- a/cmhook/config.h +++ b/cmhook/config.h @@ -11,6 +11,8 @@ #include "platform/config.h" +#include "unityhook/config.h" + struct cm_hook_config { struct platform_config platform; struct aime_config aime; @@ -19,6 +21,7 @@ struct cm_hook_config { struct vfd_config vfd; struct cm_dll_config dll; struct touch_screen_config touch; + struct unity_config unity; }; void cm_dll_config_load( diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 0e12adb..687601a 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -16,10 +16,11 @@ #include "cmhook/config.h" #include "cmhook/io4.h" #include "cmhook/cm-dll.h" -#include "cmhook/unity.h" #include "platform/platform.h" +#include "unityhook/hook.h" + #include "util/dprintf.h" static HMODULE cm_hook_mod; @@ -83,7 +84,7 @@ static DWORD CALLBACK cm_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `cmhook` initialization. */ - unity_hook_init(); + unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod); /* Initialize debug helpers */ diff --git a/cmhook/meson.build b/cmhook/meson.build index 338f773..6c645c2 100644 --- a/cmhook/meson.build +++ b/cmhook/meson.build @@ -16,6 +16,7 @@ shared_library( hooklib_lib, cmio_lib, platform_lib, + unityhook_lib, util_lib, ], sources : [ @@ -26,7 +27,5 @@ shared_library( 'io4.h', 'cm-dll.c', 'cm-dll.h', - 'unity.h', - 'unity.c', ], ) diff --git a/cmhook/unity.c b/cmhook/unity.c deleted file mode 100644 index efefc32..0000000 --- a/cmhook/unity.c +++ /dev/null @@ -1,95 +0,0 @@ -#include - -#include - -#include "hook/table.h" - -#include "hooklib/dll.h" -#include "hooklib/path.h" - -#include "util/dprintf.h" - -static void dll_hook_insert_hooks(HMODULE target); - -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); -static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); - -static const struct hook_symbol unity_kernel32_syms[] = { - { - .name = "LoadLibraryW", - .patch = my_LoadLibraryW, - .link = (void **) &next_LoadLibraryW, - }, -}; - -static const wchar_t *target_modules[] = { - L"mono.dll", - L"cri_ware_unity.dll", -}; -static const size_t target_modules_len = _countof(target_modules); - -void unity_hook_init(void) -{ - dll_hook_insert_hooks(NULL); -} - -static void dll_hook_insert_hooks(HMODULE target) -{ - hook_table_apply( - target, - "kernel32.dll", - unity_kernel32_syms, - _countof(unity_kernel32_syms)); -} - -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) -{ - const wchar_t *name_end; - const wchar_t *target_module; - bool already_loaded; - HMODULE result; - size_t name_len; - size_t target_module_len; - - if (name == NULL) { - SetLastError(ERROR_INVALID_PARAMETER); - - return NULL; - } - - // Check if the module is already loaded - already_loaded = GetModuleHandleW(name) != NULL; - - // Must call the next handler so the DLL reference count is incremented - result = next_LoadLibraryW(name); - - if (!already_loaded && result != NULL) { - name_len = wcslen(name); - - for (size_t i = 0; i < target_modules_len; i++) { - target_module = target_modules[i]; - target_module_len = wcslen(target_module); - - // Check if the newly loaded library is at least the length of - // the name of the target module - if (name_len < target_module_len) { - continue; - } - - name_end = &name[name_len - target_module_len]; - - // Check if the name of the newly loaded library is one of the - // modules the path hooks should be injected into - if (_wcsicmp(name_end, target_module) != 0) { - continue; - } - - dprintf("Unity: Loaded %S\n", target_module); - - dll_hook_insert_hooks(result); - path_hook_insert_hooks(result); - } - } - - return result; -} diff --git a/cmhook/unity.h b/cmhook/unity.h deleted file mode 100644 index 99c3bd9..0000000 --- a/cmhook/unity.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void unity_hook_init(void); diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 37f5708..181c785 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -68,6 +68,11 @@ dipsw1=0 ; Enable/Disable WinTouch emulation enable=0 +[unity] +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 3aa8758..ed8cc0a 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -83,6 +83,15 @@ path= ; Leave empty if you want to use Segatools built-in keyboard input. path= +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + +[unity] +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index ac897df..c55cbbb 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -72,6 +72,11 @@ dipsw1=1 [gfx] enable=1 +[unity] +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/mai2hook/config.c b/mai2hook/config.c index 86b9764..d41a1d6 100644 --- a/mai2hook/config.c +++ b/mai2hook/config.c @@ -39,4 +39,5 @@ void mai2_hook_config_load( io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); mai2_dll_config_load(&cfg->dll, filename); + unity_config_load(&cfg->unity, filename); } diff --git a/mai2hook/config.h b/mai2hook/config.h index 2def3a7..7e86822 100644 --- a/mai2hook/config.h +++ b/mai2hook/config.h @@ -10,6 +10,8 @@ #include "platform/config.h" +#include "unityhook/config.h" + struct mai2_hook_config { struct platform_config platform; struct aime_config aime; @@ -17,6 +19,7 @@ struct mai2_hook_config { struct io4_config io4; struct vfd_config vfd; struct mai2_dll_config dll; + struct unity_config unity; }; void mai2_dll_config_load( diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 5d53368..1d10c60 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -12,10 +12,11 @@ #include "mai2hook/config.h" #include "mai2hook/io4.h" #include "mai2hook/mai2-dll.h" -#include "mai2hook/unity.h" #include "platform/platform.h" +#include "unityhook/hook.h" + #include "util/dprintf.h" static HMODULE mai2_hook_mod; @@ -80,7 +81,7 @@ static DWORD CALLBACK mai2_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `mai2hook` initialization. */ - unity_hook_init(); + unity_hook_init(&mai2_hook_cfg.unity, mai2_hook_mod); /* Initialize debug helpers */ diff --git a/mai2hook/meson.build b/mai2hook/meson.build index 8578c51..f43fccc 100644 --- a/mai2hook/meson.build +++ b/mai2hook/meson.build @@ -15,6 +15,7 @@ shared_library( hooklib_lib, mai2io_lib, platform_lib, + unityhook_lib, util_lib, ], sources : [ @@ -25,7 +26,5 @@ shared_library( 'io4.h', 'mai2-dll.c', 'mai2-dll.h', - 'unity.h', - 'unity.c', ], ) diff --git a/mai2hook/unity.h b/mai2hook/unity.h deleted file mode 100644 index 99c3bd9..0000000 --- a/mai2hook/unity.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void unity_hook_init(void); diff --git a/meson.build b/meson.build index a0db24a..90ac292 100644 --- a/meson.build +++ b/meson.build @@ -42,6 +42,7 @@ shlwapi_lib = cc.find_library('shlwapi') dinput8_lib = cc.find_library('dinput8') dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') +pathcch_lib = cc.find_library('pathcch') inc = include_directories('.') capnhook = subproject('capnhook') @@ -55,6 +56,7 @@ subdir('platform') subdir('util') subdir('gfxhook') +subdir('unityhook') subdir('aimeio') subdir('chuniio') diff --git a/mu3hook/config.c b/mu3hook/config.c index bb51103..290d5ae 100644 --- a/mu3hook/config.c +++ b/mu3hook/config.c @@ -42,4 +42,5 @@ void mu3_hook_config_load( gfx_config_load(&cfg->gfx, filename); vfd_config_load(&cfg->vfd, filename); mu3_dll_config_load(&cfg->dll, filename); + unity_config_load(&cfg->unity, filename); } diff --git a/mu3hook/config.h b/mu3hook/config.h index f1b2cdf..930a766 100644 --- a/mu3hook/config.h +++ b/mu3hook/config.h @@ -13,6 +13,8 @@ #include "platform/config.h" +#include "unityhook/config.h" + struct mu3_hook_config { struct platform_config platform; struct aime_config aime; @@ -22,6 +24,7 @@ struct mu3_hook_config { // struct led15093_config led15093; struct vfd_config vfd; struct mu3_dll_config dll; + struct unity_config unity; }; void mu3_dll_config_load( diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index 3f940dd..bd1ec2b 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -2,7 +2,6 @@ #include -#include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" @@ -20,10 +19,12 @@ #include "mu3hook/config.h" #include "mu3hook/io4.h" #include "mu3hook/mu3-dll.h" -#include "mu3hook/unity.h" #include "platform/platform.h" +#include "unityhook/config.h" +#include "unityhook/hook.h" + #include "util/dprintf.h" static HMODULE mu3_hook_mod; @@ -99,7 +100,7 @@ static DWORD CALLBACK mu3_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `mu3hook` initialization. */ - unity_hook_init(); + unity_hook_init(&mu3_hook_cfg.unity, mu3_hook_mod); /* Initialize debug helpers */ diff --git a/mu3hook/meson.build b/mu3hook/meson.build index 27ba7f7..a722428 100644 --- a/mu3hook/meson.build +++ b/mu3hook/meson.build @@ -17,6 +17,7 @@ shared_library( hooklib_lib, mu3io_lib, platform_lib, + unityhook_lib, util_lib, ], sources : [ @@ -27,7 +28,5 @@ shared_library( 'io4.h', 'mu3-dll.c', 'mu3-dll.h', - 'unity.h', - 'unity.c', ], ) diff --git a/mu3hook/unity.c b/mu3hook/unity.c deleted file mode 100644 index efefc32..0000000 --- a/mu3hook/unity.c +++ /dev/null @@ -1,95 +0,0 @@ -#include - -#include - -#include "hook/table.h" - -#include "hooklib/dll.h" -#include "hooklib/path.h" - -#include "util/dprintf.h" - -static void dll_hook_insert_hooks(HMODULE target); - -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); -static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); - -static const struct hook_symbol unity_kernel32_syms[] = { - { - .name = "LoadLibraryW", - .patch = my_LoadLibraryW, - .link = (void **) &next_LoadLibraryW, - }, -}; - -static const wchar_t *target_modules[] = { - L"mono.dll", - L"cri_ware_unity.dll", -}; -static const size_t target_modules_len = _countof(target_modules); - -void unity_hook_init(void) -{ - dll_hook_insert_hooks(NULL); -} - -static void dll_hook_insert_hooks(HMODULE target) -{ - hook_table_apply( - target, - "kernel32.dll", - unity_kernel32_syms, - _countof(unity_kernel32_syms)); -} - -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) -{ - const wchar_t *name_end; - const wchar_t *target_module; - bool already_loaded; - HMODULE result; - size_t name_len; - size_t target_module_len; - - if (name == NULL) { - SetLastError(ERROR_INVALID_PARAMETER); - - return NULL; - } - - // Check if the module is already loaded - already_loaded = GetModuleHandleW(name) != NULL; - - // Must call the next handler so the DLL reference count is incremented - result = next_LoadLibraryW(name); - - if (!already_loaded && result != NULL) { - name_len = wcslen(name); - - for (size_t i = 0; i < target_modules_len; i++) { - target_module = target_modules[i]; - target_module_len = wcslen(target_module); - - // Check if the newly loaded library is at least the length of - // the name of the target module - if (name_len < target_module_len) { - continue; - } - - name_end = &name[name_len - target_module_len]; - - // Check if the name of the newly loaded library is one of the - // modules the path hooks should be injected into - if (_wcsicmp(name_end, target_module) != 0) { - continue; - } - - dprintf("Unity: Loaded %S\n", target_module); - - dll_hook_insert_hooks(result); - path_hook_insert_hooks(result); - } - } - - return result; -} diff --git a/mu3hook/unity.h b/mu3hook/unity.h deleted file mode 100644 index 99c3bd9..0000000 --- a/mu3hook/unity.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void unity_hook_init(void); diff --git a/unityhook/config.c b/unityhook/config.c new file mode 100644 index 0000000..6f0a0cc --- /dev/null +++ b/unityhook/config.c @@ -0,0 +1,14 @@ +#include "config.h" + +void unity_config_load(struct unity_config *cfg, const wchar_t *filename) { + cfg->enable = GetPrivateProfileIntW(L"unity", L"enable", 1, filename); + + GetPrivateProfileStringW( + L"unity", + L"targetAssembly", + L"", + cfg->target_assembly, + _countof(cfg->target_assembly), + filename + ); +} diff --git a/unityhook/config.h b/unityhook/config.h new file mode 100644 index 0000000..6fca14a --- /dev/null +++ b/unityhook/config.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include + +struct unity_config { + bool enable; + wchar_t target_assembly[MAX_PATH]; +}; + +void unity_config_load(struct unity_config *cfg, const wchar_t *filename); diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c new file mode 100644 index 0000000..07b6799 --- /dev/null +++ b/unityhook/doorstop.c @@ -0,0 +1,173 @@ +// A simplified version of NeighTools' UnityDoorstop, allowing mod loaders +// like BepInEx to be loaded into Unity games. +// +// SPDX-License-Identifier: CC0 +// https://github.com/NeighTools/UnityDoorstop +#include + +#include +#include + +#include "hooklib/procaddr.h" +#include "util/dprintf.h" + +#include "doorstop.h" +#include "mono.h" +#include "util.h" + +static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version); +void doorstop_invoke(void *domain); + +static char module_name[MAX_PATH]; +static bool doorstop_hook_initted; +static struct unity_config unity_config; +static struct hook_symbol unity_mono_syms[] = { +{ + .name = "mono_jit_init_version", + .patch = my_mono_jit_init_version, + } +}; + +void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module) { + if (doorstop_hook_initted || cfg->target_assembly[0] == 0) { + return; + } + + GetModuleBaseNameA(GetCurrentProcess(), module, module_name, MAX_PATH); + + memcpy(&unity_config, cfg, sizeof(*cfg)); + load_mono_functions(module); + proc_addr_table_push(module_name, unity_mono_syms, _countof(unity_mono_syms)); + + doorstop_hook_initted = true; +} + +static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version) { + dprintf("Unity: Starting Mono domain \"%s\"\n", root_domain_name); + + SetEnvironmentVariableW(L"DOORSTOP_DLL_SEARCH_DIRS", widen(mono_assembly_getrootdir())); + + void* domain = mono_jit_init_version(root_domain_name, runtime_version); + + doorstop_invoke(domain); + return domain; +} + +void doorstop_invoke(void* domain) { + if (GetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", NULL, 0) != 0) { + dprintf("Unity: Doorstop is already initialized.\n"); + return; + } + + SetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", L"TRUE"); + + mono_thread_set_main(mono_thread_current()); + + if (mono_domain_set_config) { +#define CONFIG_EXT L".config" + + wchar_t exe_path[MAX_PATH]; + size_t exe_path_len = GetModuleFileNameW(NULL, exe_path, MAX_PATH); + wchar_t *folder_name = wcsdup(exe_path); + + PathCchRemoveFileSpec(folder_name, exe_path_len + 1); + + char *exe_path_n = narrow(exe_path); + char *folder_name_n = narrow(folder_name); + + dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, exe_path_n); + + mono_domain_set_config(domain, folder_name_n, exe_path_n); + + free(folder_name); + free(exe_path_n); + free(folder_name_n); + +#undef CONFIG_EXT + } + + SetEnvironmentVariableW(L"DOORSTOP_INVOKE_DLL_PATH", unity_config.target_assembly); + + char *assembly_dir = mono_assembly_getrootdir(); + dprintf("Unity: Assembly directory: %s\n", assembly_dir); + + SetEnvironmentVariableA("DOORSTOP_MANAGED_FOLDER_DIR", assembly_dir); + + wchar_t app_path[MAX_PATH]; + GetModuleFileNameW(NULL, app_path, MAX_PATH); + SetEnvironmentVariableW(L"DOORSTOP_PROCESS_PATH", app_path); + + char* dll_path = narrow(unity_config.target_assembly); + + dprintf("Unity: Loading assembly: %s\n", dll_path); + + void* assembly = mono_domain_assembly_open(domain, dll_path); + + if (!assembly) { + dprintf("Unity: Failed to load assembly\n"); + free(dll_path); + return; + } + + void *image = mono_assembly_get_image(assembly); + + if (!image) { + dprintf("Unity: Assembly image doesn't exist\n"); + free(dll_path); + return; + } + + void *desc = mono_method_desc_new("*:Main", FALSE); + void *method = mono_method_desc_search_in_image(desc, image); + + if (!method) { + dprintf("Unity: Assembly does not have a valid entrypoint.\n"); + free(dll_path); + return; + } + + void *signature = mono_method_signature(method); + UINT32 params = mono_signature_get_param_count(signature); + void **args = NULL; + + if (params == 1) { + // If there is a parameter, it's most likely a string[]. + void *args_array = mono_array_new(domain, mono_get_string_class(), 0); + args = malloc(sizeof(void*) * 1); + args[0] = args_array; + } + + dprintf("Unity: Invoking method %p\n", method); + + void *exc = NULL; + mono_runtime_invoke(method, NULL, args, &exc); + + if (exc) { + dprintf("Unity: Error invoking method!\n"); + + void *ex_class = mono_get_exception_class(); + void *to_string_desc = mono_method_desc_new("*:ToString()", FALSE); + void* to_string_method = mono_method_desc_search_in_class(to_string_desc, ex_class); + + mono_method_desc_free(to_string_desc); + + if (to_string_method) { + void* real_to_string_method = mono_object_get_virtual_method(exc, to_string_method); + void* exc2 = NULL; + void* str = mono_runtime_invoke(real_to_string_method, exc, NULL, &exc2); + + if (!exc2) { + char* exc_str = mono_string_to_utf8(str); + dprintf("Unity: Error message: %s\n", exc_str); + } + } + } + + mono_method_desc_free(desc); + free(dll_path); + + if (args) { + free(args); + args = NULL; + } +} diff --git a/unityhook/doorstop.h b/unityhook/doorstop.h new file mode 100644 index 0000000..8cc961e --- /dev/null +++ b/unityhook/doorstop.h @@ -0,0 +1,5 @@ +#pragma once + +#include "config.h" + +void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module); \ No newline at end of file diff --git a/mai2hook/unity.c b/unityhook/hook.c similarity index 70% rename from mai2hook/unity.c rename to unityhook/hook.c index 64195be..060233b 100644 --- a/mai2hook/unity.c +++ b/unityhook/hook.c @@ -1,14 +1,23 @@ +#include #include -#include - #include "hook/table.h" - -#include "hooklib/dll.h" #include "hooklib/path.h" - #include "util/dprintf.h" +#include "doorstop.h" +#include "hook.h" + +static bool unity_hook_initted; +static struct unity_config unity_config; + +static const wchar_t *target_modules[] = { + L"mono.dll", + L"mono-2.0-bdwgc.dll", + L"cri_ware_unity.dll", +}; +static const size_t target_modules_len = _countof(target_modules); + static void dll_hook_insert_hooks(HMODULE target); static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); @@ -22,28 +31,33 @@ static const struct hook_symbol unity_kernel32_syms[] = { }, }; -static const wchar_t *target_modules[] = { - L"mono-2.0-bdwgc.dll", - L"cri_ware_unity.dll", -}; -static const size_t target_modules_len = _countof(target_modules); +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { + assert(cfg != NULL); -void unity_hook_init(void) -{ + if (!cfg->enable) { + return; + } + + if (unity_hook_initted) { + return; + } + + memcpy(&unity_config, cfg, sizeof(*cfg)); dll_hook_insert_hooks(NULL); + + unity_hook_initted = true; + dprintf("Unity: Hook enabled.\n"); } -static void dll_hook_insert_hooks(HMODULE target) -{ +static void dll_hook_insert_hooks(HMODULE target) { hook_table_apply( - target, - "kernel32.dll", - unity_kernel32_syms, - _countof(unity_kernel32_syms)); + target, + "kernel32.dll", + unity_kernel32_syms, + _countof(unity_kernel32_syms)); } -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) -{ +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) { const wchar_t *name_end; const wchar_t *target_module; bool already_loaded; @@ -66,6 +80,11 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) if (!already_loaded && result != NULL) { name_len = wcslen(name); + // mono entrypoint for injecting target_assembly + if (GetProcAddress(result, "mono_jit_init_version")) { + doorstop_mono_hook_init(&unity_config, result); + } + for (size_t i = 0; i < target_modules_len; i++) { target_module = target_modules[i]; target_module_len = wcslen(target_module); diff --git a/unityhook/hook.h b/unityhook/hook.h new file mode 100644 index 0000000..684868c --- /dev/null +++ b/unityhook/hook.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "config.h" + +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self); diff --git a/unityhook/meson.build b/unityhook/meson.build new file mode 100644 index 0000000..9fd7a7b --- /dev/null +++ b/unityhook/meson.build @@ -0,0 +1,20 @@ +unityhook_lib = static_library( + 'unityhook', + include_directories: inc, + implicit_include_directories: false, + c_pch: '../precompiled.h', + dependencies: [ + capnhook.get_variable('hook_dep'), + pathcch_lib + ], + sources: [ + 'mono.h', + 'config.c', + 'config.h', + 'doorstop.c', + 'doorstop.h', + 'hook.c', + 'hook.h', + 'util.h' + ], +) diff --git a/unityhook/mono.h b/unityhook/mono.h new file mode 100644 index 0000000..7056e75 --- /dev/null +++ b/unityhook/mono.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: CC0 +// https://github.com/NeighTools/UnityDoorstop +#pragma once + +#include + +// Here we define the pointers to some functions within mono.dll +// Note to C learners: these are not signature definitions, but rather "variable" +// definitions with the function pointer type. + +// Note: we use void* instead of the real intented structs defined in mono API +// This way we don't need to include or define any of Mono's structs, which saves space +// This, obviously, comes with a drawback of not being able to easily access the contents of the structs + +void * (*mono_thread_current)(); +void (*mono_thread_set_main)(void *); + +void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); +void *(*mono_domain_assembly_open)(void *domain, const char *name); +void *(*mono_assembly_get_image)(void *assembly); +void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); + +void *(*mono_method_desc_new)(const char *name, int include_namespace); +void* (*mono_method_desc_search_in_image)(void* desc, void* image); +void *(*mono_method_desc_search_in_class)(void *desc, void *klass); +void (*mono_method_desc_free)(void *desc); +void *(*mono_method_signature)(void *method); +UINT32 (*mono_signature_get_param_count)(void *sig); + +void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name); +void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); +void *(*mono_get_string_class)(); + +char *(*mono_assembly_getrootdir)(); + +// Additional funcs to bootstrap custom MONO +void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir); +void (*mono_config_parse)(const char* filename); +void (*mono_set_assemblies_path)(const char* path); +void *(*mono_object_to_string)(void* obj, void** exc); +char *(*mono_string_to_utf8)(void* s); + +void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly, + const char *name); + +void* (*mono_get_exception_class)(); +void* (*mono_object_get_virtual_method)(void* obj_raw, void* method); + +void* (*mono_jit_parse_options)(int argc, const char** argv); + +typedef enum { + MONO_DEBUG_FORMAT_NONE, + MONO_DEBUG_FORMAT_MONO, + /* Deprecated, the mdb debugger is not longer supported. */ + MONO_DEBUG_FORMAT_DEBUGGER +} MonoDebugFormat; + +void* (*mono_debug_init)(MonoDebugFormat format); +void* (*mono_debug_domain_create)(void* domain); + +/** +* \brief Loads Mono C API function pointers so that the above definitions can be called. +* \param mono_lib Mono.dll module. +*/ +void load_mono_functions(HMODULE mono_lib) { + // Enjoy the fact that C allows such sloppy casting + // In C++ you would have to cast to the precise function pointer type +#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name) + + // Find and assign all our functions that we are going to use + GET_MONO_PROC(mono_domain_assembly_open); + GET_MONO_PROC(mono_assembly_get_image); + GET_MONO_PROC(mono_runtime_invoke); + GET_MONO_PROC(mono_jit_init_version); + GET_MONO_PROC(mono_method_desc_new); + GET_MONO_PROC(mono_method_desc_search_in_class); + GET_MONO_PROC(mono_method_desc_search_in_image); + GET_MONO_PROC(mono_method_desc_free); + GET_MONO_PROC(mono_method_signature); + GET_MONO_PROC(mono_signature_get_param_count); + GET_MONO_PROC(mono_array_new); + GET_MONO_PROC(mono_get_string_class); + GET_MONO_PROC(mono_assembly_getrootdir); + GET_MONO_PROC(mono_thread_current); + GET_MONO_PROC(mono_thread_set_main); + GET_MONO_PROC(mono_domain_set_config); + GET_MONO_PROC(mono_set_dirs); + GET_MONO_PROC(mono_config_parse); + GET_MONO_PROC(mono_set_assemblies_path); + GET_MONO_PROC(mono_object_to_string); + GET_MONO_PROC(mono_string_to_utf8); + GET_MONO_PROC(mono_image_open_from_data_with_name); + GET_MONO_PROC(mono_get_exception_class); + GET_MONO_PROC(mono_object_get_virtual_method); + GET_MONO_PROC(mono_jit_parse_options); + GET_MONO_PROC(mono_debug_init); + GET_MONO_PROC(mono_debug_domain_create); + +#undef GET_MONO_PROC +} \ No newline at end of file diff --git a/unityhook/util.h b/unityhook/util.h new file mode 100644 index 0000000..41def7b --- /dev/null +++ b/unityhook/util.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +wchar_t *widen(const char *str) { + const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + wchar_t *result = malloc(reqsz * sizeof(wchar_t)); + + MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz); + return result; +} + +char *narrow(const wchar_t *str) { + const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + char *result = malloc(reqsz * sizeof(char)); + + WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL); + return result; +} + From 65173e1fa66316878ab7b4a91d7f8db2f68e774a Mon Sep 17 00:00:00 2001 From: beerpsi Date: Mon, 29 Apr 2024 23:12:10 +0700 Subject: [PATCH 097/204] [unity] Fix Unity config path --- unityhook/doorstop.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index 07b6799..b1330ca 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -66,21 +66,22 @@ void doorstop_invoke(void* domain) { if (mono_domain_set_config) { #define CONFIG_EXT L".config" - wchar_t exe_path[MAX_PATH]; - size_t exe_path_len = GetModuleFileNameW(NULL, exe_path, MAX_PATH); - wchar_t *folder_name = wcsdup(exe_path); + wchar_t config_path[MAX_PATH]; + size_t config_path_len = GetModuleFileNameW(NULL, config_path, MAX_PATH); + wchar_t *folder_name = wcsdup(config_path); - PathCchRemoveFileSpec(folder_name, exe_path_len + 1); + PathCchRemoveFileSpec(folder_name, config_path_len + 1); + wmemcpy(config_path + config_path_len, CONFIG_EXT, sizeof(CONFIG_EXT) / sizeof(CONFIG_EXT[0])); - char *exe_path_n = narrow(exe_path); + char *config_path_n = narrow(config_path); char *folder_name_n = narrow(folder_name); - dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, exe_path_n); + dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, config_path_n); - mono_domain_set_config(domain, folder_name_n, exe_path_n); + mono_domain_set_config(domain, folder_name_n, config_path_n); free(folder_name); - free(exe_path_n); + free(config_path_n); free(folder_name_n); #undef CONFIG_EXT From 482a6e530aaa19e8c45fa83e7faf06898fac2341 Mon Sep 17 00:00:00 2001 From: Sucareto <28331534+Sucareto@users.noreply.github.com> Date: Tue, 30 Apr 2024 02:19:10 +0800 Subject: [PATCH 098/204] print vfd message --- board/vfd.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/board/vfd.c b/board/vfd.c index 0442439..b216706 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -26,6 +26,7 @@ static HRESULT vfd_handle_irp(struct irp *irp); static struct uart vfd_uart; static uint8_t vfd_written[512]; static uint8_t vfd_readable[512]; +UINT codepage; HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no) { @@ -41,6 +42,7 @@ HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no) vfd_uart.readable.bytes = vfd_readable; vfd_uart.readable.nbytes = sizeof(vfd_readable); + codepage = GetACP(); dprintf("VFD: hook enabled.\n"); return iohook_push_handler(vfd_handle_irp); @@ -62,8 +64,60 @@ static HRESULT vfd_handle_irp(struct irp *irp) return hr; } - dprintf("VFD TX:\n"); - dump_iobuf(&vfd_uart.written); + uint8_t cmd = 0; + uint8_t str_1[512]; + uint8_t str_2[512]; + uint8_t str_1_len = 0; + uint8_t str_2_len = 0; + for (size_t i = 0; i < vfd_uart.written.pos; i++) { + if (vfd_uart.written.bytes[i] == 0x1B) { + i++; + cmd = vfd_uart.written.bytes[i]; + if (cmd == 0x30) { + i += 3; + } + else if (cmd == 0x50) { + i++; + } + continue; + } + if (cmd == 0x30) { + str_1[str_1_len++] = vfd_uart.written.bytes[i]; + } + else if (cmd == 0x50) { + str_2[str_2_len++] = vfd_uart.written.bytes[i]; + } + } + + if (str_1_len) { + str_1[str_1_len++] = '\0'; + if (codepage != 932) { + WCHAR buffer[512]; + MultiByteToWideChar(932, 0, (LPCSTR)str_1, str_1_len, buffer, str_1_len); + char str_recode[str_1_len * 3]; + WideCharToMultiByte(codepage, 0, buffer, str_1_len, str_recode, str_1_len * 3, NULL, NULL); + dprintf("VFD: %s\n", str_recode); + } + else { + dprintf("VFD: %s\n", str_1); + } + } + + if (str_2_len) { + str_2[str_2_len++] = '\0'; + if (codepage != 932) { + WCHAR buffer[512]; + MultiByteToWideChar(932, 0, (LPCSTR)str_2, str_2_len, buffer, str_2_len); + char str_recode[str_2_len * 3]; + WideCharToMultiByte(codepage, 0, buffer, str_2_len, str_recode, str_2_len * 3, NULL, NULL); + dprintf("VFD: %s\n", str_recode); + } else { + dprintf("VFD: %s\n", str_2); + } + } + + // dprintf("VFD TX:\n"); + // dump_iobuf(&vfd_uart.written); vfd_uart.written.pos = 0; return hr; From eb1ec0e2615d76a73b75173031d7c99eefd545f3 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 29 Apr 2024 21:34:30 +0200 Subject: [PATCH 099/204] idac: updated start.bat script --- dist/idac/start.bat | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/dist/idac/start.bat b/dist/idac/start.bat index ac77096..eb1b103 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -2,20 +2,6 @@ pushd %~dp0 -REM set the APP_DIR to the Y drive -set APP_DIR=Y:\SDGT - -REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder -if not exist "%APP_DIR%" ( - subst Y: %TEMP% - REM timeout /t 1 - if not exist "%APP_DIR%" ( - mkdir "%APP_DIR%" - ) -) - -echo Mounted the Y:\ drive to the %TEMP%\SDGT folder - set AMDAEMON_CFG=config_common.json ^ config_ex.json ^ config_jp.json ^ @@ -40,11 +26,14 @@ config_seat_single_jp.json ^ config_hook.json start "AM Daemon" /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG% -inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED -taskkill /f /im amdaemon.exe > nul 2>&1 -REM unmount the APP_DIR -subst Y: /d > nul 2>&1 +rem JP +rem inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED + +rem EXP +inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED + +taskkill /f /im amdaemon.exe > nul 2>&1 echo. echo Game processes have terminated From 04fcd0d09a115250496a9ad75c60735e882c0aa1 Mon Sep 17 00:00:00 2001 From: arcfox Date: Thu, 9 May 2024 09:48:08 +0800 Subject: [PATCH 100/204] dns: amlog hook & subdomain wildcard parse --- hooklib/dns.c | 43 +++++++++++++++++++++++++++++++++++++------ platform/dns.c | 8 +++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/hooklib/dns.c b/hooklib/dns.c index e8b0e69..d7f0c4a 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -194,6 +194,37 @@ static void dns_hook_init(void) _countof(dns_hook_syms_winhttp)); } +// This function match domain and subdomains like *.naominet.jp. +bool match_domain(const wchar_t* target, const wchar_t* pattern) { + if (_wcsicmp(pattern, target) == 0) { + return true; + } + + int pattern_ptr_index = 0; + int target_ptr_index = 0; + + while (pattern[pattern_ptr_index] != '\0' && target[target_ptr_index] != '\0') { + if (pattern[pattern_ptr_index] == '*') { + pattern_ptr_index++; // Check next character for wildcard match. + + while (pattern[pattern_ptr_index] != target[target_ptr_index]) { + target_ptr_index++; + + if (target[target_ptr_index] == '\0') return false; + } + } + else if (pattern[pattern_ptr_index] != target[target_ptr_index]) { + return false; + } + else { + pattern_ptr_index++; + target_ptr_index++; + } + } + + return pattern[pattern_ptr_index] == '\0' && target[target_ptr_index] == '\0'; +} + HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src) { HRESULT hr; @@ -297,7 +328,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_A( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(wstr, pos->from) == 0) { + if (match_domain(wstr, pos->from)) { if(pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); @@ -361,7 +392,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_W( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(pszName, pos->from) == 0) { + if (match_domain(pszName, pos->from)) { if(pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); @@ -405,7 +436,7 @@ static DNS_STATUS WINAPI hook_DnsQueryEx( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(pRequest->QueryName, pos->from) == 0) { + if (match_domain(pRequest->QueryName, pos->from)) { if(pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); @@ -472,7 +503,7 @@ static int WSAAPI hook_getaddrinfo( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(wstr, pos->from) == 0) { + if (match_domain(wstr, pos->from)) { if(pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); result = EAI_NONAME; @@ -526,7 +557,7 @@ static HINTERNET WINAPI hook_WinHttpConnect( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(pwszServerName, pos->from) == 0) { + if (match_domain(pwszServerName, pos->from)) { if(pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return NULL; @@ -558,7 +589,7 @@ static bool WINAPI hook_WinHttpCrackUrl( for (i = 0 ; i < dns_hook_nentries ; i++) { pos = &dns_hook_entries[i]; - if (_wcsicmp(pwszUrl, pos->from) == 0) { + if (match_domain(pwszUrl, pos->from)) { wchar_t* toAddr = pos->to; wchar_t titleBuffer[255]; diff --git a/platform/dns.c b/platform/dns.c index 692ee13..d32ce8d 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -126,7 +126,13 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) // Disable api/polling to the original servers - hr = dns_hook_push(L"amlog.sys-all.net", NULL); + hr = dns_hook_push(L"*.amlog.sys-all.net", NULL); + + if (FAILED(hr)) { + return hr; + } + + hr = dns_hook_push(L"*.d-amlog.sys-all.net", NULL); if (FAILED(hr)) { return hr; From 00b3d5b7bb3b8677eee8710a62d736012adcecf1 Mon Sep 17 00:00:00 2001 From: arcfox Date: Thu, 9 May 2024 23:37:20 +0800 Subject: [PATCH 101/204] unityhook: check for new entrypoint The new entrypoint has been introduced in UnityDoorstop 4.1.0, which is used by BepInEx 5.4.23. This commit check for new entrypoint to support new version of BepInEx. --- unityhook/doorstop.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index b1330ca..ff4d269 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -118,9 +118,19 @@ void doorstop_invoke(void* domain) { return; } - void *desc = mono_method_desc_new("*:Main", FALSE); + // BepInEx 5.4.23 has upgrade its doorstop version, + // which forces entrypoint to Doorstop.Entrypoint:Start + + void *desc = mono_method_desc_new("Doorstop.Entrypoint:Start", TRUE); void *method = mono_method_desc_search_in_image(desc, image); + if (!method) { + // Fallback to old entrypoint definition. + + desc = mono_method_desc_new("*:Main", FALSE); + method = mono_method_desc_search_in_image(desc, image); + } + if (!method) { dprintf("Unity: Assembly does not have a valid entrypoint.\n"); free(dll_path); From 517469a60c49c14c47ba238a4e00a2be915a8ed9 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 12 May 2024 19:36:08 +0200 Subject: [PATCH 102/204] switched to new capnhook, updated unityhook, added LED 15093 to MU3 --- cxbhook/led.c | 4 +- cxbhook/revio.c | 4 +- dist/fgo/segatools.ini | 1 - dist/mu3/segatools.ini | 3 + fgohook/fgo-dll.c | 2 +- fgohook/fgohook.def | 2 +- fgoio/fgoio.c | 4 +- fgoio/fgoio.h | 2 +- hooklib/meson.build | 2 - hooklib/procaddr.c | 125 ----------------------------- hooklib/procaddr.h | 18 ----- hooklib/reg.c | 165 +++++++++++++++++++++++++++++++++++++- hooklib/reg.h | 2 + hooklib/touch.c | 11 ++- hooklib/touch.h | 1 + meson.build | 7 +- mu3hook/config.c | 61 ++++++++++++++ mu3hook/config.h | 4 +- mu3hook/dllmain.c | 18 ++--- mu3hook/mu3-dll.c | 38 +++++++-- mu3hook/mu3-dll.h | 2 + mu3hook/mu3hook.def | 2 + mu3io/mu3io.c | 12 ++- mu3io/mu3io.h | 49 +++++++++++ subprojects/capnhook.wrap | 4 +- unityhook/doorstop.c | 4 +- unityhook/hook.c | 45 ++++++++++- 27 files changed, 406 insertions(+), 186 deletions(-) delete mode 100644 hooklib/procaddr.c delete mode 100644 hooklib/procaddr.h diff --git a/cxbhook/led.c b/cxbhook/led.c index be3f26f..b7d4f9b 100644 --- a/cxbhook/led.c +++ b/cxbhook/led.c @@ -5,7 +5,7 @@ #include "cxbhook/led.h" #include "cxbhook/cxb-dll.h" -#include "hooklib/procaddr.h" +#include "hook/procaddr.h" #include "hook/table.h" @@ -56,7 +56,7 @@ HRESULT led_hook_init(struct led_config *cfg) } dprintf("LED: Hook enabled.\n"); - return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms)); + return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms)); } static int my_cCommLamp_Open(char *port) diff --git a/cxbhook/revio.c b/cxbhook/revio.c index 601c75a..7b3d25b 100644 --- a/cxbhook/revio.c +++ b/cxbhook/revio.c @@ -6,7 +6,7 @@ #include "cxbhook/revio.h" #include "cxbhook/cxb-dll.h" -#include "hooklib/procaddr.h" +#include "hook/procaddr.h" #include "hook/table.h" @@ -89,7 +89,7 @@ HRESULT revio_hook_init(struct revio_config *cfg) } dprintf("Revio: Hook enabled.\n"); - return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms)); + return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms)); } static int my_cCommIo_Open(char *port) diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 2afe1fe..0884c2d 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -128,7 +128,6 @@ path= ; world. An improved solution will be provided later. [io4] -; Input API selection for JVS input emulator. ; Test button virtual-key code. Default is the F1 key. test=0x70 ; Service button virtual-key code. Default is the F2 key. diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index c55cbbb..1da77e9 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -73,6 +73,9 @@ dipsw1=1 enable=1 [unity] +; Enable Unity hook. This will allow you to run custom .NET code before the game +enable=1 + ; Path to a .NET DLL that should run before the game. Useful for loading ; modding frameworks such as BepInEx. targetAssembly= diff --git a/fgohook/fgo-dll.c b/fgohook/fgo-dll.c index dce25ab..991ec06 100644 --- a/fgohook/fgo-dll.c +++ b/fgohook/fgo-dll.c @@ -28,7 +28,7 @@ const struct dll_bind_sym fgo_dll_syms[] = { .sym = "fgo_io_led_init", .off = offsetof(struct fgo_dll, led_init), }, { - .sym = "fgo_io_led_set_leds", + .sym = "fgo_io_led_set_colors", .off = offsetof(struct fgo_dll, led_set_leds), } }; diff --git a/fgohook/fgohook.def b/fgohook/fgohook.def index 2f4c1c6..4f769fe 100644 --- a/fgohook/fgohook.def +++ b/fgohook/fgohook.def @@ -18,7 +18,7 @@ EXPORTS fgo_io_init fgo_io_poll fgo_io_led_init - fgo_io_led_set_leds + fgo_io_led_set_colors fwdlusb_open fwdlusb_close fwdlusb_listupPrinter diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index ff3e953..faba36c 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -145,7 +145,7 @@ HRESULT fgo_io_led_init(void) return S_OK; } -void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb) +void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb) { return; -} \ No newline at end of file +} diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h index 5a815a7..1adf6b7 100644 --- a/fgoio/fgoio.h +++ b/fgoio/fgoio.h @@ -83,4 +83,4 @@ HRESULT fgo_io_led_init(void); Exact layout is TBD. */ -void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb); +void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb); diff --git a/hooklib/meson.build b/hooklib/meson.build index 4f7f762..4a74e05 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -23,8 +23,6 @@ hooklib_lib = static_library( 'fdshark.h', 'path.c', 'path.h', - 'procaddr.c', - 'procaddr.h', 'reg.c', 'reg.h', 'setupapi.c', diff --git a/hooklib/procaddr.c b/hooklib/procaddr.c deleted file mode 100644 index 2409f28..0000000 --- a/hooklib/procaddr.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include - -#include "hooklib/procaddr.h" - -#include "hook/table.h" - -#include "util/dprintf.h" - -static struct proc_addr_table *proc_addr_hook_list; -static size_t proc_addr_hook_count; -static CRITICAL_SECTION proc_addr_hook_lock; -static bool proc_addr_hook_initted; - -static FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name); -static FARPROC (WINAPI *next_GetProcAddress)(HMODULE hModule, const char *name); -static void proc_addr_hook_init(void); - -static const struct hook_symbol win32_hooks[] = { - { - .name = "GetProcAddress", - .patch = my_GetProcAddress, - .link = (void **) &next_GetProcAddress - } -}; - -HRESULT proc_addr_table_push( - const char *target, - struct hook_symbol *syms, - size_t nsyms -) -{ - HRESULT hr; - struct proc_addr_table *new_item; - struct proc_addr_table *new_mem; - - proc_addr_hook_init(); - - EnterCriticalSection(&proc_addr_hook_lock); - - new_mem = realloc( - proc_addr_hook_list, - (proc_addr_hook_count + 1) * sizeof(struct proc_addr_table)); - - if (new_mem == NULL) { - hr = E_OUTOFMEMORY; - - LeaveCriticalSection(&proc_addr_hook_lock); - return hr; - } - - new_item = &new_mem[proc_addr_hook_count]; - new_item->name = target; - new_item->nsyms = nsyms; - new_item->syms = syms; - - proc_addr_hook_list = new_mem; - proc_addr_hook_count++; - hr = S_OK; - - LeaveCriticalSection(&proc_addr_hook_lock); - - return hr; -} - -static void proc_addr_hook_init(void) -{ - if (proc_addr_hook_initted) { - return; - } - - dprintf("ProcAddr: Hook init\n"); - proc_addr_hook_initted = true; - - InitializeCriticalSection(&proc_addr_hook_lock); - - hook_table_apply( - NULL, - "kernel32.dll", - win32_hooks, - _countof(win32_hooks)); -} - -FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name) -{ - uintptr_t ordinal = (uintptr_t) name; - char mod_path[PATH_MAX]; - char *mod_name; - const struct hook_symbol *sym; - FARPROC result = next_GetProcAddress(hModule, name); - - GetModuleFileNameA(hModule, mod_path, PATH_MAX); - mod_name = basename(mod_path); - - for (int i = 0; i < proc_addr_hook_count; i++) { - - if (strcmp(proc_addr_hook_list[i].name, mod_name) == 0) { - - for (int j = 0; j < proc_addr_hook_list[i].nsyms; j++) { - sym = &proc_addr_hook_list[i].syms[j]; - - if (ordinal > 0xFFFF) { - - if (strcmp(sym->name, name) == 0) { - - dprintf("ProcAddr: Hooking %s from %s\n", name, mod_name); - result = (FARPROC) sym->patch; - } - } - - else { - if (sym->ordinal == ordinal) { - - dprintf("ProcAddr: Hooking Ord %p from %s\n", (void *)ordinal, mod_name); - result = (FARPROC) sym->patch; - } - } - } - } - } - - return result; -} \ No newline at end of file diff --git a/hooklib/procaddr.h b/hooklib/procaddr.h deleted file mode 100644 index 750e154..0000000 --- a/hooklib/procaddr.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include -#include -#include - -#include "hook/table.h" - -struct proc_addr_table { - const char *name; - size_t nsyms; - struct hook_symbol *syms; -}; - -HRESULT proc_addr_table_push( - const char *target, - struct hook_symbol *syms, - size_t nsyms -); \ No newline at end of file diff --git a/hooklib/reg.c b/hooklib/reg.c index cc3c584..bc18dbb 100644 --- a/hooklib/reg.c +++ b/hooklib/reg.c @@ -7,6 +7,7 @@ #include "hook/table.h" #include "hooklib/reg.h" +#include "hook/procaddr.h" #include "util/dprintf.h" #include "util/str.h" @@ -99,6 +100,29 @@ static LSTATUS WINAPI hook_RegGetValueW( uint32_t *numData ); +static LSTATUS WINAPI hook_RegQueryInfoKeyW( + HKEY hKey, + LPWSTR lpClass, + LPDWORD lpcchClass, + LPDWORD lpReserved, + LPDWORD lpcSubKeys, + LPDWORD lpcbMaxSubKeyLen, + LPDWORD lpcbMaxClassLen, + LPDWORD lpcValues, + LPDWORD lpcbMaxValueNameLen, + LPDWORD lpcbMaxValueLen, + LPDWORD lpcbSecurityDescriptor, + PFILETIME lpftLastWriteTime); + +static LSTATUS WINAPI hook_RegEnumValueW( + HKEY hkey, + DWORD dwIndex, + LPWSTR lpValueName, + LPDWORD lpcchValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData); /* Link pointers */ static LSTATUS (WINAPI *next_RegOpenKeyExW)( @@ -155,6 +179,30 @@ static LSTATUS (WINAPI *next_RegGetValueW)( uint32_t *numData ); +static LSTATUS (WINAPI *next_RegQueryInfoKeyW)( + HKEY hKey, + LPWSTR lpClass, + LPDWORD lpcchClass, + LPDWORD lpReserved, + LPDWORD lpcSubKeys, + LPDWORD lpcbMaxSubKeyLen, + LPDWORD lpcbMaxClassLen, + LPDWORD lpcValues, + LPDWORD lpcbMaxValueNameLen, + LPDWORD lpcbMaxValueLen, + LPDWORD lpcbSecurityDescriptor, + PFILETIME lpftLastWriteTime); + +static LSTATUS (WINAPI *next_RegEnumValueW)( + HKEY hkey, + DWORD dwIndex, + LPWSTR lpValueName, + LPDWORD lpcchValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData); + static const struct hook_symbol reg_hook_syms[] = { { .name = "RegOpenKeyExW", @@ -184,6 +232,14 @@ static const struct hook_symbol reg_hook_syms[] = { .name = "RegGetValueW", .patch = hook_RegGetValueW, .link = (void **) &next_RegGetValueW, + }, { + .name = "RegQueryInfoKeyW", + .patch = hook_RegQueryInfoKeyW, + .link = (void **) &next_RegQueryInfoKeyW, + }, { + .name = "RegEnumValueW", + .patch = hook_RegEnumValueW, + .link = (void **) &next_RegEnumValueW, } }; @@ -254,11 +310,24 @@ static void reg_hook_init(void) InitializeCriticalSection(®_hook_lock); dprintf("Reg hook init\n"); + reg_hook_insert_hooks(NULL); + + proc_addr_table_push( + NULL, + "ADVAPI32.dll", + (struct hook_symbol *) reg_hook_syms, + _countof(reg_hook_syms)); + +} + +void reg_hook_insert_hooks(HMODULE target) +{ hook_table_apply( - NULL, + target, "advapi32.dll", reg_hook_syms, _countof(reg_hook_syms)); + } static LRESULT reg_hook_propagate_hr(HRESULT hr) @@ -331,6 +400,7 @@ static LSTATUS reg_hook_open_locked( /* Assume reg keys are referenced from a root key and not from some intermediary key */ key = ®_hook_keys[i]; + //dprintf("Reg: %ls vs %ls\n", name, key->name); if (key->root == parent && wstr_ieq(key->name, name)) { break; @@ -821,6 +891,99 @@ static LSTATUS WINAPI hook_RegGetValueW( return err; } +static LSTATUS WINAPI hook_RegQueryInfoKeyW( + HKEY hKey, + LPWSTR lpClass, + LPDWORD lpcchClass, + LPDWORD lpReserved, + LPDWORD lpcSubKeys, + LPDWORD lpcbMaxSubKeyLen, + LPDWORD lpcbMaxClassLen, + LPDWORD lpcValues, + LPDWORD lpcbMaxValueNameLen, + LPDWORD lpcbMaxValueLen, + LPDWORD lpcbSecurityDescriptor, + PFILETIME lpftLastWriteTime) +{ + struct reg_hook_key *key; + LSTATUS err; + + EnterCriticalSection(®_hook_lock); + + key = reg_hook_match_key_locked(hKey); + + /* Check if this is a virtualized registry key */ + + if (key == NULL) { + LeaveCriticalSection(®_hook_lock); + + return next_RegQueryInfoKeyW( + hKey, + lpClass, + lpcchClass, + lpReserved, + lpcSubKeys, + lpcbMaxSubKeyLen, + lpcbMaxClassLen, + lpcValues, + lpcbMaxValueNameLen, + lpcbMaxValueLen, + lpcbSecurityDescriptor, + lpftLastWriteTime); + } + + // This is the only one I've seen even be changed, so it's all I'm doing + // until I see otherwise. + *lpcValues = key->nvals; + LeaveCriticalSection(®_hook_lock); + return ERROR_SUCCESS; +} + +static LSTATUS WINAPI hook_RegEnumValueW( + HKEY hkey, + DWORD dwIndex, + LPWSTR lpValueName, + LPDWORD lpcchValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData) +{ + struct reg_hook_key *key; + HRESULT hr; + LSTATUS err; + + EnterCriticalSection(®_hook_lock); + + key = reg_hook_match_key_locked(hkey); + + /* Check if this is a virtualized registry key */ + + if (key == NULL) { + LeaveCriticalSection(®_hook_lock); + + return next_RegEnumValueW( + hkey, + dwIndex, + lpValueName, + lpcchValueName, + lpReserved, + lpType, + lpData, + lpcbData); + } + + if (dwIndex >= key->nvals) { + LeaveCriticalSection(®_hook_lock); + return ERROR_NO_MORE_ITEMS; // Pretty sure this is what it actually returns here? + } + + wcscpy_s(lpValueName, *lpcchValueName, key->vals[dwIndex].name); + *lpcchValueName = wcslen(key->vals[dwIndex].name); + LeaveCriticalSection(®_hook_lock); + return ERROR_SUCCESS; +} + HRESULT reg_hook_read_bin( void *bytes, uint32_t *nbytes, diff --git a/hooklib/reg.h b/hooklib/reg.h index eb280c6..20e3dda 100644 --- a/hooklib/reg.h +++ b/hooklib/reg.h @@ -12,6 +12,8 @@ struct reg_hook_val { uint32_t type; }; +void reg_hook_insert_hooks(HMODULE target); + HRESULT reg_hook_push_key( HKEY root, const wchar_t *name, diff --git a/hooklib/touch.c b/hooklib/touch.c index df6a9ea..a76692a 100644 --- a/hooklib/touch.c +++ b/hooklib/touch.c @@ -119,10 +119,19 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel defaultCursor = LoadCursorA(NULL, IDC_CROSS); memcpy(&touch_config, cfg, sizeof(*cfg)); - hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks)); + touch_hook_insert_hooks(NULL); dprintf("TOUCH: hook enabled.\n"); } +void touch_hook_insert_hooks(HMODULE target) +{ + hook_table_apply( + target, + "user32.dll", + touch_hooks, + _countof(touch_hooks)); +} + static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) { if (cursor == 0 && touch_config.cursor) return next_SetCursor(defaultCursor); diff --git a/hooklib/touch.h b/hooklib/touch.h index dad00ad..dcb9082 100644 --- a/hooklib/touch.h +++ b/hooklib/touch.h @@ -14,3 +14,4 @@ struct touch_screen_config { blah blah you know the drill by now. */ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self); +void touch_hook_insert_hooks(HMODULE target); diff --git a/meson.build b/meson.build index 90ac292..d5d28a6 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ add_project_arguments( '-D_WIN32_WINNT=_WIN32_WINNT_WIN7', '-DMINGW_HAS_SECURE_API=1', '-Wno-unused', + # '-ggdb', # Add debug information language: 'c', ) @@ -23,7 +24,6 @@ if cc.get_id() != 'msvc' add_project_arguments( '-ffunction-sections', '-fdata-sections', - '-flto', # Enable Link-Time Optimization language: 'c', ) @@ -32,8 +32,9 @@ if cc.get_id() != 'msvc' '-Wl,--exclude-all-symbols', '-Wl,--gc-sections', '-static-libgcc', - '-flto', # Enable Link-Time Optimization - '-Wl,-s', # Strip debug symbols + # '-ggdb', # Add debug information + '-lcrypt32', # Bcrypt needed for prashook + # '-Wl,-s', # Strip debug symbols language: 'c', ) endif diff --git a/mu3hook/config.c b/mu3hook/config.c index 290d5ae..32d4341 100644 --- a/mu3hook/config.c +++ b/mu3hook/config.c @@ -28,6 +28,66 @@ void mu3_dll_config_load( filename); } +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710A", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } +} + void mu3_hook_config_load( struct mu3_hook_config *cfg, const wchar_t *filename) @@ -40,6 +100,7 @@ void mu3_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); gfx_config_load(&cfg->gfx, filename); + led15093_config_load(&cfg->led15093, filename); vfd_config_load(&cfg->vfd, filename); mu3_dll_config_load(&cfg->dll, filename); unity_config_load(&cfg->unity, filename); diff --git a/mu3hook/config.h b/mu3hook/config.h index 930a766..b2094c2 100644 --- a/mu3hook/config.h +++ b/mu3hook/config.h @@ -3,7 +3,7 @@ #include #include "board/config.h" -// #include "board/led15093.h" +#include "board/led15093.h" #include "gfxhook/gfx.h" @@ -21,7 +21,7 @@ struct mu3_hook_config { struct dvd_config dvd; struct io4_config io4; struct gfx_config gfx; - // struct led15093_config led15093; + struct led15093_config led15093; struct vfd_config vfd; struct mu3_dll_config dll; struct unity_config unity; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index bd1ec2b..c4495c1 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -62,14 +62,18 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - /* - // Does not work, Unity moment - hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2); + hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = led15093_hook_init(&mu3_hook_cfg.led15093, + mu3_dll.led_init, mu3_dll.led_set_leds, 3, 1, 1, 2); if (FAILED(hr)) { return hr; } - */ hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod); @@ -83,12 +87,6 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod); - - if (FAILED(hr)) { - goto fail; - } - hr = mu3_io4_hook_init(&mu3_hook_cfg.io4); if (FAILED(hr)) { diff --git a/mu3hook/mu3-dll.c b/mu3hook/mu3-dll.c index 9e8e93e..6acf929 100644 --- a/mu3hook/mu3-dll.c +++ b/mu3hook/mu3-dll.c @@ -24,9 +24,28 @@ const struct dll_bind_sym mu3_dll_syms[] = { }, { .sym = "mu3_io_get_lever", .off = offsetof(struct mu3_dll, get_lever), + }, { + .sym = "mu3_io_led_init", + .off = offsetof(struct mu3_dll, led_init), + }, { + .sym = "mu3_io_led_set_colors", + .off = offsetof(struct mu3_dll, led_set_leds), } }; +/* Helper function to determine upon dll_bind failure whether the required functions were found + NOTE: relies on symbols order declared above */ +static HRESULT has_enough_symbols(uint16_t version, uint8_t count) +{ + if ( version <= 0x0100 && count == 5 ) + return S_OK; + + if ( version >= 0x0101 && count == 7 ) + return S_OK; + + return E_FAIL; +} + struct mu3_dll mu3_dll; // Copypasta DLL binding and diagnostic message boilerplate. @@ -86,16 +105,25 @@ HRESULT mu3_dll_init(const struct mu3_dll_config *cfg, HINSTANCE self) } sym = mu3_dll_syms; + const struct dll_bind_sym *init_sym = &sym[0]; + hr = dll_bind(&mu3_dll, src, &sym, _countof(mu3_dll_syms)); if (FAILED(hr)) { if (src != self) { - dprintf("Ongeki IO: Custom IO DLL does not provide function " - "\"%s\". Please contact your IO DLL's developer for " - "further assistance.\n", - sym->sym); + // Might still be ok depending on external dll API version + int bind_count = sym - init_sym; + if (has_enough_symbols(mu3_dll.api_version, bind_count) == S_OK) + { + hr = S_OK; + } else { + dprintf("Ongeki IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); - goto end; + goto end; + } } else { dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); } diff --git a/mu3hook/mu3-dll.h b/mu3hook/mu3-dll.h index 41f280f..2a919ea 100644 --- a/mu3hook/mu3-dll.h +++ b/mu3hook/mu3-dll.h @@ -11,6 +11,8 @@ struct mu3_dll { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint8_t *left, uint8_t *right); void (*get_lever)(int16_t *pos); + HRESULT (*led_init)(void); + void (*led_set_leds)(uint8_t board, uint8_t *rgb); }; struct mu3_dll_config { diff --git a/mu3hook/mu3hook.def b/mu3hook/mu3hook.def index d90abd5..0393a2e 100644 --- a/mu3hook/mu3hook.def +++ b/mu3hook/mu3hook.def @@ -23,3 +23,5 @@ EXPORTS mu3_io_get_opbtns mu3_io_init mu3_io_poll + mu3_io_led_init + mu3_io_led_set_colors diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index cb8d6e3..918c22d 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -21,7 +21,7 @@ const double MOUSE_SENSITIVITY = 0.5; uint16_t mu3_io_get_api_version(void) { - return 0x0100; + return 0x0101; } HRESULT mu3_io_init(void) @@ -195,3 +195,13 @@ void mu3_io_get_lever(int16_t *pos) *pos = mu3_lever_xpos; } } + +HRESULT mu3_io_led_init(void) +{ + return S_OK; +} + +void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb) +{ + return; +} diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h index a156038..522ef1b 100644 --- a/mu3io/mu3io.h +++ b/mu3io/mu3io.h @@ -1,5 +1,15 @@ #pragma once +/* + MU3 CUSTOM IO API + + Changelog: + + - 0x0100: Initial API version (assumed if chuni_io_get_api_version is not + exported) + - 0x0101: Added mu3_io_led_init and mu3_io_set_leds +*/ + #include #include @@ -18,6 +28,29 @@ enum { MU3_IO_GAMEBTN_MENU = 0x10, }; +enum { + /* These are the bitmasks to use when checking which + lights are triggered on incoming IO4 GPIO writes. */ + MU3_IO_LED_L1_R = 1 << 31, + MU3_IO_LED_L1_G = 1 << 28, + MU3_IO_LED_L1_B = 1 << 30, + MU3_IO_LED_L2_R = 1 << 27, + MU3_IO_LED_L2_G = 1 << 29, + MU3_IO_LED_L2_B = 1 << 26, + MU3_IO_LED_L3_R = 1 << 25, + MU3_IO_LED_L3_G = 1 << 24, + MU3_IO_LED_L3_B = 1 << 23, + MU3_IO_LED_R1_R = 1 << 22, + MU3_IO_LED_R1_G = 1 << 21, + MU3_IO_LED_R1_B = 1 << 20, + MU3_IO_LED_R2_R = 1 << 19, + MU3_IO_LED_R2_G = 1 << 18, + MU3_IO_LED_R2_B = 1 << 17, + MU3_IO_LED_R3_R = 1 << 16, + MU3_IO_LED_R3_G = 1 << 15, + MU3_IO_LED_R3_B = 1 << 14, +}; + /* Get the version of the Ongeki IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the @@ -83,3 +116,19 @@ void mu3_io_get_gamebtns(uint8_t *left, uint8_t *right); Minimum API version: 0x0100 */ void mu3_io_get_lever(int16_t *pos); + + +/* Initialize LED emulation. This function will be called before any + other mu3_io_led_*() function calls. + + 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 mu3_io_led_init(void); + +/* Update the RGB LEDs. + + Exact layout is TBD. */ + +void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb); diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index af30eae..584b4a1 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook -url = https://github.com/decafcode/capnhook -revision = 69f7e3b48c2e0ff5be1d7a83cdcc2597a458357b +url = https://github.com/Hay1tsme/capnhook +revision = 09306229f1fd09bae0e617865a26778d3537ff93 diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index ff4d269..1b94ad5 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -8,7 +8,7 @@ #include #include -#include "hooklib/procaddr.h" +#include "hook/procaddr.h" #include "util/dprintf.h" #include "doorstop.h" @@ -37,7 +37,7 @@ void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module) { memcpy(&unity_config, cfg, sizeof(*cfg)); load_mono_functions(module); - proc_addr_table_push(module_name, unity_mono_syms, _countof(unity_mono_syms)); + proc_addr_table_push(NULL, module_name, unity_mono_syms, _countof(unity_mono_syms)); doorstop_hook_initted = true; } diff --git a/unityhook/hook.c b/unityhook/hook.c index 060233b..02a1e38 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -2,7 +2,16 @@ #include #include "hook/table.h" +#include "hook/procaddr.h" +#include "hook/iohook.h" + +#include "hooklib/dll.h" #include "hooklib/path.h" +#include "hooklib/printer.h" +#include "hooklib/reg.h" +#include "hooklib/touch.h" +#include "hooklib/serial.h" + #include "util/dprintf.h" #include "doorstop.h" @@ -15,22 +24,35 @@ static const wchar_t *target_modules[] = { L"mono.dll", L"mono-2.0-bdwgc.dll", L"cri_ware_unity.dll", + L"SerialPortAPI.dll", + L"C300usb.dll", + L"C300FWDLusb.dll", + L"apmled.dll", + L"apmmount.dll", }; + static const size_t target_modules_len = _countof(target_modules); static void dll_hook_insert_hooks(HMODULE target); -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name); static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); +static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags); +static HMODULE (WINAPI *next_LoadLibraryExW)(const wchar_t *name, HANDLE hFile, DWORD dwFlags); static const struct hook_symbol unity_kernel32_syms[] = { { .name = "LoadLibraryW", - .patch = my_LoadLibraryW, + .patch = hook_LoadLibraryW, .link = (void **) &next_LoadLibraryW, - }, + }, { + .name = "LoadLibraryExW", + .patch = hook_LoadLibraryExW, + .link = (void **) &next_LoadLibraryExW, + } }; + void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { assert(cfg != NULL); @@ -57,7 +79,14 @@ static void dll_hook_insert_hooks(HMODULE target) { _countof(unity_kernel32_syms)); } -static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) { +static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags) +{ + // dprintf("Unity: LoadLibraryExW %ls\n", name); + return hook_LoadLibraryW(name); +} + +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) +{ const wchar_t *name_end; const wchar_t *target_module; bool already_loaded; @@ -107,6 +136,14 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) { dll_hook_insert_hooks(result); path_hook_insert_hooks(result); + + // printer_hook_insert_hooks(result); + + reg_hook_insert_hooks(result); + + proc_addr_insert_hooks(result); + serial_hook_apply_hooks(result); + iohook_apply_hooks(result); } } From b77ce7b4570b2698cc422acf50b5465d5d6a5177 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 12 May 2024 19:39:56 +0200 Subject: [PATCH 103/204] io3: added basic rotary input support --- board/io3.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++ board/io3.h | 1 + 2 files changed, 70 insertions(+) diff --git a/board/io3.c b/board/io3.c index 369714f..4bab05e 100644 --- a/board/io3.c +++ b/board/io3.c @@ -79,6 +79,11 @@ static HRESULT io3_cmd_read_analogs( struct const_iobuf *req_buf, struct iobuf *resp_buf); +static HRESULT io3_cmd_read_rotarys( + struct io3 *io3, + struct const_iobuf *req_buf, + struct iobuf *resp_buf); + static HRESULT io3_cmd_write_gpio( struct io3 *io3, struct const_iobuf *req_buf, @@ -116,6 +121,13 @@ static uint8_t io3_features[] = { 0x03, 8, 10, 0, + /* Feature : 0x04 : Rotary inputs + Param1 : 4 : Number of rotary channels + Param2 : 0 : N/A + Param3 : 0 : N/A */ + + 0x04, 4, 0, 0, + /* Feature : 0x12 : GPIO outputs Param1 : 3 : Number of ports (8 bits per port) Param2 : 0 : N/A @@ -218,6 +230,9 @@ static HRESULT io3_cmd( case JVS_CMD_READ_ANALOGS: return io3_cmd_read_analogs(io3, req, resp); + + case JVS_CMD_READ_ROTARYS: + return io3_cmd_read_rotarys(io3, req, resp); case JVS_CMD_WRITE_GPIO: return io3_cmd_write_gpio(io3, req, resp); @@ -536,6 +551,60 @@ static HRESULT io3_cmd_read_analogs( } +static HRESULT io3_cmd_read_rotarys( + struct io3 *io3, + struct const_iobuf *req_buf, + struct iobuf *resp_buf) +{ + struct jvs_req_read_rotarys req; + uint16_t rotarys[4]; + uint8_t i; + HRESULT hr; + + /* Read req */ + + hr = iobuf_read(req_buf, &req, sizeof(req)); + + if (FAILED(hr)) { + return hr; + } + + if (req.nrotarys > _countof(rotarys)) { + dprintf("JVS I/O: Invalid analog count %i\n", req.nrotarys); + + return E_FAIL; + } + + //dprintf("JVS I/O: Read rotarys, nrotarys=%i\n", req.nrotarys); + + /* Write report byte */ + + hr = iobuf_write_8(resp_buf, 0x01); + + if (FAILED(hr)) { + return hr; + } + + /* Write analogs */ + + memset(rotarys, 0, sizeof(rotarys)); + + if (io3->ops->read_rotarys != NULL) { + io3->ops->read_rotarys(io3->ops_ctx, rotarys, req.nrotarys); + } + + for (i = 0 ; i < req.nrotarys ; i++) { + hr = iobuf_write_be16(resp_buf, rotarys[i]); + + if (FAILED(hr)) { + return hr; + } + } + + return hr; + +} + static HRESULT io3_cmd_write_gpio( struct io3 *io3, struct const_iobuf *req_buf, diff --git a/board/io3.h b/board/io3.h index a094a2a..78fdca8 100644 --- a/board/io3.h +++ b/board/io3.h @@ -18,6 +18,7 @@ struct io3_ops { void (*write_gpio)(void *ctx, uint32_t state); void (*read_switches)(void *ctx, struct io3_switch_state *out); void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs); + void (*read_rotarys)(void *ctx, uint16_t *rotaries, uint8_t nrotaries); void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out); }; From 9fe98b227b910d38e10d301fbba26eb775e666f5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 12 May 2024 22:02:53 +0200 Subject: [PATCH 104/204] mu3: added lights hook --- board/io4.c | 8 +- board/io4.h | 3 + chuniio/config.c | 10 +-- chuniio/config.h | 9 +-- chuniio/ledoutput.c | 18 ++--- chuniio/pipeimpl.h | 1 + dist/chuni/segatools.ini | 28 +++---- dist/chusan/segatools.ini | 38 ++++----- dist/mu3/segatools.ini | 48 ++++++++++++ jvs/jvs-cmd.h | 6 ++ mu3hook/io4.c | 46 +++++++++++ mu3io/config.c | 23 ++++++ mu3io/config.h | 11 +++ mu3io/leddata.h | 23 ++++++ mu3io/ledoutput.c | 130 +++++++++++++++++++++++++++++++ mu3io/ledoutput.h | 20 +++++ mu3io/meson.build | 11 ++- mu3io/mu3io.c | 16 +++- mu3io/pipeimpl.c | 160 ++++++++++++++++++++++++++++++++++++++ mu3io/pipeimpl.h | 15 ++++ mu3io/serialimpl.c | 88 +++++++++++++++++++++ mu3io/serialimpl.h | 15 ++++ 22 files changed, 669 insertions(+), 58 deletions(-) create mode 100644 mu3io/leddata.h create mode 100644 mu3io/ledoutput.c create mode 100644 mu3io/ledoutput.h create mode 100644 mu3io/pipeimpl.c create mode 100644 mu3io/pipeimpl.h create mode 100644 mu3io/serialimpl.c create mode 100644 mu3io/serialimpl.h diff --git a/board/io4.c b/board/io4.c index 912f733..5c7d822 100644 --- a/board/io4.c +++ b/board/io4.c @@ -48,7 +48,7 @@ static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size"); struct io4_report_out { uint8_t report_id; uint8_t cmd; - uint8_t payload[62]; + uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN]; }; static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size"); @@ -223,7 +223,11 @@ static HRESULT io4_handle_write(struct irp *irp) return S_OK; case IO4_CMD_SET_GENERAL_OUTPUT: - dprintf("USB I/O: GPIO Out\n"); + // dprintf("USB I/O: GPIO Out\n"); + + if (io4_ops->write_gpio != NULL) { + return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN); + } return S_OK; diff --git a/board/io4.h b/board/io4.h index 1a6cc05..914c045 100644 --- a/board/io4.h +++ b/board/io4.h @@ -4,6 +4,8 @@ #include +#define IO4_REPORT_OUT_PAYLOAD_LEN 62 + enum { /* System buttons in button[0] */ @@ -24,6 +26,7 @@ struct io4_state { struct io4_ops { HRESULT (*poll)(void *ctx, struct io4_state *state); + HRESULT (*write_gpio)(uint8_t* payload, size_t len); }; HRESULT io4_hook_init( diff --git a/chuniio/config.c b/chuniio/config.c index c41ae99..aaa048e 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -57,11 +57,11 @@ void chuni_io_config_load( filename); } - cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename); - cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename); + cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename); + cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename); - cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename); - cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename); + cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename); + cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename); cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename); @@ -70,7 +70,7 @@ void chuni_io_config_load( L"serialPort", L"COM5", port_input, - 6, + _countof(port_input), filename); // Sanitize the output path. If it's a serial COM port, it needs to be prefixed diff --git a/chuniio/config.h b/chuniio/config.h index fc8884c..3eb8223 100644 --- a/chuniio/config.h +++ b/chuniio/config.h @@ -12,16 +12,15 @@ struct chuni_io_config { uint8_t vk_cell[32]; // Which ways to output LED information are enabled - bool led_output_pipe; - bool led_output_serial; + bool cab_led_output_pipe; + bool cab_led_output_serial; - bool slider_led_output_pipe; - bool slider_led_output_serial; + bool controller_led_output_pipe; + bool controller_led_output_serial; // The name of a COM port to output LED data on, in serial mode wchar_t led_serial_port[12]; int32_t led_serial_baud; - }; void chuni_io_config_load( diff --git a/chuniio/ledoutput.c b/chuniio/ledoutput.c index ab0187f..8cac5a3 100644 --- a/chuniio/ledoutput.c +++ b/chuniio/ledoutput.c @@ -48,15 +48,15 @@ HRESULT led_output_init(struct chuni_io_config* const cfg) led_escaped_buf[i].data_len = chuni_led_board_data_lens[i]; } - any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe - || config->led_output_serial || config->slider_led_output_serial; + any_outputs_enabled = config->cab_led_output_pipe || config->controller_led_output_pipe + || config->cab_led_output_serial || config->controller_led_output_serial; - if (config->led_output_pipe || config->slider_led_output_pipe) + if (config->cab_led_output_pipe || config->controller_led_output_pipe) { led_pipe_init(); // don't really care about errors here tbh } - if (config->led_output_serial || config->slider_led_output_serial) + if (config->cab_led_output_serial || config->controller_led_output_serial) { led_serial_init(config->led_serial_port, config->led_serial_baud); } @@ -106,13 +106,13 @@ void led_output_update(uint8_t board, const byte* rgb) if (board < 2) { - // billboard - if (config->led_output_pipe) + // billboard (cab) + if (config->cab_led_output_pipe) { led_pipe_update(escaped_data); } - if (config->led_output_serial) + if (config->cab_led_output_serial) { led_serial_update(escaped_data); } @@ -120,12 +120,12 @@ void led_output_update(uint8_t board, const byte* rgb) else { // slider - if (config->slider_led_output_pipe) + if (config->controller_led_output_pipe) { led_pipe_update(escaped_data); } - if (config->slider_led_output_serial) + if (config->controller_led_output_serial) { led_serial_update(escaped_data); } diff --git a/chuniio/pipeimpl.h b/chuniio/pipeimpl.h index 4f7a268..c95801f 100644 --- a/chuniio/pipeimpl.h +++ b/chuniio/pipeimpl.h @@ -4,6 +4,7 @@ Credits: somewhatlurker, skogaby */ + #pragma once #include diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 5497643..87d923d 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -63,20 +63,6 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 -; ----------------------------------------------------------------------------- -; Custom IO settings -; ----------------------------------------------------------------------------- - -[aimeio] -; To use a custom card reader IO DLL enter its path here. -; Leave empty if you want to use Segatools built-in keyboard input. -path= - -[chuniio] -; To use a custom Chunithm IO DLL enter its path here. -; Leave empty if you want to use Segatools built-in keyboard input. -path= - ; ----------------------------------------------------------------------------- ; LED settings ; ----------------------------------------------------------------------------- @@ -122,6 +108,20 @@ controllerLedOutputSerial=0 ; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[chuniio] +; To use a custom Chunithm IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index a5e3d51..f41f630 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -88,25 +88,6 @@ framed=0 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 -; ----------------------------------------------------------------------------- -; Custom IO settings -; ----------------------------------------------------------------------------- - -[aimeio] -; To use a custom card reader IO DLL (x64) enter its path here. -; Leave empty if you want to use Segatools built-in keyboard input. -path= - -[chuniio] -; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL. -; (will use chu2to3 engine internally) -;path= - -; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs. -; x86 chuniio to path32, x64 to path64. Both are necessary. -;path32= -;path64= - ; ----------------------------------------------------------------------------- ; LED settings ; ----------------------------------------------------------------------------- @@ -152,6 +133,25 @@ controllerLedOutputSerial=0 ; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL (x64) enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[chuniio] +; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL. +; (will use chu2to3 engine internally) +;path= + +; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs. +; x86 chuniio to path32, x64 to path64. Both are necessary. +;path32= +;path64= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 1da77e9..d7b8166 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -80,6 +80,54 @@ enable=1 ; modding frameworks such as BepInEx. targetAssembly= +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15093] +; Enable emulation of the 15093-06 controlled lights, which handle the air tower +; RGBs and the rear LED panel (billboard) on the cabinet. +enable=1 + +[led] +; Output billboard LED strip data to a named pipe called "\\.\pipe\ongeki_led" +cabLedOutputPipe=1 +; Output billboard LED strip data to serial +cabLedOutputSerial=0 + +; Output slider LED data to the named pipe +controllerLedOutputPipe=1 +; Output slider LED data to the serial port +controllerLedOutputSerial=0 + +; Serial port to send data to if using serial output. Default is COM5. +;serialPort=COM5 +; Baud rate for serial data +;serialBaud=921600 + +; Data output a sequence of bytes, with JVS-like framing. +; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere, +; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore +; it and use the next sent byte plus one instead. +; +; After the sync is one byte for the board number that was updated, followed by +; the red, green and blue values for each LED. +; +; Board 0 has 61 LEDs: +; [0]-[1]: left side button +; [2]-[8]: left pillar lower LEDs +; [9]-[17]: left pillar center LEDs +; [18]-[24]: left pillar upper LEDs +; [25]-[35]: billboard LEDs +; [36]-[42]: right pillar upper LEDs +; [43]-[51]: right pillar center LEDs +; [52]-[58]: right pillar lower LEDs +; [59]-[60]: right side button +; +; Board 1 has 6 LEDs: +; [0]-[5]: 3 left and 3 right controller buttons +; + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/jvs/jvs-cmd.h b/jvs/jvs-cmd.h index 0197c9f..65ad599 100644 --- a/jvs/jvs-cmd.h +++ b/jvs/jvs-cmd.h @@ -9,6 +9,7 @@ enum { JVS_CMD_READ_SWITCHES = 0x20, JVS_CMD_READ_COIN = 0x21, JVS_CMD_READ_ANALOGS = 0x22, + JVS_CMD_READ_ROTARYS = 0x23, JVS_CMD_WRITE_GPIO = 0x32, JVS_CMD_RESET = 0xF0, JVS_CMD_ASSIGN_ADDR = 0xF1, @@ -32,6 +33,11 @@ struct jvs_req_read_analogs { uint8_t nanalogs; }; +struct jvs_req_read_rotarys { + uint8_t cmd; + uint8_t nrotarys; +}; + struct jvs_req_reset { uint8_t cmd; uint8_t unknown; diff --git a/mu3hook/io4.c b/mu3hook/io4.c index 9515b50..1af69e7 100644 --- a/mu3hook/io4.c +++ b/mu3hook/io4.c @@ -11,10 +11,13 @@ #include "util/dprintf.h" static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state); +static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len); + static uint16_t coins; static const struct io4_ops mu3_io4_ops = { .poll = mu3_io4_poll, + .write_gpio = mu3_io4_write_gpio, }; HRESULT mu3_io4_hook_init(const struct io4_config *cfg) @@ -124,3 +127,46 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state) return S_OK; } + +static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len) +{ + // Just fast fail if there aren't enough bytes in the payload + if (len < 3) + return S_OK; + + // This command is used for lights in Ongeki, but it only contains button lights, + // and only in the first 3 bytes of the payload; everything else is padding to + // make the payload 62 bytes. The rest of the cabinet lights and the side button + // lights are handled separately, by the 15093 lights controller. + uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); + + // Since Sega uses an odd ordering for the first part of the bitfield, + // let's normalize the data and just send over bytes for the receiver + // to interpret as RGB values. + uint8_t rgb_out[6 * 3] = { + lights_data & MU3_IO_LED_L1_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L1_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L1_B ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L2_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L2_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L2_B ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L3_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L3_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_L3_B ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R1_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R1_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R1_B ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R2_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R2_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R2_B ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R3_R ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R3_G ? 0xFF : 0x00, + lights_data & MU3_IO_LED_R3_B ? 0xFF : 0x00, + }; + + mu3_io_led_set_colors(1, rgb_out); + + return S_OK; +} diff --git a/mu3io/config.c b/mu3io/config.c index 612c860..fd4b0a7 100644 --- a/mu3io/config.c +++ b/mu3io/config.c @@ -14,6 +14,8 @@ void mu3_io_config_load( assert(cfg != NULL); assert(filename != NULL); + wchar_t output_path_input[6]; + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); @@ -30,4 +32,25 @@ void mu3_io_config_load( cfg->vk_right_3 = GetPrivateProfileIntW(L"io4", L"right3", 'L', filename); cfg->vk_left_menu = GetPrivateProfileIntW(L"io4", L"leftMenu", 'U', filename); cfg->vk_right_menu = GetPrivateProfileIntW(L"io4", L"rightMenu", 'O', filename); + + cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename); + cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename); + + cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename); + cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename); + + cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename); + + GetPrivateProfileStringW( + L"led", + L"serialPort", + L"COM5", + output_path_input, + _countof(output_path_input), + filename); + + // Sanitize the output path. If it's a serial COM port, it needs to be prefixed + // with `\\.\`. + wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4); + wcsncat_s(cfg->led_serial_port, MAX_PATH, output_path_input, MAX_PATH); } diff --git a/mu3io/config.h b/mu3io/config.h index ff74c3b..328a460 100644 --- a/mu3io/config.h +++ b/mu3io/config.h @@ -22,6 +22,17 @@ struct mu3_io_config { uint8_t vk_right_3; uint8_t vk_left_menu; uint8_t vk_right_menu; + + // Which ways to output LED information are enabled + bool cab_led_output_pipe; + bool cab_led_output_serial; + + bool controller_led_output_pipe; + bool controller_led_output_serial; + + // The name of a COM port to output LED data on, in serial mode + wchar_t led_serial_port[12]; + int32_t led_serial_baud; }; void mu3_io_config_load( diff --git a/mu3io/leddata.h b/mu3io/leddata.h new file mode 100644 index 0000000..1dcf42d --- /dev/null +++ b/mu3io/leddata.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include + +#define LED_PACKET_FRAMING 0xE0 +#define LED_PACKET_ESCAPE 0xD0 +#define LED_NUM_MAX 66 +#define LED_BOARDS_TOTAL 2 +#define LED_OUTPUT_HEADER_SIZE 2 +#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped +#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX + +// This struct is used to send data related to the button and cab LEDs +struct _ongeki_led_data_buf_t { + byte framing; // Sync byte + uint8_t board; // LED output the data is for (0: cab, 1: control deck) + byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs + byte data_len; // How many bytes to output from the buffer +}; + +static byte ongeki_led_board_data_lens[LED_BOARDS_TOTAL] = {9*3, 6*3}; diff --git a/mu3io/ledoutput.c b/mu3io/ledoutput.c new file mode 100644 index 0000000..9c20d1a --- /dev/null +++ b/mu3io/ledoutput.c @@ -0,0 +1,130 @@ +#include + +#include +#include +#include + +#include "mu3io/config.h" +#include "mu3io/leddata.h" +#include "mu3io/ledoutput.h" +#include "mu3io/pipeimpl.h" +#include "mu3io/serialimpl.h" + +static struct _ongeki_led_data_buf_t mu3_led_unescaped_buf[LED_BOARDS_TOTAL]; +static struct _ongeki_led_data_buf_t mu3_led_escaped_buf[LED_BOARDS_TOTAL]; + +static bool mu3_led_output_is_init = false; +static struct mu3_io_config* mu3_io_config; +static bool mu3_led_any_outputs_enabled; + +HANDLE mu3_led_init_mutex; + +HRESULT mu3_led_output_init(struct mu3_io_config* const cfg) +{ + DWORD dwWaitResult = WaitForSingleObject(mu3_led_init_mutex, INFINITE); + if (dwWaitResult == WAIT_FAILED) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + else if (dwWaitResult != WAIT_OBJECT_0) + { + return E_FAIL; + } + + if (!mu3_led_output_is_init) + { + mu3_io_config = cfg; + + // Setup the framing bytes for the packets + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + mu3_led_unescaped_buf[i].framing = LED_PACKET_FRAMING; + mu3_led_unescaped_buf[i].board = i; + mu3_led_unescaped_buf[i].data_len = ongeki_led_board_data_lens[i]; + + mu3_led_escaped_buf[i].framing = LED_PACKET_FRAMING; + mu3_led_escaped_buf[i].board = i; + mu3_led_escaped_buf[i].data_len = ongeki_led_board_data_lens[i]; + } + + mu3_led_any_outputs_enabled = mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe + || mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial; + + if (mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe) + { + mu3_led_pipe_init(); // don't really care about errors here tbh + } + + if (mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial) + { + mu3_led_serial_init(mu3_io_config->led_serial_port, mu3_io_config->led_serial_baud); + } + } + + mu3_led_output_is_init = true; + + ReleaseMutex(mu3_led_init_mutex); + return S_OK; +} + +struct _ongeki_led_data_buf_t* escape_led_data(struct _ongeki_led_data_buf_t* unescaped) +{ + struct _ongeki_led_data_buf_t* out_struct = &mu3_led_escaped_buf[unescaped->board]; + + byte* in_buf = unescaped->data; + byte* out_buf = out_struct->data; + int i = 0; + int o = 0; + + while (i < unescaped->data_len) + { + byte b = in_buf[i++]; + if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE) + { + out_buf[o++] = LED_PACKET_ESCAPE; + b--; + } + out_buf[o++] = b; + } + + out_struct->data_len = o; + + return out_struct; +} + +void mu3_led_output_update(int board, const byte* rgb) +{ + if (board < 0 || board > 1 || !mu3_led_any_outputs_enabled) + { + return; + } + + memcpy(mu3_led_unescaped_buf[board].data, rgb, mu3_led_unescaped_buf[board].data_len); + struct _ongeki_led_data_buf_t* escaped_data = escape_led_data(&mu3_led_unescaped_buf[board]); + + if (board == 0) + { + // cab + if (mu3_io_config->cab_led_output_pipe) + { + mu3_led_pipe_update(escaped_data); + } + + if (mu3_io_config->cab_led_output_serial) + { + mu3_led_serial_update(escaped_data); + } + } + else + { + // slider + if (mu3_io_config->controller_led_output_pipe) + { + mu3_led_pipe_update(escaped_data); + } + + if (mu3_io_config->controller_led_output_serial) + { + mu3_led_serial_update(escaped_data); + } + } +} diff --git a/mu3io/ledoutput.h b/mu3io/ledoutput.h new file mode 100644 index 0000000..eb9e810 --- /dev/null +++ b/mu3io/ledoutput.h @@ -0,0 +1,20 @@ +/* + LED output functions + + Credits: + somewhatlurker, skogaby +*/ + +#pragma once + +#include + +#include +#include + +#include "mu3io/config.h" + +extern HANDLE mu3_led_init_mutex; + +HRESULT mu3_led_output_init(struct mu3_io_config* const cfg); +void mu3_led_output_update(int board, const byte* rgb); diff --git a/mu3io/meson.build b/mu3io/meson.build index 0b509bd..3a2b571 100644 --- a/mu3io/meson.build +++ b/mu3io/meson.build @@ -8,9 +8,16 @@ mu3io_lib = static_library( xinput_lib, ], sources : [ - 'mu3io.c', - 'mu3io.h', 'config.c', 'config.h', + 'leddata.h', + 'ledoutput.c', + 'ledoutput.h', + 'mu3io.c', + 'mu3io.h', + 'pipeimpl.c', + 'pipeimpl.h', + 'serialimpl.c', + 'serialimpl.h' ], ) diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index 918c22d..2658612 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -6,6 +6,8 @@ #include "mu3io/mu3io.h" #include "mu3io/config.h" +#include "mu3io/ledoutput.h" + #include "util/dprintf.h" static uint8_t mu3_opbtn; @@ -32,7 +34,17 @@ HRESULT mu3_io_init(void) dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse); dprintf("XInput: --- End configuration ---\n"); - return S_OK; + mu3_led_init_mutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (mu3_led_init_mutex == NULL) + { + return E_FAIL; + } + + return mu3_led_output_init(&mu3_io_cfg); } HRESULT mu3_io_poll(void) @@ -203,5 +215,5 @@ HRESULT mu3_io_led_init(void) void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb) { - return; + mu3_led_output_update(board, rgb); } diff --git a/mu3io/pipeimpl.c b/mu3io/pipeimpl.c new file mode 100644 index 0000000..7010601 --- /dev/null +++ b/mu3io/pipeimpl.c @@ -0,0 +1,160 @@ +#include + +#include +#include +#include + +#include "mu3io/leddata.h" +#include "mu3io/pipeimpl.h" + +static bool mu3_pipe_update[LED_BOARDS_TOTAL]; + +// incoming data is copied into these to ensure it isn't written during output +static struct _ongeki_led_data_buf_t mu3_pipe_write_buf[LED_BOARDS_TOTAL]; +static HANDLE mu3_pipe_write_mutex; + +static HRESULT mu3_pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize) +{ + *hPipe = INVALID_HANDLE_VALUE; + + *hPipe = CreateNamedPipeW( + lpszPipename, // pipe name + PIPE_ACCESS_OUTBOUND, // read/write access + PIPE_TYPE_BYTE | // byte type pipe + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + dwBufSize, // output buffer size + 0, // input buffer size + 0, // client time-out + NULL); // default security attribute + + if (*hPipe == INVALID_HANDLE_VALUE) + { + return E_FAIL; + } + + return S_OK; +} + +static HRESULT mu3_pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize) +{ + DWORD cbWritten = 0; + + bool fSuccess = WriteFile( + hPipe, + lpBuffer, + dwSize, + &cbWritten, + NULL); + + if (!fSuccess || cbWritten != dwSize) + { + DWORD last_err = GetLastError(); + return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL; + } + + return S_OK; +} + +static unsigned int __stdcall mu3_io_led_pipe_thread_proc(void *ctx) +{ + HANDLE hPipe; + LPCWSTR lpszPipename = L"\\\\.\\pipe\\ongeki_led"; + + while (true) + { + hPipe = INVALID_HANDLE_VALUE; + + if (mu3_pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK) + { + continue; + } + + // wait for a connection to the pipe + bool fConnected = ConnectNamedPipe(hPipe, NULL) ? + true : (GetLastError() == ERROR_PIPE_CONNECTED); + + while (fConnected) + { + if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0) + { + continue; + } + + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + if (mu3_pipe_update[i]) + { + HRESULT result = mu3_pipe_write( + hPipe, + &mu3_pipe_write_buf[i], + LED_OUTPUT_HEADER_SIZE + mu3_pipe_write_buf[i].data_len); + + if (result != S_OK) + { + //if (result == E_ABORT) + //{ + fConnected = false; + //} + break; + } + + mu3_pipe_update[i] = false; + } + } + + ReleaseMutex(mu3_pipe_write_mutex); + } + + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + CloseHandle(hPipe); + } + + return 0; +} + +HRESULT mu3_led_pipe_init() +{ + mu3_pipe_write_mutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (mu3_pipe_write_mutex == NULL) + { + return E_FAIL; + } + + // clear out update bools + for (int i = 0; i < LED_BOARDS_TOTAL; i++) { + mu3_pipe_update[i] = false; + } + + _beginthreadex( + NULL, + 0, + mu3_io_led_pipe_thread_proc, + 0, + 0, + NULL); + + return S_OK; +} + +void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data) +{ + if (data->board > 1) + { + return; + } + + if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0) + { + return; + } + + memcpy(&mu3_pipe_write_buf[data->board], data, sizeof(struct _ongeki_led_data_buf_t)); + mu3_pipe_update[data->board] = true; + + ReleaseMutex(mu3_pipe_write_mutex); +} diff --git a/mu3io/pipeimpl.h b/mu3io/pipeimpl.h new file mode 100644 index 0000000..cb5162a --- /dev/null +++ b/mu3io/pipeimpl.h @@ -0,0 +1,15 @@ +/* + Pipe implementation for chuniio + + Credits: + somewhatlurker, skogaby +*/ + +#pragma once + +#include + +#include "mu3io/leddata.h" + +HRESULT mu3_led_pipe_init(); +void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data); diff --git a/mu3io/serialimpl.c b/mu3io/serialimpl.c new file mode 100644 index 0000000..6ad07a6 --- /dev/null +++ b/mu3io/serialimpl.c @@ -0,0 +1,88 @@ +#include + +#include +#include +#include + +#include "mu3io/leddata.h" +#include "mu3io/serialimpl.h" + +#include "util/dprintf.h" + +static HANDLE mu3_serial_port; + +HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud) +{ + // Setup the serial communications + BOOL status; + + mu3_serial_port = CreateFileW(led_com, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (mu3_serial_port == INVALID_HANDLE_VALUE) + { + dprintf("Ongeki Serial LEDs: Failed to open COM port (attempted on %S)\n", led_com); + return E_FAIL; + } + + DCB dcb_serial_params = { 0 }; + dcb_serial_params.DCBlength = sizeof(dcb_serial_params); + status = GetCommState(mu3_serial_port, &dcb_serial_params); + + dcb_serial_params.BaudRate = baud; + dcb_serial_params.ByteSize = 8; + dcb_serial_params.StopBits = ONESTOPBIT; + dcb_serial_params.Parity = NOPARITY; + SetCommState(mu3_serial_port, &dcb_serial_params); + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + SetCommTimeouts(mu3_serial_port, &timeouts); + + if (!status) + { + return E_FAIL; + } + + return S_OK; +} + +void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data) +{ + if (data->board > 1) + { + return; + } + + if (mu3_serial_port != INVALID_HANDLE_VALUE) + { + DWORD bytes_written = 0; + + BOOL status = WriteFile( + mu3_serial_port, + data, + LED_OUTPUT_HEADER_SIZE + data->data_len, + &bytes_written, + NULL); + + if (!status) + { + DWORD last_err = GetLastError(); + dprintf("Ongeki Serial LEDs: Serial port write failed -- %d\n", (int) last_err); + } + } + else + { + dprintf("Ongeki Serial LEDs: Invalid serial port handle\n"); + } +} diff --git a/mu3io/serialimpl.h b/mu3io/serialimpl.h new file mode 100644 index 0000000..151d042 --- /dev/null +++ b/mu3io/serialimpl.h @@ -0,0 +1,15 @@ +/* + Serial LED implementation for chuniio + + Credits: + somewhatlurker, skogaby +*/ + +#pragma once + +#include + +#include "mu3io/leddata.h" + +HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud); +void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data); From 3bfb046afca1a5716b544c8789e5af2be0dabc9f Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 15 May 2024 21:42:15 +0200 Subject: [PATCH 105/204] mu3, chusan: improved library doc --- chuniio/chuniio.h | 12 ++++++++++-- dist/mai2/segatools.ini | 21 ++++++++++++--------- mu3io/mu3io.h | 29 +++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index e149a52..8c575c9 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -163,9 +163,17 @@ HRESULT chuni_io_led_init(void); Chunithm uses two chains/boards with WS2811 protocol (each logical led corresponds to 3 physical leds). board 0 is on the left side and board 1 on the right side of the cab - left side has 5*10 rgb values for the billboard, followed by 3 rgb values for the air tower - right side has 6*10 rgb values for the billboard, followed by 3 rgb values for the air tower + Board 0 has 53 LEDs: + [0]-[49]: snakes through left half of billboard (first column starts at top) + [50]-[52]: left side partition LEDs + Board 1 has 63 LEDs: + [0]-[59]: right half of billboard (first column starts at bottom) + [60]-[62]: right side partition LEDs + + Board 2 is the slider and has 31 LEDs: + [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers + Each rgb value is comprised of 3 bytes in R,G,B order NOTE: billboard strips have alternating direction (bottom to top, top to bottom, ...) diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index ed8cc0a..596a295 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -69,6 +69,18 @@ freeplay=0 ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + +[unity] +; Enable Unity hook. This will allow you to run custom .NET code before the game +enable=1 + +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- @@ -83,15 +95,6 @@ path= ; Leave empty if you want to use Segatools built-in keyboard input. path= -; ----------------------------------------------------------------------------- -; Misc. hook settings -; ----------------------------------------------------------------------------- - -[unity] -; Path to a .NET DLL that should run before the game. Useful for loading -; modding frameworks such as BepInEx. -targetAssembly= - ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h index 522ef1b..b5f2c10 100644 --- a/mu3io/mu3io.h +++ b/mu3io/mu3io.h @@ -123,12 +123,33 @@ void mu3_io_get_lever(int16_t *pos); All subsequent calls may originate from arbitrary threads and some may overlap with each other. Ensuring synchronization inside your IO DLL is - your responsibility. */ + your responsibility. + + Minimum API version: 0x0101 */ HRESULT mu3_io_led_init(void); -/* Update the RGB LEDs. - - Exact layout is TBD. */ +/* Update the RGB LEDs. rgb is a pointer to an array of up to 61 * 3 = 183 bytes. + + ONGEKI uses one board with WS2811 protocol (each logical led corresponds to 3 + physical leds). Board 0 is used for all cab lights and both WAD button lights. + + Board 0 has 61 LEDs: + [0]-[1]: left side button + [2]-[8]: left pillar lower LEDs + [9]-[17]: left pillar center LEDs + [18]-[24]: left pillar upper LEDs + [25]-[35]: billboard LEDs + [36]-[42]: right pillar upper LEDs + [43]-[51]: right pillar center LEDs + [52]-[58]: right pillar lower LEDs + [59]-[60]: right side button + + Board 1 has 6 LEDs: + [0]-[5]: 3 left and 3 right controller buttons + + Each rgb value is comprised of 3 bytes in R,G,B order + + Minimum API version: 0x0101 */ void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb); From d8b3d418093a3e6161d84e19a94715cab0c42ce1 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 16 May 2024 08:10:05 +0200 Subject: [PATCH 106/204] mu3: hotfix for calling `mu3_io_led_set_colors` --- chusanhook/chuni-dll.c | 2 +- mu3hook/io4.c | 2 +- mu3io/mu3io.h | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c index e02b60b..0e7c634 100644 --- a/chusanhook/chuni-dll.c +++ b/chusanhook/chuni-dll.c @@ -170,7 +170,7 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self) "\"%s\". Please contact your IO DLL's developer for " "further assistance.\n", sym->sym); - dprintf("imported %d symbols\n",bind_count); + dprintf("imported %d symbols\n", bind_count); goto end; } } else { diff --git a/mu3hook/io4.c b/mu3hook/io4.c index 1af69e7..dfa7ad8 100644 --- a/mu3hook/io4.c +++ b/mu3hook/io4.c @@ -166,7 +166,7 @@ static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len) lights_data & MU3_IO_LED_R3_B ? 0xFF : 0x00, }; - mu3_io_led_set_colors(1, rgb_out); + mu3_dll.led_set_leds(1, rgb_out); return S_OK; } diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h index b5f2c10..2f3b263 100644 --- a/mu3io/mu3io.h +++ b/mu3io/mu3io.h @@ -117,7 +117,6 @@ void mu3_io_get_gamebtns(uint8_t *left, uint8_t *right); void mu3_io_get_lever(int16_t *pos); - /* Initialize LED emulation. This function will be called before any other mu3_io_led_*() function calls. @@ -148,7 +147,11 @@ HRESULT mu3_io_led_init(void); Board 1 has 6 LEDs: [0]-[5]: 3 left and 3 right controller buttons - Each rgb value is comprised of 3 bytes in R,G,B order + Each rgb value is comprised of 3 bytes in R,G,B order. The tricky part is + that the board 0 is called from mu3 and the board 1 is called from amdaemon. + So the library must be able to handle both calls, using shared memory f.e. + This is up to the developer to decide how to handle this, recommended way is + to use the amdaemon process as the main one and the mu3 call as a sub one. Minimum API version: 0x0101 */ From 9353c9872fb97f0258c5fced530843079d1178b9 Mon Sep 17 00:00:00 2001 From: zaphkito Date: Sun, 19 May 2024 09:37:57 +0000 Subject: [PATCH 107/204] dns: added CHN DNS block --- platform/dns.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/platform/dns.c b/platform/dns.c index d32ce8d..2e8f64b 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -105,6 +105,21 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) hr = dns_hook_push(L"shop.tfps.thincacloud.com", cfg->startup); + if (FAILED(hr)) { + return hr; + } + + // CHN + // PowerOn + hr = dns_hook_push(L"at.sys-all.cn", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + + // WeChat AimeDB Server + hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb); + if (FAILED(hr)) { return hr; } From b0f307f427c600376f868934488d6fe751124e65 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 9 Jun 2024 00:50:54 +0200 Subject: [PATCH 108/204] Fixed option loading, thanks @Hay1tsme, close #16 --- cmhook/dllmain.c | 12 +++++----- mu3io/mu3io.h | 2 +- platform/platform.c | 2 +- platform/vfs.c | 54 ++++++++++++++++++++++++++++++++++++++++++--- platform/vfs.h | 2 +- unityhook/hook.c | 6 ++--- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 687601a..65556da 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -55,6 +55,12 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } + hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod); if (FAILED(hr)) { @@ -67,12 +73,6 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod); - - if (FAILED(hr)) { - goto fail; - } - hr = cm_io4_hook_init(&cm_hook_cfg.io4); if (FAILED(hr)) { diff --git a/mu3io/mu3io.h b/mu3io/mu3io.h index 2f3b263..1fddac0 100644 --- a/mu3io/mu3io.h +++ b/mu3io/mu3io.h @@ -151,7 +151,7 @@ HRESULT mu3_io_led_init(void); that the board 0 is called from mu3 and the board 1 is called from amdaemon. So the library must be able to handle both calls, using shared memory f.e. This is up to the developer to decide how to handle this, recommended way is - to use the amdaemon process as the main one and the mu3 call as a sub one. + to use the amdaemon process as the main one and the mu3 process as a sub one. Minimum API version: 0x0101 */ diff --git a/platform/platform.c b/platform/platform.c index 6b11c2c..5a1b5f6 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -76,7 +76,7 @@ HRESULT platform_hook_init( return hr; } - hr = vfs_hook_init(&cfg->vfs); + hr = vfs_hook_init(&cfg->vfs, game_id); if (FAILED(hr)) { return hr; diff --git a/platform/vfs.c b/platform/vfs.c index c44bbb0..26e4d34 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -9,6 +9,9 @@ #include "hooklib/path.h" #include "hooklib/reg.h" +#include "hook/procaddr.h" +#include "hook/table.h" + #include "platform/vfs.h" #include "util/dprintf.h" @@ -31,6 +34,26 @@ static HRESULT vfs_path_hook_option( static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); +static wchar_t* hook_System_getAppRootPath(); +static wchar_t* (*next_System_getAppRootPath)(); + +static wchar_t* hook_AppImage_getOptionMountRootPath(); +static wchar_t* (*next_AppImage_getOptionMountRootPath)(); + +static const struct hook_symbol amdaemon_syms[] = { + { + .name = "System_getAppRootPath", + .patch = hook_System_getAppRootPath, + .link = (void **) &next_System_getAppRootPath, + }, + { + .name = "AppImage_getOptionMountRootPath", + .patch = hook_AppImage_getOptionMountRootPath, + .link = (void **) &next_AppImage_getOptionMountRootPath, + }, +}; + +static wchar_t game[5] = {0}; static wchar_t vfs_nthome_real[MAX_PATH]; static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; @@ -55,7 +78,7 @@ static const struct reg_hook_val vfs_reg_vals[] = { static struct vfs_config vfs_config; -HRESULT vfs_hook_init(const struct vfs_config *config) +HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id) { wchar_t temp[MAX_PATH]; size_t nthome_len; @@ -68,6 +91,8 @@ HRESULT vfs_hook_init(const struct vfs_config *config) return S_FALSE; } + mbstowcs(game, game_id, 4); + if (config->amfs[0] == L'\0') { dprintf("Vfs: FATAL: AMFS path not specified in INI file\n"); @@ -175,6 +200,13 @@ HRESULT vfs_hook_init(const struct vfs_config *config) return hr; } + proc_addr_table_push( + NULL, + "amdaemon_api.dll", + amdaemon_syms, + _countof(amdaemon_syms) + ); + return S_OK; } @@ -287,8 +319,6 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) } switch (src[0]) { - // case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it - // case L'd': case L'e': case L'E': redir = vfs_config.amfs; @@ -479,3 +509,21 @@ static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, L"Y:\\"); } + +static wchar_t* hook_System_getAppRootPath() +{ + wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); + wcscpy_s(path, MAX_PATH, vfs_config.appdata); + wcscat_s(path, MAX_PATH, game); + wcscat_s(path, MAX_PATH, L"\\"); + + return path; +} + +static wchar_t* hook_AppImage_getOptionMountRootPath() +{ + wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); + wcscpy_s(path, MAX_PATH, vfs_config.option); + + return path; +} diff --git a/platform/vfs.h b/platform/vfs.h index 8767305..a7e513f 100644 --- a/platform/vfs.h +++ b/platform/vfs.h @@ -12,4 +12,4 @@ struct vfs_config { wchar_t option[MAX_PATH]; }; -HRESULT vfs_hook_init(const struct vfs_config *config); +HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id); diff --git a/unityhook/hook.c b/unityhook/hook.c index 02a1e38..bd380f9 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -24,11 +24,13 @@ static const wchar_t *target_modules[] = { L"mono.dll", L"mono-2.0-bdwgc.dll", L"cri_ware_unity.dll", + L"amdaemon_api.dll", L"SerialPortAPI.dll", L"C300usb.dll", L"C300FWDLusb.dll", L"apmled.dll", - L"apmmount.dll", + L"HKBSys_api.dll", + L"amptw.dll" }; static const size_t target_modules_len = _countof(target_modules); @@ -138,9 +140,7 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) path_hook_insert_hooks(result); // printer_hook_insert_hooks(result); - reg_hook_insert_hooks(result); - proc_addr_insert_hooks(result); serial_hook_apply_hooks(result); iohook_apply_hooks(result); From 7d3cab256b0afa0bfe6a1fcae13e5ca446950900 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Thu, 20 Jun 2024 01:22:01 +0100 Subject: [PATCH 109/204] Add configurable debug logging --- .gitignore | 3 ++ Makefile | 9 ++++-- amex/jvs.c | 4 +-- board/io3.c | 4 +-- board/led15093.c | 14 +++++----- board/sg-nfc.c | 4 +-- board/sg-reader.c | 4 +-- carolhook/controlbd.c | 14 +++++----- carolhook/ledbd.c | 4 +-- carolhook/touch.c | 10 +++---- chunihook/slider.c | 4 +-- chusanhook/slider.c | 4 +-- divahook/slider.c | 4 +-- jvs/jvs-util.c | 4 +-- mercuryhook/touch.c | 18 ++++++------ meson.build | 37 ++++++++++++++++++++++++ meson.options | 65 +++++++++++++++++++++++++++++++++++++++++++ platform/clock.c | 2 +- 18 files changed, 159 insertions(+), 49 deletions(-) create mode 100644 meson.options diff --git a/.gitignore b/.gitignore index 5b84f6e..d42760f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ build/ # External dependencies subprojects/capnhook + +# For enabling debug logging on local builds +MesonLocalOptions.mk diff --git a/Makefile b/Makefile index a05bb64..66a6e24 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,11 @@ DOC_DIR := doc DIST_DIR := dist +# Add "-D[option]=[value]" here as necessary +MESON_OPTIONS := +# For options that shouldn't be committed +include MesonLocalOptions.mk + # ----------------------------------------------------------------------------- # Targets # ----------------------------------------------------------------------------- @@ -19,9 +24,9 @@ include Package.mk .PHONY: build # Build the project build: - $(V)meson --cross cross-mingw-32.txt $(BUILD_DIR_32) + $(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-32.txt $(BUILD_DIR_32) $(V)ninja -C $(BUILD_DIR_32) - $(V)meson --cross cross-mingw-64.txt $(BUILD_DIR_64) + $(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-64.txt $(BUILD_DIR_64) $(V)ninja -C $(BUILD_DIR_64) .PHONY: dist # Build and create a zip distribution package diff --git a/amex/jvs.c b/amex/jvs.c index 40d9673..dc55137 100644 --- a/amex/jvs.c +++ b/amex/jvs.c @@ -185,14 +185,14 @@ static HRESULT jvs_ioctl_sense(struct irp *irp) static HRESULT jvs_ioctl_transact(struct irp *irp) { -#if 0 +#if defined(LOG_JVS) dprintf("\nJVS Port: Outbound frame:\n"); dump_const_iobuf(&irp->write); #endif jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read); -#if 0 +#if defined(LOG_JVS) dprintf("JVS Port: Inbound frame:\n"); dump_iobuf(&irp->read); dprintf("\n"); diff --git a/board/io3.c b/board/io3.c index 4bab05e..24d1b5e 100644 --- a/board/io3.c +++ b/board/io3.c @@ -230,7 +230,7 @@ static HRESULT io3_cmd( case JVS_CMD_READ_ANALOGS: return io3_cmd_read_analogs(io3, req, resp); - + case JVS_CMD_READ_ROTARYS: return io3_cmd_read_rotarys(io3, req, resp); @@ -390,7 +390,7 @@ static HRESULT io3_cmd_read_switches( return hr; } -#if 0 +#if defined(LOG_IO3) dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n", req.num_players, req.bytes_per_player); diff --git a/board/led15093.c b/board/led15093.c index 606ce27..f92a6f2 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -1,6 +1,6 @@ /* SEGA 837-15093-XX LED Controller Board emulator - + Supported variants: 837-15093 @@ -106,7 +106,7 @@ static uint8_t led15093_host_adr = 1; static io_led_init_t led_init; static io_led_set_leds_t set_leds; -HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, +HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) { @@ -236,12 +236,12 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) } } */ - + if (irp->op == IRP_OP_OPEN) { dprintf("LED 15093: Starting backend DLL\n"); // int res = led_init(); hr = led_init(); - + /* if (res != 0) { dprintf("LED 15093: Backend error, LED board disconnected: " @@ -267,7 +267,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_LED15093) dprintf("TX Buffer:\n"); dump_iobuf(&boarduart->written); #endif @@ -294,7 +294,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) return hr; } -#if 0 +#if defined(LOG_LED15093) dprintf("Deframe Buffer:\n"); dump_iobuf(&req_iobuf); #endif @@ -717,7 +717,7 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set resp.status = v->status_code; if (req->cmd == LED_15093_CMD_SET_IMM_LED) { resp.cmd = LED_15093_CMD_SET_IMM_LED; - } + } // else { // resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY; // } diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 8f7c9bd..1f023be 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -420,7 +420,7 @@ static HRESULT sg_nfc_cmd_felica_encap( f_res.nbytes = sizeof(res->payload); f_res.pos = 1; -#if 0 +#if defined(LOG_NFC) dprintf("FELICA OUTBOUND:\n"); dump_const_iobuf(&f_req); #endif @@ -434,7 +434,7 @@ static HRESULT sg_nfc_cmd_felica_encap( sg_res_init(&res->res, &req->req, f_res.pos); res->payload[0] = f_res.pos; -#if 0 +#if defined(LOG_NFC) dprintf("FELICA INBOUND:\n"); dump_iobuf(&f_res); #endif diff --git a/board/sg-reader.c b/board/sg-reader.c index 24df4df..bcbef56 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -115,14 +115,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp) { HRESULT hr; -#if 0 +#if defined(LOG_NFC) if (irp->op == IRP_OP_WRITE) { dprintf("WRITE:\n"); dump_const_iobuf(&irp->write); } #endif -#if 0 +#if defined(LOG_NFC) if (irp->op == IRP_OP_READ) { dprintf("READ:\n"); dump_iobuf(&sg_reader_uart.readable); diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index 63a65f4..240e35b 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -78,7 +78,7 @@ static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobu uint8_t checksum_pos = src->pos - 1; uint8_t calculated_checksum = 0; uint8_t checksum = 0; - + if (src->pos < 6) { dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos); return SEC_E_BUFFER_TOO_SMALL; @@ -137,7 +137,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) for (;;) { if (controlbd_uart.written.bytes[0] == 0xE0) { -#if 0 +#if defined(LOG_CAROL_CONTROL_BD) dprintf("Control Board: TX Buffer:\n"); dump_iobuf(&controlbd_uart.written); #endif @@ -147,12 +147,12 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) return hr; } - hr = controlbd_req_dispatch(&req); + hr = controlbd_req_dispatch(&req); if (FAILED(hr)) { dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); return hr; } -#if 0 +#if defined(LOG_CAROL_CONTROL_BD) dprintf("Control Board: RX Buffer:\n"); dump_iobuf(&controlbd_uart.readable); #endif @@ -206,7 +206,7 @@ static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req) case CONTROLBD_CMD_FIRM_SUM: return controlbd_req_firmware_checksum(); - case CONTROLBD_CMD_TIMEOUT: + case CONTROLBD_CMD_TIMEOUT: dprintf("Control Board: Acknowledge Timeout\n"); return controlbd_req_ack_any(req->hdr.cmd); @@ -278,7 +278,7 @@ static HRESULT controlbd_req_get_board_info(void) resp.rev = 0x90; resp.bfr_size = 0x0001; resp.ack = 1; - + strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 "); strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 "); resp.chip_no[5] = 0xFF; @@ -317,7 +317,7 @@ static HRESULT controlbd_req_polling(const struct controlbd_req_any *req) resp.unk7 = 3; resp.unk8 = 1; resp.unk9 = 1; - + resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge resp.coord_x = 0x0; resp.coord_y = 0x0; diff --git a/carolhook/ledbd.c b/carolhook/ledbd.c index 1513359..58de42a 100644 --- a/carolhook/ledbd.c +++ b/carolhook/ledbd.c @@ -94,7 +94,7 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_CAROL_LED_BD) dprintf("LED Board: TX Buffer:\n"); dump_iobuf(&ledbd_uart.written); #endif @@ -165,4 +165,4 @@ static HRESULT ledbd_req_unkF0(uint8_t cmd) iobuf_write(&ledbd_uart.readable, resp, 16); return S_OK; -} \ No newline at end of file +} diff --git a/carolhook/touch.c b/carolhook/touch.c index ba61e42..70c2e92 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -54,7 +54,7 @@ HRESULT touch_hook_init(const struct touch_config *cfg) if (!cfg->enable) { return S_OK; } - + InitializeCriticalSection(&touch_lock); uart_init(&touch_uart, 1); @@ -112,7 +112,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_CAROL_TOUCH) dprintf("Touchscreen: TX Buffer:\n"); dump_iobuf(&touch_uart.written); #endif @@ -188,7 +188,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const resp.touches[0].touch_id = 1; tmp_x = mouse_x & 0x7FFF; tmp_y = mouse_y & 0x7FFF; - + resp.touches[0].x1 = tmp_x & 0x7F; resp.touches[0].x2 = (tmp_x >> 7) & 0x7F; resp.touches[0].y1 = tmp_y & 0x7F; @@ -201,7 +201,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2); #endif - + last_x1 = resp.touches[0].x1; last_x2 = resp.touches[0].x2; last_y1 = resp.touches[0].y1; @@ -220,7 +220,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const iobuf_write(&touch_uart.readable, &resp, sizeof(resp)); LeaveCriticalSection(&touch_lock); -#if 0 +#if defined(LOG_CAROL_TOUCH) dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos); dump_iobuf(&touch_uart.readable); #endif diff --git a/chunihook/slider.c b/chunihook/slider.c index 753a608..0a42cb3 100644 --- a/chunihook/slider.c +++ b/chunihook/slider.c @@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_CHUNI_SLIDER) dprintf("TX Buffer:\n"); dump_iobuf(&slider_uart.written); #endif @@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) return hr; } -#if 0 +#if defined(LOG_CHUNI_SLIDER) dprintf("Deframe Buffer:\n"); dump_iobuf(&req_iobuf); #endif diff --git a/chusanhook/slider.c b/chusanhook/slider.c index 78f5d53..2bd98d5 100644 --- a/chusanhook/slider.c +++ b/chusanhook/slider.c @@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_CHUSAN_SLIDER) dprintf("TX Buffer:\n"); dump_iobuf(&slider_uart.written); #endif @@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) return hr; } -#if 0 +#if defined(LOG_CHUSAN_SLIDER) dprintf("Deframe Buffer:\n"); dump_iobuf(&req_iobuf); #endif diff --git a/divahook/slider.c b/divahook/slider.c index 8294923..3046142 100644 --- a/divahook/slider.c +++ b/divahook/slider.c @@ -99,7 +99,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_DIVA_SLIDER) dprintf("TX Buffer:\n"); dump_iobuf(&slider_uart.written); #endif @@ -118,7 +118,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp) return hr; } -#if 0 +#if defined(LOG_DIVA_SLIDER) dprintf("Deframe Buffer:\n"); dump_iobuf(&req_iobuf); #endif diff --git a/jvs/jvs-util.c b/jvs/jvs-util.c index 1bbe10e..5df33c7 100644 --- a/jvs/jvs-util.c +++ b/jvs/jvs-util.c @@ -46,7 +46,7 @@ void jvs_crack_request( return; } -#if 0 +#if defined(LOG_JVS) dprintf("Decoded request:\n"); dump_iobuf(&decode); #endif @@ -96,7 +96,7 @@ void jvs_crack_request( resp_bytes[2] = 0x01; /* Status: Success */ } -#if 0 +#if defined(LOG_JVS) dprintf("Encoding response:\n"); dump_iobuf(&encode); #endif diff --git a/mercuryhook/touch.c b/mercuryhook/touch.c index 87ba6d5..3f73a2b 100644 --- a/mercuryhook/touch.c +++ b/mercuryhook/touch.c @@ -130,7 +130,7 @@ static HRESULT touch0_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_MERCURY_SLIDER) dprintf("TX0 Buffer:\n"); dump_iobuf(&touch0_uart.written); #endif @@ -177,7 +177,7 @@ static HRESULT touch1_handle_irp_locked(struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_MERCURY_SLIDER) dprintf("TX1 Buffer:\n"); dump_iobuf(&touch1_uart.written); #endif @@ -305,11 +305,11 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req) resp.cmd = 0xa8; resp.checksum = 0; - if (req->side == 0) { + if (req->side == 0) { resp.version[6] = 'R'; resp.checksum = calc_checksum(&resp, sizeof(resp)); - #if 0 + #if defined(LOG_MERCURY_SLIDER) for (int i = 0; i < sizeof(resp.version); i++) { dprintf("0x%02x ", resp.version[i]); } @@ -322,7 +322,7 @@ static HRESULT touch_handle_get_unit_board_ver(const struct touch_req *req) resp.version[6] = 'L'; resp.checksum = calc_checksum(&resp, sizeof(resp)); - #if 0 + #if defined(LOG_MERCURY_SLIDER) for (int i = 0; i < sizeof(resp.version); i++) { dprintf("0x%02x ", resp.version[i]); } @@ -370,7 +370,7 @@ static HRESULT touch_handle_mystery2(const struct touch_req *req) if (req->side == 0) { hr = iobuf_write(&touch0_uart.readable, &resp, sizeof(resp)); - } + } else { hr = iobuf_write(&touch1_uart.readable, &resp, sizeof(resp)); } @@ -388,7 +388,7 @@ static HRESULT touch_handle_start_auto_scan(const struct touch_req *req) dprintf("Wacca Touch%d: Start Auto", req->side); - #if 0 + #if defined(LOG_MERCURY_SLIDER) for (int i = 0; i < req->data_length; i++) dprintf("0x%02x ", req->data[i]); #endif @@ -451,13 +451,13 @@ static void touch_res_auto_scan(const bool *state) counter++; } } - + memcpy(frame0.data1, dataR, sizeof(dataR)); memcpy(frame0.data2, data2, sizeof(data2)); memcpy(frame1.data1, dataL, sizeof(dataL)); memcpy(frame1.data2, data2, sizeof(data2)); - + frame0.checksum = 0; frame0.checksum = calc_checksum(&frame0, sizeof(frame0)); diff --git a/meson.build b/meson.build index d5d28a6..40f62e3 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,43 @@ if cc.get_id() != 'msvc' ) endif +if get_option('log_all') or get_option('log_jvs') + add_project_arguments('-DLOG_JVS', language: 'c') +endif +if get_option('log_all') or get_option('log_io3') + add_project_arguments('-DLOG_IO3', language: 'c') +endif +if get_option('log_all') or get_option('log_led15093') + add_project_arguments('-DLOG_LED15093', language: 'c') +endif +if get_option('log_all') or get_option('log_nfc') + add_project_arguments('-DLOG_NFC', language: 'c') +endif +if get_option('log_all') or get_option('log_carol_control_bd') + add_project_arguments('-DLOG_CAROL_CONTROL_BD', language: 'c') +endif +if get_option('log_all') or get_option('log_carol_led_bd') + add_project_arguments('-DLOG_CAROL_LED_BD', language: 'c') +endif +if get_option('log_all') or get_option('log_carol_touch') + add_project_arguments('-DLOG_CAROL_TOUCH', language: 'c') +endif +if get_option('log_all') or get_option('log_chuni_slider') + add_project_arguments('-DLOG_CHUNI_SLIDER', language: 'c') +endif +if get_option('log_all') or get_option('log_chusan_slider') + add_project_arguments('-DLOG_CHUSAN_SLIDER', language: 'c') +endif +if get_option('log_all') or get_option('log_diva_slider') + add_project_arguments('-DLOG_DIVA_SLIDER', language: 'c') +endif +if get_option('log_all') or get_option('log_mercury_slider') + add_project_arguments('-DLOG_MERCURY_SLIDER', language: 'c') +endif +if get_option('log_all') or get_option('log_clock') + add_project_arguments('-DLOG_CLOCK', language: 'c') +endif + shlwapi_lib = cc.find_library('shlwapi') dinput8_lib = cc.find_library('dinput8') dxguid_lib = cc.find_library('dxguid') diff --git a/meson.options b/meson.options new file mode 100644 index 0000000..fb39b10 --- /dev/null +++ b/meson.options @@ -0,0 +1,65 @@ +option('log_all', + type : 'boolean', + value : false, + description : 'Enables all of the subsequent debug logging options' +) +option('log_jvs', + type : 'boolean', + value : false, + description : 'Enable debug logging for JVS' +) +option('log_io3', + type : 'boolean', + value : false, + description : 'Enable debug logging for JVS' +) +option('log_led15093', + type : 'boolean', + value : false, + description : 'Enable debug logging for the 15093 LED board emulation' +) +option('log_nfc', + type : 'boolean', + value : false, + description : 'Enable debug logging for NFC' +) +option('log_carol_control_bd', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Carlo Control Board' +) +option('log_carol_led_bd', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Carlo LED Board' +) +option('log_carol_touch', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Carlo Touchscreen' +) +option('log_chuni_slider', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Chunithm Slider' +) +option('log_chusan_slider', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Chusan Slider' +) +option('log_diva_slider', + type : 'boolean', + value : false, + description : 'Enable debug logging for the Diva Slider' +) +option('log_mercury_slider', + type : 'boolean', + value : false, + description : 'Enable debug logging for the WACCA Slider' +) +option('log_clock', + type : 'boolean', + value : false, + description : 'Enable debug logging for clock APIs' +) diff --git a/platform/clock.c b/platform/clock.c index b67b111..a263413 100644 --- a/platform/clock.c +++ b/platform/clock.c @@ -158,7 +158,7 @@ static BOOL WINAPI my_GetSystemTime(SYSTEMTIME *out) return ok; } -#if 0 +#if defined(LOG_CLOCK) static int last_second; if (out->wSecond != last_second) { From 4e58d3b9a2160ca1d415eee8c19d6d2acfa170ed Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 23 Jun 2024 21:04:08 +0200 Subject: [PATCH 110/204] added game specific devices documentation --- carolhook/dllmain.c | 28 ++++++++++++++++++++++++++++ chunihook/dllmain.c | 12 ++++++++++++ chusanhook/dllmain.c | 24 ++++++++++++++++++++++++ cmhook/dllmain.c | 13 +++++++++++++ dist/chusan/segatools.ini | 1 + divahook/dllmain.c | 11 +++++++++++ fgohook/dllmain.c | 17 +++++++++++++++++ idachook/dllmain.c | 14 ++++++++++++++ mai2hook/dllmain.c | 21 +++++++++++++++++++++ mercuryhook/dllmain.c | 13 +++++++++++++ mu3hook/dllmain.c | 12 ++++++++++++ swdchook/dllmain.c | 15 +++++++++++++++ 12 files changed, 181 insertions(+) diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 3e86f6d..cc422b9 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -1,3 +1,31 @@ +/* + "Wonderland Wars" (carol*) hook + + Devices: + + JVS: 837-14572 "Type 3" I/O Board + + [Satellite] + + USB: "WinTouch" Controller Board + ^ (DIPSW2 ON, Version 5.xx.xx or above) + COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board + ^ (DIPSW2 OFF) + COM10: TN32MSEC003S "Gen 1" Aime Reader + OR + 837-15286 "Gen 2" Aime Reader + ^ (Version 1.6x.xx or above) + COM11: 837-15070-02 LED Controller Board + COM12: 837-15312 Pen Controller I/O Board + + [Terminal] + + COM10: 837-15286 "Gen 2" Aime Reader + + *: SEGA's abbreviation for Lewis Carroll, author of Alice's Adventures in + Wonderland. +*/ + #include #include diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 1a3fb57..81c8910 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -1,3 +1,15 @@ +/* + "CHUNITHM" (chuni) hook + + Devices + + JVS: 837-14572 "Type 3" I/O Board + COM1: 837-15330 Ground Slider + COM10: 837-15093-06 LED Controller Board + COM11: 837-15093-06 LED Controller Board + COM12: TN32MSEC003S "Gen 1" Aime Reader +*/ + #include #include diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 136db03..9f59301 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -1,3 +1,27 @@ +/* + "CHUNITHM NEW" (chusan) hook + + Devices + + USB: 837-15257-02 "Type 4" I/O Board + COM1: 837-15330 Ground Slider + + [CVT mode (DIPSW2 ON)] + + COM2: 837-15093-06 LED Controller Board + COM3: 837-15093-06 LED Controller Board + COM4: 837-15286 "Gen 2" Aime Reader + + [SP mode (DIPSW2 OFF)] + + USB: 837-15067-02 USB Serial I/F Board + connected to + 837-15093-06 LED Controller Board (COM20) + 837-15093-06 LED Controller Board (COM21) + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM4: 837-15396 "Gen 3" Aime Reader +*/ + #include #include diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 65556da..143ec5a 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -1,3 +1,16 @@ +/* + "Card Maker" (cm) hook + + Devices + + USB: 837-15257-01 "Type 4" I/O Board + USB: 838-20006 "WinTouch" Controller Board + USB: 630-00009 Sinfonia CHC-C310 Printer + COM1: 837-15396 "Gen 3" Aime Reader + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM3: 220-5872 AS-6DB Coin Selector +*/ + #include #include diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index f41f630..c167f26 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -43,6 +43,7 @@ default=127.0.0.1 ; Chunithm is extremely picky about its LAN environment, so leaving this ; setting enabled is strongly recommended. enable=1 + ; The final octet of the local host's IP address on the virtualized subnet (so, ; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the ; local host's virtualized LAN IP is `192.168.32.11`). diff --git a/divahook/dllmain.c b/divahook/dllmain.c index 8bd13de..412fe9c 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -1,3 +1,14 @@ +/* + "Hatsune Miku Project DIVA Arcade " (diva) hook + + Devices + + JVS: 837-14572 "Type 3" I/O Board + COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board + COM10: TN32MSEC003S "Gen 1" Aime Reader + COM11: 837-15275 Touch Slider +*/ + #include #include diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 43ac26e..dfbbdb5 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -1,3 +1,20 @@ +/* + "Fate Grand/Order Arcade" (fgo) hook + + Devices + + USB: 837-15257 "Type 4" I/O Board + USB: 838-15405 "WinTouch" Controller Board + USB: 630-00008 Sinfonia CHC-C330 Printer + USB: 837-14509-02 USB-SER I/F BD Mini-B FTDI Board + connected to + 837-15093-06 LED Controller Board + COM1: 200-6275 VFD GP1232A02A FUTABA Board + COM2: 837-15345 RFID Deck Reader Noard + COM3: 837-15396 "Gen 3" Aime Reader + COM4: 837-15347 RFID Reader/Writer Board (inside the printer) +*/ + #include #include diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 500e9c5..accc661 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -1,3 +1,16 @@ +/* + "Initial D THE ARCADE" (idac) hook + + Devices + + USB: 837-15257 "Type 4" I/O Board + COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board + COM2: 837-15070-02 IC BD LED Controller Board + COM3: 837-15286 "Gen 2" Aime Reader (DIPSW2 OFF) + OR + 837-15396 "Gen 3" Aime Reader (DIPSW2 ON) +*/ + #include #include @@ -5,6 +18,7 @@ #include "board/sg-reader.h" #include "board/io4.h" +#include "board/ffb.h" #include "hook/process.h" diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 1d10c60..02f32a4 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -1,3 +1,22 @@ +/* + "maimai DX" (mai2) hook + + Devices + + USB: 837-15257-01 "Type 4" I/O Board + USB: 2 * 601-13216 USB "QR Code" Camera (SDEZ2, SDEZ3) + USB: 601-13249 USB "Player" Camera (SDEZ1) + USB: 837-15067-02 IC BD USB to Serial 232 + connected to + 837-15070-04 LED Board Controller (COM21) + 837-15070-04 LED Board Controller (COM23) + + COM1: 837-15396 "Gen 3" Aime Reader + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM3: 509-6483 Touch Panel Controller + COM4: 509-6483 Touch Panel Controller +*/ + #include #include "board/io4.h" @@ -5,6 +24,8 @@ #include "board/vfd.h" #include "hook/process.h" +#include "hook/table.h" +#include "hook/iohook.h" #include "hooklib/serial.h" #include "hooklib/spike.h" diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index 06b62ad..ea30458 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -1,3 +1,16 @@ +/* + "WACCA" (mercury) hook + + Devices + + USB: 837-15257-01 "Type 4" I/O Board + USB: 14-1497-R "Elisabeth" LED Board Controller + COM1: 837-15396 "Gen 3" Aime Reader + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM3: PSS-7135-L02-01 "Left Side" Touch Board + COM4: PSS-7135-L02-01 "Right Sdde" Touch Board +*/ + #include #include "board/io4.h" diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index c4495c1..bab6c0b 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -1,3 +1,15 @@ +/* + "O.N.G.E.K.I." (mu3) hook + + Devices + + USB: 837-15257-01 "Type 4" I/O Board + USB: 3 * 601-13216 USB "QR Code" Camera (SDDT1-SDDT3) + COM1: 837-15396 "Gen 3" Aime Reader + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM3: 837-15093-06 LED Controller Board +*/ + #include #include diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index 9806123..94d68ea 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -1,3 +1,18 @@ +/* + "SEGA World Drivers Championship" (swdc) hook + + Devices + + USB: 837-15257 "Type 4" I/O Board + USB: 838-15415 Indicator BD Main Board (COM21) + WITH + 838-15416 Indicator BD LED Board + COM1: 838-15069 MOTOR DRIVE BD RS232/422 board + COM2: 837-15396 "Gen 3" Aime reader + COM3: 837-15070-04 IC BD LED controller board + COM4: 200-6275 VFD GP1232A02A FUTABA board +*/ + #include #include From 7e5e0f132ef8143c645a450cb7527d80113361d5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 23 Jun 2024 21:21:57 +0200 Subject: [PATCH 111/204] idac: 837-15070 board implementation --- board/led15070-cmd.h | 81 +++ board/led15070-frame.c | 194 ++++++ board/led15070-frame.h | 26 + board/led15070.c | 1250 +++++++++++++++++++++++++++++++++++++++ board/led15070.h | 29 + board/meson.build | 5 + dist/idac/segatools.ini | 9 + idachook/config.c | 38 ++ idachook/config.h | 2 + idachook/dllmain.c | 19 +- idachook/idac-dll.c | 12 + idachook/idac-dll.h | 4 + idachook/idachook.def | 4 + idachook/io4.c | 33 ++ idacio/dllmain.c | 43 +- idacio/idacio.def | 4 + idacio/idacio.h | 69 ++- idzhook/dllmain.c | 11 + 18 files changed, 1825 insertions(+), 8 deletions(-) create mode 100644 board/led15070-cmd.h create mode 100644 board/led15070-frame.c create mode 100644 board/led15070-frame.h create mode 100644 board/led15070.c create mode 100644 board/led15070.h diff --git a/board/led15070-cmd.h b/board/led15070-cmd.h new file mode 100644 index 0000000..d5d739a --- /dev/null +++ b/board/led15070-cmd.h @@ -0,0 +1,81 @@ +#pragma once + +#include "board/led15070-frame.h" + +/* Command IDs */ + +enum { + LED_15070_CMD_RESET = 0x10, + LED_15070_CMD_SET_INPUT = 0x28, // No known use case + LED_15070_CMD_SET_NORMAL_12BIT = 0x30, // TODO + LED_15070_CMD_SET_NORMAL_8BIT = 0x31, + LED_15070_CMD_SET_MULTI_FLASH_8BIT = 0x32, + LED_15070_CMD_SET_MULTI_FADE_8BIT = 0x33, + LED_15070_CMD_SET_PALETTE_7_NORMAL_LED = 0x34, // No known use case + LED_15070_CMD_SET_PALETTE_6_FLASH_LED = 0x35, // No known use case + LED_15070_CMD_SET_15DC_OUT = 0x36, // No known use case + LED_15070_CMD_SET_15GS_OUT = 0x37, // No known use case + LED_15070_CMD_SET_PSC_MAX = 0x38, // No known use case + LED_15070_CMD_SET_FET_OUTPUT = 0x39, + LED_15070_CMD_SET_GS_PALETTE = 0x3A, + LED_15070_CMD_DC_UPDATE = 0x3B, + LED_15070_CMD_GS_UPDATE = 0x3C, + LED_15070_CMD_ROTATE = 0x3E, // No known use case, wtf is this? + LED_15070_CMD_SET_DC_DATA = 0x3F, + LED_15070_CMD_EEPROM_WRITE = 0x7B, + LED_15070_CMD_EEPROM_READ = 0x7C, + LED_15070_CMD_ACK_ON = 0x7D, + LED_15070_CMD_ACK_OFF = 0x7E, + LED_15070_CMD_BOARD_INFO = 0xF0, + LED_15070_CMD_BOARD_STATUS = 0xF1, + LED_15070_CMD_FW_SUM = 0xF2, + LED_15070_CMD_PROTOCOL_VER = 0xF3, + LED_15070_CMD_TO_BOOT_MODE = 0xFD, + LED_15070_CMD_FW_UPDATE = 0xFE, +}; + +/* Response codes */ + +enum { + LED_15070_STATUS_OK = 0x01, + LED_15070_STATUS_SUM_ERR = 0x02, + LED_15070_STATUS_PARITY_ERR = 0x03, + LED_15070_STATUS_FRAMING_ERR = 0x04, + LED_15070_STATUS_OVERRUN_ERR = 0x05, + LED_15070_STATUS_BUFFER_OVERFLOW = 0x06, +}; + +enum { + LED_15070_REPORT_OK = 0x01, + LED_15070_REPORT_WAIT = 0x02, + LED_15070_REPORT_ERR1 = 0x03, + LED_15070_REPORT_ERR2 = 0x04, +}; + +/* Request data structures */ + +struct led15070_req_any { + struct led15070_hdr hdr; + uint8_t cmd; + uint8_t payload[256]; +}; + +/* Response data structures */ + +struct led15070_resp_any { + struct led15070_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t data[32]; +}; + +struct led15070_resp_board_info { + struct led15070_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + char board_num[8]; + uint8_t endcode; // Always 0xFF + uint8_t fw_ver; +}; diff --git a/board/led15070-frame.c b/board/led15070-frame.c new file mode 100644 index 0000000..f550fbd --- /dev/null +++ b/board/led15070-frame.c @@ -0,0 +1,194 @@ +#include + +#include +#include +#include +#include + +#include "board/led15070-frame.h" + +#include "hook/iobuf.h" + +static void led15070_frame_sync(struct iobuf *src); +static HRESULT led15070_frame_accept(const struct iobuf *dest); +static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte); + +/* Frame structure: + + [0] Sync byte (0xE0) + [1] Destination address + [2] Source Address + [3] Length of data/payload + [4] Data/payload + For requests (host to board): + [0] Command + ... Payload + For responses (board to host): + [0] Status + [1] Command + [2] Report + ... Payload + [n] Checksum: Sum of all prior bytes (excluding sync byte) + + Byte stuffing: + + 0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */ + +static void led15070_frame_sync(struct iobuf *src) +{ + size_t i; + + for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++); + + src->pos -= i; + memmove(&src->bytes[0], &src->bytes[i], i); +} + +static HRESULT led15070_frame_accept(const struct iobuf *dest) +{ + uint8_t checksum; + size_t i; + + if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) { + return S_FALSE; + } + + checksum = 0; + + for (i = 1 ; i < dest->pos - 1 ; i++) { + checksum += dest->bytes[i]; + } + + //dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]); + + if (checksum != dest->bytes[dest->pos - 1]) { + return HRESULT_FROM_WIN32(ERROR_CRC); + } + + return S_OK; +} + +HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src) +{ + uint8_t byte; + bool escape; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(src != NULL); + assert(src->bytes != NULL || src->nbytes == 0); + assert(src->pos <= src->nbytes); + + led15070_frame_sync(src); + + dest->pos = 0; + escape = false; + + for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) { + /* Step the FSM to unstuff another byte */ + + byte = src->bytes[i]; + + if (dest->pos >= dest->nbytes) { + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } else if (i == 0) { + dest->bytes[dest->pos++] = byte; + } else if (byte == 0xE0) { + hr = E_FAIL; + } else if (byte == 0xD0) { + if (escape) { + hr = E_FAIL; + } + + escape = true; + } else if (escape) { + dest->bytes[dest->pos++] = byte + 1; + escape = false; + } else { + dest->bytes[dest->pos++] = byte; + } + + /* Try to accept the packet we've built up so far */ + + if (SUCCEEDED(hr)) { + hr = led15070_frame_accept(dest); + } + } + + /* Handle FSM terminal state */ + + if (hr != S_FALSE) { + /* Frame was either accepted or rejected, remove it from src */ + memmove(&src->bytes[0], &src->bytes[i], src->pos - i); + src->pos -= i; + } + + return hr; +} + +HRESULT led15070_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes) +{ + const uint8_t *src; + uint8_t checksum; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes); + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xE0; + checksum = 0; + // dprintf("%02x ", 0xe0); + + for (i = 1 ; i < nbytes ; i++) { + byte = src[i]; + checksum += byte; + // dprintf("%02x ", byte); + + hr = led15070_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } + // dprintf("%02x \n", checksum); + + return led15070_frame_encode_byte(dest, checksum); +} + +static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte) +{ + if (byte == 0xE0 || byte == 0xD0) { + if (dest->pos + 2 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = byte - 1; + } else { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + } + + return S_OK; +} diff --git a/board/led15070-frame.h b/board/led15070-frame.h new file mode 100644 index 0000000..078dd32 --- /dev/null +++ b/board/led15070-frame.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + LED_15070_FRAME_SYNC = 0xE0, +}; + +struct led15070_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src); + +HRESULT led15070_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/led15070.c b/board/led15070.c new file mode 100644 index 0000000..6a634e8 --- /dev/null +++ b/board/led15070.c @@ -0,0 +1,1250 @@ +/* + SEGA 837-15070-0X LED Controller Board Emulator + + Credits: + 837-15070-04 LED Controller Board Emulator (emihiok) + 837-15093-06 LED Controller Board Emulator (somewhatlurker, skogaby) + (a/o June 2023) +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "board/led15070-cmd.h" +#include "board/led15070-frame.h" + +#include "board/led15070.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/dump.h" + +static HRESULT led15070_handle_irp(struct irp *irp); +static HRESULT led15070_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led15070_req_dispatch(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req); +static HRESULT led15070_req_board_info(int board); +static HRESULT led15070_req_board_status(int board); +static HRESULT led15070_req_fw_sum(int board); +static HRESULT led15070_req_protocol_ver(int board); +static HRESULT led15070_req_to_boot_mode(int board); +static HRESULT led15070_req_fw_update(int board, const struct led15070_req_any *req); + +static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle); +static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle); + +static char led15070_board_num[8]; +static uint8_t led15070_fw_ver; +static uint16_t led15070_fw_sum; +static uint8_t led15070_host_adr = 0x01; + +#define led15070_nboards 2 + +typedef struct { + CRITICAL_SECTION lock; + bool started; + HRESULT start_hr; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + uint8_t gs[32][4]; + uint8_t dc[32][3]; + uint8_t fet[3]; + uint8_t gs_palette[8][3]; + wchar_t eeprom_path[MAX_PATH]; + HANDLE eeprom_handle; + uint8_t boardadr; + bool enable_bootloader; + bool enable_response; +} _led15070_per_board_vars; + +_led15070_per_board_vars led15070_per_board_vars[led15070_nboards]; + +static io_led_init_t led_init; +static io_led_set_fet_output_t led_set_fet_output; +static io_led_dc_update_t led_dc_update; +static io_led_gs_update_t led_gs_update; + +HRESULT led15070_hook_init( + const struct led15070_config *cfg, + io_led_init_t _led_init, + io_led_set_fet_output_t _led_set_fet_output, + io_led_dc_update_t _led_dc_update, + io_led_gs_update_t _led_gs_update, + unsigned int first_port, + unsigned int num_boards) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + if (cfg->port_no != 0) { + first_port = cfg->port_no; + } + + led_init = _led_init; + led_set_fet_output = _led_set_fet_output; + led_dc_update = _led_dc_update; + led_gs_update = _led_gs_update; + + memcpy(led15070_board_num, cfg->board_number, sizeof(led15070_board_num)); + led15070_fw_ver = cfg->fw_ver; + led15070_fw_sum = cfg->fw_sum; + + for (int i = 0; i < num_boards; i++) + { + _led15070_per_board_vars *v = &led15070_per_board_vars[i]; + + InitializeCriticalSection(&v->lock); + + // TODO: IMPROVE! + first_port = i == 1 ? first_port + 2 : first_port; + + uart_init(&v->boarduart, first_port); + v->boarduart.baud.BaudRate = 115200; + v->boarduart.written.bytes = v->written_bytes; + v->boarduart.written.nbytes = sizeof(v->written_bytes); + v->boarduart.readable.bytes = v->readable_bytes; + v->boarduart.readable.nbytes = sizeof(v->readable_bytes); + + memset(v->gs, 0, sizeof(v->gs)); + memset(v->dc, 0, sizeof(v->dc)); + memset(v->fet, 0, sizeof(v->fet)); + memset(v->gs_palette, 0, sizeof(v->gs_palette)); + memset(v->eeprom_path, 0, sizeof(v->eeprom_path)); + v->eeprom_handle = NULL; + + swprintf_s + ( + v->eeprom_path, MAX_PATH, + L"%s\\led15070_eeprom_%d.bin", + cfg->eeprom_path, i + ); + + /* Generate board EEPROM file if it doesn't already exist */ + led15070_eeprom_open(i, v->eeprom_path, &(v->eeprom_handle)); + led15070_eeprom_close(i, v->eeprom_path, &(v->eeprom_handle)); + + v->boardadr = 0x11; + v->enable_bootloader = false; + v->enable_response = false; + } + + dprintf("LED 15070: hook enabled.\n"); + + return iohook_push_handler(led15070_handle_irp); +} + +static HRESULT led15070_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led15070_nboards; i++) + { + _led15070_per_board_vars *v = &led15070_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led15070_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led15070_handle_irp_locked(int board, struct irp *irp) +{ + struct led15070_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + _led15070_per_board_vars *v = &led15070_per_board_vars[board]; + struct uart *boarduart = &led15070_per_board_vars[board].boarduart; + + if (irp->op == IRP_OP_OPEN) { + // Unfortunately the LED board UART gets opened and closed + // repeatedly + + if (!v->started) { + dprintf("LED 15070: Starting LED backend\n"); + hr = led_init(); + + v->started = true; + v->start_hr = hr; + + if (FAILED(hr)) { + dprintf("LED 15070: Backend error, LED controller " + "disconnected: %x\n", + (int) hr); + + return hr; + } + } else { + hr = v->start_hr; + + if (FAILED(hr)) { + return hr; + } + } + } + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led15070_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (FAILED(hr)) { + dprintf("LED 15070: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led15070_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("LED 15070: Processing error: %x\n", (int) hr); + } + } +} + +static HRESULT led15070_req_dispatch(int board, const struct led15070_req_any *req) +{ + switch (req->cmd) { + case LED_15070_CMD_RESET: + return led15070_req_reset(board, req); + + case LED_15070_CMD_SET_INPUT: + return led15070_req_set_input(board, req); + + case LED_15070_CMD_SET_NORMAL_12BIT: + return led15070_req_set_normal_12bit(board, req); + + case LED_15070_CMD_SET_NORMAL_8BIT: + return led15070_req_set_normal_8bit(board, req); + + case LED_15070_CMD_SET_MULTI_FLASH_8BIT: + return led15070_req_set_multi_flash_8bit(board, req); + + case LED_15070_CMD_SET_MULTI_FADE_8BIT: + return led15070_req_set_multi_fade_8bit(board, req); + + case LED_15070_CMD_SET_PALETTE_7_NORMAL_LED: + return led15070_req_set_palette_7_normal_led(board, req); + + case LED_15070_CMD_SET_PALETTE_6_FLASH_LED: + return led15070_req_set_palette_6_flash_led(board, req); + + case LED_15070_CMD_SET_15DC_OUT: + return led15070_req_set_15dc_out(board, req); + + case LED_15070_CMD_SET_15GS_OUT: + return led15070_req_set_15gs_out(board, req); + + case LED_15070_CMD_SET_PSC_MAX: + return led15070_req_set_psc_max(board, req); + + case LED_15070_CMD_SET_FET_OUTPUT: + return led15070_req_set_fet_output(board, req); + + case LED_15070_CMD_SET_GS_PALETTE: + return led15070_req_set_gs_palette(board, req); + + case LED_15070_CMD_DC_UPDATE: + return led15070_req_dc_update(board, req); + + case LED_15070_CMD_GS_UPDATE: + return led15070_req_gs_update(board, req); + + case LED_15070_CMD_ROTATE: + return led15070_req_rotate(board, req); + + case LED_15070_CMD_SET_DC_DATA: + return led15070_req_set_dc_data(board, req); + + case LED_15070_CMD_EEPROM_WRITE: + return led15070_req_eeprom_write(board, req); + + case LED_15070_CMD_EEPROM_READ: + return led15070_req_eeprom_read(board, req); + + case LED_15070_CMD_ACK_ON: + return led15070_req_ack_on(board, req); + + case LED_15070_CMD_ACK_OFF: + return led15070_req_ack_off(board, req); + + case LED_15070_CMD_BOARD_INFO: + return led15070_req_board_info(board); + + case LED_15070_CMD_BOARD_STATUS: + return led15070_req_board_status(board); + + case LED_15070_CMD_FW_SUM: + return led15070_req_fw_sum(board); + + case LED_15070_CMD_PROTOCOL_VER: + return led15070_req_protocol_ver(board); + + case LED_15070_CMD_TO_BOOT_MODE: + return led15070_req_to_boot_mode(board); + + case LED_15070_CMD_FW_UPDATE: + return led15070_req_fw_update(board, req); + + default: + dprintf("LED 15070: Unhandled command %02x\n", req->cmd); + + return S_OK; + } +} + +static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Reset (board %u)\n", board); + + led15070_per_board_vars[board].enable_bootloader = false; + led15070_per_board_vars[board].enable_response = true; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_RESET; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set input (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_INPUT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req) +{ + uint8_t idx = req->payload[0]; + + dprintf("LED 15070: Set LED - Normal 12bit (board %u, index %u)\n", + board, idx); + + // TODO: Data for this command. Seen with Carol + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_NORMAL_12BIT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req) +{ + uint8_t idx = req->payload[0]; + + // dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n", + // board, idx); + + led15070_per_board_vars[board].gs[idx][0] = req->payload[1]; // R + led15070_per_board_vars[board].gs[idx][1] = req->payload[2]; // G + led15070_per_board_vars[board].gs[idx][2] = req->payload[3]; // B + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_NORMAL_8BIT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led15070_req_any *req) +{ + uint8_t idx_start = req->payload[0]; + uint8_t idx_end = req->payload[1]; + uint8_t idx_skip = req->payload[2]; + + // TODO: useful? + // dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n", + // board, idx_start, idx_end, idx_skip); + + if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { + idx_start += idx_skip; + } + + int i = idx_start; + do { + led15070_per_board_vars[board].gs[i][0] = req->payload[3]; // R + led15070_per_board_vars[board].gs[i][1] = req->payload[4]; // G + led15070_per_board_vars[board].gs[i][2] = req->payload[5]; // B + /* Always 0, tells the controller to immediately change to this color */ + led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed + i++; + } while (i < idx_end); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_MULTI_FLASH_8BIT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070_req_any *req) +{ + uint8_t idx_start = req->payload[0]; + uint8_t idx_end = req->payload[1]; + uint8_t idx_skip = req->payload[2]; + + // dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n", + // board, idx_start, idx_end, idx_skip); + + if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { + idx_start += idx_skip; + } + + int i = idx_start; + do { + led15070_per_board_vars[board].gs[i][0] = req->payload[3]; // R + led15070_per_board_vars[board].gs[i][1] = req->payload[4]; // G + led15070_per_board_vars[board].gs[i][2] = req->payload[5]; // B + led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed + i++; + } while (i < idx_end); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_MULTI_FADE_8BIT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set palette - 7 Normal LED (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_PALETTE_7_NORMAL_LED; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set palette - 6 Flash LED (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_PALETTE_6_FLASH_LED; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set 15DC out (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_15DC_OUT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set 15GS out (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_15GS_OUT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set PSC max (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_PSC_MAX; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Set FET output (board %u)\n", board); + + led15070_per_board_vars[board].fet[0] = req->payload[0]; // R or FET0 intensity + led15070_per_board_vars[board].fet[1] = req->payload[1]; // G or FET1 intensity + led15070_per_board_vars[board].fet[2] = req->payload[2]; // B or FET2 intensity + + if (led_set_fet_output) + led_set_fet_output((const uint8_t*)led15070_per_board_vars[board].fet); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_FET_OUTPUT; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req) +{ + uint8_t idx = req->payload[0]; + + dprintf("LED 15070: Set GS palette (board %u, index %u)\n", board, idx); + + led15070_per_board_vars[board].gs_palette[idx][0] = req->payload[1]; // R + led15070_per_board_vars[board].gs_palette[idx][1] = req->payload[2]; // G + led15070_per_board_vars[board].gs_palette[idx][2] = req->payload[3]; // B + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_GS_PALETTE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req) +{ + // dprintf("LED 15070: DC update (board %u)\n", board); + + if (led_dc_update) + led_dc_update((const uint8_t*)led15070_per_board_vars[board].dc); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_DC_UPDATE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req) +{ + // dprintf("LED 15070: GS update (board %u)\n", board); + + if (led_gs_update) + led_gs_update((const uint8_t*)led15070_per_board_vars[board].gs); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_GS_UPDATE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Rotate (board %u)\n", board); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_ROTATE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any *req) +{ + uint8_t idx_start = req->payload[0]; + uint8_t idx_end = req->payload[1]; + uint8_t idx_skip = req->payload[2]; + + // dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n", + // board, idx_start, idx_end, idx_skip); + + if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { + idx_start += idx_skip; + } + + int i = idx_start; + do { + led15070_per_board_vars[board].dc[i][0] = req->payload[3]; // R + led15070_per_board_vars[board].dc[i][1] = req->payload[4]; // G + led15070_per_board_vars[board].dc[i][2] = req->payload[5]; // B + i++; + } while (i < idx_end); + + if (!led15070_per_board_vars[board].enable_response) + return S_OK; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_SET_DC_DATA; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_any *req) +{ + DWORD eeprom_bytes_written = 0; + HRESULT hr; + BOOL ok; + + uint8_t addr = req->payload[0]; + uint8_t data = req->payload[1]; + + dprintf("LED 15070: EEPROM write (board %u, address %02x, data %02x)\n", + board, addr, data); + + if (addr > 0x07) { + dprintf("LED 15070: Error -- Invalid EEPROM write address %02x\n", + addr); + + return E_INVALIDARG; + } + + hr = led15070_eeprom_open( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + if (FAILED(hr)) { + return hr; + } + + hr = SetFilePointer( + led15070_per_board_vars[board].eeprom_handle, + addr, + NULL, + FILE_BEGIN); + + if (hr == INVALID_SET_FILE_POINTER) { + dprintf("LED 10570: Error -- Failed to set pointer to EEPROM file " + "(board %u)\n", board); + led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + return hr; + } + + ok = WriteFile( + led15070_per_board_vars[board].eeprom_handle, + &data, + sizeof(data), + &eeprom_bytes_written, NULL); + + if (!ok || eeprom_bytes_written == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("LED 15070: Error -- Failed to write to EEPROM file: %x " + "(board %u)\n", (int) hr, board); + led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + return hr; + } + + hr = led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + if (FAILED(hr)) { + return hr; + } + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_EEPROM_WRITE; + resp.report = LED_15070_REPORT_OK; + + resp.data[0] = addr; + resp.data[1] = data; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any *req) +{ + DWORD eeprom_bytes_read = 0; + HRESULT hr; + BOOL ok; + + uint8_t addr = req->payload[0]; + uint8_t data = 0; + + dprintf("LED 15070: EEPROM read (board %u, address %02x)\n", board, addr); + + if (addr > 0x07) { + dprintf("LED 15070: Error -- Invalid EEPROM read address %02x\n", + addr); + + return E_INVALIDARG; + } + + hr = led15070_eeprom_open( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + if (FAILED(hr)) { + return hr; + } + + hr = SetFilePointer( + led15070_per_board_vars[board].eeprom_handle, + addr, + NULL, + FILE_BEGIN); + + if (hr == INVALID_SET_FILE_POINTER) { + dprintf("LED 10570: Error -- Failed to set pointer to EEPROM file " + "(board %u)\n", board); + led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + return hr; + } + + ok = ReadFile( + led15070_per_board_vars[board].eeprom_handle, + &data, + sizeof(data), + &eeprom_bytes_read, + NULL); + + if (!ok || eeprom_bytes_read == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("LED 15070: Error -- Failed to read from EEPROM file: %x " + "(board %u)\n", (int) hr, board); + led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + return hr; + } + + hr = led15070_eeprom_close( + board, + led15070_per_board_vars[board].eeprom_path, + &(led15070_per_board_vars[board].eeprom_handle)); + + if (FAILED(hr)) { + return hr; + } + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_EEPROM_READ; + resp.report = LED_15070_REPORT_OK; + + resp.data[0] = data; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Acknowledge commands ON (board %u)\n", board); + + led15070_per_board_vars[board].enable_response = true; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_ACK_ON; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Acknowledge commands OFF (board %u)\n", board); + + led15070_per_board_vars[board].enable_response = false; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_ACK_OFF; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_board_info(int board) +{ + dprintf("LED 15070: Get board info (board %u)\n", board); + + struct led15070_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 10 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_BOARD_INFO; + resp.report = LED_15070_REPORT_OK; + + memcpy(resp.board_num, led15070_board_num, sizeof(resp.board_num)); + resp.endcode = 0xff; + resp.fw_ver = led15070_fw_ver; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_board_status(int board) +{ + dprintf("LED 15070: Get board status (board %u)\n", board); + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 4 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_BOARD_STATUS; + resp.report = LED_15070_REPORT_OK; + + resp.data[0] = 0; // Timeout status + resp.data[1] = 0; // Timeout sec + resp.data[2] = 0; // PWM IO + resp.data[3] = 0; // FET timeout + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_fw_sum(int board) +{ + dprintf("LED 15070: Get firmware checksum (board %u)\n", board); + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_FW_SUM; + resp.report = LED_15070_REPORT_OK; + + resp.data[0] = (led15070_fw_sum >> 8) & 0xff; + resp.data[1] = led15070_fw_sum & 0xff; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_protocol_ver(int board) +{ + dprintf("LED 15070: Get protocol version (board %u)\n", board); + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3 + 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_PROTOCOL_VER; + resp.report = LED_15070_REPORT_OK; + + if (led15070_per_board_vars[board].enable_bootloader) { + resp.data[0] = 0; // BOOT mode + resp.data[1] = 1; // Version major + resp.data[2] = 1; // Version minor + } else { + resp.data[0] = 1; // APPLI mode + resp.data[1] = 1; // Version major + resp.data[2] = 4; // Version minor + } + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_to_boot_mode(int board) +{ + dprintf("LED 15070: To boot mode (board %u)\n", board); + + led15070_per_board_vars[board].enable_bootloader = true; + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_TO_BOOT_MODE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_req_fw_update(int board, const struct led15070_req_any *req) +{ + dprintf("LED 15070: Firmware update (UNIMPLEMENTED) (board %u)\n", board); + + struct led15070_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15070_FRAME_SYNC; + resp.hdr.dest_adr = led15070_host_adr; + resp.hdr.src_adr = led15070_per_board_vars[board].boardadr; + resp.hdr.nbytes = 3; + + resp.status = LED_15070_STATUS_OK; + resp.cmd = LED_15070_CMD_FW_UPDATE; + resp.report = LED_15070_REPORT_OK; + + return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle) +{ + DWORD eeprom_bytes_written; + BYTE null_bytes[8] = { 0x00 }; + HRESULT hr; + BOOL ok; + +#if 0 + dprintf("LED 15070: Opening EEPROM file '%S' handle (board %u)\n", path, board); +#endif + + *handle = CreateFileW( + path, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (*handle == INVALID_HANDLE_VALUE) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("LED 15070: Failed to open EEPROM file '%S' handle: %x " + "(board %u)\n", path, (int) hr, board); + + return hr; + } + + if (GetLastError() == ERROR_ALREADY_EXISTS) return S_OK; + + ok = WriteFile( + *handle, + null_bytes, + sizeof(null_bytes), + &eeprom_bytes_written, + NULL); + + if (!ok || eeprom_bytes_written != sizeof(null_bytes)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("LED 15070: Failed to initialize empty EEPROM file '%S': %x " + "(board %u)\n", path, (int) hr, board); + + return hr; + } + + return S_OK; +} + +static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle) +{ + HRESULT hr; + BOOL ok; + +#if 0 + dprintf("LED 15070: Closing EEPROM file '%S' handle (board %u)\n", path, board); +#endif + + ok = CloseHandle(*handle); + + if (!ok) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("LED 15070: Failed to close EEPROM file '%S' handle: %x " + "(board %u)\n", path, (int) hr, board); + + return hr; + } + + return S_OK; +} diff --git a/board/led15070.h b/board/led15070.h new file mode 100644 index 0000000..a2ad863 --- /dev/null +++ b/board/led15070.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include +#include + +struct led15070_config { + bool enable; + unsigned int port_no; + char board_number[8]; + uint8_t fw_ver; + uint16_t fw_sum; + wchar_t eeprom_path[MAX_PATH]; +}; + +typedef HRESULT (*io_led_init_t)(void); +typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb); +typedef void (*io_led_dc_update_t)(const uint8_t *rgb); +typedef void (*io_led_gs_update_t)(const uint8_t *rgb); + +HRESULT led15070_hook_init( + const struct led15070_config *cfg, + io_led_init_t _led_init, + io_led_set_fet_output_t _led_set_fet_output, + io_led_dc_update_t _led_dc_update, + io_led_gs_update_t _led_gs_update, + unsigned int first_port, + unsigned int num_boards); diff --git a/board/meson.build b/board/meson.build index b0dd300..0bf4fbc 100644 --- a/board/meson.build +++ b/board/meson.build @@ -25,6 +25,11 @@ board_lib = static_library( 'led15093-frame.h', 'led15093.c', 'led15093.h', + 'led15070-cmd.h', + 'led15070-frame.c', + 'led15070-frame.h', + 'led15070.c', + 'led15070.h', 'sg-cmd.c', 'sg-cmd.h', 'sg-frame.c', diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 8ed90a2..eab33e2 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -75,6 +75,15 @@ dipsw3=0 dipsw4=0 dipsw5=0 +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15070] +; Enable emulation of the 15070-02 controlled lights, which handle the cabinet +; and seat LEDs. +enable=1 + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/idachook/config.c b/idachook/config.c index 5452bf6..f3bf349 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -13,6 +13,43 @@ #include "platform/config.h" #include "platform/platform.h" + +void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); + /* TODO: Unknown, no firmware file available */ + cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename); + + GetPrivateProfileStringW( + L"led15070", + L"boardNumber", + L"15070-02", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15070", + L"eepromPath", + L"DEVICE", + cfg->eeprom_path, + _countof(cfg->eeprom_path), + filename); +} + void idac_dll_config_load( struct idac_dll_config *cfg, const wchar_t *filename) @@ -42,6 +79,7 @@ void idac_hook_config_load( zinput_config_load(&cfg->zinput, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + led15070_config_load(&cfg->led15070, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/idachook/config.h b/idachook/config.h index 9c7dfd7..2ff8d33 100644 --- a/idachook/config.h +++ b/idachook/config.h @@ -4,6 +4,7 @@ #include #include "board/config.h" +#include "board/led15070.h" #include "hooklib/dvd.h" @@ -19,6 +20,7 @@ struct idac_hook_config { struct io4_config io4; struct idac_dll_config dll; struct zinput_config zinput; + struct led15070_config led15070; }; void idac_dll_config_load( diff --git a/idachook/dllmain.c b/idachook/dllmain.c index accc661..bbd3f8a 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -67,24 +67,31 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } - hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod); - - if (FAILED(hr)) { - goto fail; - } - hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); if (FAILED(hr)) { goto fail; } + hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + hr = idac_io4_hook_init(&idac_hook_cfg.io4); if (FAILED(hr)) { goto fail; } + hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init, + idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1); + + if (FAILED(hr)) { + goto fail; + } + /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c index b463a6d..3019608 100644 --- a/idachook/idac-dll.c +++ b/idachook/idac-dll.c @@ -24,6 +24,18 @@ const struct dll_bind_sym idac_dll_syms[] = { }, { .sym = "idac_io_get_analogs", .off = offsetof(struct idac_dll, get_analogs), + }, { + .sym = "idac_io_led_init", + .off = offsetof(struct idac_dll, led_init), + }, { + .sym = "idac_io_led_set_fet_output", + .off = offsetof(struct idac_dll, led_set_fet_output), + }, { + .sym = "idac_io_led_gs_update", + .off = offsetof(struct idac_dll, led_gs_update), + }, { + .sym = "idac_io_led_set_leds", + .off = offsetof(struct idac_dll, led_set_leds), } }; diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h index cc4a492..acdce35 100644 --- a/idachook/idac-dll.h +++ b/idachook/idac-dll.h @@ -11,6 +11,10 @@ struct idac_dll { void (*get_gamebtns)(uint8_t *gamebtn); void (*get_shifter)(uint8_t *gear); void (*get_analogs)(struct idac_io_analog_state *out); + HRESULT (*led_init)(void); + void (*led_set_fet_output)(const uint8_t *rgb); + void (*led_gs_update)(const uint8_t *rgb); + void (*led_set_leds)(const uint8_t *rgb); }; struct idac_dll_config { diff --git a/idachook/idachook.def b/idachook/idachook.def index a8b05b5..32cdffc 100644 --- a/idachook/idachook.def +++ b/idachook/idachook.def @@ -17,3 +17,7 @@ EXPORTS idac_io_get_gamebtns idac_io_get_shifter idac_io_get_analogs + idac_io_led_init + idac_io_led_set_fet_output + idac_io_led_gs_update + idac_io_led_set_leds diff --git a/idachook/io4.c b/idachook/io4.c index b5e13be..5340f5a 100644 --- a/idachook/io4.c +++ b/idachook/io4.c @@ -11,10 +11,12 @@ #include "util/dprintf.h" static HRESULT idac_io4_poll(void *ctx, struct io4_state *state); +static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len); static uint16_t coins; static const struct io4_ops idac_io4_ops = { .poll = idac_io4_poll, + .write_gpio = idac_io4_write_gpio }; static const uint16_t idac_gear_signals[] = { @@ -128,3 +130,34 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) return S_OK; } + +static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) +{ + // Just fast fail if there aren't enough bytes in the payload + if (len < 3) + return S_OK; + + // This command is used for lights in IDAC, but it only contains button lights, + // and only in the first 3 bytes of the payload; everything else is padding to + // make the payload 62 bytes. The rest of the cabinet lights and the side button + // lights are handled separately, by the 15070 lights controller. + uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); + + // Since Sega uses an odd ordering for the first part of the bitfield, + // let's normalize the data and just send over bytes for the receiver + // to interpret as ON/OFF values. + uint8_t rgb_out[6] = { + lights_data & IDAC_IO_LED_START ? 0xFF : 0x00, + lights_data & IDAC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00, + lights_data & IDAC_IO_LED_UP ? 0xFF : 0x00, + lights_data & IDAC_IO_LED_DOWN ? 0xFF : 0x00, + lights_data & IDAC_IO_LED_RIGHT ? 0xFF : 0x00, + lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00, + }; + + idac_dll.led_set_leds(rgb_out); + + return S_OK; +} diff --git a/idacio/dllmain.c b/idacio/dllmain.c index f524139..fbdc7d8 100644 --- a/idacio/dllmain.c +++ b/idacio/dllmain.c @@ -19,7 +19,7 @@ static bool idac_io_coin; uint16_t idac_io_get_api_version(void) { - return 0x0100; + return 0x0101; } HRESULT idac_io_init(void) @@ -118,3 +118,44 @@ void idac_io_get_analogs(struct idac_io_analog_state *out) out->accel = tmp.accel; out->brake = tmp.brake; } + +HRESULT idac_io_led_init(void) +{ + return S_OK; +} + +void idac_io_led_set_fet_output(const uint8_t *rgb) +{ +#if 0 + dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]); + dprintf("IDAC LED: RIGHT SEAT LED: %02X\n", rgb[1]); +#endif + + return; +} + +void idac_io_led_gs_update(const uint8_t *rgb) +{ +#if 0 + for (int i = 0; i < 9; i++) { + dprintf("IDAC LED: LED %d: %02X %02X %02X Speed: %02X\n", + i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + } +#endif + + return; +} + +void idac_io_led_set_leds(const uint8_t *rgb) +{ +#if 0 + dprintf("IDAC LED: START: %02X\n", rgb[0]); + dprintf("IDAC LED: VIEW CHANGE: %02X\n", rgb[1]); + dprintf("IDAC LED: UP: %02X\n", rgb[2]); + dprintf("IDAC LED: DOWN: %02X\n", rgb[3]); + dprintf("IDAC LED: RIGHT: %02X\n", rgb[4]); + dprintf("IDAC LED: LEFT: %02X\n", rgb[5]); +#endif + + return; +} diff --git a/idacio/idacio.def b/idacio/idacio.def index e888510..6b447ac 100644 --- a/idacio/idacio.def +++ b/idacio/idacio.def @@ -6,3 +6,7 @@ EXPORTS idac_io_get_gamebtns idac_io_get_shifter idac_io_get_analogs + idac_io_led_init + idac_io_led_set_fet_output + idac_io_led_gs_update + idac_io_led_set_leds diff --git a/idacio/idacio.h b/idacio/idacio.h index 04c1b10..5e36b5b 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -19,6 +19,17 @@ enum { IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20, }; +enum { + /* These are the bitmasks to use when checking which + lights are triggered on incoming IO4 GPIO writes. */ + IDAC_IO_LED_START = 1 << 31, + IDAC_IO_LED_VIEW_CHANGE = 1 << 30, + IDAC_IO_LED_UP = 1 << 25, + IDAC_IO_LED_DOWN = 1 << 24, + IDAC_IO_LED_LEFT = 1 << 23, + IDAC_IO_LED_RIGHT = 1 << 22, +}; + struct idac_io_analog_state { /* Current steering wheel position, where zero is the centered position. @@ -92,4 +103,60 @@ void idac_io_get_analogs(struct idac_io_analog_state *out); Minimum API version: 0x0100 */ -void idac_io_get_shifter(uint8_t *gear); \ No newline at end of file +void idac_io_get_shifter(uint8_t *gear); + +/* Initialize LED emulation. This function will be called before any + other idac_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0101 */ + +HRESULT idac_io_led_init(void); + +/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes. + + The following bits are used to control the FET outputs: + [0]: LEFT SEAT LED + [1]: RIGHT SEAT LED + + The LED is truned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void idac_io_led_set_fet_output(const uint8_t *rgb); + +/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. + + The LEDs are laid out as follows: + [0]: LEFT UP LED + [1-2]: LEFT CENTER LED + [3]: LEFT DOWN LED + [5]: RIGHT UP LED + [6-7]: RIGHT CENTER LED + [8]: RIGHT DOWN LED + + Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed. + Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest. + + Minimum API version: 0x0101 */ + +void idac_io_led_gs_update(const uint8_t *rgb); + +/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. + + The LEDs are laid out as follows: + [0]: START LED + [1]: VIEW CHANGE LED + [2]: UP LED + [3]: DOWN LED + [4]: RIGHT LED + [5]: LEFT LED + + The LED is turned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void idac_io_led_set_leds(const uint8_t *rgb); diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index 82ae124..cb2fdde 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -1,3 +1,14 @@ +/* + "Initial D ARCADE STAGE Zero" (idz) hook + + Devices + + JVS: 837-15257 "Type 4" I/O Board + COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board + COM10: 837-15286 "Gen 2" Aime Reader + COM11: 837-15070-02 IC BD LED Controller Board +*/ + #include #include From 050951e56f34ab1a6ed3f421c4fac4111d4c56d3 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 24 Jun 2024 17:15:29 +0200 Subject: [PATCH 112/204] idac: removed unused include --- idachook/dllmain.c | 1 - 1 file changed, 1 deletion(-) diff --git a/idachook/dllmain.c b/idachook/dllmain.c index bbd3f8a..d16c175 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -18,7 +18,6 @@ #include "board/sg-reader.h" #include "board/io4.h" -#include "board/ffb.h" #include "hook/process.h" From 965126c68af3eeedd45c779aa5b42c178e47cc66 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 30 Jun 2024 14:23:20 +0200 Subject: [PATCH 113/204] idac: improved compatibility with newer versions --- dist/idac/segatools.ini | 14 ++- idachook/config.c | 11 ++ idachook/config.h | 10 +- idachook/dllmain.c | 7 ++ idachook/indrun.c | 260 ++++++++++++++++++++++++++++++++++++++++ idachook/indrun.h | 9 ++ idachook/meson.build | 2 + 7 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 idachook/indrun.c create mode 100644 idachook/indrun.h diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index eab33e2..f678a77 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -80,8 +80,18 @@ dipsw5=0 ; ----------------------------------------------------------------------------- [led15070] -; Enable emulation of the 15070-02 controlled lights, which handle the cabinet -; and seat LEDs. +; Enable emulation of the 837-15070-02 controlled lights, which handle the +; cabinet and seat LEDs. +enable=1 + +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[indrun] +; Hooks to patch GameProject-Win64-Shipping.exe and IndRun.dll. This is needed +; to boot version 1.60.00 and up. The hooks are not needed for version 1.50.00 +; and below. enable=1 ; ----------------------------------------------------------------------------- diff --git a/idachook/config.c b/idachook/config.c index f3bf349..a4fe392 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -66,6 +66,16 @@ void idac_dll_config_load( filename); } +void indrun_config_load( + struct indrun_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"indrun", L"enable", 1, filename); +} + void idac_hook_config_load( struct idac_hook_config *cfg, const wchar_t *filename) @@ -80,6 +90,7 @@ void idac_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); led15070_config_load(&cfg->led15070, filename); + indrun_config_load(&cfg->indrun, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/idachook/config.h b/idachook/config.h index 2ff8d33..b7ca6d3 100644 --- a/idachook/config.h +++ b/idachook/config.h @@ -10,6 +10,7 @@ #include "idachook/idac-dll.h" #include "idachook/zinput.h" +#include "idachook/indrun.h" #include "platform/platform.h" @@ -21,6 +22,7 @@ struct idac_hook_config { struct idac_dll_config dll; struct zinput_config zinput; struct led15070_config led15070; + struct indrun_config indrun; }; void idac_dll_config_load( @@ -31,4 +33,10 @@ void idac_hook_config_load( struct idac_hook_config *cfg, const wchar_t *filename); -void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename); +void zinput_config_load( + struct zinput_config *cfg, + const wchar_t *filename); + +void indrun_config_load( + struct indrun_config *cfg, + const wchar_t *filename); diff --git a/idachook/dllmain.c b/idachook/dllmain.c index d16c175..63b0954 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -91,6 +91,13 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } + /* Initialize native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the initialization. */ + + indrun_hook_init(&idac_hook_cfg.indrun); + /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); diff --git a/idachook/indrun.c b/idachook/indrun.c new file mode 100644 index 0000000..1b9eb77 --- /dev/null +++ b/idachook/indrun.c @@ -0,0 +1,260 @@ +#include +#include + +#include "hook/table.h" + +#include "hooklib/dll.h" + +#include "util/dprintf.h" + +#include "indrun.h" + +static const wchar_t *target_modules[] = { + L"IndRun.dll", +}; + +static const size_t target_modules_len = _countof(target_modules); + +static void dll_hook_insert_hooks(HMODULE target); +static void app_hook_insert_hooks(HMODULE target); + +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name); +static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); + +static int WINAPI hook_GetSystemMetrics(int nIndex); +static int (WINAPI *next_GetSystemMetrics)(int nIndex); + +static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize); +static DWORD WINAPI hook_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer); +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); +static int (WINAPI *next_GetVersionExW)(LPOSVERSIONINFOW lpVersionInformation); +static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); +static BOOL (WINAPI *next_VerifyVersionInfoW)(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); +static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded); +static BOOL (WINAPI *next_K32EnumProcesses)(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded); + +static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer); + +static const struct hook_symbol idac_app_user32_syms[] = { + { + .name = "GetSystemMetrics", + .patch = hook_GetSystemMetrics, + .link = (void **) &next_GetSystemMetrics, + } +}; + +static const struct hook_symbol idac_app_kernel32_syms[] = { + { + .name = "GetComputerNameW", + .patch = hook_GetComputerNameW, + }, + { + .name = "GetCurrentDirectoryW", + .patch = hook_GetCurrentDirectoryW, + }, + { + .name = "GetVersionExW", + .patch = hook_GetVersionExW, + .link = (void **) &next_GetVersionExW, + }, + { + .name = "VerifyVersionInfoW", + .patch = hook_VerifyVersionInfoW, + .link = (void **) &next_VerifyVersionInfoW, + }, + { + .name = "K32EnumProcesses", + .patch = hook_K32EnumProcesses, + .link = (void **) &next_K32EnumProcesses, + } +}; + +static const struct hook_symbol idac_app_advapi32_syms[] = { + { + .name = "GetUserNameW", + .patch = hook_GetUserNameW, + } +}; + +static const struct hook_symbol indrun_kernel32_syms[] = { + { + .name = "LoadLibraryW", + .patch = hook_LoadLibraryW, + .link = (void **) &next_LoadLibraryW, + } +}; + +void indrun_hook_init(struct indrun_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + dprintf("IDAC: Hooks enabled.\n"); + + // GameProject-Win64-Shipping.exe hooks + app_hook_insert_hooks(NULL); + + // IndRun.dll hooks + dll_hook_insert_hooks(NULL); +} + +static void dll_hook_insert_hooks(HMODULE target) { + hook_table_apply( + target, + "kernel32.dll", + indrun_kernel32_syms, + _countof(indrun_kernel32_syms)); +} + +void app_hook_insert_hooks(HMODULE target) { + hook_table_apply( + target, + "user32.dll", + idac_app_user32_syms, + _countof(idac_app_user32_syms)); + + hook_table_apply( + target, + "kernel32.dll", + idac_app_kernel32_syms, + _countof(idac_app_kernel32_syms)); + + hook_table_apply( + target, + "advapi32.dll", + idac_app_advapi32_syms, + _countof(idac_app_advapi32_syms)); +} + +static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) +{ + const wchar_t *name_end; + const wchar_t *target_module; + bool already_loaded; + HMODULE result; + size_t name_len; + size_t target_module_len; + + if (name == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + + return NULL; + } + + // Check if the module is already loaded + already_loaded = GetModuleHandleW(name) != NULL; + + // Must call the next handler so the DLL reference count is incremented + result = next_LoadLibraryW(name); + + if (!already_loaded && result != NULL) { + name_len = wcslen(name); + + for (size_t i = 0; i < target_modules_len; i++) { + target_module = target_modules[i]; + target_module_len = wcslen(target_module); + + // Check if the newly loaded library is at least the length of + // the name of the target module + if (name_len < target_module_len) { + continue; + } + + name_end = &name[name_len - target_module_len]; + + // Check if the name of the newly loaded library is one of the + // modules the path hooks should be injected into + if (_wcsicmp(name_end, target_module) != 0) { + continue; + } + + dprintf("IDAC: Hooked %S\n", target_module); + + dll_hook_insert_hooks(result); + app_hook_insert_hooks(result); + } + } + + return result; +} + +static int WINAPI hook_GetSystemMetrics(int nIndex) { + int ret = next_GetSystemMetrics(nIndex); + + // Disable mouse buttons detection + if (nIndex == SM_CMOUSEBUTTONS) { + dprintf("IDAC: GetSystemMetrics(%d) -> 0\n", nIndex); + return 0; + } + + return ret; +} + +static BOOL WINAPI hook_GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize) { + dprintf("IDAC: GetComputerNameW -> ACAE01A99999999\n"); + + // Fake the computer name as ACAE01A999999999 + wcscpy(lpBuffer, L"ACAE01A999999999"); + *nSize = _countof(L"ACAE01A99999999"); + + return TRUE; +} + +static DWORD WINAPI hook_GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) { + dprintf("IDAC: GetCurrentDirectoryW -> X:\\\n"); + + // Fake the current diretory as X: + wcscpy(lpBuffer, L"X"); + return 1; +} + +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) { + int result = next_GetVersionExW(lpVersionInformation); + + // Fake the version as Windows 10 1809 + if (result) { + dprintf("IDAC: GetVersionExW -> Windows 10 1809\n"); + lpVersionInformation->dwMajorVersion = 10; + lpVersionInformation->dwMinorVersion = 0; + lpVersionInformation->dwBuildNumber = 17763; + return TRUE; + } + + return result; +} + +static BOOL WINAPI hook_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) { + dprintf("IDAC: GetUserNameW -> AppUser\n"); + + // Fake the user name as AppUser + wcscpy(lpBuffer, L"AppUser"); + *pcbBuffer = _countof(L"AppUser"); + + return TRUE; +} + +static BOOL WINAPI hook_VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask) { + BOOL result = next_VerifyVersionInfoW(lpVersionInformation, dwTypeMask, dwlConditionMask); + + // Fake the version as Windows 10 1809 + if (lpVersionInformation->dwBuildNumber == 17763) { + dprintf("IDAC: VerifyVersionInfoW -> Windows 10 1809\n"); + return TRUE; + } + + return result; +} + +static BOOL WINAPI hook_K32EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded) { + BOOL result = next_K32EnumProcesses(lpidProcess, cb, lpcbNeeded); + + // Rteurn an empy process list + dprintf("IDAC: K32EnumProcesses -> NULL\n"); + lpidProcess = NULL; + *lpcbNeeded = 0; + + return TRUE; +} diff --git a/idachook/indrun.h b/idachook/indrun.h new file mode 100644 index 0000000..4605285 --- /dev/null +++ b/idachook/indrun.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +struct indrun_config { + bool enable; +}; + +void indrun_hook_init(struct indrun_config *cfg); diff --git a/idachook/meson.build b/idachook/meson.build index 72214ac..8de655e 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -28,5 +28,7 @@ shared_library( 'io4.h', 'zinput.c', 'zinput.h', + 'indrun.c', + 'indrun.h', ], ) From f3e31fc2ae0c9c4fe8e23c2d8eb7e4784e5c03cf Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 30 Jun 2024 19:37:04 +0200 Subject: [PATCH 114/204] improved doc --- doc/config/common.md | 2 +- segatools.md | 456 ------------------------------------------- 2 files changed, 1 insertion(+), 457 deletions(-) delete mode 100644 segatools.md diff --git a/doc/config/common.md b/doc/config/common.md index 59ec2e1..ad9e348 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -352,7 +352,7 @@ Enable keychip emulation. Disable to use a real keychip. Default: `A69E-01A88888888` Keychip serial number. Keychip serials observed in the wild follow this -pattern: `A6xE-01Ayyyyyyyy`. +pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`. ### `gameId` diff --git a/segatools.md b/segatools.md deleted file mode 100644 index 51b97e0..0000000 --- a/segatools.md +++ /dev/null @@ -1,456 +0,0 @@ -# Segatools common configuration settings - -This file describes configuration settings for Segatools that are common to -all games. - -Keyboard binding settings use -[Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). - -## `[aimeio]` - -Controls the card reader driver. - -### `path` - -Specify a path for a third-party card reader driver DLL. Default is empty -(use built-in emulation based on text files and keyboard input). - -In previous versions of Segatools this was accomplished by replacing the -AIMEIO.DLL file that came with Segatools. Segatools no longer ships with a -separate AIMEIO.DLL file (its functionality is now built into the various hook -DLLs). - -## `[aime]` - -Controls emulation of the Aime card reader assembly. - -### `enable` - -Default: `1` - -Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime -reader (COM port number varies by game). - -### `aimePath` - -Default: `DEVICE\aime.txt` - -Path to a text file containing a classic Aime IC card ID. **This does not -currently work**. - -### `felicaPath` - -Default: `DEVICE\felica.txt` - -Path to a text file containing a FeliCa e-cash card IDm serial number. - -### `felicaGen` - -Default: `1` - -Whether to generate a random FeliCa ID if the file at `felicaPath` does not -exist. - -### `scan` - -Default: `0x0D` (`VK_RETURN`) - -Virtual-key code. If this button is **held** then the emulated IC card reader -emulates an IC card in its proximity. A variety of different IC cards can be -emulated; the exact choice of card that is emulated depends on the presence or -absence of the configured card ID files. - -## `[amvideo]` - -Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is -normally present on the SEGA operating system image which is responsible for -changing screen resolution and orientation. - -### `enable` - -Default: `1` - -Enable stub `amvideo.dll`. Disable to use a real `amvideo.dll` build. Note that -you must have the correct registry settings installed and you must use the -version of `amvideo.dll` that matches your GPU vendor (since these DLLs make -use of vendor-specific APIs). - -## `[clock]` - -Controls hooks for Windows time-of-day APIs. - -### `timezone` - -Default: `1` - -Make the system time zone appear to be JST. SEGA games malfunction in strange -ways if the system time zone is not JST. There should not be any reason to -disable this hook other than possible implementation bugs, but the option is -provided if you need it. - -### `timewarp` - -Default: `0` - -Experimental time-of-day warping hook that skips over the hardcoded server -maintenance period. Causes an incorrect in-game time-of-day to be reported. -Better solutions for this problem exist and this feature will probably be -removed soon. - -### `writeable` - -Default: `0` - -Allow game to adjust system clock and time zone settings. This should normally -be left at `0`, but the option is provided if you need it. - -## `[dns]` - -Controls redirection of network server hostname lookups - -### `default` - -Default: `localhost` - -Controls hostname of all of the common network services servers, unless -overriden by a specific setting below. Most users will only need to change this -setting. Also, loopback addresses are specifically checked for and rejected by -the games themselves; this needs to be a LAN or WAN IP (or a hostname that -resolves to one). - -### `router` - -Default: Empty string (i.e. use value from `default` setting) - -Overrides the target of the `tenporouter.loc` and `bbrouter.loc` hostname -lookups. - -### `startup` - -Default: Empty string (i.e. use value from `default` setting) - -Overrides the target of the `naominet.jp` host lookup. - -### `billing` - -Default: Empty string (i.e. use value from `default` setting) - -Overrides the target of the `ib.naominet.jp` host lookup. - -### `aimedb` - -Default: Empty string (i.e. use value from `default` setting) - -Overrides the target of the `aime.naominet.jp` host lookup. - -## `[ds]` - -Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX -PCIe board. This is a small (32 byte) EEPROM that contains serial number and -region code information. It is not normally written to outside of inital -factory provisioning of a Sega Nu. - -### `enable` - -Default: `1` - -Enable DS EEPROM emulation. Disable to use the DS EEPROM chip on a real AMEX. - -### `region` - -Default: `1` - -AMEX Board region code. This appears to be a bit mask? - -- `1`: Japan -- `2`: USA? (Dead code, not used) -- `4`: Export -- `8`: China - -### `serialNo` - -Default `AAVE-01A99999999` - -"MAIN ID" serial number. First three characters are hardware series: - -- `AAV`: Nu-series -- `AAW`: NuSX-series -- `ACA`: ALLS-series - -## `[eeprom]` - -Controls emulation of the bulk EEPROM on the AMEX PCIe board. This chip stores -status and configuration information. - -### `enable` - -Default: `1` - -Enable bulk EEPROM emulation. Disable to use the bulk EEPROM chip on a real -AMEX. - -### `path` - -Default: `DEVICE\eeprom.bin` - -Path to the storage file for EEPROM emulation. This file is automatically -created and initialized with a suitable number of zero bytes if it does not -already exist. - -## `[gpio]` - -Configure emulation of the AMEX PCIe GPIO (General Purpose Input Output) -controller. - -### `enable` - -Default: `1` - -Enable GPIO emulation. Disable to use the GPIO controller on a real AMEX. - -### `sw1` - -Default `0x70` (`VK_F1`) - -Keyboard binding for Nu chassis SW1 button (alternative Test) - -### `sw2` - -Default `0x71` (`VK_F2`) - -Keyboard binding for Nu chassis SW2 button (alternative Service) - -### `dipsw1` .. `dipsw8` - -Defaults: `1`, `0`, `0`, `0`, `0`, `0`, `0`, `0` - -Nu chassis DIP switch settings: - -- Switch 1: Game-specific, but usually controls the "distribution server" - setting. Exactly one arcade machine on a cabinet router must be set to the - Server setting. - - `0`: Client - - `1`: Server -- Switch 2,3: Game-specific. - - Used by Mario&Sonic to configure cabinet ID, possibly other games. -- Switch 4: Screen orientation. Only used by the Nu system startup program. - - `0`: YOKO/Horizontal - - `1`: TATE/Vertical -- Switch 5,6,7: Screen resolution. Only used by the Nu system startup program. - - `000`: No change - - `100`: 640x480 - - `010`: 1024x600 - - `110`: 1024x768 - - `001`: 1280x720 - - `101`: 1280x1024 - - `110`: 1360x768 - - `111`: 1920x1080 -- Switch 8: Game-specific. Not used in any shipping game. - -## `[hwmon]` - -Configure stub implementation of the platform hardware monitor driver. The -real implementation of this driver monitors CPU temperatures by reading from -Intel Model Specific Registers, which is an action that is only permitted from -kernel mode. - -### `enable` - -Default `1` - -Enable hwmon emulation. Disable to use the real hwmon driver. - -## `[jvs]` - -Configure emulation of the AMEX PCIe JVS *controller* (not IO board!) - -### `enable` - -Default `1` - -Enable JVS port emulation. Disable to use the JVS port on a real AMEX. - -## `[keychip]` - -Configure keychip emulation. - -### `enable` - -Enable keychip emulation. Disable to use a real keychip. - -### `id` - -Default: `A69E-01A88888888` - -Keychip serial number. Keychip serials observed in the wild follow this -pattern: `A\d{2}(E01|X20)[ABCDU]\d{8}`. - -### `gameId` - -Default: (Varies depending on game) - -Override the game's four-character model code. Changing this from the game's -expected value will probably just cause a system error. - -### `platformId` - -Default: (Varies depending on game) - -Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This -is actually supposed to be a separate three-character `platformId` and -integer `modelType` setting, but they are combined here for convenience. Valid -values include: - -- `AAV0`: Nu 1 (Project DIVA) -- `AAV1`: Nu 1.1 (Chunithm) -- `AAV2`: Nu 2 (Initial D Zero) -- `AAW0`: NuSX 1 -- `AAW1`: NuSX 1.1 -- `ACA0`: ALLS UX -- `ACA1`: ALLS HX -- `ACA2`: ALLS UX (without dedicated GPU) -- `ACA4`: ALLS MX - -### `region` - -Default: `1` - -Override the keychip's region code. Most games seem to pay attention to the -DS EEPROM region code and not the keychip region code, and this seems to be -a bit mask that controls which Nu PCB region codes this keychip is authorized -for. So it probably only affects the system software and not the game software. -Bit values are: - -- 1: JPN: Japan -- 2: USA (unused) -- 3: EXP: Export (for Asian markets) -- 4: CHS: China (Simplified Chinese?) - -### `systemFlag` - -Default: `0x64` - -An 8-bit bitfield of unclear meaning. The least significant bit indicates a -developer dongle, I think? Changing this doesn't seem to have any effect on -anything other than Project DIVA. - -Other values observed in the wild: - -- `0x04`: SDCH, SDCA -- `0x20`: SDCA - -### `subnet` - -Default `192.168.100.0` - -The LAN IP range that the game will expect. The prefix length is hardcoded into -the game program: for some games this is `/24`, for others it is `/20`. - -## `[netenv]` - -Configure network environment virtualization. This module helps bypass various -restrictions placed upon the game's LAN environment. - -### `enable` - -Default `1` - -Enable network environment virtualization. You may need to disable this if -you want to do any head-to-head play on your LAN. - -Note: The virtualized LAN IP range is taken from the emulated keychip's -`subnet` setting. - -### `addrSuffix` - -Default: `11` - -The final octet of the local host's IP address on the virtualized subnet (so, -if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the -local host's virtualized LAN IP is `192.168.32.11`). - -### `routerSuffix` - -Default: `1` - -The final octet of the default gateway's IP address on the virtualized subnet. - -### `macAddr` - -Default: `01:02:03:04:05:06` - -The MAC address of the virtualized Ethernet adapter. The exact value shouldn't -ever matter. - -## `[pcbid]` - -Configure Windows host name virtualization. The ALLS-series platform no longer -has an AMEX board, so the MAIN ID serial number is stored in the Windows -hostname. - -### `enable` - -Default: `1` - -Enable Windows host name virtualization. This is only needed for ALLS-platform -games (since the ALLS lacks an AMEX and therefore has no DS EEPROM, so it needs -another way to store the PCB serial), but it does no harm on games that run on -earlier hardware. - -### `serialNo` - -Default: `ACAE01A99999999` - -Set the Windows host name. This should be an ALLS MAIN ID, without the -hyphen (which is not a valid character in a Windows host name). - -## `[sram]` - -Configure emulation of the AMEX PCIe battery-backed SRAM. This stores -bookkeeping state and settings. This file is automatically created and -initialized with a suitable number of zero bytes if it does not already exist. - -### `enable` - -Default `1` - -Enable SRAM emulation. Disable to use the SRAM on a real AMEX. - -### `path` - -Default `DEVICE\sram.bin` - -Path to the storage file for SRAM emulation. - -## `[vfs]` - -Configure Windows path redirection hooks. - -### `enable` - -Default: `1` - -Enable path redirection. - -### `amfs` - -Default: Empty string (causes a startup error) - -Configure the location of the SEGA AMFS volume. Stored on the `E` partition on -real hardware. - -### `appdata` - -Default: Empty string (causes a startup error) - -Configure the location of the SEGA "APPDATA" volume (nothing to do with the -Windows user's `%APPDATA%` directory). Stored on the `Y` partition on real -hardware. - -### `option` - -Default: Empty string - -Configure the location of the "Option" data mount point. This mount point is -optional (hence the name, probably) and contains directories which contain -minor over-the-air content updates. From ded89f6343e86c580fcd29c4b2da46a754496c47 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Mon, 1 Jul 2024 19:28:23 +0100 Subject: [PATCH 115/204] Make fixes based on #22 review --- Makefile | 2 +- meson.options => meson_options.txt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename meson.options => meson_options.txt (100%) diff --git a/Makefile b/Makefile index 66a6e24..28562a1 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ DIST_DIR := dist # Add "-D[option]=[value]" here as necessary MESON_OPTIONS := # For options that shouldn't be committed -include MesonLocalOptions.mk +-include MesonLocalOptions.mk # ----------------------------------------------------------------------------- # Targets diff --git a/meson.options b/meson_options.txt similarity index 100% rename from meson.options rename to meson_options.txt From 8c839b0d4ee423697484310e980efdf75f904b62 Mon Sep 17 00:00:00 2001 From: zaphkito Date: Wed, 3 Jul 2024 18:04:21 +0000 Subject: [PATCH 116/204] dns: added WAHLAP billing DNS block China have another company named universal service WACCA, but they use same PowerOn and Download Order domain with SEGA official, so we need express `sys-all.cn` is only used for WAHLAP, not all China SEGA games. WAHLAP have a unused billing domain, just in case, we blocked it now --- platform/dns.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/dns.c b/platform/dns.c index 2e8f64b..ab7574a 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -109,17 +109,23 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } - // CHN - // PowerOn + // WAHLAP PowerOn hr = dns_hook_push(L"at.sys-all.cn", cfg->startup); if (FAILED(hr)) { return hr; } - // WeChat AimeDB Server + // WAHLAP WeChat AimeDB Server hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb); + if (FAILED(hr)) { + return hr; + } + + // WAHLAP Billing + hr = dns_hook_push(L"ib.sys-all.cn", cfg->billing); + if (FAILED(hr)) { return hr; } From fe14630b3ddd197c8a6ddb48dc9b27a1a8b5fa78 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 5 Aug 2024 20:49:47 +0200 Subject: [PATCH 117/204] unity: fixed option loading crash --- unityhook/hook.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/unityhook/hook.c b/unityhook/hook.c index bd380f9..c11e744 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -139,11 +139,13 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) dll_hook_insert_hooks(result); path_hook_insert_hooks(result); - // printer_hook_insert_hooks(result); reg_hook_insert_hooks(result); proc_addr_insert_hooks(result); - serial_hook_apply_hooks(result); - iohook_apply_hooks(result); + + // Not needed? + // serial_hook_apply_hooks(result); + // Unity will crash during option loading when we hook this twice + // iohook_apply_hooks(result); } } From 5abc593b46b65fd4c8d44db39d0b3ccc426b87e2 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 5 Aug 2024 20:53:56 +0200 Subject: [PATCH 118/204] cm: added printer support --- cmhook/cmhook.def | 56 ++ cmhook/config.c | 1 + cmhook/config.h | 2 + cmhook/dllmain.c | 4 + dist/cm/segatools.ini | 10 +- hooklib/printer.c | 1602 ++++++++++++++++++++++++++++++++--------- hooklib/printer.h | 1 + 7 files changed, 1326 insertions(+), 350 deletions(-) diff --git a/cmhook/cmhook.def b/cmhook/cmhook.def index 8590794..ab7d3af 100644 --- a/cmhook/cmhook.def +++ b/cmhook/cmhook.def @@ -15,3 +15,59 @@ EXPORTS cm_io_get_opbtns cm_io_init cm_io_poll + CFW_init + CFW_term + CFW_open + CFW_close + CFW_listupPrinter + CFW_listupPrinterSN + CFW_selectPrinter + CFW_selectPrinterSN + CFW_getPrinterInfo + CFW_status + CFW_statusAll + CFW_resetPrinter + CFW_updateFirmware + CFW_getFirmwareInfo + CHCUSB_init + CHCUSB_term + CHCUSB_MakeThread + CHCUSB_open + CHCUSB_close + CHCUSB_ReleaseThread + CHCUSB_listupPrinter + CHCUSB_listupPrinterSN + CHCUSB_selectPrinter + CHCUSB_selectPrinterSN + CHCUSB_getPrinterInfo + CHCUSB_imageformat + CHCUSB_setmtf + CHCUSB_makeGamma + CHCUSB_setIcctableProfile + CHCUSB_setIcctable + CHCUSB_copies + CHCUSB_status + CHCUSB_statusAll + CHCUSB_startpage + CHCUSB_endpage + CHCUSB_write + CHCUSB_writeLaminate + CHCUSB_writeHolo + CHCUSB_setPrinterInfo + CHCUSB_setPrinterToneCurve + CHCUSB_getGamma + CHCUSB_getMtf + CHCUSB_cancelCopies + CHCUSB_getPrinterToneCurve + CHCUSB_blinkLED + CHCUSB_resetPrinter + CHCUSB_AttachThreadCount + CHCUSB_getPrintIDStatus + CHCUSB_setPrintStandby + CHCUSB_testCardFeed + CHCUSB_exitCard + CHCUSB_getCardRfidTID + CHCUSB_commCardRfidReader + CHCUSB_updateCardRfidReader + CHCUSB_getErrorLog + CHCUSB_getErrorStatus diff --git a/cmhook/config.c b/cmhook/config.c index 4c0a808..c0c0bfd 100644 --- a/cmhook/config.c +++ b/cmhook/config.c @@ -39,6 +39,7 @@ void cm_hook_config_load( io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); + printer_config_load(&cfg->printer, filename); cm_dll_config_load(&cfg->dll, filename); unity_config_load(&cfg->unity, filename); } diff --git a/cmhook/config.h b/cmhook/config.h index a840358..26d9a7c 100644 --- a/cmhook/config.h +++ b/cmhook/config.h @@ -6,6 +6,7 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" +#include "hooklib/printer.h" #include "cmhook/cm-dll.h" @@ -21,6 +22,7 @@ struct cm_hook_config { struct vfd_config vfd; struct cm_dll_config dll; struct touch_screen_config touch; + struct printer_config printer; struct unity_config unity; }; diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 143ec5a..b004db3 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -56,6 +56,10 @@ static DWORD CALLBACK cm_pre_startup(void) touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod); serial_hook_init(); + /* Hook external DLL APIs */ + + printer_hook_init(&cm_hook_cfg.printer, 4, cm_hook_mod); + /* Initialize emulation hooks */ hr = platform_hook_init( diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 181c785..f752b6b 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -50,7 +50,7 @@ enable=1 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.100.0 +subnet=192.168.165.0 [gpio] ; ALLS DIP switches. @@ -73,6 +73,14 @@ enable=0 ; modding frameworks such as BepInEx. targetAssembly= +[printer] +; Sinfonia CHC-C330 printer emulation setting. +enable=1 +; Change the printer serial number here. +serial_no="5A-A123" +; Insert the path to the image output directory here. +printerOutPath="DEVICE\print" + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/hooklib/printer.c b/hooklib/printer.c index 1ef5a0c..7a36eba 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -6,6 +6,7 @@ c310emu (rakisaionji) segatools-kancolle (OLEG) c310emu (doremi) + chc (emihiok) */ #include "hooklib/printer.h" @@ -18,6 +19,7 @@ #include #include "hook/table.h" +#include "hook/procaddr.h" #include "hooklib/dll.h" #include "hooklib/uart.h" #include "util/dprintf.h" @@ -52,7 +54,11 @@ static int32_t CURVE[3][3]; static uint8_t POLISH[2]; static int32_t MTF[9]; -/* C3xxFWDLusb API hooks */ +/* Printer status */ + +static uint8_t STATUS = 0; + +/* C3XXFWDLusb API hooks */ int fwdlusb_open(uint16_t *rResult); void fwdlusb_close(); @@ -71,7 +77,7 @@ int fwdlusb_ReleaseThread(uint16_t *rResult); int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); -/* C3xxusb API hooks */ +/* C3XXusb API hooks */ int chcusb_MakeThread(uint16_t maxCount); int chcusb_open(uint16_t *rResult); @@ -137,6 +143,65 @@ int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); +/* PrintDLL API hooks */ + +void CFW_close(const void *handle); +int CFW_getFirmwareInfo(const void *handle, uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int CFW_getPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int CFW_init(LPCSTR dllpath); +int CFW_listupPrinter(const void *handle, uint8_t *rIdArray); +int CFW_listupPrinterSN(const void *handle, uint64_t *rSerialArray); +int CFW_open(const void *handle, uint16_t *rResult); +int CFW_resetPrinter(const void *handle, uint16_t *rResult); +int CFW_selectPrinter(const void *handle, uint8_t printerId, uint16_t *rResult); +int CFW_selectPrinterSN(const void *handle, uint64_t printerSN, uint16_t *rResult); +int CFW_status(const void *handle, uint16_t *rResult); +int CFW_statusAll(const void *handle, uint8_t *idArray, uint16_t *rResultArray); +void CFW_term(const void *handle); +int CFW_updateFirmware(const void *handle, uint8_t update, LPCSTR filename, uint16_t *rResult); +int CHCUSB_AttachThreadCount(const void *handle, uint16_t *rCount, uint16_t *rMaxCount); +int CHCUSB_MakeThread(const void *handle, uint16_t maxCount); +int CHCUSB_ReleaseThread(const void *handle, uint16_t *rResult); +int CHCUSB_blinkLED(const void *handle, uint16_t *rResult); +int CHCUSB_cancelCopies(const void *handle, uint16_t pageId, uint16_t *rResult); +void CHCUSB_close(const void *handle); +int CHCUSB_commCardRfidReader(const void *handle, uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); +int CHCUSB_copies(const void *handle, uint16_t copies, uint16_t *rResult); +int CHCUSB_endpage(const void *handle, uint16_t *rResult); +int CHCUSB_exitCard(const void *handle, uint16_t *rResult); +int CHCUSB_getCardRfidTID(const void *handle, uint8_t *rCardTID, uint16_t *rResult); +int CHCUSB_getErrorLog(const void *handle, uint16_t index, uint8_t *rData, uint16_t *rResult); +int CHCUSB_getErrorStatus(const void *handle, uint16_t *rBuffer); +int CHCUSB_getGamma(const void *handle, LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); +int CHCUSB_getMtf(const void *handle, LPCSTR filename, int32_t *mtf, uint16_t *rResult); +int CHCUSB_getPrintIDStatus(const void *handle, uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); +int CHCUSB_getPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int CHCUSB_getPrinterToneCurve(const void *handle, uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int CHCUSB_imageformat(const void *handle, uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint8_t *inputImage, uint16_t *rResult); +int CHCUSB_init(LPCSTR dllpath); +int CHCUSB_listupPrinter(const void *handle, uint8_t *rIdArray); +int CHCUSB_listupPrinterSN(const void *handle, uint64_t *rSerialArray); +int CHCUSB_makeGamma(const void *handle, uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); +int CHCUSB_open(const void *handle, uint16_t *rResult); +int CHCUSB_resetPrinter(const void *handle, uint16_t *rResult); +int CHCUSB_selectPrinter(const void *handle, uint8_t printerId, uint16_t *rResult); +int CHCUSB_selectPrinterSN(const void *handle, uint64_t printerSN, uint16_t *rResult); +int CHCUSB_setIcctable(const void *handle, uint16_t intents, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB, uint8_t *outtoneR, uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult); +int CHCUSB_setIcctableProfile(const void *handle, LPCSTR icc1, LPCSTR icc2, uint16_t intents, uint16_t *rResult); +int CHCUSB_setPrintStandby(const void *handle, uint16_t position, uint16_t *rResult); +int CHCUSB_setPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int CHCUSB_setPrinterToneCurve(const void *handle, uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int CHCUSB_setmtf(const void *handle, int32_t *mtf); +int CHCUSB_startpage(const void *handle, uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); +int CHCUSB_status(const void *handle, uint16_t *rResult); +int CHCUSB_statusAll(const void *handle, uint8_t *idArray, uint16_t *rResultArray); +int CHCUSB_testCardFeed(const void *handle, uint16_t mode, uint16_t times, uint16_t *rResult); +void CHCUSB_term(const void *handle); +int CHCUSB_updateCardRfidReader(const void *handle, uint8_t *data, uint32_t size, uint16_t *rResult); +int CHCUSB_write(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult); +int CHCUSB_writeHolo(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult); +int CHCUSB_writeLaminate(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult); + /* Bitmap writing utils */ DWORD WriteDataToBitmapFile( @@ -253,331 +318,831 @@ static uint8_t deck_readable_bytes[1024]; static uint8_t current_card_idx = 0; static bool read_pending = false; -/* C3xxFWDLusb hook tbl. */ +/* C3XXFWDLusb hook tbl. The ordinals are required, as some games, for example + Sekito, will import this library by ordinal and not by name. */ static const struct hook_symbol C3XXFWDLusb_hooks[] = { - {.name = "fwdlusb_open", - .patch = fwdlusb_open, - .link = NULL}, - {.name = "fwdlusb_close", - .patch = fwdlusb_close, - .link = NULL}, - {.name = "fwdlusb_listupPrinter", - .patch = fwdlusb_listupPrinter, - .link = NULL}, - {.name = "fwdlusb_listupPrinterSN", - .patch = fwdlusb_listupPrinterSN, - .link = NULL}, - {.name = "fwdlusb_selectPrinter", - .patch = fwdlusb_selectPrinter, - .link = NULL}, - {.name = "fwdlusb_selectPrinterSN", - .patch = fwdlusb_selectPrinterSN, - .link = NULL}, - {.name = "fwdlusb_getPrinterInfo", - .patch = fwdlusb_getPrinterInfo, - .link = NULL}, - {.name = "fwdlusb_status", - .patch = fwdlusb_status, - .link = NULL}, - {.name = "fwdlusb_statusAll", - .patch = fwdlusb_statusAll, - .link = NULL}, - {.name = "fwdlusb_resetPrinter", - .patch = fwdlusb_resetPrinter, - .link = NULL}, - {.name = "fwdlusb_updateFirmware", - .patch = fwdlusb_updateFirmware, - .link = NULL}, - {.name = "fwdlusb_getFirmwareInfo", - .patch = fwdlusb_getFirmwareInfo, - .link = NULL}, - {.name = "fwdlusb_MakeThread", - .patch = fwdlusb_MakeThread, - .link = NULL}, - {.name = "fwdlusb_ReleaseThread", - .patch = fwdlusb_ReleaseThread, - .link = NULL}, - {.name = "fwdlusb_AttachThreadCount", - .patch = fwdlusb_AttachThreadCount, - .link = NULL}, - {.name = "fwdlusb_getErrorLog", - .patch = fwdlusb_getErrorLog, - .link = NULL}, -}; - -/* C310A-Busb/C320Ausb/C330Ausb hook tbl. */ - -static const struct hook_symbol C3XXusb_hooks[] = { - {.name = "chcusb_MakeThread", - .patch = chcusb_MakeThread, - .link = NULL}, - {.name = "chcusb_open", - .patch = chcusb_open, - .link = NULL}, - {.name = "chcusb_close", - .patch = chcusb_close, - .link = NULL}, - {.name = "chcusb_ReleaseThread", - .patch = chcusb_ReleaseThread, - .link = NULL}, - {.name = "chcusb_listupPrinter", - .patch = chcusb_listupPrinter, - .link = NULL}, - {.name = "chcusb_listupPrinterSN", - .patch = chcusb_listupPrinterSN, - .link = NULL}, - {.name = "chcusb_selectPrinter", - .patch = chcusb_selectPrinter, - .link = NULL}, - {.name = "chcusb_selectPrinterSN", - .patch = chcusb_selectPrinterSN, - .link = NULL}, - {.name = "chcusb_getPrinterInfo", - .patch = chcusb_getPrinterInfo, - .link = NULL}, - {.name = "chcusb_imageformat", - .patch = chcusb_imageformat, - .link = NULL}, - {.name = "chcusb_setmtf", - .patch = chcusb_setmtf, - .link = NULL}, - {.name = "chcusb_makeGamma", - .patch = chcusb_makeGamma, - .link = NULL}, - {.name = "chcusb_setIcctable", - .patch = chcusb_setIcctable, - .link = NULL}, - {.name = "chcusb_copies", - .patch = chcusb_copies, - .link = NULL}, - {.name = "chcusb_status", - .patch = chcusb_status, - .link = NULL}, - {.name = "chcusb_statusAll", - .patch = chcusb_statusAll, - .link = NULL}, - {.name = "chcusb_startpage", - .patch = chcusb_startpage, - .link = NULL}, - {.name = "chcusb_endpage", - .patch = chcusb_endpage, - .link = NULL}, - {.name = "chcusb_write", - .patch = chcusb_write, - .link = NULL}, - {.name = "chcusb_writeLaminate", - .patch = chcusb_writeLaminate, - .link = NULL}, - {.name = "chcusb_writeHolo", - .patch = chcusb_writeHolo, - .link = NULL}, - {.name = "chcusb_setPrinterInfo", - .patch = chcusb_setPrinterInfo, - .link = NULL}, - {.name = "chcusb_getGamma", - .patch = chcusb_getGamma, - .link = NULL}, - {.name = "chcusb_getMtf", - .patch = chcusb_getMtf, - .link = NULL}, - {.name = "chcusb_cancelCopies", - .patch = chcusb_cancelCopies, - .link = NULL}, - {.name = "chcusb_setPrinterToneCurve", - .patch = chcusb_setPrinterToneCurve, - .link = NULL}, - {.name = "chcusb_getPrinterToneCurve", - .patch = chcusb_getPrinterToneCurve, - .link = NULL}, - {.name = "chcusb_blinkLED", - .patch = chcusb_blinkLED, - .link = NULL}, - {.name = "chcusb_resetPrinter", - .patch = chcusb_resetPrinter, - .link = NULL}, - {.name = "chcusb_AttachThreadCount", - .patch = chcusb_AttachThreadCount, - .link = NULL}, - {.name = "chcusb_getPrintIDStatus", - .patch = chcusb_getPrintIDStatus, - .link = NULL}, - {.name = "chcusb_setPrintStandby", - .patch = chcusb_setPrintStandby, - .link = NULL}, - {.name = "chcusb_testCardFeed", - .patch = chcusb_testCardFeed, - .link = NULL}, - {.name = "chcusb_exitCard", - .patch = chcusb_exitCard, - .link = NULL}, - {.name = "chcusb_getCardRfidTID", - .patch = chcusb_getCardRfidTID, - .link = NULL}, - {.name = "chcusb_commCardRfidReader", - .patch = chcusb_commCardRfidReader, - .link = NULL}, - {.name = "chcusb_updateCardRfidReader", - .patch = chcusb_updateCardRfidReader, - .link = NULL}, - {.name = "chcusb_getErrorLog", - .patch = chcusb_getErrorLog, - .link = NULL}, - {.name = "chcusb_getErrorStatus", - .patch = chcusb_getErrorStatus, - .link = NULL}, - {.name = "chcusb_setCutList", - .patch = chcusb_setCutList, - .link = NULL}, - {.name = "chcusb_setLaminatePattern", - .patch = chcusb_setLaminatePattern, - .link = NULL}, - {.name = "chcusb_color_adjustment", - .patch = chcusb_color_adjustment, - .link = NULL}, - {.name = "chcusb_color_adjustmentEx", - .patch = chcusb_color_adjustmentEx, - .link = NULL}, - {.name = "chcusb_getEEPROM", - .patch = chcusb_getEEPROM, - .link = NULL}, - {.name = "chcusb_setParameter", - .patch = chcusb_setParameter, - .link = NULL}, - {.name = "chcusb_getParameter", - .patch = chcusb_getParameter, - .link = NULL}, - {.name = "chcusb_universal_command", - .patch = chcusb_universal_command, - .link = NULL}, + { + .name = "fwdlusb_open", + .ordinal = 0x0001, + .patch = fwdlusb_open, + .link = NULL + }, { + .name = "fwdlusb_close", + .ordinal = 0x0002, + .patch = fwdlusb_close, + .link = NULL + }, { + .name = "fwdlusb_listupPrinter", + .ordinal = 0x0003, + .patch = fwdlusb_listupPrinter, + .link = NULL + }, { + .name = "fwdlusb_listupPrinterSN", + .ordinal = 0x0004, + .patch = fwdlusb_listupPrinterSN, + .link = NULL + }, { + .name = "fwdlusb_selectPrinter", + .ordinal = 0x0005, + .patch = fwdlusb_selectPrinter, + .link = NULL + }, { + .name = "fwdlusb_selectPrinterSN", + .ordinal = 0x0006, + .patch = fwdlusb_selectPrinterSN, + .link = NULL + }, { + .name = "fwdlusb_getPrinterInfo", + .ordinal = 0x0007, + .patch = fwdlusb_getPrinterInfo, + .link = NULL + }, { + .name = "fwdlusb_status", + .ordinal = 0x0008, + .patch = fwdlusb_status, + .link = NULL + }, { + .name = "fwdlusb_statusAll", + .ordinal = 0x0009, + .patch = fwdlusb_statusAll, + .link = NULL + }, { + .name = "fwdlusb_resetPrinter", + .ordinal = 0x000a, + .patch = fwdlusb_resetPrinter, + .link = NULL + }, { + .name = "fwdlusb_updateFirmware", + .ordinal = 0x000b, + .patch = fwdlusb_updateFirmware, + .link = NULL + }, { + .name = "fwdlusb_getFirmwareInfo", + .ordinal = 0x000c, + .patch = fwdlusb_getFirmwareInfo, + .link = NULL + }, { + .name = "fwdlusb_MakeThread", + .ordinal = 0x0065, + .patch = fwdlusb_MakeThread, + .link = NULL + }, { + .name = "fwdlusb_ReleaseThread", + .ordinal = 0x0066, + .patch = fwdlusb_ReleaseThread, + .link = NULL + }, { + .name = "fwdlusb_AttachThreadCount", + .ordinal = 0x0067, + .patch = fwdlusb_AttachThreadCount, + .link = NULL + }, { + .name = "fwdlusb_getErrorLog", + .ordinal = 0x0068, + .patch = fwdlusb_getErrorLog, + .link = NULL + }, }; /* C300usb hook tbl */ -static struct hook_symbol C300usb_hooks[] = { - {.name = "chcusb_MakeThread", - .patch = chcusb_MakeThread, - .link = NULL}, - {.name = "chcusb_open", - .patch = chcusb_open, - .link = NULL}, - {.name = "chcusb_close", - .patch = chcusb_close, - .link = NULL}, - {.name = "chcusb_ReleaseThread", - .patch = chcusb_ReleaseThread, - .link = NULL}, - {.name = "chcusb_listupPrinter", - .patch = chcusb_listupPrinter, - .link = NULL}, - {.name = "chcusb_listupPrinterSN", - .patch = chcusb_listupPrinterSN, - .link = NULL}, - {.name = "chcusb_selectPrinter", - .patch = chcusb_selectPrinter, - .link = NULL}, - {.name = "chcusb_selectPrinterSN", - .patch = chcusb_selectPrinterSN, - .link = NULL}, - {.name = "chcusb_getPrinterInfo", - .patch = chcusb_getPrinterInfo, - .link = NULL}, - {.name = "chcusb_imageformat", - .patch = chcusb_imageformat, - .link = NULL}, - {.name = "chcusb_setmtf", - .patch = chcusb_setmtf, - .link = NULL}, - {.name = "chcusb_makeGamma", - .patch = chcusb_makeGamma, - .link = NULL}, - {.name = "chcusb_setIcctable", - .patch = chcusb_setIcctable, - .link = NULL}, - {.name = "chcusb_copies", - .patch = chcusb_copies, - .link = NULL}, - {.name = "chcusb_status", - .patch = chcusb_status, - .link = NULL}, - {.name = "chcusb_statusAll", - .patch = chcusb_statusAll, - .link = NULL}, - {.name = "chcusb_startpage", - .patch = chcusb_startpage, - .link = NULL}, - {.name = "chcusb_endpage", - .patch = chcusb_endpage, - .link = NULL}, - {.name = "chcusb_write", - .patch = chcusb_write, - .link = NULL}, - {.name = "chcusb_writeLaminate", - .patch = chcusb_writeLaminate, - .link = NULL}, - {.name = "chcusb_setPrinterInfo", - .patch = chcusb_setPrinterInfo, - .link = NULL}, - {.name = "chcusb_getGamma", - .patch = chcusb_getGamma, - .link = NULL}, - {.name = "chcusb_getMtf", - .patch = chcusb_getMtf, - .link = NULL}, - {.name = "chcusb_cancelCopies", - .patch = chcusb_cancelCopies, - .link = NULL}, - {.name = "chcusb_setPrinterToneCurve", - .patch = chcusb_setPrinterToneCurve, - .link = NULL}, - {.name = "chcusb_getPrinterToneCurve", - .patch = chcusb_getPrinterToneCurve, - .link = NULL}, - {.name = "chcusb_blinkLED", - .patch = chcusb_blinkLED, - .link = NULL}, - {.name = "chcusb_resetPrinter", - .patch = chcusb_resetPrinter, - .link = NULL}, - {.name = "chcusb_AttachThreadCount", - .patch = chcusb_AttachThreadCount, - .link = NULL}, - {.name = "chcusb_getPrintIDStatus", - .patch = chcusb_getPrintIDStatus, - .link = NULL}, - {.name = "chcusb_setPrintStandby", - .patch = chcusb_setPrintStandby, - .link = NULL}, - {.name = "chcusb_testCardFeed", - .patch = chcusb_testCardFeed, - .link = NULL}, - {.name = "chcusb_setParameter", - .patch = chcusb_setParameter, - .link = NULL}, - {.name = "chcusb_getParameter", - .patch = chcusb_getParameter, - .link = NULL}, - {.name = "chcusb_getErrorStatus", - .patch = chcusb_getErrorStatus, - .link = NULL}, - {.name = "chcusb_setCutList", - .patch = chcusb_setCutList, - .link = NULL}, - {.name = "chcusb_setLaminatePattern", - .patch = chcusb_setLaminatePattern, - .link = NULL}, - {.name = "chcusb_color_adjustment", - .patch = chcusb_color_adjustment, - .link = NULL}, - {.name = "chcusb_color_adjustmentEx", - .patch = chcusb_color_adjustmentEx, - .link = NULL}, - {.name = "chcusb_getEEPROM", - .patch = chcusb_getEEPROM, - .link = NULL}, - {.name = "chcusb_universal_command", - .patch = chcusb_universal_command, - .link = NULL}, +static const struct hook_symbol C300usb_hooks[] = { + { + .name = "chcusb_MakeThread", + .ordinal = 0x0001, + .patch = chcusb_MakeThread, + .link = NULL + }, { + .name = "chcusb_open", + .ordinal = 0x0002, + .patch = chcusb_open, + .link = NULL + }, { + .name = "chcusb_close", + .ordinal = 0x0003, + .patch = chcusb_close, + .link = NULL + }, { + .name = "chcusb_ReleaseThread", + .ordinal = 0x0004, + .patch = chcusb_ReleaseThread, + .link = NULL + }, { + .name = "chcusb_listupPrinter", + .ordinal = 0x0005, + .patch = chcusb_listupPrinter, + .link = NULL + }, { + .name = "chcusb_listupPrinterSN", + .ordinal = 0x0006, + .patch = chcusb_listupPrinterSN, + .link = NULL + }, { + .name = "chcusb_selectPrinter", + .ordinal = 0x0007, + .patch = chcusb_selectPrinter, + .link = NULL + }, { + .name = "chcusb_selectPrinterSN", + .ordinal = 0x0008, + .patch = chcusb_selectPrinterSN, + .link = NULL + }, { + .name = "chcusb_getPrinterInfo", + .ordinal = 0x0009, + .patch = chcusb_getPrinterInfo, + .link = NULL + }, { + .name = "chcusb_imageformat", + .ordinal = 0x000a, + .patch = chcusb_imageformat, + .link = NULL + }, { + .name = "chcusb_setmtf", + .ordinal = 0x000b, + .patch = chcusb_setmtf, + .link = NULL + }, { + .name = "chcusb_makeGamma", + .ordinal = 0x000c, + .patch = chcusb_makeGamma, + .link = NULL + }, { + .name = "chcusb_setIcctable", + .ordinal = 0x000d, + .patch = chcusb_setIcctable, + .link = NULL + }, { + .name = "chcusb_copies", + .ordinal = 0x000e, + .patch = chcusb_copies, + .link = NULL + }, { + .name = "chcusb_status", + .ordinal = 0x000f, + .patch = chcusb_status, + .link = NULL + }, { + .name = "chcusb_statusAll", + .ordinal = 0x0010, + .patch = chcusb_statusAll, + .link = NULL + }, { + .name = "chcusb_startpage", + .ordinal = 0x0011, + .patch = chcusb_startpage, + .link = NULL + }, { + .name = "chcusb_endpage", + .ordinal = 0x0012, + .patch = chcusb_endpage, + .link = NULL + }, { + .name = "chcusb_write", + .ordinal = 0x0013, + .patch = chcusb_write, + .link = NULL + }, { + .name = "chcusb_writeLaminate", + .ordinal = 0x0014, + .patch = chcusb_writeLaminate, + .link = NULL + }, { + .name = "chcusb_setPrinterInfo", + .ordinal = 0x0015, + .patch = chcusb_setPrinterInfo, + .link = NULL + }, { + .name = "chcusb_getGamma", + .ordinal = 0x0016, + .patch = chcusb_getGamma, + .link = NULL + }, { + .name = "chcusb_getMtf", + .ordinal = 0x0017, + .patch = chcusb_getMtf, + .link = NULL + }, { + .name = "chcusb_cancelCopies", + .ordinal = 0x0018, + .patch = chcusb_cancelCopies, + .link = NULL + }, { + .name = "chcusb_setPrinterToneCurve", + .ordinal = 0x0019, + .patch = chcusb_setPrinterToneCurve, + .link = NULL + }, { + .name = "chcusb_getPrinterToneCurve", + .ordinal = 0x001a, + .patch = chcusb_getPrinterToneCurve, + .link = NULL + }, { + .name = "chcusb_blinkLED", + .ordinal = 0x001b, + .patch = chcusb_blinkLED, + .link = NULL + }, { + .name = "chcusb_resetPrinter", + .ordinal = 0x001c, + .patch = chcusb_resetPrinter, + .link = NULL + }, { + .name = "chcusb_AttachThreadCount", + .ordinal = 0x001d, + .patch = chcusb_AttachThreadCount, + .link = NULL + }, { + .name = "chcusb_getPrintIDStatus", + .ordinal = 0x001e, + .patch = chcusb_getPrintIDStatus, + .link = NULL + }, { + .name = "chcusb_setPrintStandby", + .ordinal = 0x001f, + .patch = chcusb_setPrintStandby, + .link = NULL + }, { + .name = "chcusb_testCardFeed", + .ordinal = 0x0020, + .patch = chcusb_testCardFeed, + .link = NULL + }, { + .name = "chcusb_setParameter", + .ordinal = 0x0021, + .patch = chcusb_setParameter, + .link = NULL + }, { + .name = "chcusb_getParameter", + .ordinal = 0x0022, + .patch = chcusb_getParameter, + .link = NULL + }, { + .name = "chcusb_getErrorStatus", + .ordinal = 0x0023, + .patch = chcusb_getErrorStatus, + .link = NULL + }, { + .name = "chcusb_setCutList", + .ordinal = 0x0028, + .patch = chcusb_setCutList, + .link = NULL + }, { + .name = "chcusb_setLaminatePattern", + .ordinal = 0x0029, + .patch = chcusb_setLaminatePattern, + .link = NULL + }, { + .name = "chcusb_color_adjustment", + .ordinal = 0x002a, + .patch = chcusb_color_adjustment, + .link = NULL + }, { + .name = "chcusb_color_adjustmentEx", + .ordinal = 0x002b, + .patch = chcusb_color_adjustmentEx, + .link = NULL + }, { + .name = "chcusb_getEEPROM", + .ordinal = 0x003a, + .patch = chcusb_getEEPROM, + .link = NULL + }, { + .name = "chcusb_universal_command", + .ordinal = 0x0049, + .patch = chcusb_universal_command, + .link = NULL + }, +}; + +/* C310A-Busb/C320Ausb/C330Ausb hook tbl. The ordinals are required, as some + games, for example Sekito, will import this library by ordinal and not by + name. */ + +static const struct hook_symbol C3XXusb_hooks[] = { + { + .name = "chcusb_MakeThread", + .ordinal = 0x0001, + .patch = chcusb_MakeThread, + .link = NULL + }, { + .name = "chcusb_open", + .ordinal = 0x0002, + .patch = chcusb_open, + .link = NULL + }, { + .name = "chcusb_close", + .ordinal = 0x0003, + .patch = chcusb_close, + .link = NULL + }, { + .name = "chcusb_ReleaseThread", + .ordinal = 0x0004, + .patch = chcusb_ReleaseThread, + .link = NULL + }, { + .name = "chcusb_listupPrinter", + .ordinal = 0x0005, + .patch = chcusb_listupPrinter, + .link = NULL + }, { + .name = "chcusb_listupPrinterSN", + .ordinal = 0x0006, + .patch = chcusb_listupPrinterSN, + .link = NULL + }, { + .name = "chcusb_selectPrinter", + .ordinal = 0x0007, + .patch = chcusb_selectPrinter, + .link = NULL + }, { + .name = "chcusb_selectPrinterSN", + .ordinal = 0x0008, + .patch = chcusb_selectPrinterSN, + .link = NULL + }, { + .name = "chcusb_getPrinterInfo", + .ordinal = 0x0009, + .patch = chcusb_getPrinterInfo, + .link = NULL + }, { + .name = "chcusb_imageformat", + .ordinal = 0x000a, + .patch = chcusb_imageformat, + .link = NULL + }, { + .name = "chcusb_setmtf", + .ordinal = 0x000b, + .patch = chcusb_setmtf, + .link = NULL + }, { + .name = "chcusb_makeGamma", + .ordinal = 0x000c, + .patch = chcusb_makeGamma, + .link = NULL + }, { + .name = "chcusb_setIcctable", + .ordinal = 0x000d, + .patch = chcusb_setIcctable, + .link = NULL + }, { + .name = "chcusb_copies", + .ordinal = 0x000e, + .patch = chcusb_copies, + .link = NULL + }, { + .name = "chcusb_status", + .ordinal = 0x000f, + .patch = chcusb_status, + .link = NULL + }, { + .name = "chcusb_statusAll", + .ordinal = 0x0010, + .patch = chcusb_statusAll, + .link = NULL + }, { + .name = "chcusb_startpage", + .ordinal = 0x0011, + .patch = chcusb_startpage, + .link = NULL + }, { + .name = "chcusb_endpage", + .ordinal = 0x0012, + .patch = chcusb_endpage, + .link = NULL + }, { + .name = "chcusb_write", + .ordinal = 0x0013, + .patch = chcusb_write, + .link = NULL + }, { + .name = "chcusb_writeLaminate", + .ordinal = 0x0014, + .patch = chcusb_writeLaminate, + .link = NULL + }, { + .name = "chcusb_writeHolo", + .ordinal = 0x0015, + .patch = chcusb_writeHolo, + .link = NULL + }, { + .name = "chcusb_setPrinterInfo", + .ordinal = 0x0016, + .patch = chcusb_setPrinterInfo, + .link = NULL + }, { + .name = "chcusb_getGamma", + .ordinal = 0x0017, + .patch = chcusb_getGamma, + .link = NULL + }, { + .name = "chcusb_getMtf", + .ordinal = 0x0018, + .patch = chcusb_getMtf, + .link = NULL + }, { + .name = "chcusb_cancelCopies", + .ordinal = 0x0019, + .patch = chcusb_cancelCopies, + .link = NULL + }, { + .name = "chcusb_setPrinterToneCurve", + .ordinal = 0x001a, + .patch = chcusb_setPrinterToneCurve, + .link = NULL + }, { + .name = "chcusb_getPrinterToneCurve", + .ordinal = 0x001b, + .patch = chcusb_getPrinterToneCurve, + .link = NULL + }, { + .name = "chcusb_blinkLED", + .ordinal = 0x001c, + .patch = chcusb_blinkLED, + .link = NULL + }, { + .name = "chcusb_resetPrinter", + .ordinal = 0x001d, + .patch = chcusb_resetPrinter, + .link = NULL + }, { + .name = "chcusb_AttachThreadCount", + .ordinal = 0x001e, + .patch = chcusb_AttachThreadCount, + .link = NULL + }, { + .name = "chcusb_getPrintIDStatus", + .ordinal = 0x001f, + .patch = chcusb_getPrintIDStatus, + .link = NULL + }, { + .name = "chcusb_setPrintStandby", + .ordinal = 0x0020, + .patch = chcusb_setPrintStandby, + .link = NULL + }, { + .name = "chcusb_testCardFeed", + .ordinal = 0x0021, + .patch = chcusb_testCardFeed, + .link = NULL + }, { + .name = "chcusb_exitCard", + .ordinal = 0x0022, + .patch = chcusb_exitCard, + .link = NULL + }, { + .name = "chcusb_getCardRfidTID", + .ordinal = 0x0023, + .patch = chcusb_getCardRfidTID, + .link = NULL + }, { + .name = "chcusb_commCardRfidReader", + .ordinal = 0x0024, + .patch = chcusb_commCardRfidReader, + .link = NULL + }, { + .name = "chcusb_updateCardRfidReader", + .ordinal = 0x0025, + .patch = chcusb_updateCardRfidReader, + .link = NULL + }, { + .name = "chcusb_getErrorLog", + .ordinal = 0x0026, + .patch = chcusb_getErrorLog, + .link = NULL + }, { + .name = "chcusb_getErrorStatus", + .ordinal = 0x0027, + .patch = chcusb_getErrorStatus, + .link = NULL + }, { + .name = "chcusb_setCutList", + .ordinal = 0x0028, + .patch = chcusb_setCutList, + .link = NULL + }, { + .name = "chcusb_setLaminatePattern", + .ordinal = 0x0029, + .patch = chcusb_setLaminatePattern, + .link = NULL + }, { + .name = "chcusb_color_adjustment", + .ordinal = 0x002a, + .patch = chcusb_color_adjustment, + .link = NULL + }, { + .name = "chcusb_color_adjustmentEx", + .ordinal = 0x002b, + .patch = chcusb_color_adjustmentEx, + .link = NULL + }, { + .name = "chcusb_getEEPROM", + .ordinal = 0x003a, + .patch = chcusb_getEEPROM, + .link = NULL + }, { + .name = "chcusb_setParameter", + .ordinal = 0x0040, + .patch = chcusb_setParameter, + .link = NULL + }, { + .name = "chcusb_getParameter", + .ordinal = 0x0041, + .patch = chcusb_getParameter, + .link = NULL + }, { + .name = "chcusb_universal_command", + .ordinal = 0x0049, + .patch = chcusb_universal_command, + .link = NULL + }, +}; + +/* PrintDLL hook tbl */ + +static struct hook_symbol printdll_hooks[] = { + { + .name = "CFW_close", + .ordinal = 0x0001, + .patch = CFW_close, + .link = NULL + }, { + .name = "CFW_getFirmwareInfo", + .ordinal = 0x0002, + .patch = CFW_getFirmwareInfo, + .link = NULL + }, { + .name = "CFW_getPrinterInfo", + .ordinal = 0x0003, + .patch = CFW_getPrinterInfo, + .link = NULL + }, { + .name = "CFW_init", + .ordinal = 0x0004, + .patch = CFW_init, + .link = NULL + }, { + .name = "CFW_listupPrinter", + .ordinal = 0x0005, + .patch = CFW_listupPrinter, + .link = NULL + }, { + .name = "CFW_listupPrinterSN", + .ordinal = 0x0006, + .patch = CFW_listupPrinterSN, + .link = NULL + }, { + .name = "CFW_open", + .ordinal = 0x0007, + .patch = CFW_open, + .link = NULL + }, { + .name = "CFW_resetPrinter", + .ordinal = 0x0008, + .patch = CFW_resetPrinter, + .link = NULL + }, { + .name = "CFW_selectPrinter", + .ordinal = 0x0009, + .patch = CFW_selectPrinter, + .link = NULL + }, { + .name = "CFW_selectPrinterSN", + .ordinal = 0x000a, + .patch = CFW_selectPrinterSN, + .link = NULL + }, { + .name = "CFW_status", + .ordinal = 0x000b, + .patch = CFW_status, + .link = NULL + }, { + .name = "CFW_statusAll", + .ordinal = 0x000c, + .patch = CFW_statusAll, + .link = NULL + }, { + .name = "CFW_term", + .ordinal = 0x000d, + .patch = CFW_term, + .link = NULL + }, { + .name = "CFW_updateFirmware", + .ordinal = 0x000e, + .patch = CFW_updateFirmware, + .link = NULL + }, { + .name = "CHCUSB_AttachThreadCount", + .ordinal = 0x000f, + .patch = CHCUSB_AttachThreadCount, + .link = NULL + }, { + .name = "CHCUSB_MakeThread", + .ordinal = 0x0010, + .patch = CHCUSB_MakeThread, + .link = NULL + }, { + .name = "CHCUSB_ReleaseThread", + .ordinal = 0x0011, + .patch = CHCUSB_ReleaseThread, + .link = NULL + }, { + .name = "CHCUSB_blinkLED", + .ordinal = 0x0012, + .patch = CHCUSB_blinkLED, + .link = NULL + }, { + .name = "CHCUSB_cancelCopies", + .ordinal = 0x0013, + .patch = CHCUSB_cancelCopies, + .link = NULL + }, { + .name = "CHCUSB_close", + .ordinal = 0x0014, + .patch = CHCUSB_close, + .link = NULL + }, { + .name = "CHCUSB_commCardRfidReader", + .ordinal = 0x0015, + .patch = CHCUSB_commCardRfidReader, + .link = NULL + }, { + .name = "CHCUSB_copies", + .ordinal = 0x0016, + .patch = CHCUSB_copies, + .link = NULL + }, { + .name = "CHCUSB_endpage", + .ordinal = 0x0017, + .patch = CHCUSB_endpage, + .link = NULL + }, { + .name = "CHCUSB_exitCard", + .ordinal = 0x0018, + .patch = CHCUSB_exitCard, + .link = NULL + }, { + .name = "CHCUSB_getCardRfidTID", + .ordinal = 0x0019, + .patch = CHCUSB_getCardRfidTID, + .link = NULL + }, { + .name = "CHCUSB_getErrorLog", + .ordinal = 0x001a, + .patch = CHCUSB_getErrorLog, + .link = NULL + }, { + .name = "CHCUSB_getErrorStatus", + .ordinal = 0x001b, + .patch = CHCUSB_getErrorStatus, + .link = NULL + }, { + .name = "CHCUSB_getGamma", + .ordinal = 0x001c, + .patch = CHCUSB_getGamma, + .link = NULL + }, { + .name = "CHCUSB_getMtf", + .ordinal = 0x001d, + .patch = CHCUSB_getMtf, + .link = NULL + }, { + .name = "CHCUSB_getPrintIDStatus", + .ordinal = 0x001e, + .patch = CHCUSB_getPrintIDStatus, + .link = NULL + }, { + .name = "CHCUSB_getPrinterInfo", + .ordinal = 0x001f, + .patch = CHCUSB_getPrinterInfo, + .link = NULL + }, { + .name = "CHCUSB_getPrinterToneCurve", + .ordinal = 0x0020, + .patch = CHCUSB_getPrinterToneCurve, + .link = NULL + }, { + .name = "CHCUSB_imageformat", + .ordinal = 0x0021, + .patch = CHCUSB_imageformat, + .link = NULL + }, { + .name = "CHCUSB_init", + .ordinal = 0x0022, + .patch = CHCUSB_init, + .link = NULL + }, { + .name = "CHCUSB_listupPrinter", + .ordinal = 0x0023, + .patch = CHCUSB_listupPrinter, + .link = NULL + }, { + .name = "CHCUSB_listupPrinterSN", + .ordinal = 0x0024, + .patch = CHCUSB_listupPrinterSN, + .link = NULL + }, { + .name = "CHCUSB_makeGamma", + .ordinal = 0x0025, + .patch = CHCUSB_makeGamma, + .link = NULL + }, { + .name = "CHCUSB_open", + .ordinal = 0x0026, + .patch = CHCUSB_open, + .link = NULL + }, { + .name = "CHCUSB_resetPrinter", + .ordinal = 0x0027, + .patch = CHCUSB_resetPrinter, + .link = NULL + }, { + .name = "CHCUSB_selectPrinter", + .ordinal = 0x0028, + .patch = CHCUSB_selectPrinter, + .link = NULL + }, { + .name = "CHCUSB_selectPrinterSN", + .ordinal = 0x0029, + .patch = CHCUSB_selectPrinterSN, + .link = NULL + }, { + .name = "CHCUSB_setIcctable", + .ordinal = 0x002a, + .patch = CHCUSB_setIcctable, + .link = NULL + }, { + .name = "CHCUSB_setIcctableProfile", + .ordinal = 0x002b, + .patch = CHCUSB_setIcctableProfile, + .link = NULL + }, { + .name = "CHCUSB_setPrintStandby", + .ordinal = 0x002c, + .patch = CHCUSB_setPrintStandby, + .link = NULL + }, { + .name = "CHCUSB_setPrinterInfo", + .ordinal = 0x002d, + .patch = CHCUSB_setPrinterInfo, + .link = NULL + }, { + .name = "CHCUSB_setPrinterToneCurve", + .ordinal = 0x0023, + .patch = CHCUSB_setPrinterToneCurve, + .link = NULL + }, { + .name = "CHCUSB_setmtf", + .ordinal = 0x002f, + .patch = CHCUSB_setmtf, + .link = NULL + }, { + .name = "CHCUSB_startpage", + .ordinal = 0x0030, + .patch = CHCUSB_startpage, + .link = NULL + }, { + .name = "CHCUSB_status", + .ordinal = 0x0031, + .patch = CHCUSB_status, + .link = NULL + }, { + .name = "CHCUSB_statusAll", + .ordinal = 0x0032, + .patch = CHCUSB_statusAll, + .link = NULL + }, { + .name = "CHCUSB_term", + .ordinal = 0x0033, + .patch = CHCUSB_term, + .link = NULL + }, { + .name = "CHCUSB_testCardFeed", + .ordinal = 0x0034, + .patch = CHCUSB_testCardFeed, + .link = NULL + }, { + .name = "CHCUSB_updateCardRfidReader", + .ordinal = 0x0035, + .patch = CHCUSB_updateCardRfidReader, + .link = NULL + }, { + .name = "CHCUSB_write", + .ordinal = 0x0036, + .patch = CHCUSB_write, + .link = NULL + }, { + .name = "CHCUSB_writeHolo", + .ordinal = 0x0037, + .patch = CHCUSB_writeHolo, + .link = NULL + }, { + .name = "CHCUSB_writeLaminate", + .ordinal = 0x0038, + .patch = CHCUSB_writeLaminate, + .link = NULL + }, }; static struct printer_config printer_config; @@ -600,29 +1165,23 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST rotate180 = cfg->rotate_180; memcpy(&printer_config, cfg, sizeof(*cfg)); - hook_table_apply(NULL, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks)); - hook_table_apply(NULL, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); - hook_table_apply(NULL, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); - hook_table_apply(NULL, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); - hook_table_apply(NULL, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); - hook_table_apply(NULL, "C310BFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); - hook_table_apply(NULL, "C320Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); - hook_table_apply(NULL, "C320AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); - hook_table_apply(NULL, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); - hook_table_apply(NULL, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + printer_hook_insert_hooks(NULL); + /* if (self != NULL) { - dll_hook_push(self, L"C300usb.dll"); // TODO: This doesn't work. Unity moment - dll_hook_push(self, L"C300FWDLusb.dll"); // TODO: ...and this... + // dll_hook_push(self, L"PrintDLL.dll"); // TODO: This doesn't work. Unity moment + dll_hook_push(self, L"C300usb.dll"); + dll_hook_push(self, L"C300FWDLusb.dll"); dll_hook_push(self, L"C310Ausb.dll"); - dll_hook_push(self, L"C310Busb.dll"); // TODO: ...and this... + dll_hook_push(self, L"C310Busb.dll"); dll_hook_push(self, L"C310FWDLusb.dll"); - dll_hook_push(self, L"C310BFWDLusb.dll"); // TODO: ...aaaand this. + dll_hook_push(self, L"C310BFWDLusb.dll"); dll_hook_push(self, L"C320Ausb.dll"); dll_hook_push(self, L"C320AFWDLusb.dll"); dll_hook_push(self, L"C330Ausb.dll"); dll_hook_push(self, L"C330AFWDLusb.dll"); } + */ // Load firmware if has previously been written to fwFile = CreateFileW(cfg->main_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -665,6 +1224,22 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST dprintf("Printer: hook enabled.\n"); } +void printer_hook_insert_hooks(HMODULE target) { + hook_table_apply(target, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(target, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(target, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(target, "C310BFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(target, "C320Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(target, "C320AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + hook_table_apply(target, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); + hook_table_apply(target, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); + + /* Unity workaround */ + proc_addr_table_push(target, "PrintDLL.dll", printdll_hooks, _countof(printdll_hooks)); + proc_addr_table_push(target, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks)); + proc_addr_table_push(target, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); +} + static void generate_rfid(void) { for (int i = 0; i < sizeof(cardRFID); i++) cardRFID[i] = rand(); @@ -1824,6 +2399,8 @@ int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); + STATUS = 2; + *pageId = 1; *rResult = 0; return 1; @@ -1866,13 +2443,13 @@ int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) SYSTEMTIME t; GetLocalTime(&t); - char dumpPath[0x80]; - sprintf_s( - dumpPath, 0x80, - "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeLaminate.bin", - t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + wchar_t dumpPath[MAX_PATH]; + swprintf_s( + dumpPath, MAX_PATH, + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_writeLaminate.bmp", + printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); - // WriteArrayToFile(dumpPath, data, *writeSize, FALSE); + // WriteDataToBitmapFile(dumpPath, 8, WIDTH, HEIGHT, data, HOLO_SIZE, NULL, 0, rotate180); dprintf("Printer: C3XXusb: %s\n", __func__); // *writeSize = written; @@ -1885,13 +2462,13 @@ int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); - char dumpPath[0x80]; - sprintf_s( - dumpPath, 0x80, - "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeHolo.bin", - t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + wchar_t dumpPath[MAX_PATH]; + swprintf_s( + dumpPath, MAX_PATH, + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_writeHolo.bmp", + printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); - // WriteArrayToFile(dumpPath, data, HOLO_SIZE, FALSE); + WriteDataToBitmapFile(dumpPath, 8, WIDTH, HEIGHT, data, HOLO_SIZE, NULL, 0, rotate180); dprintf("Printer: C3XXusb: %s\n", __func__); *writeSize = HOLO_SIZE; @@ -2014,14 +2591,34 @@ int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 8); - *((uint16_t *)(rBuffer + 6)) = 2300; + + if (STATUS > 1) + { + STATUS = 0; + *((uint16_t*)(rBuffer + 6)) = 2212; + } + else + { + *((uint16_t*)(rBuffer + 6)) = 2300; + } + *rResult = 0; return 1; } int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); - *rResult = 0; + + if (STATUS == 0) + { + STATUS = 1; + *rResult = 2100; + } + else + { + *rResult = 0; + } + return 1; } @@ -2178,6 +2775,313 @@ int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, ui return 1; } +/* PrintDll hooks */ + +int CFW_AttachThreadCount(const void *handle, uint16_t *rCount, uint16_t *rMaxCount) +{ + return fwdlusb_AttachThreadCount(rCount, rMaxCount); +} + +void CFW_close(const void *handle) +{ + fwdlusb_close(); +} + +int CFW_getErrorLog(const void *handle, uint16_t index, uint8_t *rData, uint16_t *rResult) +{ + return fwdlusb_getErrorLog(index, rData, rResult); +} + +int CFW_getFirmwareInfo(const void *handle, uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) +{ + return fwdlusb_getFirmwareInfo(update, filename, rBuffer, rLen, rResult); +} + +int CFW_getPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) +{ + return fwdlusb_getPrinterInfo(tagNumber, rBuffer, rLen); +} + +int CFW_init(LPCSTR dllpath) +{ + dprintf("Printer PrintDLL: %s (dllpath: %s)\n", __func__, dllpath); + return 1; +} + +int CFW_listupPrinter(const void *handle, uint8_t *rIdArray) +{ + return fwdlusb_listupPrinter(rIdArray); +} + +int CFW_listupPrinterSN(const void *handle, uint64_t *rSerialArray) +{ + return fwdlusb_listupPrinterSN(rSerialArray); +} + +int CFW_MakeThread(const void *handle, uint16_t maxCount) +{ + return fwdlusb_MakeThread(maxCount); +} + +int CFW_open(const void *handle, uint16_t *rResult) +{ + return fwdlusb_open(rResult); +} + +int CFW_ReleaseThread(const void *handle, uint16_t *rResult) +{ + return fwdlusb_ReleaseThread(rResult); +} + +int CFW_resetPrinter(const void *handle, uint16_t *rResult) +{ + return fwdlusb_resetPrinter(rResult); +} + +int CFW_selectPrinter(const void *handle, uint8_t printerId, uint16_t *rResult) +{ + return fwdlusb_selectPrinter(printerId, rResult); +} + +int CFW_selectPrinterSN(const void *handle, uint64_t printerSN, uint16_t *rResult) +{ + return fwdlusb_selectPrinterSN(printerSN, rResult); +} + +int CFW_status(const void *handle, uint16_t *rResult) +{ + return fwdlusb_status(rResult); +} + +int CFW_statusAll(const void *handle, uint8_t *idArray, uint16_t *rResultArray) +{ + return fwdlusb_statusAll(idArray, rResultArray); +} + +void CFW_term(const void *handle) +{ + dprintf("Printer PrintDLL: %s\n", __func__); +} + +int CFW_updateFirmware(const void *handle, uint8_t update, LPCSTR filename, uint16_t *rResult) +{ + return fwdlusb_updateFirmware(update, filename, rResult); +} + +int CHCUSB_AttachThreadCount(const void *handle, uint16_t *rCount, uint16_t *rMaxCount) +{ + return chcusb_AttachThreadCount(rCount, rMaxCount); +} + +int CHCUSB_MakeThread(const void *handle, uint16_t maxCount) +{ + return chcusb_MakeThread(maxCount); +} + +int CHCUSB_ReleaseThread(const void *handle, uint16_t *rResult) +{ + return chcusb_ReleaseThread(rResult); +} + +int CHCUSB_blinkLED(const void *handle, uint16_t *rResult) +{ + return chcusb_blinkLED(rResult); +} + +int CHCUSB_cancelCopies(const void *handle, uint16_t pageId, uint16_t *rResult) +{ + return chcusb_cancelCopies(pageId, rResult); +} + +void CHCUSB_close(const void *handle) +{ + chcusb_close(); +} + +int CHCUSB_commCardRfidReader(const void *handle, uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) +{ + return chcusb_commCardRfidReader(sendData, rRecvData, sendSize, rRecvSize, rResult); +} + +int CHCUSB_copies(const void *handle, uint16_t copies, uint16_t *rResult) +{ + return chcusb_copies(copies, rResult); +} + +int CHCUSB_endpage(const void *handle, uint16_t *rResult) +{ + return chcusb_endpage(rResult); +} + +int CHCUSB_exitCard(const void *handle, uint16_t *rResult) +{ + return chcusb_exitCard(rResult); +} + +int CHCUSB_getCardRfidTID(const void *handle, uint8_t *rCardTID, uint16_t *rResult) +{ + return chcusb_getCardRfidTID(rCardTID, rResult); +} + +int CHCUSB_getErrorLog(const void *handle, uint16_t index, uint8_t *rData, uint16_t *rResult) +{ + return chcusb_getErrorLog(index, rData, rResult); +} + +int CHCUSB_getErrorStatus(const void *handle, uint16_t *rBuffer) +{ + return chcusb_getErrorStatus(rBuffer); +} + +int CHCUSB_getGamma(const void *handle, LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) +{ + return chcusb_getGamma(filename, r, g, b, rResult); +} + +int CHCUSB_getMtf(const void *handle, LPCSTR filename, int32_t *mtf, uint16_t *rResult) +{ + return chcusb_getMtf(filename, mtf, rResult); +} + +int CHCUSB_getPrintIDStatus(const void *handle, uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) +{ + return chcusb_getPrintIDStatus(pageId, rBuffer, rResult); +} + +int CHCUSB_getPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) +{ + return chcusb_getPrinterInfo(tagNumber, rBuffer, rLen); +} + +int CHCUSB_getPrinterToneCurve(const void *handle, uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) +{ + return chcusb_getPrinterToneCurve(type, number, data, rResult); +} + +int CHCUSB_imageformat(const void *handle, uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint8_t *inputImage, uint16_t *rResult) +{ + return chcusb_imageformat(format, ncomp, depth, width, height, rResult); +} + +int CHCUSB_init(LPCSTR dllpath) +{ + dprintf("Printer PrintDLL: %s (dllpath: %s)\n", __func__, dllpath); + return 1; +} + +int CHCUSB_listupPrinter(const void *handle, uint8_t *rIdArray) +{ + return chcusb_listupPrinter(rIdArray); +} + +int CHCUSB_listupPrinterSN(const void *handle, uint64_t *rSerialArray) +{ + return chcusb_listupPrinterSN(rSerialArray); +} + +int CHCUSB_makeGamma(const void *handle, uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) +{ + return chcusb_makeGamma(k, intoneR, intoneG, intoneB); +} + +int CHCUSB_open(const void *handle, uint16_t *rResult) +{ + return chcusb_open(rResult); +} + +int CHCUSB_resetPrinter(const void *handle, uint16_t *rResult) +{ + return chcusb_resetPrinter(rResult); +} + +int CHCUSB_selectPrinter(const void *handle, uint8_t printerId, uint16_t *rResult) +{ + return chcusb_selectPrinter(printerId, rResult); +} + +int CHCUSB_selectPrinterSN(const void *handle, uint64_t printerSN, uint16_t *rResult) +{ + return chcusb_selectPrinterSN(printerSN, rResult); +} + +int CHCUSB_setIcctableProfile(const void *handle, LPCSTR icc1, LPCSTR icc2, uint16_t intents, uint16_t *rResult) +{ + dprintf("Printer PrintDLL: %s (icc1: %s, icc2: %s)\n", + __func__, icc1, icc2); + *rResult = 0; + return 1; +} + +int CHCUSB_setIcctable(const void *handle, uint16_t intents, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB, uint8_t *outtoneR, uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult) +{ + return chcusb_setIcctable("CFW", "CFW", intents, intoneR, intoneG, intoneB, outtoneR, outtoneG, outtoneB, rResult); +} + +int CHCUSB_setPrintStandby(const void *handle, uint16_t position, uint16_t *rResult) +{ + return chcusb_setPrintStandby(position, rResult); +} + +int CHCUSB_setPrinterInfo(const void *handle, uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) +{ + return chcusb_setPrinterInfo(tagNumber, rBuffer, rLen, rResult); +} + +int CHCUSB_setPrinterToneCurve(const void *handle, uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) +{ + return chcusb_setPrinterToneCurve(type, number, data, rResult); +} + +int CHCUSB_setmtf(const void *handle, int32_t *mtf) +{ + return chcusb_setmtf(mtf); +} + +int CHCUSB_startpage(const void *handle, uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) +{ + return chcusb_startpage(postCardState, pageId, rResult); +} + +int CHCUSB_status(const void *handle, uint16_t *rResult) +{ + return chcusb_status(rResult); +} + +int CHCUSB_statusAll(const void *handle, uint8_t *idArray, uint16_t *rResultArray) +{ + return chcusb_statusAll(idArray, rResultArray); +} + +int CHCUSB_testCardFeed(const void *handle, uint16_t mode, uint16_t times, uint16_t *rResult) +{ + return chcusb_testCardFeed(mode, times, rResult); +} + +void CHCUSB_term(const void *handle) +{ + dprintf("Printer PrintDLL: %s\n", __func__); +} + +int CHCUSB_updateCardRfidReader(const void *handle, uint8_t *data, uint32_t size, uint16_t *rResult) +{ + return chcusb_updateCardRfidReader(data, size, rResult); +} + +int CHCUSB_write(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult) +{ + return chcusb_write(data, writeSize, rResult); +} + +int CHCUSB_writeHolo(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult) +{ + return chcusb_writeHolo(data, writeSize, rResult); +} + +int CHCUSB_writeLaminate(const void *handle, uint8_t *data, uint32_t offset, uint32_t *writeSize, uint16_t *rResult) +{ + return chcusb_writeLaminate(data, writeSize, rResult); +} + // copy pasted from https://dev.s-ul.net/domeori/c310emu #define BITMAPHEADERSIZE 0x36 diff --git a/hooklib/printer.h b/hooklib/printer.h index e83ef17..229cff7 100644 --- a/hooklib/printer.h +++ b/hooklib/printer.h @@ -14,3 +14,4 @@ struct printer_config { }; void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self); +void printer_hook_insert_hooks(HMODULE target); From b9204d4765fc282bfe7be758761fb237bc69da87 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 5 Aug 2024 21:59:59 +0200 Subject: [PATCH 119/204] unity: hopefully fixes timezone spoofing #27 --- platform/clock.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/platform/clock.c b/platform/clock.c index a263413..5a9a8f4 100644 --- a/platform/clock.c +++ b/platform/clock.c @@ -4,6 +4,7 @@ #include #include "hook/table.h" +#include "hook/procaddr.h" #include "platform/clock.h" @@ -236,6 +237,13 @@ HRESULT clock_hook_init(const struct clock_config *cfg) "kernel32.dll", clock_base_hook_syms, _countof(clock_base_hook_syms)); + + proc_addr_table_push( + NULL, + "kernel32.dll", + clock_base_hook_syms, + _countof(clock_base_hook_syms) + ); } if (cfg->timezone) { @@ -244,6 +252,13 @@ HRESULT clock_hook_init(const struct clock_config *cfg) "kernel32.dll", clock_read_hook_syms, _countof(clock_read_hook_syms)); + + proc_addr_table_push( + NULL, + "kernel32.dll", + clock_read_hook_syms, + _countof(clock_read_hook_syms) + ); } if (!cfg->writeable) { @@ -253,6 +268,13 @@ HRESULT clock_hook_init(const struct clock_config *cfg) "kernel32.dll", clock_write_hook_syms, _countof(clock_write_hook_syms)); + + proc_addr_table_push( + NULL, + "kernel32.dll", + clock_write_hook_syms, + _countof(clock_write_hook_syms) + ); } return S_OK; From 686d57d3ee5e9fc10d56b32a74f1123c02b64f26 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 6 Aug 2024 11:14:27 +0200 Subject: [PATCH 120/204] unity: timezone spoofing fixed, close #27 --- platform/clock.c | 45 ++++++++++++++++----------------------------- platform/clock.h | 1 + unityhook/hook.c | 3 +++ 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/platform/clock.c b/platform/clock.c index 5a9a8f4..e163961 100644 --- a/platform/clock.c +++ b/platform/clock.c @@ -20,7 +20,9 @@ static BOOL WINAPI my_SetTimeZoneInformation(TIME_ZONE_INFORMATION *tzinfo); static BOOL (WINAPI * next_GetSystemTimeAsFileTime)(FILETIME *out); static int64_t clock_current_day; +static bool clock_timezone; static bool clock_time_warp; +static bool clock_writeable; static const struct hook_symbol clock_base_hook_syms[] = { { @@ -226,56 +228,41 @@ HRESULT clock_hook_init(const struct clock_config *cfg) { assert(cfg != NULL); + clock_timezone = cfg->timezone; clock_time_warp = cfg->timewarp; + clock_writeable = cfg->writeable; - if (cfg->timezone || cfg->timewarp || !cfg->writeable) { + clock_hook_insert_hooks(NULL); + + return S_OK; +} + +void clock_hook_insert_hooks(HMODULE target) { + if (clock_timezone || clock_time_warp || !clock_writeable) { /* All the clock hooks require the core GSTAFT hook to be installed */ /* Note the ! up there btw. */ hook_table_apply( - NULL, + target, "kernel32.dll", clock_base_hook_syms, _countof(clock_base_hook_syms)); - - proc_addr_table_push( - NULL, - "kernel32.dll", - clock_base_hook_syms, - _countof(clock_base_hook_syms) - ); } - if (cfg->timezone) { + if (clock_timezone) { hook_table_apply( - NULL, + target, "kernel32.dll", clock_read_hook_syms, _countof(clock_read_hook_syms)); - - proc_addr_table_push( - NULL, - "kernel32.dll", - clock_read_hook_syms, - _countof(clock_read_hook_syms) - ); } - if (!cfg->writeable) { + if (!clock_writeable) { /* Install hook if this config parameter is FALSE! */ hook_table_apply( - NULL, + target, "kernel32.dll", clock_write_hook_syms, _countof(clock_write_hook_syms)); - - proc_addr_table_push( - NULL, - "kernel32.dll", - clock_write_hook_syms, - _countof(clock_write_hook_syms) - ); } - - return S_OK; } diff --git a/platform/clock.h b/platform/clock.h index 4d67754..6d8c201 100644 --- a/platform/clock.h +++ b/platform/clock.h @@ -11,3 +11,4 @@ struct clock_config { }; HRESULT clock_hook_init(const struct clock_config *cfg); +void clock_hook_insert_hooks(HMODULE target); diff --git a/unityhook/hook.c b/unityhook/hook.c index c11e744..0058ec1 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -1,6 +1,8 @@ #include #include +#include "platform/clock.h" + #include "hook/table.h" #include "hook/procaddr.h" #include "hook/iohook.h" @@ -140,6 +142,7 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) path_hook_insert_hooks(result); reg_hook_insert_hooks(result); + clock_hook_insert_hooks(result); proc_addr_insert_hooks(result); // Not needed? From 37c26ecadb2ce4d2cb3a61ce96c2c931ba2fc346 Mon Sep 17 00:00:00 2001 From: d4nin3u Date: Tue, 6 Aug 2024 21:35:51 +0000 Subject: [PATCH 121/204] chuniio: Add OpeNITHM LED protocol support (#26) This commit basically copy-pastes the last commits from https://dev.s-ul.net/VeroxZik/segatools/-/commits/master to add OpenITHM LED support. Doesn't need to edit segatools.ini because the relevant config lines are already there for some reason. Tested with my OpenITHM controller and behaves exactly like the other fork. Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/26 Co-authored-by: d4nin3u Co-committed-by: d4nin3u --- chuniio/chuniio.h | 7 ++++--- chuniio/config.c | 2 ++ chuniio/config.h | 2 ++ chuniio/ledoutput.c | 6 +++++- chuniio/meson.build | 1 + chuniio/serialimpl.c | 24 ++++++++++++++++++++++++ chuniio/serialimpl.h | 1 + dist/chuni/segatools.ini | 4 +++- dist/chusan/segatools.ini | 8 +++----- 9 files changed, 45 insertions(+), 10 deletions(-) diff --git a/chuniio/chuniio.h b/chuniio/chuniio.h index 8c575c9..c13bff4 100644 --- a/chuniio/chuniio.h +++ b/chuniio/chuniio.h @@ -139,9 +139,10 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback); void chuni_io_slider_stop(void); /* Update the RGB lighting on the slider. A pointer to an array of 32 * 3 = 96 - bytes is supplied. The illuminated areas on the touch slider are some - combination of rectangular regions and dividing lines between these regions - but the exact mapping of this lighting control buffer is still TBD. + bytes is supplied, organized in BRG format. + The first set of bytes is the right-most slider key, and from there the bytes + alternate between the dividers and the keys until the left-most key. + There are 31 illuminated sections in total. Minimum API version: 0x0100 */ diff --git a/chuniio/config.c b/chuniio/config.c index aaa048e..0f8b31b 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -63,6 +63,8 @@ void chuni_io_config_load( cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename); cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename); + cfg->controller_led_output_openithm = GetPrivateProfileIntW(L"led", L"controllerLedOutputOpeNITHM", 0, filename); + cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename); GetPrivateProfileStringW( diff --git a/chuniio/config.h b/chuniio/config.h index 3eb8223..8c5bf2c 100644 --- a/chuniio/config.h +++ b/chuniio/config.h @@ -18,6 +18,8 @@ struct chuni_io_config { bool controller_led_output_pipe; bool controller_led_output_serial; + bool controller_led_output_openithm; + // The name of a COM port to output LED data on, in serial mode wchar_t led_serial_port[12]; int32_t led_serial_baud; diff --git a/chuniio/ledoutput.c b/chuniio/ledoutput.c index 8cac5a3..6052e42 100644 --- a/chuniio/ledoutput.c +++ b/chuniio/ledoutput.c @@ -127,7 +127,11 @@ void led_output_update(uint8_t board, const byte* rgb) if (config->controller_led_output_serial) { - led_serial_update(escaped_data); + if (config->controller_led_output_openithm){ + led_serial_update_openithm(rgb); + } else { + led_serial_update(escaped_data); + } } } } diff --git a/chuniio/meson.build b/chuniio/meson.build index 864aa87..8b03dff 100644 --- a/chuniio/meson.build +++ b/chuniio/meson.build @@ -4,6 +4,7 @@ chuniio_lib = static_library( include_directories : inc, implicit_include_directories : false, c_pch : '../precompiled.h', + sources : [ 'chu2to3.c', 'chu2to3.h', diff --git a/chuniio/serialimpl.c b/chuniio/serialimpl.c index 57ebb7f..7a68435 100644 --- a/chuniio/serialimpl.c +++ b/chuniio/serialimpl.c @@ -97,3 +97,27 @@ void led_serial_update(struct _chuni_led_data_buf_t* data) ReleaseMutex(serial_write_mutex); } + +void led_serial_update_openithm(const byte* rgb) +{ + if (serial_port != INVALID_HANDLE_VALUE) + { + char led_buffer[100]; + DWORD bytes_to_write; // No of bytes to write into the port + DWORD bytes_written = 0; // No of bytes written to the port + bytes_to_write = sizeof(led_buffer); + BOOL status; + + led_buffer[0] = 0xAA; + led_buffer[1] = 0xAA; + memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96); + led_buffer[98] = 0xDD; + led_buffer[99] = 0xDD; + + status = WriteFile(serial_port, // Handle to the Serial port + led_buffer, // Data to be written to the port + bytes_to_write, // No of bytes to write + &bytes_written, // Bytes written + NULL); + } +} diff --git a/chuniio/serialimpl.h b/chuniio/serialimpl.h index f8f276b..3f37803 100644 --- a/chuniio/serialimpl.h +++ b/chuniio/serialimpl.h @@ -13,3 +13,4 @@ HRESULT led_serial_init(wchar_t led_com[12], DWORD baud); void led_serial_update(struct _chuni_led_data_buf_t* data); +void led_serial_update_openithm(const byte* rgb); \ No newline at end of file diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 87d923d..5b8af0c 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -82,10 +82,12 @@ cabLedOutputSerial=0 controllerLedOutputPipe=1 ; Output slider LED data to the serial port controllerLedOutputSerial=0 +; Use the OpeNITHM protocol for serial LED output +controllerLedOutputOpeNITHM=0 ; Serial port to send data to if using serial output. Default is COM5. ;serialPort=COM5 -; Baud rate for serial data +; Baud rate for serial data (set to 115200 if using OpeNITHM) ;serialBaud=921600 ; Data output a sequence of bytes, with JVS-like framing. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index c167f26..c0b19de 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -108,10 +108,12 @@ cabLedOutputSerial=0 controllerLedOutputPipe=1 ; Output slider LED data to the serial port controllerLedOutputSerial=0 +; Use the OpeNITHM protocol for serial LED output +controllerLedOutputOpeNITHM=0 ; Serial port to send data to if using serial output. Default is COM5. ;serialPort=COM5 -; Baud rate for serial data +; Baud rate for serial data (set to 115200 if using OpeNITHM) ;serialBaud=921600 ; Data output a sequence of bytes, with JVS-like framing. @@ -202,7 +204,3 @@ ir=0x20 ; ... etc ... ;cell31=0x53 ;cell32=0x53 - -; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. -; eg. COM5 -;ledport= From 383039e16ef3744866dd8ec287869e639847552a Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Sat, 17 Aug 2024 21:17:23 +0100 Subject: [PATCH 122/204] Add bounds checking for D3D9 adapter number --- gfxhook/d3d9.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/gfxhook/d3d9.c b/gfxhook/d3d9.c index 34a165d..7db36e5 100644 --- a/gfxhook/d3d9.c +++ b/gfxhook/d3d9.c @@ -224,9 +224,19 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice( gfx_util_frame_window(hwnd); } - dprintf("Gfx: Using adapter %d\n", gfx_config.monitor); + UINT max_adapter = IDirect3D9_GetAdapterCount(real); + adapter = gfx_config.monitor; + if (adapter >= max_adapter) { + dprintf( + "Gfx: Requested adapter %d but maximum is %d. Using primary monitor\n", + gfx_config.monitor, max_adapter - 1 + ); + adapter = D3DADAPTER_DEFAULT; + } else { + dprintf("Gfx: Using adapter %d\n", gfx_config.monitor); + } - return IDirect3D9_CreateDevice(real, gfx_config.monitor, type, hwnd, flags, pp, pdev); + return IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev); } static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice( From c91c7db3c7ebe336f073715babb7a3bdfe01fee6 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 20 Aug 2024 10:48:08 +0200 Subject: [PATCH 123/204] renamed [gpio] dipsw settings to [system] --- chusanhook/dllmain.c | 2 +- cmhook/dllmain.c | 2 +- cmio/cmio.h | 4 +-- dist/chusan/segatools.ini | 4 +-- dist/cm/segatools.ini | 4 +-- dist/fgo/segatools.ini | 4 +-- dist/idac/segatools.ini | 4 +-- dist/mai2/segatools.ini | 4 +-- dist/mercury/segatools.ini | 4 +-- dist/mu3/segatools.ini | 4 +-- dist/swdc/segatools.ini | 4 +-- fgoio/fgoio.h | 10 ++----- platform/config.c | 12 ++++---- platform/config.h | 4 +-- platform/meson.build | 4 +-- platform/platform.c | 4 +-- platform/platform.h | 4 +-- platform/{dipsw.c => system.c} | 50 +++++++++++++++++----------------- platform/{dipsw.h => system.h} | 4 +-- 19 files changed, 64 insertions(+), 68 deletions(-) rename platform/{dipsw.c => system.c} (72%) rename platform/{dipsw.h => system.h} (59%) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 9f59301..85c6228 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -123,7 +123,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0]; + bool *dipsw = &chusan_hook_cfg.platform.system.dipsw[0]; bool is_cvt = dipsw[2]; for (int i = 0; i < 3; i++) { diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index b004db3..ac54a9d 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -58,7 +58,7 @@ static DWORD CALLBACK cm_pre_startup(void) /* Hook external DLL APIs */ - printer_hook_init(&cm_hook_cfg.printer, 4, cm_hook_mod); + printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod); /* Initialize emulation hooks */ diff --git a/cmio/cmio.h b/cmio/cmio.h index cb4aa9c..86d8ac9 100644 --- a/cmio/cmio.h +++ b/cmio/cmio.h @@ -36,9 +36,9 @@ HRESULT cm_io_init(void); HRESULT cm_io_poll(void); /* Get the state of the cabinet's operator buttons as of the last poll. See - cm_IO_OPBTN enum above: this contains bit mask definitions for button + CM_IO_OPBTN enum above: this contains bit mask definitions for button states returned in *opbtn. All buttons are active-high. Minimum API version: 0x0100 */ -void cm_io_get_opbtns(uint8_t *opbtn); \ No newline at end of file +void cm_io_get_opbtns(uint8_t *opbtn); diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index c0b19de..556df02 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -59,8 +59,8 @@ addrSuffix=11 ; that subnet must start with 192.168. subnet=192.168.139.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index f752b6b..2cd86b0 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -52,8 +52,8 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.165.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; LAN Install: If multiple machines are present on the same LAN then set diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 0884c2d..945f9a1 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -72,8 +72,8 @@ addrSuffix=11 ; that subnet must start with 192.168. subnet=192.168.167.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index f678a77..d4c828c 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -54,8 +54,8 @@ subnet=192.168.158.0 ; 1: JPN: Japan, 4: EXP: Export (for Asian markets) region=4 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 596a295..71dbf15 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -56,8 +56,8 @@ addrSuffix=11 ; that subnet must start with 192.168. subnet=192.168.172.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index a31abd7..891c4d8 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -56,8 +56,8 @@ addrSuffix=11 ; that subnet must start with 192.168. subnet=192.168.174.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index d7b8166..182e1d8 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -52,8 +52,8 @@ enable=1 ; that subnet must start with 192.168. subnet=192.168.162.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 71de4e3..6fdee71 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -56,8 +56,8 @@ addrSuffix=11 ; in order to find the MAIN cabinet. subnet=192.168.160.0 -[gpio] -; ALLS DIP switches. +[system] +; Enable ALLS system settings. enable=1 ; Enable freeplay mode. This will disable the coin slot and set the game to diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h index 1adf6b7..c5b5fd8 100644 --- a/fgoio/fgoio.h +++ b/fgoio/fgoio.h @@ -52,16 +52,12 @@ HRESULT fgo_io_poll(void); void fgo_io_get_opbtns(uint8_t *opbtn); /* Get the state of the cabinet's gameplay buttons as of the last poll. See - FGO_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into - a left hand side set of inputs and a right hand side set of inputs: the bit - mappings are the same in both cases. - - All buttons are active-high, even though some buttons' electrical signals - on a real cabinet are active-low. + FGO_IO_GAMEBTN enum above: this contains bit mask definitions for button + states returned in *gamebtn. All buttons are active-high. Minimum API version: 0x0100 */ -void fgo_io_get_gamebtns(uint8_t *btn); +void fgo_io_get_gamebtns(uint8_t *gamebtn); /* Get the position of the cabinet stick as of the last poll. The center position should be equal to or close to 32767. diff --git a/platform/config.c b/platform/config.c index fd48a3e..ad97905 100644 --- a/platform/config.c +++ b/platform/config.c @@ -22,7 +22,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" -#include "platform/dipsw.h" +#include "platform/system.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -40,7 +40,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) netenv_config_load(&cfg->netenv, filename); nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); - dipsw_config_load(&cfg->dipsw, filename); + system_config_load(&cfg->system, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -329,7 +329,7 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) filename); } -void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) +void system_config_load(struct system_config *cfg, const wchar_t *filename) { wchar_t name[7]; size_t i; @@ -337,14 +337,14 @@ void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) assert(cfg != NULL); assert(filename != NULL); - cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 0, filename); - cfg->freeplay = GetPrivateProfileIntW(L"gpio", L"freeplay", 0, filename); + cfg->enable = GetPrivateProfileIntW(L"system", L"enable", 0, filename); + cfg->freeplay = GetPrivateProfileIntW(L"system", L"freeplay", 0, filename); wcscpy_s(name, _countof(name), L"dipsw0"); for (i = 0 ; i < 8 ; i++) { name[5] = L'1' + i; - cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename); + cfg->dipsw[i] = GetPrivateProfileIntW(L"system", name, 0, filename); } } diff --git a/platform/config.h b/platform/config.h index eb04b56..e945378 100644 --- a/platform/config.h +++ b/platform/config.h @@ -18,7 +18,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" -#include "platform/dipsw.h" +#include "platform/system.h" void platform_config_load( struct platform_config *cfg, @@ -35,4 +35,4 @@ void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename); void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); -void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename); +void system_config_load(struct system_config *cfg, const wchar_t *filename); diff --git a/platform/meson.build b/platform/meson.build index 4ca2a38..aa0d362 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -34,7 +34,7 @@ platform_lib = static_library( 'platform.h', 'vfs.c', 'vfs.h', - 'dipsw.c', - 'dipsw.h', + 'system.c', + 'system.h', ], ) diff --git a/platform/platform.c b/platform/platform.c index 5a1b5f6..a769c97 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -13,7 +13,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" -#include "platform/dipsw.h" +#include "platform/system.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -82,7 +82,7 @@ HRESULT platform_hook_init( return hr; } - hr = dipsw_init(&cfg->dipsw, &cfg->vfs); + hr = system_init(&cfg->system, &cfg->vfs); if (FAILED(hr)) { return hr; diff --git a/platform/platform.h b/platform/platform.h index 8774f01..0b69f12 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -13,7 +13,7 @@ #include "platform/nusec.h" #include "platform/pcbid.h" #include "platform/vfs.h" -#include "platform/dipsw.h" +#include "platform/system.h" struct platform_config { struct amvideo_config amvideo; @@ -27,7 +27,7 @@ struct platform_config { struct netenv_config netenv; struct nusec_config nusec; struct vfs_config vfs; - struct dipsw_config dipsw; + struct system_config system; }; HRESULT platform_hook_init( diff --git a/platform/dipsw.c b/platform/system.c similarity index 72% rename from platform/dipsw.c rename to platform/system.c index 22b88ed..49f7999 100644 --- a/platform/dipsw.c +++ b/platform/system.c @@ -4,7 +4,7 @@ #include #include -#include "platform/dipsw.h" +#include "platform/system.h" #include "platform/vfs.h" #include "util/dprintf.h" @@ -30,12 +30,12 @@ typedef struct char padding[4]; uint8_t dip_switches; char data[DATA_SIZE]; -} DipSwitchBlock; +} DipSwBlock; typedef struct { CreditBlock credit_block; - DipSwitchBlock dip_switch_block; + DipSwBlock dip_switch_block; char *data; } SystemInfo; @@ -43,13 +43,13 @@ typedef struct static SystemInfo system_info; -static struct dipsw_config dipsw_config; +static struct system_config system_config; static struct vfs_config vfs_config; -static void dipsw_read_sysfile(const wchar_t *sys_file); -static void dipsw_save_sysfile(const wchar_t *sys_file); +static void system_read_sysfile(const wchar_t *sys_file); +static void system_save_sysfile(const wchar_t *sys_file); -HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg) +HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg) { HRESULT hr; wchar_t sys_file_path[MAX_PATH]; @@ -62,28 +62,28 @@ HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_ return S_FALSE; } - memcpy(&dipsw_config, cfg, sizeof(*cfg)); + memcpy(&system_config, cfg, sizeof(*cfg)); sys_file_path[0] = L'\0'; // concatenate vfs_config.amfs with L"sysfile.dat" wcsncpy(sys_file_path, vfs_cfg->amfs, MAX_PATH); wcsncat(sys_file_path, L"\\sysfile.dat", MAX_PATH); - dipsw_read_sysfile(sys_file_path); + system_read_sysfile(sys_file_path); - // now write the dipsw_config.dipsw to the dip_switch_block - dipsw_save_sysfile(sys_file_path); + // now write the system_config.system to the dip_switch_block + system_save_sysfile(sys_file_path); return S_OK; } -static void dipsw_read_sysfile(const wchar_t *sys_file) +static void system_read_sysfile(const wchar_t *sys_file) { FILE *f = _wfopen(sys_file, L"r"); if (f == NULL) { - dprintf("DipSw: First run detected, DipSw settings can only be applied AFTER the first run\n"); + dprintf("System: First run detected, system settings can only be applied AFTER the first run\n"); return; } @@ -93,7 +93,7 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) if (file_size != 0x6000) { - dprintf("DipSw: Invalid sysfile.dat file size\n"); + dprintf("System: Invalid sysfile.dat file size\n"); fclose(f); return; @@ -108,10 +108,10 @@ static void dipsw_read_sysfile(const wchar_t *sys_file) memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE); } -static void dipsw_save_sysfile(const wchar_t *sys_file) +static void system_save_sysfile(const wchar_t *sys_file) { char block[BLOCK_SIZE]; - uint8_t dipsw = 0; + uint8_t system = 0; uint8_t freeplay = 0; // open the sysfile.dat for writing in bytes mode @@ -122,28 +122,28 @@ static void dipsw_save_sysfile(const wchar_t *sys_file) return; } - // write the dipsw_config.dipsw to the dip_switch_block + // write the system_config.system to the dip_switch_block for (int i = 0; i < 8; i++) { - if (dipsw_config.dipsw[i]) + if (system_config.dipsw[i]) { - // print which dipsw is enabled - dprintf("DipSw: DipSw%d=1 set\n", i + 1); - dipsw |= (1 << i); + // print which system is enabled + dprintf("System: DipSw%d=1 set\n", i + 1); + system |= (1 << i); } } - if (dipsw_config.freeplay) + if (system_config.freeplay) { // print that freeplay is enabled - dprintf("DipSw: Freeplay enabled\n"); + dprintf("System: Freeplay enabled\n"); freeplay = 1; } // set the new credit block system_info.credit_block.freeplay = freeplay; // set the new dip_switch_block - system_info.dip_switch_block.dip_switches = dipsw; + system_info.dip_switch_block.dip_switches = system; // calculate the new checksum, skip the old crc32 value // which is at the beginning of the block, thats's why the +4 @@ -167,7 +167,7 @@ static void dipsw_save_sysfile(const wchar_t *sys_file) // print the dip_switch_block in hex /* - dprintf("DipSw Block: "); + dprintf("System Block: "); for (size_t i = 0; i < BLOCK_SIZE; i++) { dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]); diff --git a/platform/dipsw.h b/platform/system.h similarity index 59% rename from platform/dipsw.h rename to platform/system.h index 336b0d7..ba0f2a6 100644 --- a/platform/dipsw.h +++ b/platform/system.h @@ -7,10 +7,10 @@ #include "platform/vfs.h" -struct dipsw_config { +struct system_config { bool enable; bool freeplay; bool dipsw[8]; }; -HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg); +HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg); From c535f18e40d8f427f3a9e4a5c8806674f885a2f8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 20 Aug 2024 13:30:51 +0200 Subject: [PATCH 124/204] added support for tokyo --- Package.mk | 17 +++ README.md | 24 +++-- dist/tokyo/config_hook.json | 9 ++ dist/tokyo/segatools.ini | 199 ++++++++++++++++++++++++++++++++++++ dist/tokyo/start.bat | 57 +++++++++++ meson.build | 2 + tokyohook/config.c | 110 ++++++++++++++++++++ tokyohook/config.h | 30 ++++++ tokyohook/dllmain.c | 112 ++++++++++++++++++++ tokyohook/io4.c | 163 +++++++++++++++++++++++++++++ tokyohook/io4.h | 7 ++ tokyohook/meson.build | 32 ++++++ tokyohook/tokyo-dll.c | 115 +++++++++++++++++++++ tokyohook/tokyo-dll.h | 24 +++++ tokyohook/tokyohook.def | 20 ++++ tokyohook/zinput.c | 118 +++++++++++++++++++++ tokyohook/zinput.h | 11 ++ tokyoio/backend.h | 10 ++ tokyoio/config.c | 54 ++++++++++ tokyoio/config.h | 34 ++++++ tokyoio/dllmain.c | 135 ++++++++++++++++++++++++ tokyoio/kb.c | 135 ++++++++++++++++++++++++ tokyoio/kb.h | 10 ++ tokyoio/meson.build | 21 ++++ tokyoio/tokyoio.h | 139 +++++++++++++++++++++++++ tokyoio/xi.c | 130 +++++++++++++++++++++++ tokyoio/xi.h | 8 ++ 27 files changed, 1715 insertions(+), 11 deletions(-) create mode 100644 dist/tokyo/config_hook.json create mode 100644 dist/tokyo/segatools.ini create mode 100644 dist/tokyo/start.bat create mode 100644 tokyohook/config.c create mode 100644 tokyohook/config.h create mode 100644 tokyohook/dllmain.c create mode 100644 tokyohook/io4.c create mode 100644 tokyohook/io4.h create mode 100644 tokyohook/meson.build create mode 100644 tokyohook/tokyo-dll.c create mode 100644 tokyohook/tokyo-dll.h create mode 100644 tokyohook/tokyohook.def create mode 100644 tokyohook/zinput.c create mode 100644 tokyohook/zinput.h create mode 100644 tokyoio/backend.h create mode 100644 tokyoio/config.c create mode 100644 tokyoio/config.h create mode 100644 tokyoio/dllmain.c create mode 100644 tokyoio/kb.c create mode 100644 tokyoio/kb.h create mode 100644 tokyoio/meson.build create mode 100644 tokyoio/tokyoio.h create mode 100644 tokyoio/xi.c create mode 100644 tokyoio/xi.h diff --git a/Package.mk b/Package.mk index 0b60a36..f85d86f 100644 --- a/Package.mk +++ b/Package.mk @@ -203,6 +203,22 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip * +$(BUILD_DIR_ZIP)/tokyo.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo + $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/tokyohook/tokyohook.dll \ + $(DIST_DIR)/tokyo/config_hook.json \ + $(DIST_DIR)/tokyo/segatools.ini \ + $(DIST_DIR)/tokyo/start.bat \ + $(BUILD_DIR_ZIP)/tokyo + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/tokyo/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/tokyo/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/tokyo ; zip -r ../tokyo.zip * + $(BUILD_DIR_ZIP)/doc.zip: \ $(DOC_DIR)/config \ $(DOC_DIR)/chunihook.md \ @@ -225,6 +241,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/mu3.zip \ $(BUILD_DIR_ZIP)/mai2.zip \ $(BUILD_DIR_ZIP)/cm.zip \ + $(BUILD_DIR_ZIP)/tokyo.zip \ $(BUILD_DIR_ZIP)/fgo.zip \ CHANGELOG.md \ README.md \ diff --git a/README.md b/README.md index 4e4e0e3..ad64f5f 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,33 @@ # Segatools -Version: `2024-03-13` +Version: `2024-08-20` Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. ## List of supported games +* Card Maker + * starting from Card Maker * CHUNITHM * up to [CHUNITHM PARADISE LOST](doc/chunihook.md) * starting from CHUNITHM NEW!! * crossbeats REV. * up to crossbeats REV. SUNRISE +* Fate/Grand Order + * Fate/Grand Order Arcade +* Hatsune Miku: Project DIVA Arcade + * up to Future Tone * Initial D * [Initial D Arcade Stage Zero](doc/idzhook.md) * Initial D THE ARCADE -* Hatsune Miku: Project DIVA Arcade - * up to Future Tone -* SEGA World Drivers Championship - * SEGA World Drivers Championship 2019 -* Fate/Grand Order - * Fate/Grand Order Arcade -* O.N.G.E.K.I. - * starting from O.N.G.E.K.I. * maimai DX * starting from maimai DX -* Card Maker - * starting from Card Maker +* Mario & Sonic + * Mario & Sonic at the Tokyo 2020 Olympics Arcade +* O.N.G.E.K.I. + * starting from O.N.G.E.K.I. +* SEGA World Drivers Championship + * SEGA World Drivers Championship 2019 * WACCA * starting from WACCA diff --git a/dist/tokyo/config_hook.json b/dist/tokyo/config_hook.json new file mode 100644 index 0000000..3758b3d --- /dev/null +++ b/dist/tokyo/config_hook.json @@ -0,0 +1,9 @@ +{ + "network" : + { + "property" : + { + "dhcp" : true + } + } +} diff --git a/dist/tokyo/segatools.ini b/dist/tokyo/segatools.ini new file mode 100644 index 0000000..8c68b53 --- /dev/null +++ b/dist/tokyo/segatools.ini @@ -0,0 +1,199 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains OPxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.149.0` and this value is set to `205`, then the +; local host's virtualized LAN IP is `192.168.149.205`). +addrSuffix=205 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.149.0 + +; Override the keychip's region code. +; 1: JAPAN (ALL.Net, Japanese language, Option support enabled) +; 4: EXPORT (Local networking only, English language, No option support) +; 8: CHINA +; +; NOTE: Changing this setting causes a factory reset. The language can be +; changed in the game settings, so it's possible to run the JAPAN region +; with English language. +region=1 + +[system] +; Enable ALLS system settings. +enable=1 + +; Enable freeplay mode. This will disable the coin slot and set the game to +; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not +; allow you to start a game in freeplay mode. +freeplay=0 + +; For Mario & Sonic at the Tokyo 2020 Olympics Arcade, DipSw 1/2/3 must be set +; as the following: +; Cabinet ID 1 (Server): 1 0 0 +; Cabinet ID 2 (Client): 0 1 0 +; Cabinet ID 3 (Client): 0 0 1 +; Cabinet ID 4 (Client): 0 1 1 +dipsw1=1 +dipsw2=0 +dipsw3=0 + +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15093] +; Enable emulation of the 15093-04 controlled lights, which handle the cabinet +; LEDs. +enable=1 + +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + +[zinput] +; Disables the built-in DirectInput support, which is used to support a +; controller out of the box. +enable=1 + +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[tokyoio] +; To use a custom Mario & Sonic at the Tokyo 2020 Olympics Arcade IO DLL enter +; its path here. Leave empty if you want to use Segatools built-in keyboard/ +; gamepad input. +path= + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io4] +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 + +; Input API selection for IO4 input emulator. +; Set "xinput" to use a gamepad and "keyboard" to use a keyboard. +mode=xinput + +; Mario & Sonic at the Tokyo 2020 Olympics Arcade Control Panel +; +; |--|------------------ Main-Assy ------------------|--| +; | | YELLOW | | +; | | --- | | +; | | ( O ) | | +; |--| BLUE --- RED |--| +; | | --- PUSH CENTER --- | | +; | | ( O ) /---------------\ ( O ) | | +; | | --- / \ --- | | +; | | PUSH LEFT / \ PUSH RIGHT| | +; |--|---------/ Floor Assy \---------|--| +; | | |JUMP SENSE JUMP SENSE| | | +; | | |1|---------------|-|-------------->|1| | | +; | | | | Foot Panel | | Foot Panel | | | | +; | | |2|<- - - - - - - |-| - - - - - - - |2| | | +; | | | | | | | | | | +; | | |3| -FOOT SENSE - |-| - FOOT SENSE->|3| | | +; | | | | L | | R | | | | +; | | |4|<- - - - - - - |-| - - - - - - - |4| | | +; | | | | | | | | | | +; | | |5| - - - - - - - |-| - - - - - - ->|5| | | +; | | | | | | | | | | +; | | |6|<--------------|-|---------------|6| | | +; | | | | | | +; | | | | | | +; |--|----|-------------------------------------|----|--| +; + +; XInput bindings +; +; X Push Left Blue +; Y Push Center Yellow +; B Push Right Red +; D-Pad Left Push Left Blue +; D-Pad Right Push Right Red +; Left Trigger Foot Sense L/Jump Sense +; Right Trigger Foot Sense R/Jump Sense + +[keyboard] +; Keyboard bindings + +; Keyoard: Push button settings + +; PUSH LEFT (BLUE) button virtual-key code. Default is the A key. +leftBlue=0x41 +; PUSH CENTER (YELLOW) button virtual-key code. Default is the S key. +centerYellow=0x53 +; PUSH RIGHT (RED) button virtual-key code. Default is the D key. +rightRed=0x44 + +; Keyboard: Sensor settings +; FOOT SENSE L (LEFT) button virtual-key code. Default is the Left Arrow key. +footLeft=0x25 +; FOOT SENSE R (RIGHT) button virtual-key code. Default is the Right Arrow key. +footRight=0x27 + +; Keyboard: Jump sensor settings +; All jump sensors will also trigger the FOOT SENSE L and FOOT SENSE R buttons. +; JUMP SENSOR 1 button virtual-key code. Default is the Z key. +jump1=0x5A +; JUMP SENSOR 2 button virtual-key code. Default is the X key. +jump2=0x58 +; JUMP SENSOR 3 button virtual-key code. Default is the C key. +jump3=0x43 +; JUMP SENSOR 4 button virtual-key code. Default is the B key. +jump4=0x42 +; JUMP SENSOR 5 button virtual-key code. Default is the N key. +jump5=0x4E +; JUMP SENSOR 6 button virtual-key code. Default is the M key. +jump6=0x4D + +; Virtual-key code for all jump sensors. Default is the Space key. +jumpAll=0x20 diff --git a/dist/tokyo/start.bat b/dist/tokyo/start.bat new file mode 100644 index 0000000..01c4ddf --- /dev/null +++ b/dist/tokyo/start.bat @@ -0,0 +1,57 @@ +@echo off +pushd %~dp0 + +set DAEMON_WAIT_SECONDS=5 + +set AMDAEMON_CFG=config_common.json ^ +config_ch.json ^ +config_ex.json ^ +config_jp.json ^ +config_st1_ch.json ^ +config_st1_ex.json ^ +config_st1_jp.json ^ +config_st2_ch.json ^ +config_st2_ex.json ^ +config_st2_jp.json ^ +config_st3_ch.json ^ +config_st3_ex.json ^ +config_st3_jp.json ^ +config_st4_ch.json ^ +config_st4_ex.json ^ +config_st4_jp.json ^ +config_laninstall_server_ch.json ^ +config_laninstall_client1_ch.json ^ +config_laninstall_client2_ch.json ^ +config_laninstall_client3_ch.json ^ +config_laninstall_server_ex.json ^ +config_laninstall_client1_ex.json ^ +config_laninstall_client2_ex.json ^ +config_laninstall_client3_ex.json ^ +config_laninstall_server_jp.json ^ +config_laninstall_client1_jp.json ^ +config_laninstall_client2_jp.json ^ +config_laninstall_client3_jp.json ^ +config_hook.json + +start /min "AM Daemon" inject -d -k tokyohook.dll amdaemon.exe -c %AMDAEMON_CFG% +timeout %DAEMON_WAIT_SECONDS% > nul 2>&1 + +REM --------------------------------------------------------------------------- +REM Set configuration +REM --------------------------------------------------------------------------- + +REM Configuration values to be passed to the game executable. +REM All known values: +REM -forceapi:11 +REM -forcehal +REM -forcevsync:0/1 +REM -fullscreen +REM -windowed +REM Note: -windowed is recommended as the game looks sharper in windowed mode. +inject -d -k tokyohook.dll app.exe -windowed + +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause diff --git a/meson.build b/meson.build index 40f62e3..c5b3d40 100644 --- a/meson.build +++ b/meson.build @@ -108,6 +108,7 @@ subdir('mai2io') subdir('cmio') subdir('mercuryio') subdir('cxbio') +subdir('tokyoio') subdir('fgoio') subdir('chunihook') @@ -123,4 +124,5 @@ subdir('mai2hook') subdir('cmhook') subdir('mercuryhook') subdir('cxbhook') +subdir('tokyohook') subdir('fgohook') diff --git a/tokyohook/config.c b/tokyohook/config.c new file mode 100644 index 0000000..e9735d2 --- /dev/null +++ b/tokyohook/config.c @@ -0,0 +1,110 @@ +#include +#include + +#include "board/config.h" + +#include "gfxhook/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "platform/config.h" + +#include "tokyohook/config.h" + +void tokyo_dll_config_load( + struct tokyo_dll_config *cfg, + const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"tokyoio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAED9, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-04", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6704 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } +} + +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename); +} + +void tokyo_hook_config_load( + struct tokyo_hook_config *cfg, + const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + zinput_config_load(&cfg->zinput, filename); + led15093_config_load(&cfg->led15093, filename); + tokyo_dll_config_load(&cfg->dll, filename); +} diff --git a/tokyohook/config.h b/tokyohook/config.h new file mode 100644 index 0000000..54dc751 --- /dev/null +++ b/tokyohook/config.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "board/config.h" +#include "board/led15093.h" + +#include "hooklib/dvd.h" + +#include "tokyohook/tokyo-dll.h" +#include "tokyohook/zinput.h" + +#include "platform/config.h" + +struct tokyo_hook_config { + struct platform_config platform; + struct dvd_config dvd; + struct io4_config io4; + struct led15093_config led15093; + struct zinput_config zinput; + struct tokyo_dll_config dll; +}; + +void tokyo_dll_config_load( + struct tokyo_dll_config *cfg, + const wchar_t *filename); + +void tokyo_hook_config_load( + struct tokyo_hook_config *cfg, + const wchar_t *filename); diff --git a/tokyohook/dllmain.c b/tokyohook/dllmain.c new file mode 100644 index 0000000..e39fcff --- /dev/null +++ b/tokyohook/dllmain.c @@ -0,0 +1,112 @@ +/* + "Mario & Sonic at the Tokyo 2020 Olympics Arcade" (tokyo) hook + + Devices + + USB: 837-15257 "Type 4" I/O Board + COM1: 837-15093-04 LED Controller Board +*/ + +#include + +#include + +#include "board/io4.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "tokyohook/config.h" +#include "tokyohook/io4.h" +#include "tokyohook/tokyo-dll.h" + +#include "platform/platform.h" + +#include "util/dprintf.h" + +static HMODULE tokyo_hook_mod; +static process_entry_t tokyo_startup; +static struct tokyo_hook_config tokyo_hook_cfg; + +static DWORD CALLBACK tokyo_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin tokyo_pre_startup ---\n"); + + /* Load config */ + + tokyo_hook_config_load(&tokyo_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&tokyo_hook_cfg.dvd, tokyo_hook_mod); + zinput_hook_init(&tokyo_hook_cfg.zinput); + serial_hook_init(); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &tokyo_hook_cfg.platform, + "SDFV", + "ACA1", + tokyo_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = tokyo_dll_init(&tokyo_hook_cfg.dll, tokyo_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = led15093_hook_init(&tokyo_hook_cfg.led15093, + tokyo_dll.led_init, tokyo_dll.led_set_leds, 1, 1, 1, 2); + + if (FAILED(hr)) { + return hr; + } + + hr = tokyo_io4_hook_init(&tokyo_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End tokyo_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return tokyo_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + tokyo_hook_mod = mod; + + hr = process_hijack_startup(tokyo_pre_startup, &tokyo_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/tokyohook/io4.c b/tokyohook/io4.c new file mode 100644 index 0000000..b2924c7 --- /dev/null +++ b/tokyohook/io4.c @@ -0,0 +1,163 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "tokyohook/tokyo-dll.h" + +#include "util/dprintf.h" + +static HRESULT tokyo_io4_poll(void *ctx, struct io4_state *state); +static HRESULT tokyo_io4_write_gpio(uint8_t* payload, size_t len); + +static uint16_t coins; + +static const struct io4_ops tokyo_io4_ops = { + .poll = tokyo_io4_poll, + .write_gpio = tokyo_io4_write_gpio, +}; + +HRESULT tokyo_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(tokyo_dll.init != NULL); + + hr = io4_hook_init(cfg, &tokyo_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return tokyo_dll.init(); +} + +static HRESULT tokyo_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + uint8_t gamebtn; + uint8_t sense; + HRESULT hr; + + assert(tokyo_dll.get_opbtns != NULL); + assert(tokyo_dll.get_gamebtns != NULL); + assert(tokyo_dll.get_sensors != NULL); + + memset(state, 0, sizeof(*state)); + + opbtn = 0; + gamebtn = 0; + sense = 0; + + tokyo_dll.get_opbtns(&opbtn); + tokyo_dll.get_gamebtns(&gamebtn); + tokyo_dll.get_sensors(&sense); + + if (opbtn & TOKYO_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & TOKYO_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & TOKYO_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + /* Update gamebtns */ + + if (gamebtn & TOKYO_IO_GAMEBTN_BLUE) { + state->buttons[0] |= 1 << 1; + } + + if (gamebtn & TOKYO_IO_GAMEBTN_YELLOW) { + state->buttons[0] |= 1 << 0; + } + + if (gamebtn & TOKYO_IO_GAMEBTN_RED) { + state->buttons[0] |= 1 << 15; + } + + /* Update sensors */ + + // Invert the logic so that it's active high + if (!(sense & TOKYO_IO_SENSE_FOOT_LEFT)) { + state->buttons[0] |= 1 << 13; + } + + if (!(sense & TOKYO_IO_SENSE_FOOT_RIGHT)) { + state->buttons[1] |= 1 << 13; + } + + if (sense & TOKYO_IO_SENSE_JUMP_1) { + state->buttons[0] |= 1 << 12; + } + + if (sense & TOKYO_IO_SENSE_JUMP_2) { + state->buttons[1] |= 1 << 12; + } + + if (sense & TOKYO_IO_SENSE_JUMP_3) { + state->buttons[0] |= 1 << 11; + } + + if (sense & TOKYO_IO_SENSE_JUMP_4) { + state->buttons[1] |= 1 << 11; + } + + if (sense & TOKYO_IO_SENSE_JUMP_5) { + state->buttons[0] |= 1 << 10; + } + + if (sense & TOKYO_IO_SENSE_JUMP_6) { + state->buttons[1] |= 1 << 10; + } + + return S_OK; +} + +static HRESULT tokyo_io4_write_gpio(uint8_t* payload, size_t len) +{ + // Just fast fail if there aren't enough bytes in the payload + if (len < 3) + return S_OK; + + // This command is used for lights in Mario & Sonic at the Tokyo 2020 Olympics + // Arcade, but it only contains button lights, and only in the first 3 bytes of + // the payload; everything else is padding to make the payload 62 bytes. The + // rest of the cabinet lights and the side button lights are handled separately, + // by the 15093 lights controller. + uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); + + // Since Sega uses an odd ordering for the first part of the bitfield, + // let's normalize the data and just send over bytes for the receiver + // to interpret as RGB values. + uint8_t rgb_out[5 * 3] = { + lights_data & TOKYO_IO_LED_LEFT_BLUE ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CENTER_YELLOW ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_RIGHT_RED ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_LEFT_R ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_LEFT_G ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_LEFT_B ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_RIGHT_R ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_RIGHT_G ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_CONTROL_RIGHT_B ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_LEFT_R ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_LEFT_G ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_LEFT_B ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_RIGHT_R ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_RIGHT_G ? 0xFF : 0x00, + lights_data & TOKYO_IO_LED_FLOOR_RIGHT_B ? 0xFF : 0x00, + }; + + tokyo_dll.led_set_leds(1, rgb_out); + + return S_OK; +} diff --git a/tokyohook/io4.h b/tokyohook/io4.h new file mode 100644 index 0000000..508d802 --- /dev/null +++ b/tokyohook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT tokyo_io4_hook_init(const struct io4_config *cfg); diff --git a/tokyohook/meson.build b/tokyohook/meson.build new file mode 100644 index 0000000..1e4b1d8 --- /dev/null +++ b/tokyohook/meson.build @@ -0,0 +1,32 @@ +shared_library( + 'tokyohook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'tokyohook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + tokyoio_lib, + platform_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'zinput.c', + 'zinput.h', + 'tokyo-dll.c', + 'tokyo-dll.h', + ], +) diff --git a/tokyohook/tokyo-dll.c b/tokyohook/tokyo-dll.c new file mode 100644 index 0000000..0187205 --- /dev/null +++ b/tokyohook/tokyo-dll.c @@ -0,0 +1,115 @@ +#include + +#include +#include + +#include "tokyohook/tokyo-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym tokyo_dll_syms[] = { + { + .sym = "tokyo_io_init", + .off = offsetof(struct tokyo_dll, init), + }, { + .sym = "tokyo_io_get_opbtns", + .off = offsetof(struct tokyo_dll, get_opbtns), + }, { + .sym = "tokyo_io_get_gamebtns", + .off = offsetof(struct tokyo_dll, get_gamebtns), + }, { + .sym = "tokyo_io_get_sensors", + .off = offsetof(struct tokyo_dll, get_sensors), + }, { + .sym = "tokyo_io_led_init", + .off = offsetof(struct tokyo_dll, led_init), + }, { + .sym = "tokyo_io_led_set_colors", + .off = offsetof(struct tokyo_dll, led_set_leds), + } +}; + +struct tokyo_dll tokyo_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT tokyo_dll_init(const struct tokyo_dll_config *cfg, HINSTANCE self) +{ + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Tokyo IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Tokyo IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "tokyo_io_get_api_version"); + + if (get_api_version != NULL) { + tokyo_dll.api_version = get_api_version(); + } else { + tokyo_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose tokyo_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (tokyo_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Tokyo IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + tokyo_dll.api_version); + + goto end; + } + + sym = tokyo_dll_syms; + hr = dll_bind(&tokyo_dll, src, &sym, _countof(tokyo_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Tokyo IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + +end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/tokyohook/tokyo-dll.h b/tokyohook/tokyo-dll.h new file mode 100644 index 0000000..9bfeb5a --- /dev/null +++ b/tokyohook/tokyo-dll.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "tokyoio/tokyoio.h" + +struct tokyo_dll { + uint16_t api_version; + HRESULT (*init)(void); + void (*get_opbtns)(uint8_t *opbtn); + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_sensors)(uint8_t *sense); + HRESULT (*gpio_out)(uint32_t state); + HRESULT (*led_init)(void); + void (*led_set_leds)(uint8_t board, uint8_t *rgb); +}; + +struct tokyo_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct tokyo_dll tokyo_dll; + +HRESULT tokyo_dll_init(const struct tokyo_dll_config *cfg, HINSTANCE self); diff --git a/tokyohook/tokyohook.def b/tokyohook/tokyohook.def new file mode 100644 index 0000000..d60bf17 --- /dev/null +++ b/tokyohook/tokyohook.def @@ -0,0 +1,20 @@ +LIBRARY tokyohook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + tokyo_io_get_api_version + tokyo_io_init + tokyo_io_get_opbtns + tokyo_io_get_gamebtns + tokyo_io_get_sensors + tokyo_io_led_init + tokyo_io_led_set_colors diff --git a/tokyohook/zinput.c b/tokyohook/zinput.c new file mode 100644 index 0000000..2152d6c --- /dev/null +++ b/tokyohook/zinput.c @@ -0,0 +1,118 @@ +#include +#include +#include + +#include +#include + +#include "tokyohook/config.h" +#include "tokyohook/zinput.h" + +#include "hook/table.h" + +#include "util/lib.h" +#include "util/dprintf.h" + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter); + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags); + +static unsigned long WINAPI hook_AddRef(IUnknown *self); +static unsigned long WINAPI hook_Release(IUnknown *self); + +static const IDirectInput8WVtbl api_vtbl = { + .EnumDevices = hook_EnumDevices, + .AddRef = (void *) hook_AddRef, + .Release = (void *) hook_Release, +}; + +static const IDirectInput8W api = { (void *) &api_vtbl }; + +static const struct hook_symbol zinput_hook_syms[] = { + { + .name = "DirectInput8Create", + .patch = hook_DirectInput8Create, + .link = NULL, + } +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg) +{ + wchar_t *module_path; + wchar_t *file_name; + + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + module_path = module_file_name(NULL); + + if (module_path != NULL) { + file_name = PathFindFileNameW(module_path); + + free(module_path); + module_path = NULL; + + _wcslwr(file_name); + + if (wcsstr(file_name, L"amdaemon") != NULL) { + // dprintf("Executable filename contains 'amdaemon', disabling zinput\n"); + return S_OK; + } + } + + hook_table_apply( + NULL, + "dinput8.dll", + zinput_hook_syms, + _countof(zinput_hook_syms)); + + return S_OK; +} + +HRESULT WINAPI hook_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPUNKNOWN punkOuter) +{ + dprintf("ZInput: Blocking built-in DirectInput support\n"); + *ppvOut = (void *) &api; + + return DI_OK; +} + +static HRESULT WINAPI hook_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + dprintf("ZInput: %s\n", __func__); + + return DI_OK; +} + +static unsigned long WINAPI hook_AddRef(IUnknown *self) +{ + return 1; +} + +static unsigned long WINAPI hook_Release(IUnknown *self) +{ + return 1; +} diff --git a/tokyohook/zinput.h b/tokyohook/zinput.h new file mode 100644 index 0000000..13a46cd --- /dev/null +++ b/tokyohook/zinput.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +struct zinput_config { + bool enable; +}; + +HRESULT zinput_hook_init(struct zinput_config *cfg); diff --git a/tokyoio/backend.h b/tokyoio/backend.h new file mode 100644 index 0000000..52fee61 --- /dev/null +++ b/tokyoio/backend.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "tokyoio/tokyoio.h" + +struct tokyo_io_backend { + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_sensors)(uint8_t *sense); +}; diff --git a/tokyoio/config.c b/tokyoio/config.c new file mode 100644 index 0000000..0ae2d26 --- /dev/null +++ b/tokyoio/config.c @@ -0,0 +1,54 @@ +#include + +#include +#include +#include + +#include "tokyoio/config.h" + + +void tokyo_kb_config_load( + struct tokyo_kb_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + /* Load game button keyboard bindings */ + cfg->vk_push_left_b = GetPrivateProfileIntW(L"keyboard", L"leftBlue", 'A', filename); + cfg->vk_push_center_y = GetPrivateProfileIntW(L"keyboard", L"centerYellow", 'S', filename); + cfg->vk_push_right_r = GetPrivateProfileIntW(L"keyboard", L"rightRed", 'D', filename); + + /* Load sensor keyboard bindings */ + cfg->vk_foot_l = GetPrivateProfileIntW(L"keyboard", L"footLeft", VK_LEFT, filename); + cfg->vk_foot_r = GetPrivateProfileIntW(L"keyboard", L"footRight", VK_RIGHT, filename); + cfg->vk_jump_1 = GetPrivateProfileIntW(L"keyboard", L"jump1", 'Z', filename); + cfg->vk_jump_2 = GetPrivateProfileIntW(L"keyboard", L"jump2", 'X', filename); + cfg->vk_jump_3 = GetPrivateProfileIntW(L"keyboard", L"jump3", 'C', filename); + cfg->vk_jump_4 = GetPrivateProfileIntW(L"keyboard", L"jump4", 'B', filename); + cfg->vk_jump_5 = GetPrivateProfileIntW(L"keyboard", L"jump5", 'N', filename); + cfg->vk_jump_6 = GetPrivateProfileIntW(L"keyboard", L"jump6", 'M', filename); + cfg->vk_jump_all = GetPrivateProfileIntW(L"keyboard", L"jumpAll", VK_SPACE, filename); +} + +void tokyo_io_config_load( + struct tokyo_io_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename); + + GetPrivateProfileStringW( + L"io4", + L"mode", + L"xinput", + cfg->mode, + _countof(cfg->mode), + filename); + + tokyo_kb_config_load(&cfg->kb, filename); +} diff --git a/tokyoio/config.h b/tokyoio/config.h new file mode 100644 index 0000000..839b2c3 --- /dev/null +++ b/tokyoio/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include + +struct tokyo_kb_config { + uint8_t vk_push_left_b; + uint8_t vk_push_center_y; + uint8_t vk_push_right_r; + uint8_t vk_foot_l; + uint8_t vk_foot_r; + uint8_t vk_jump_1; + uint8_t vk_jump_2; + uint8_t vk_jump_3; + uint8_t vk_jump_4; + uint8_t vk_jump_5; + uint8_t vk_jump_6; + uint8_t vk_jump_all; +}; + +struct tokyo_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + wchar_t mode[9]; + + struct tokyo_kb_config kb; +}; + +void tokyo_io_config_load( + struct tokyo_io_config *cfg, + const wchar_t *filename); diff --git a/tokyoio/dllmain.c b/tokyoio/dllmain.c new file mode 100644 index 0000000..76c81ac --- /dev/null +++ b/tokyoio/dllmain.c @@ -0,0 +1,135 @@ +#include + +#include +#include +#include + +#include "tokyoio/backend.h" +#include "tokyoio/config.h" +#include "tokyoio/kb.h" +#include "tokyoio/tokyoio.h" +#include "tokyoio/xi.h" + +#include "util/dprintf.h" +#include "util/str.h" + +static struct tokyo_io_config tokyo_io_cfg; +static const struct tokyo_io_backend *tokyo_io_backend; +static bool tokyo_io_coin; + +uint16_t tokyo_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT tokyo_io_init(void) +{ + HINSTANCE inst; + HRESULT hr; + + assert(tokyo_io_backend == NULL); + + inst = GetModuleHandleW(NULL); + + if (inst == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("GetModuleHandleW failed: %lx\n", hr); + + return hr; + } + + tokyo_io_config_load(&tokyo_io_cfg, L".\\segatools.ini"); + + if (wstr_ieq(tokyo_io_cfg.mode, L"keyboard")) { + hr = tokyo_kb_init(&tokyo_io_cfg.kb, &tokyo_io_backend); + } else if (wstr_ieq(tokyo_io_cfg.mode, L"xinput")) { + hr = tokyo_xi_init(&tokyo_io_backend); + } else { + hr = E_INVALIDARG; + dprintf("IDAC IO: Invalid IO mode \"%S\", use keyboard or xinput\n", + tokyo_io_cfg.mode); + } + + return hr; +} + +void tokyo_io_get_opbtns(uint8_t *opbtn_out) +{ + uint8_t opbtn; + + assert(tokyo_io_backend != NULL); + assert(opbtn_out != NULL); + + opbtn = 0; + + /* Common operator buttons, not backend-specific */ + + if (GetAsyncKeyState(tokyo_io_cfg.vk_test) & 0x8000) { + opbtn |= TOKYO_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(tokyo_io_cfg.vk_service) & 0x8000) { + opbtn |= TOKYO_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(tokyo_io_cfg.vk_coin) & 0x8000) { + if (!tokyo_io_coin) { + tokyo_io_coin = true; + opbtn |= TOKYO_IO_OPBTN_COIN; + } + } else { + tokyo_io_coin = false; + } + + *opbtn_out = opbtn; +} + + +void tokyo_io_get_gamebtns(uint8_t *gamebtn_out) +{ + assert(tokyo_io_backend != NULL); + assert(gamebtn_out != NULL); + + tokyo_io_backend->get_gamebtns(gamebtn_out); +} + +void tokyo_io_get_sensors(uint8_t *sense_out) +{ + assert(sense_out != NULL); + assert(tokyo_io_backend != NULL); + + tokyo_io_backend->get_sensors(sense_out); +} + +HRESULT tokyo_io_led_init(void) +{ + return S_OK; +} + +void tokyo_io_led_set_colors(uint8_t board, uint8_t *rgb) +{ +#if 0 + if (board == 0) { + dprintf("Board 0:\n"); + // Change GRB order to RGB order + for (int i = 0; i < 27; i++) { + dprintf("Tokyo LED: MONITOR LEFT: %02X %02X %02X\n", rgb[i * 3 + 1], rgb[i * 3], rgb[i * 3 + 2]); + } + + for (int i = 27; i < 54; i++) { + dprintf("Tokyo LED: MONITOR RIGHT: %d, %02X %02X %02X\n", i, rgb[i * 3 + 1], rgb[i * 3], rgb[i * 3 + 2]); + } + } else { + dprintf("Board 1:\n"); + dprintf("Tokyo LED: LEFT BLUE: %02X\n", rgb[0]); + dprintf("Tokyo LED: CENTER YELLOW: %02X\n", rgb[1]); + dprintf("Tokyo LED: RIGHT RED: %02X\n", rgb[2]); + dprintf("Tokyo LED: CONTROL LEFT: %02X %02X %02X\n", rgb[3], rgb[4], rgb[5]); + dprintf("Tokyo LED: CONTROL RIGHT: %02X %02X %02X\n", rgb[6], rgb[7], rgb[8]); + dprintf("Tokyo LED: FLOOR LEFT: %02X %02X %02X\n", rgb[9], rgb[10], rgb[11]); + dprintf("Tokyo LED: FLOOR RIGHT: %02X %02X %02X\n", rgb[12], rgb[13], rgb[14]); + } +#endif + + return; +} diff --git a/tokyoio/kb.c b/tokyoio/kb.c new file mode 100644 index 0000000..3b3c34d --- /dev/null +++ b/tokyoio/kb.c @@ -0,0 +1,135 @@ +#include + +#include +#include +#include + +#include "tokyoio/backend.h" +#include "tokyoio/config.h" +#include "tokyoio/kb.h" +#include "tokyoio/tokyoio.h" + +#include "util/dprintf.h" +#include "util/str.h" + +static HRESULT tokyo_kb_config_apply(const struct tokyo_kb_config *cfg); + +static void tokyo_kb_get_gamebtns(uint8_t *gamebtn_out); +static void tokyo_kb_get_sensors(uint8_t *sense_out); + +static const struct tokyo_io_backend tokyo_kb_backend = { + .get_gamebtns = tokyo_kb_get_gamebtns, + .get_sensors = tokyo_kb_get_sensors, +}; + +static struct tokyo_kb_config tokyo_kb_cfg; + +HRESULT tokyo_kb_init(const struct tokyo_kb_config *cfg, const struct tokyo_io_backend **backend) +{ + HRESULT hr; + + assert(cfg != NULL); + assert(backend != NULL); + + hr = tokyo_kb_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + dprintf("TokyoIO: Using keyboard input\n"); + *backend = &tokyo_kb_backend; + return S_OK; +} + +static HRESULT tokyo_kb_config_apply(const struct tokyo_kb_config *cfg) +{ + tokyo_kb_cfg = *cfg; + + return S_OK; +} + +static void tokyo_kb_get_gamebtns(uint8_t *gamebtn_out) +{ + uint8_t gamebtn; + + assert(gamebtn_out != NULL); + + gamebtn = 0; + + /* PUSH BUTTON inputs */ + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_left_b) & 0x8000) { + gamebtn |= TOKYO_IO_GAMEBTN_BLUE; + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_center_y) & 0x8000) { + gamebtn |= TOKYO_IO_GAMEBTN_YELLOW; + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_push_right_r) & 0x8000) { + gamebtn |= TOKYO_IO_GAMEBTN_RED; + } + + *gamebtn_out = gamebtn; +} + +static void tokyo_kb_get_sensors(uint8_t *sense_out) +{ + uint8_t sense; + + assert(sense_out != NULL); + + sense = 0; + + /* FOOT SENSOR inputs */ + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_foot_l) & 0x8000) { + sense |= TOKYO_IO_SENSE_FOOT_LEFT; + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_foot_r) & 0x8000) { + sense |= TOKYO_IO_SENSE_FOOT_RIGHT; + } + + /* JUMP SENSOR inputs */ + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_1) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_1); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_2) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_2); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_3) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_3); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_4) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_4); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_5) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_5); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_6) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT + TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_6); + } + + if (GetAsyncKeyState(tokyo_kb_cfg.vk_jump_all) & 0x8000) { + sense |= (TOKYO_IO_SENSE_FOOT_LEFT+ TOKYO_IO_SENSE_FOOT_RIGHT + + TOKYO_IO_SENSE_JUMP_1 + TOKYO_IO_SENSE_JUMP_2 + + TOKYO_IO_SENSE_JUMP_3 + TOKYO_IO_SENSE_JUMP_4 + + TOKYO_IO_SENSE_JUMP_5 + TOKYO_IO_SENSE_JUMP_6); + } + + *sense_out = sense; +} diff --git a/tokyoio/kb.h b/tokyoio/kb.h new file mode 100644 index 0000000..2a6691f --- /dev/null +++ b/tokyoio/kb.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "tokyoio/backend.h" +#include "tokyoio/config.h" + +HRESULT tokyo_kb_init( + const struct tokyo_kb_config *cfg, + const struct tokyo_io_backend **backend); diff --git a/tokyoio/meson.build b/tokyoio/meson.build new file mode 100644 index 0000000..aa4e198 --- /dev/null +++ b/tokyoio/meson.build @@ -0,0 +1,21 @@ +tokyoio_lib = static_library( + 'tokyoio', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + dependencies : [ + xinput_lib, + ], + sources : [ + 'backend.h', + 'config.c', + 'config.h', + 'dllmain.c', + 'tokyoio.h', + 'kb.c', + 'kb.h', + 'xi.c', + 'xi.h', + ], +) diff --git a/tokyoio/tokyoio.h b/tokyoio/tokyoio.h new file mode 100644 index 0000000..6edec63 --- /dev/null +++ b/tokyoio/tokyoio.h @@ -0,0 +1,139 @@ +#pragma once + +#include + +#include + +enum { + TOKYO_IO_OPBTN_TEST = 0x01, + TOKYO_IO_OPBTN_SERVICE = 0x02, + TOKYO_IO_OPBTN_COIN = 0x04, +}; + +enum { + TOKYO_IO_GAMEBTN_BLUE = 0x01, + TOKYO_IO_GAMEBTN_YELLOW = 0x02, + TOKYO_IO_GAMEBTN_RED = 0x04, +}; + +enum { + TOKYO_IO_SENSE_FOOT_LEFT = 0x01, + TOKYO_IO_SENSE_FOOT_RIGHT = 0x02, + TOKYO_IO_SENSE_JUMP_1 = 0x04, + TOKYO_IO_SENSE_JUMP_2 = 0x08, + TOKYO_IO_SENSE_JUMP_3 = 0x10, + TOKYO_IO_SENSE_JUMP_4 = 0x20, + TOKYO_IO_SENSE_JUMP_5 = 0x40, + TOKYO_IO_SENSE_JUMP_6 = 0x80, +}; + +enum { + /* These are the bitmasks to use when checking which + lights are triggered on incoming IO4 GPIO writes. */ + TOKYO_IO_LED_LEFT_BLUE = 1 << 31, + TOKYO_IO_LED_CENTER_YELLOW = 1 << 30, + TOKYO_IO_LED_RIGHT_RED = 1 << 29, + TOKYO_IO_LED_CONTROL_LEFT_R = 1 << 25, + TOKYO_IO_LED_CONTROL_LEFT_G = 1 << 24, + TOKYO_IO_LED_CONTROL_LEFT_B = 1 << 23, + TOKYO_IO_LED_CONTROL_RIGHT_R = 1 << 22, + TOKYO_IO_LED_CONTROL_RIGHT_G = 1 << 21, + TOKYO_IO_LED_CONTROL_RIGHT_B = 1 << 20, + TOKYO_IO_LED_FLOOR_LEFT_R = 1 << 19, + TOKYO_IO_LED_FLOOR_LEFT_G = 1 << 18, + TOKYO_IO_LED_FLOOR_LEFT_B = 1 << 17, + TOKYO_IO_LED_FLOOR_RIGHT_R = 1 << 16, + TOKYO_IO_LED_FLOOR_RIGHT_G = 1 << 15, + TOKYO_IO_LED_FLOOR_RIGHT_B = 1 << 14, +}; + +/* Get the version of the Mario & Sonic at the Olympic Games Tokyo 2020 Arcade + Edition IO API that this DLL supports. This function should return a + positive 16-bit integer, where the high byte is the major version and the + low byte is the minor version (as defined by the Semantic Versioning + standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t tokyo_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after tokyo_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT tokyo_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT tokyo_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + TOKYO_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void tokyo_io_get_opbtns(uint8_t *opbtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + TOKYO_IO_GAMEBTN enum above: this contains bit mask definitions for button + states returned in *gamebtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void tokyo_io_get_gamebtns(uint8_t *gamebtn); + +/* Get the state of the cabinet's gameplay buttons as of the last poll. See + TOKYO_IO_SENSE enum above: this contains bit mask definitions for button + states returned in *sense. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void tokyo_io_get_sensors(uint8_t *sense); + +/* Initialize LED emulation. This function will be called before any + other tokyo_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0100 */ + +HRESULT tokyo_io_led_init(void); + +/* Update the RGB LEDs. rgb is a pointer to an array of up to 54 * 3 = 162 bytes. + + Mario & Sonic at the Tokyo 2020 Olympics Arcade uses one board with 15 LEDs for + all buttons, control panel, and floor LEDs. Board 1 is just used for the + left and right monitor LEDs. + + Board 0 has 54 LEDs (GRB order): + [0]-[26]: left monitor LEDs + [27]-[53]: right monitor LEDs + + Board 1 has 15 LEDs (RGB order): + [0]: left blue LED + [1]: center yellow LED + [2]: right red LED + [3]-[5]: left control panel LEDs + [6]-[8]: right control panel LEDs + [9]-[11]: left floor LEDs + [12]-[14]: right floor LEDs + + Each rgb value is comprised of 3 bytes in G,R,B order for board 0 and R,G,B + order for board 1. The tricky part is that the board 0 is called from app and + the board 1 is called from amdaemon. So the library must be able to handle both + calls, using shared memory f.e. This is up to the developer to decide how to + handle this, recommended way is to use the amdaemon process as the main one + and the app process as a sub one. + + Minimum API version: 0x0100 */ + +void tokyo_io_led_set_colors(uint8_t board, uint8_t *rgb); diff --git a/tokyoio/xi.c b/tokyoio/xi.c new file mode 100644 index 0000000..b6b5749 --- /dev/null +++ b/tokyoio/xi.c @@ -0,0 +1,130 @@ +#include +#include +#include + +#include +#include +#include + +#include "tokyoio/backend.h" +#include "tokyoio/config.h" +#include "tokyoio/tokyoio.h" +#include "tokyoio/xi.h" + +#include "util/dprintf.h" +#include "util/str.h" + +static void tokyo_xi_get_gamebtns(uint8_t *gamebtn_out); +static void tokyo_xi_get_sensors(uint8_t *sense_out); + +static const struct tokyo_io_backend tokyo_xi_backend = { + .get_gamebtns = tokyo_xi_get_gamebtns, + .get_sensors = tokyo_xi_get_sensors, +}; + +HRESULT tokyo_xi_init(const struct tokyo_io_backend **backend) +{ + wchar_t dll_path[MAX_PATH]; + HMODULE xinput; + HRESULT hr; + UINT path_pos; + + assert(backend != NULL); + + dprintf("TokyoIO: IO4: Using XInput controller\n"); + *backend = &tokyo_xi_backend; + return S_OK; +} + +static void tokyo_xi_get_gamebtns(uint8_t *gamebtn_out) +{ + uint8_t gamebtn; + + assert(gamebtn_out != NULL); + + gamebtn = 0; + + XINPUT_STATE xi; + WORD xb; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + + /* PUSH BUTTON inputs */ + + if ((xb & XINPUT_GAMEPAD_X) || (xb & XINPUT_GAMEPAD_DPAD_LEFT)) { + gamebtn |= TOKYO_IO_GAMEBTN_BLUE; + } + + if (xb & XINPUT_GAMEPAD_Y || (xb & XINPUT_GAMEPAD_A)) { + gamebtn |= TOKYO_IO_GAMEBTN_YELLOW; + } + + if ((xb & XINPUT_GAMEPAD_B) || (xb & XINPUT_GAMEPAD_DPAD_RIGHT)) { + gamebtn |= TOKYO_IO_GAMEBTN_RED; + } + + *gamebtn_out = gamebtn; +} + +static void tokyo_xi_get_sensors(uint8_t *sense_out) +{ + uint8_t sense; + + XINPUT_STATE xi; + WORD xb; + BYTE xt_l; + BYTE xt_r; + + assert(sense_out != NULL); + + sense = 0; + + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + xb = xi.Gamepad.wButtons; + xt_l = xi.Gamepad.bLeftTrigger; + xt_r = xi.Gamepad.bRightTrigger; + + float xt_l_f = xt_l / 255.0f; + float xt_r_f = xt_r / 255.0f; + + // Normalize both triggers to 0..1 and find the max directly + float trigger = fmaxf(xt_l_f, xt_r_f); + + const int max_jump_levels = 6; + float jump_threshold = 1.0f / max_jump_levels; + + /* FOOT SENSOR inputs */ + + // Determine if both foot sensors should be set + bool left_active = xt_l_f > jump_threshold; + bool right_active = xt_r_f > jump_threshold; + + // Set foot sensors based on individual trigger activity + if (left_active) { + sense |= TOKYO_IO_SENSE_FOOT_LEFT; + } + if (right_active) { + sense |= TOKYO_IO_SENSE_FOOT_RIGHT; + } + + /* JUMP SENSOR inputs */ + + // If both triggers are active, set jump levels and both foot sensors + if (left_active && right_active) { + float trigger_avg = (xt_l_f + xt_r_f) / 2.0f; + + // Calculate the appropriate jump level + for (int i = 1; i <= max_jump_levels; ++i) { + if (trigger_avg >= i * jump_threshold) { + sense |= (TOKYO_IO_SENSE_JUMP_1 << (i - 1)); + } else { + break; + } + } + } + + *sense_out = sense; +} diff --git a/tokyoio/xi.h b/tokyoio/xi.h new file mode 100644 index 0000000..368fff3 --- /dev/null +++ b/tokyoio/xi.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#include "tokyoio/backend.h" +#include "tokyoio/config.h" + +HRESULT tokyo_xi_init(const struct tokyo_io_backend **backend); From 006115818830437e340907c03bb15cc58b005a1a Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 20 Aug 2024 13:40:47 +0200 Subject: [PATCH 125/204] printer: changed filename for holo cards --- hooklib/printer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hooklib/printer.c b/hooklib/printer.c index 7a36eba..7ce0ee0 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -2446,7 +2446,7 @@ int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) wchar_t dumpPath[MAX_PATH]; swprintf_s( dumpPath, MAX_PATH, - L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_writeLaminate.bmp", + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_laminate.bmp", printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); // WriteDataToBitmapFile(dumpPath, 8, WIDTH, HEIGHT, data, HOLO_SIZE, NULL, 0, rotate180); @@ -2465,7 +2465,7 @@ int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { wchar_t dumpPath[MAX_PATH]; swprintf_s( dumpPath, MAX_PATH, - L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_writeHolo.bmp", + L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d_holo.bmp", printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); WriteDataToBitmapFile(dumpPath, 8, WIDTH, HEIGHT, data, HOLO_SIZE, NULL, 0, rotate180); From ac0f9f0587acc342194afb4bd1194335f99cc339 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Wed, 21 Aug 2024 15:13:09 +0200 Subject: [PATCH 126/204] aime firmware fix, mu3 keybinding fix --- board/sg-nfc-cmd.h | 30 ++++++++++++++++-------------- board/sg-nfc.c | 26 +++++++++++++++++++++++++- dist/mu3/segatools.ini | 2 +- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index c44586a..604783b 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -5,19 +5,21 @@ #pragma pack(push, 1) enum { - SG_NFC_CMD_GET_FW_VERSION = 0x30, - SG_NFC_CMD_GET_HW_VERSION = 0x32, - SG_NFC_CMD_RADIO_ON = 0x40, - SG_NFC_CMD_RADIO_OFF = 0x41, - SG_NFC_CMD_POLL = 0x42, - SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, - SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, - SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, - SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ - SG_NFC_CMD_SEND_HEX_DATA = 0x61, - SG_NFC_CMD_RESET = 0x62, - SG_NFC_CMD_FELICA_ENCAP = 0x71, + SG_NFC_CMD_GET_FW_VERSION = 0x30, + SG_NFC_CMD_GET_HW_VERSION = 0x32, + SG_NFC_CMD_RADIO_ON = 0x40, + SG_NFC_CMD_RADIO_OFF = 0x41, + SG_NFC_CMD_POLL = 0x42, + SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, + SG_NFC_CMD_MIFARE_SET_KEY_A = 0x50, + SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51, + SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, + SG_NFC_CMD_MIFARE_SET_KEY_B = 0x54, + SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55, + SG_NFC_CMD_TO_UPDATE_MODE = 0x60, + SG_NFC_CMD_SEND_HEX_DATA = 0x61, + SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, }; struct sg_nfc_res_get_fw_version { @@ -32,7 +34,7 @@ struct sg_nfc_res_get_hw_version { struct sg_nfc_req_mifare_set_key { struct sg_req_header req; - uint8_t key_a[6]; + uint8_t key[6]; }; struct sg_nfc_req_mifare_50 { diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 1f023be..19a6ad6 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -60,6 +60,11 @@ static HRESULT sg_nfc_cmd_felica_encap( const struct sg_nfc_req_felica_encap *req, struct sg_nfc_res_felica_encap *res); +static HRESULT sg_nfc_cmd_send_hex_data( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + static HRESULT sg_nfc_cmd_dummy( struct sg_nfc *nfc, const struct sg_req_header *req, @@ -185,12 +190,15 @@ static HRESULT sg_nfc_dispatch( &res->felica_encap); case SG_NFC_CMD_MIFARE_AUTHENTICATE: + case SG_NFC_CMD_SEND_HEX_DATA: + return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); + case SG_NFC_CMD_MIFARE_SELECT_TAG: case SG_NFC_CMD_MIFARE_SET_KEY_AIME: case SG_NFC_CMD_MIFARE_SET_KEY_BANA: case SG_NFC_CMD_RADIO_ON: case SG_NFC_CMD_RADIO_OFF: - case SG_NFC_CMD_SEND_HEX_DATA: // TODO: implement? + case SG_NFC_CMD_TO_UPDATE_MODE: return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); default: @@ -442,6 +450,22 @@ static HRESULT sg_nfc_cmd_felica_encap( return S_OK; } +static HRESULT sg_nfc_cmd_send_hex_data( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + sg_res_init(res, req, 0); + + /* Firmware checksum length? */ + if (req->payload_len == 0x2b) { + /* The firmware is identical flag? */ + res->status = 0x20; + } + + return S_OK; +} + static HRESULT sg_nfc_cmd_dummy( struct sg_nfc *nfc, const struct sg_req_header *req, diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 182e1d8..f24e510 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -190,7 +190,7 @@ leftSide=0x01 ; Mouse Left rightSide=0x02 ; Mouse Right right1=0x4A ; J -right1=0x4B ; K +right2=0x4B ; K right3=0x4C ; L leftMenu=0x55 ; U From 54cbbffae9dd1ea804b85794a9e0d80f202da5b9 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:30:22 +0200 Subject: [PATCH 127/204] add almost full vfd implementation --- board/config.c | 2 + board/meson.build | 3 + board/vfd-cmd.h | 123 ++++++++++++ board/vfd-frame.c | 88 +++++++++ board/vfd-frame.h | 20 ++ board/vfd.c | 395 +++++++++++++++++++++++++++++++------ board/vfd.h | 5 +- chusanhook/dllmain.c | 2 +- cmhook/dllmain.c | 2 +- dist/chusan/segatools.ini | 5 +- dist/cm/segatools.ini | 5 +- dist/fgo/segatools.ini | 5 +- dist/mai2/segatools.ini | 5 +- dist/mercury/segatools.ini | 5 +- dist/mu3/segatools.ini | 5 +- dist/swdc/segatools.ini | 5 +- fgohook/dllmain.c | 2 +- mai2hook/dllmain.c | 2 +- mercuryhook/dllmain.c | 2 +- mu3hook/dllmain.c | 2 +- swdchook/dllmain.c | 2 +- 21 files changed, 607 insertions(+), 78 deletions(-) create mode 100644 board/vfd-cmd.h create mode 100644 board/vfd-frame.c create mode 100644 board/vfd-frame.h diff --git a/board/config.c b/board/config.c index 9b69b42..b94915f 100644 --- a/board/config.c +++ b/board/config.c @@ -90,4 +90,6 @@ void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename); + cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 1, filename); + cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename); } diff --git a/board/meson.build b/board/meson.build index 0bf4fbc..b26851f 100644 --- a/board/meson.build +++ b/board/meson.build @@ -47,5 +47,8 @@ board_lib = static_library( 'slider-frame.h', 'vfd.c', 'vfd.h', + 'vfd-cmd.h', + 'vfd-frame.c', + 'vfd-frame.h', ], ) diff --git a/board/vfd-cmd.h b/board/vfd-cmd.h new file mode 100644 index 0000000..28bcb16 --- /dev/null +++ b/board/vfd-cmd.h @@ -0,0 +1,123 @@ +#pragma once + +#include "board/vfd-frame.h" + +enum { + VFD_CMD_GET_VERSION = 0x5B, + VFD_CMD_RESET = 0x0B, + VFD_CMD_CLEAR_SCREEN = 0x0C, + VFD_CMD_SET_BRIGHTNESS = 0x20, + VFD_CMD_SET_SCREEN_ON = 0x21, + VFD_CMD_SET_H_SCROLL = 0x22, + VFD_CMD_DRAW_IMAGE = 0x2E, + VFD_CMD_SET_CURSOR = 0x30, + VFD_CMD_SET_ENCODING = 0x32, + VFD_CMD_SET_TEXT_WND = 0x40, + VFD_CMD_SET_TEXT_SPEED = 0x41, + VFD_CMD_WRITE_TEXT = 0x50, + VFD_CMD_ENABLE_SCROLL = 0x51, + VFD_CMD_DISABLE_SCROLL = 0x52, + VFD_CMD_ROTATE = 0x5D, + VFD_CMD_CREATE_CHAR = 0xA3, + VFD_CMD_CREATE_CHAR2 = 0xA4, +}; + +enum { + VFD_ENC_GB2312 = 0, + VFD_ENC_BIG5 = 1, + VFD_ENC_SHIFT_JIS = 2, + VFD_ENC_KSC5601 = 3, + VFD_ENC_MAX = 3, +}; + +struct vfd_req_hdr { + uint8_t sync; + uint8_t cmd; +}; + +struct vfd_req_any { + struct vfd_req_hdr hdr; + uint8_t payload[2054]; +}; + +struct vfd_req_board_info { + struct vfd_req_hdr hdr; + uint8_t unk1; +}; + +struct vfd_resp_board_info { // \x0201.20\x03 + uint8_t unk1; + char version[5]; + uint8_t unk2; +}; + +struct vfd_req_reset { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_cls { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_brightness { + struct vfd_req_hdr hdr; + uint8_t brightness; +}; + +struct vfd_req_power { + struct vfd_req_hdr hdr; + uint8_t power_state; +}; + +struct vfd_req_hscroll { + struct vfd_req_hdr hdr; + uint8_t x_pos; +}; + +struct vfd_req_draw { + struct vfd_req_hdr hdr; + uint16_t x0; + uint8_t y0; + uint16_t x1; + uint8_t y1; + uint8_t image[2048]; +}; + +struct vfd_req_cursor { + struct vfd_req_hdr hdr; + uint16_t x; + uint8_t y; +}; + +struct vfd_req_encoding { + struct vfd_req_hdr hdr; + uint8_t encoding; +}; + +struct vfd_req_wnd { + struct vfd_req_hdr hdr; + uint16_t x0; + uint8_t y0; + uint16_t x1; + uint8_t y1; +}; + +struct vfd_req_speed { + struct vfd_req_hdr hdr; + uint8_t encoding; +}; + +struct vfd_req_scroll { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_rotate { + struct vfd_req_hdr hdr; + uint8_t unk1; +}; + +struct vfd_req_create_char { + struct vfd_req_hdr hdr; + uint8_t type; + uint8_t pixels[32]; +}; diff --git a/board/vfd-frame.c b/board/vfd-frame.c new file mode 100644 index 0000000..05fe302 --- /dev/null +++ b/board/vfd-frame.c @@ -0,0 +1,88 @@ +#include + +#include +#include +#include +#include + +#define SUPER_VERBOSE 1 + +#include "board/vfd-frame.h" + +#include "hook/iobuf.h" + +#include "util/dprintf.h" + +static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte); + +/* Frame structure: + + REQUEST: + [0] Sync byte (0x1A or 0x1B) + [1] Packet ID + [2...n-1] Data/payload + + --- OR --- + + if no sync byte is given, plain static text in the currently configured encoding is expected. + + RESPONSE: + This thing never responds, unless it's VFD_CMD_GET_VERSION + */ + +bool vfd_frame_sync(struct const_iobuf *src) { + return src->bytes[src->pos] == VFD_SYNC_BYTE || src->bytes[src->pos] == VFD_SYNC_BYTE2; +} + +HRESULT vfd_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes) { + const uint8_t *src; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + +#if SUPER_VERBOSE + dprintf("VFD: RX Buffer:\n"); +#endif + + for (i = 1; i < nbytes; i++) { + byte = src[i]; +#if SUPER_VERBOSE + dprintf("%02x ", byte); +#endif + + hr = vfd_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } +#if SUPER_VERBOSE + dprintf("\n"); +#endif + + return hr; +} + +static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte) { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + + return S_OK; +} diff --git a/board/vfd-frame.h b/board/vfd-frame.h new file mode 100644 index 0000000..7055f5b --- /dev/null +++ b/board/vfd-frame.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + VFD_SYNC_BYTE = 0x1B, + VFD_SYNC_BYTE2 = 0x1A, +}; + +bool vfd_frame_sync(struct const_iobuf *src); + +HRESULT vfd_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/vfd.c b/board/vfd.c index b216706..1b6c626 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -2,17 +2,16 @@ directly by amdaemon, and it has something to do with displaying the status of electronic payments. - Part number in schematics is "VFD GP1232A02A FUTABA". - - Little else about this board is known. Black-holing the RS232 comms that it - receives seems to be sufficient for the time being. */ + Part number in schematics is "VFD GP1232A02A FUTABA". */ #include #include #include +#include "board/config.h" #include "board/vfd.h" +#include "board/vfd-cmd.h" #include "hook/iohook.h" @@ -21,33 +20,96 @@ #include "util/dprintf.h" #include "util/dump.h" +#define SUPER_VERBOSE 0 + static HRESULT vfd_handle_irp(struct irp *irp); static struct uart vfd_uart; -static uint8_t vfd_written[512]; -static uint8_t vfd_readable[512]; -UINT codepage; +static uint8_t vfd_written[4096]; +static uint8_t vfd_readable[4096]; -HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no) +static int encoding = VFD_ENC_SHIFT_JIS; + +HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); + +static bool utf_enabled; + +HRESULT vfd_hook_init(struct vfd_config *cfg) { - assert(cfg != NULL); - - if (!cfg->enable) { + if (!cfg->enable){ return S_FALSE; } - uart_init(&vfd_uart, port_no); + utf_enabled = cfg->utf_conversion; + + dprintf("VFD: enabling (port=%d)\n", cfg->port); + uart_init(&vfd_uart, cfg->port); vfd_uart.written.bytes = vfd_written; vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.readable.bytes = vfd_readable; vfd_uart.readable.nbytes = sizeof(vfd_readable); - codepage = GetACP(); - dprintf("VFD: hook enabled.\n"); - return iohook_push_handler(vfd_handle_irp); } + +const char* get_encoding_name(int b){ + switch (b){ + case 0: return "gb2312"; + case 1: return "big5"; + case 2: return "shift-jis"; + case 3: return "ks_c_5601-1987"; + default: return "unknown"; + } +} + +void print_vfd_text(const char* str, int len){ + + if (utf_enabled){ + + wchar_t encoded[1024]; + memset(encoded, 0, 1024 * sizeof(wchar_t)); + + int codepage = 0; + if (encoding == VFD_ENC_GB2312){ + codepage = 936; + } else if (encoding == VFD_ENC_BIG5){ + codepage = 950; + } else if (encoding == VFD_ENC_SHIFT_JIS){ + codepage = 932; + } else if (encoding == VFD_ENC_KSC5601) { + codepage = 949; + } + + if (!MultiByteToWideChar(codepage, MB_USEGLYPHCHARS, str, len, encoded, 1024)){ + dprintf("VFD: Text conversion failed: %ld", GetLastError()); + return; + } + + dprintf("VFD: Text: %ls\n", encoded); + } else { + + dprintf("VFD: Text: %s\n", str); + + } +} + static HRESULT vfd_handle_irp(struct irp *irp) { HRESULT hr; @@ -58,67 +120,274 @@ static HRESULT vfd_handle_irp(struct irp *irp) return iohook_invoke_next(irp); } + if (irp->op == IRP_OP_OPEN){ + dprintf("VFD: Open\n"); + } else if (irp->op == IRP_OP_CLOSE){ + dprintf("VFD: Close\n"); + } + hr = uart_handle_irp(&vfd_uart, irp); if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } - uint8_t cmd = 0; - uint8_t str_1[512]; - uint8_t str_2[512]; - uint8_t str_1_len = 0; - uint8_t str_2_len = 0; - for (size_t i = 0; i < vfd_uart.written.pos; i++) { - if (vfd_uart.written.bytes[i] == 0x1B) { - i++; - cmd = vfd_uart.written.bytes[i]; - if (cmd == 0x30) { - i += 3; - } - else if (cmd == 0x50) { - i++; - } - continue; - } - if (cmd == 0x30) { - str_1[str_1_len++] = vfd_uart.written.bytes[i]; - } - else if (cmd == 0x50) { - str_2[str_2_len++] = vfd_uart.written.bytes[i]; - } - } +#if SUPER_VERBOSE + dprintf("VFD TX:\n"); + dump_iobuf(&vfd_uart.written); +#endif - if (str_1_len) { - str_1[str_1_len++] = '\0'; - if (codepage != 932) { - WCHAR buffer[512]; - MultiByteToWideChar(932, 0, (LPCSTR)str_1, str_1_len, buffer, str_1_len); - char str_recode[str_1_len * 3]; - WideCharToMultiByte(codepage, 0, buffer, str_1_len, str_recode, str_1_len * 3, NULL, NULL); - dprintf("VFD: %s\n", str_recode); - } - else { - dprintf("VFD: %s\n", str_1); - } - } + struct const_iobuf reader; + iobuf_flip(&reader, &vfd_uart.written); - if (str_2_len) { - str_2[str_2_len++] = '\0'; - if (codepage != 932) { - WCHAR buffer[512]; - MultiByteToWideChar(932, 0, (LPCSTR)str_2, str_2_len, buffer, str_2_len); - char str_recode[str_2_len * 3]; - WideCharToMultiByte(codepage, 0, buffer, str_2_len, str_recode, str_2_len * 3, NULL, NULL); - dprintf("VFD: %s\n", str_recode); + struct iobuf* writer = &vfd_uart.readable; + for (; reader.pos < reader.nbytes ; ){ + + if (vfd_frame_sync(&reader)) { + + reader.pos++; // get the sync byte out of the way + + uint8_t cmd; + iobuf_read_8(&reader, &cmd); + + if (cmd == VFD_CMD_GET_VERSION) { + hr = vfd_handle_get_version(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_RESET) { + hr = vfd_handle_reset(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CLEAR_SCREEN) { + hr = vfd_handle_clear_screen(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_BRIGHTNESS) { + hr = vfd_handle_set_brightness(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_SCREEN_ON) { + hr = vfd_handle_set_screen_on(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_H_SCROLL) { + hr = vfd_handle_set_h_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_DRAW_IMAGE) { + hr = vfd_handle_draw_image(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_CURSOR) { + hr = vfd_handle_set_cursor(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_ENCODING) { + hr = vfd_handle_set_encoding(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_TEXT_WND) { + hr = vfd_handle_set_text_wnd(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_TEXT_SPEED) { + hr = vfd_handle_set_text_speed(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_WRITE_TEXT) { + hr = vfd_handle_write_text(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_ENABLE_SCROLL) { + hr = vfd_handle_enable_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_DISABLE_SCROLL) { + hr = vfd_handle_disable_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_ROTATE) { + hr = vfd_handle_rotate(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CREATE_CHAR) { + hr = vfd_handle_create_char(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CREATE_CHAR2) { + hr = vfd_handle_create_char2(&reader, writer, &vfd_uart); + } else { + dprintf("VFD: Unknown command 0x%x\n", cmd); + dump_const_iobuf(&reader); + hr = S_FALSE; + } } else { - dprintf("VFD: %s\n", str_2); + + // if no sync byte is sent, we are just getting plain text... + + if (reader.pos < reader.nbytes){ + int len = 0; + + // read chars until we hit a new sync byte or the data ends + while (reader.pos + len + 1 < reader.nbytes && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE2){ + len++; + } + + char* str = malloc(len); + memset(str, 0, len); + iobuf_read(&reader, str, len); + print_vfd_text(str, len); + free(str); + + reader.pos += len; + } + } + + if (!SUCCEEDED(hr)){ + return hr; + } + } - // dprintf("VFD TX:\n"); - // dump_iobuf(&vfd_uart.written); vfd_uart.written.pos = 0; return hr; } + +HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Get Version\n"); + + struct vfd_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.unk1 = 2; + strcpy(resp.version, "01.20"); + resp.unk2 = 1; + + return vfd_frame_encode(writer, &resp, sizeof(resp)); +} +HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Reset\n"); + + encoding = VFD_ENC_SHIFT_JIS; + + return S_FALSE; +} +HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Clear Screen\n"); + + return S_FALSE; +} +HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + if (b > 4){ + dprintf("VFD: Brightness, invalid argument\n"); + return E_FAIL; + } + + dprintf("VFD: Brightness, %d\n", b); + + return S_FALSE; +} +HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + if (b > 1){ + dprintf("VFD: Screen Power, invalid argument\n"); + return E_FAIL; + } + + dprintf("VFD: Screen Power, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t x; + iobuf_read_8(reader, &x); + + dprintf("VFD: Horizontal Scroll, X=%d\n", x); + return S_FALSE; +} +HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + int w, h; + uint16_t x0, x1; + uint8_t y0, y1; + uint8_t image[2048]; + + iobuf_read_be16(reader, &x0); + iobuf_read_8(reader, &y0); + iobuf_read_be16(reader, &x1); + iobuf_read_8(reader, &y1); + w = x1 - x0; + h = y1 - y0; + iobuf_read(reader, image, w*h); + + dprintf("VFD: Draw image, %dx%d\n", w, h); + return S_FALSE; +} + +HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint16_t x; + uint8_t y; + + iobuf_read_be16(reader, &x); + iobuf_read_8(reader, &y); + + dprintf("VFD: Set Cursor, x=%d,y=%d\n", x, y); + + return S_FALSE; +} + +HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Set Encoding, %d (%s)\n", b, get_encoding_name(b)); + + if (b < 0 || b > VFD_ENC_MAX){ + dprintf("Invalid encoding specified\n"); + return E_FAIL; + } + + encoding = b; + + return S_FALSE; +} +HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint16_t x0, x1; + uint8_t y0, y1; + + iobuf_read_be16(reader, &x0); + iobuf_read_8(reader, &y0); + iobuf_read_be16(reader, &x1); + iobuf_read_8(reader, &y1); + + dprintf("VFD: Set Text Window, p0:%d,%d, p1:%d,%d\n", x0, y0, x1, y1); + return S_FALSE; +} +HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Set Text Speed, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t len; + iobuf_read_8(reader, &len); + + char* str = malloc(len); + iobuf_read(reader, str, len); + + print_vfd_text(str, len); + free(str); + + return S_FALSE; +} +HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Enable Scrolling\n"); + return S_FALSE; +} +HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Disable Scrolling\n"); + return S_FALSE; +} +HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Rotate, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + char buf[32]; + + iobuf_read(reader, buf, 32); + + dprintf("VFD: Create character, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b, b2; + iobuf_read_8(reader, &b); + iobuf_read_8(reader, &b2); + char buf[16]; + + iobuf_read(reader, buf, 16); + + dprintf("VFD: Create character, %d, %d\n", b, b2); + return S_FALSE; +} diff --git a/board/vfd.h b/board/vfd.h index e37386f..42c2e04 100644 --- a/board/vfd.h +++ b/board/vfd.h @@ -4,7 +4,10 @@ struct vfd_config { bool enable; + int port; + bool utf_conversion; }; -HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no); +HRESULT vfd_hook_init(struct vfd_config *cfg); + diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 85c6228..43509ef 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -146,7 +146,7 @@ static DWORD CALLBACK chusan_pre_startup(void) unsigned int first_port = is_cvt ? 2 : 20; if (!is_cvt) { - hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2); + hr = vfd_hook_init(&chusan_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index ac54a9d..4123443 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -84,7 +84,7 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = vfd_hook_init(&cm_hook_cfg.vfd, 2); + hr = vfd_hook_init(&cm_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 556df02..1ca8691 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -25,10 +25,13 @@ aimePath=DEVICE\aime.txt ;highBaud=1 [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=2 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 2cd86b0..188696d 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=2 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 945f9a1..8ea9766 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=1 + [deckReader] ; 837-15345 RFID deck reader emulation setting. enable=1 diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 71dbf15..969489d 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=2 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 891c4d8..6916d1e 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=2 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index f24e510..af9558b 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=2 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 6fdee71..a05f4c5 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -23,10 +23,13 @@ enable=1 aimePath=DEVICE\aime.txt [vfd] -; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; Enable VFD emulation. Disable to use a real VFD ; GP1232A02A FUTABA assembly. enable=1 +; COM port where the VFD is connected to. +portNo=4 + ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index dfbbdb5..9b8613d 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -84,7 +84,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = vfd_hook_init(&fgo_hook_cfg.vfd, 1); + hr = vfd_hook_init(&fgo_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 02f32a4..3b4f6a7 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -79,7 +79,7 @@ static DWORD CALLBACK mai2_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mai2_hook_cfg.vfd, 2); + hr = vfd_hook_init(&mai2_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index ea30458..2810574 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -77,7 +77,7 @@ static DWORD CALLBACK mercury_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mercury_hook_cfg.vfd, 2); + hr = vfd_hook_init(&mercury_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index bab6c0b..10e1226 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -93,7 +93,7 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mu3_hook_cfg.vfd, 2); + hr = vfd_hook_init(&mu3_hook_cfg.vfd); if (FAILED(hr)) { goto fail; diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index 94d68ea..d40cc52 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -79,7 +79,7 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } - hr = vfd_hook_init(&swdc_hook_cfg.vfd, 4); + hr = vfd_hook_init(&swdc_hook_cfg.vfd); if (FAILED(hr)) { return hr; From e6794807a61032be51d8456ebefa7ee1ec0d2c06 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:20:05 +0200 Subject: [PATCH 128/204] add default port fallback for vfd --- board/vfd.c | 11 ++++++++--- board/vfd.h | 2 +- chusanhook/dllmain.c | 2 +- cmhook/dllmain.c | 2 +- fgohook/dllmain.c | 2 +- mai2hook/dllmain.c | 2 +- mercuryhook/dllmain.c | 2 +- mu3hook/dllmain.c | 2 +- swdchook/dllmain.c | 2 +- 9 files changed, 16 insertions(+), 11 deletions(-) diff --git a/board/vfd.c b/board/vfd.c index 1b6c626..abc487a 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -50,7 +50,7 @@ HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer static bool utf_enabled; -HRESULT vfd_hook_init(struct vfd_config *cfg) +HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port) { if (!cfg->enable){ return S_FALSE; @@ -58,8 +58,13 @@ HRESULT vfd_hook_init(struct vfd_config *cfg) utf_enabled = cfg->utf_conversion; - dprintf("VFD: enabling (port=%d)\n", cfg->port); - uart_init(&vfd_uart, cfg->port); + int port = cfg->port; + if (port == 0){ + port = default_port; + } + + dprintf("VFD: enabling (port=%d)\n", port); + uart_init(&vfd_uart, port); vfd_uart.written.bytes = vfd_written; vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.readable.bytes = vfd_readable; diff --git a/board/vfd.h b/board/vfd.h index 42c2e04..3e67061 100644 --- a/board/vfd.h +++ b/board/vfd.h @@ -9,5 +9,5 @@ struct vfd_config { }; -HRESULT vfd_hook_init(struct vfd_config *cfg); +HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port); diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 43509ef..85c6228 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -146,7 +146,7 @@ static DWORD CALLBACK chusan_pre_startup(void) unsigned int first_port = is_cvt ? 2 : 20; if (!is_cvt) { - hr = vfd_hook_init(&chusan_hook_cfg.vfd); + hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 4123443..ac54a9d 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -84,7 +84,7 @@ static DWORD CALLBACK cm_pre_startup(void) goto fail; } - hr = vfd_hook_init(&cm_hook_cfg.vfd); + hr = vfd_hook_init(&cm_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 9b8613d..dfbbdb5 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -84,7 +84,7 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = vfd_hook_init(&fgo_hook_cfg.vfd); + hr = vfd_hook_init(&fgo_hook_cfg.vfd, 1); if (FAILED(hr)) { goto fail; diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 3b4f6a7..02f32a4 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -79,7 +79,7 @@ static DWORD CALLBACK mai2_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mai2_hook_cfg.vfd); + hr = vfd_hook_init(&mai2_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index 2810574..ea30458 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -77,7 +77,7 @@ static DWORD CALLBACK mercury_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mercury_hook_cfg.vfd); + hr = vfd_hook_init(&mercury_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index 10e1226..bab6c0b 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -93,7 +93,7 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } - hr = vfd_hook_init(&mu3_hook_cfg.vfd); + hr = vfd_hook_init(&mu3_hook_cfg.vfd, 2); if (FAILED(hr)) { goto fail; diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index d40cc52..94d68ea 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -79,7 +79,7 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } - hr = vfd_hook_init(&swdc_hook_cfg.vfd); + hr = vfd_hook_init(&swdc_hook_cfg.vfd, 4); if (FAILED(hr)) { return hr; From cc5b87b5597f1218ee6fefd2631d555207148769 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:23:59 +0200 Subject: [PATCH 129/204] add vfd settings to docs --- doc/config/common.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/config/common.md b/doc/config/common.md index ad9e348..e778a8a 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -92,9 +92,21 @@ Controls emulation of the VFD GP1232A02A FUTABA assembly. Default: `1` -Enable VFD emulation (currently just stubbed). Disable to use a real VFD +Enable VFD emulation. Disable to use a real VFD GP1232A02A FUTABA assembly (COM port number varies by game). +### `portNo` + +Default: (game specific) + +Sets the COM port to use for the VFD. + +### `utfConversion` + +Default: `0` + +Converts the strings from the VFD from their respective encoding to UTF, so console output will display as it should on non-Japanese locales. + ## `[amvideo]` Controls the `amvideo.dll` stub built into Segatools. This is a DLL that is From 824bc9abdaf9dac4a44bd745870c143412ea8c0b Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:24:47 +0200 Subject: [PATCH 130/204] default vfd port number to zero (use game-specific port) --- board/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/config.c b/board/config.c index b94915f..c1cd713 100644 --- a/board/config.c +++ b/board/config.c @@ -90,6 +90,6 @@ void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename); - cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 1, filename); + cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename); cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename); } From 26624f25b1619c9f9ecacdc7447469afdca4b75c Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:14:13 +0200 Subject: [PATCH 131/204] hide default vfd ports from configs --- dist/chusan/segatools.ini | 3 --- dist/cm/segatools.ini | 3 --- dist/fgo/segatools.ini | 3 --- dist/mai2/segatools.ini | 3 --- dist/mercury/segatools.ini | 3 --- dist/mu3/segatools.ini | 3 --- dist/swdc/segatools.ini | 3 --- 7 files changed, 21 deletions(-) diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 1ca8691..ee3af18 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -29,9 +29,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=2 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index 188696d..cd42cd6 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=2 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 8ea9766..790de88 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=1 - [deckReader] ; 837-15345 RFID deck reader emulation setting. enable=1 diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 969489d..c253334 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=2 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 6916d1e..0755bac 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=2 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index af9558b..59ec0d2 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=2 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index a05f4c5..72ea69d 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -27,9 +27,6 @@ aimePath=DEVICE\aime.txt ; GP1232A02A FUTABA assembly. enable=1 -; COM port where the VFD is connected to. -portNo=4 - ; ----------------------------------------------------------------------------- ; Network settings ; ----------------------------------------------------------------------------- From 84e9ed3c9a076e21abba64b0b1de74d32a05220c Mon Sep 17 00:00:00 2001 From: zaphkito Date: Sat, 31 Aug 2024 13:57:18 +0000 Subject: [PATCH 132/204] felica: fix rare card scan error (cucorrect PMm) from real aime card with official card reader --- iccard/felica.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iccard/felica.c b/iccard/felica.c index 09e3a77..b251d54 100644 --- a/iccard/felica.c +++ b/iccard/felica.c @@ -37,7 +37,7 @@ uint64_t felica_get_generic_PMm(void) Suica passes and other payment and transportation cards do not seem to be supported anymore. */ - return 0x01168B868FBECBFFULL; + return 0x00F1000000014300; } HRESULT felica_transact( From 068651b6fa9e70dac15d3472cbd26d04be9222d1 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:31:23 +0200 Subject: [PATCH 133/204] kemono: add support --- board/sg-nfc-cmd.h | 4 +- board/sg-nfc.c | 2 +- cmhook/dllmain.c | 2 +- dist/kemono/segatools.ini | 145 +++++++++++++++++ dist/kemono/start.bat | 12 ++ hooklib/printer.c | 317 +++++++++++++++++++++----------------- hooklib/printer.h | 1 + kemonohook/config.c | 105 +++++++++++++ kemonohook/config.h | 36 +++++ kemonohook/dllmain.c | 121 +++++++++++++++ kemonohook/hooks.c | 59 +++++++ kemonohook/hooks.h | 5 + kemonohook/jvs.c | 133 ++++++++++++++++ kemonohook/jvs.h | 7 + kemonohook/kemono-dll.c | 115 ++++++++++++++ kemonohook/kemono-dll.h | 27 ++++ kemonohook/kemonohook.def | 82 ++++++++++ kemonohook/meson.build | 34 ++++ kemonoio/config.c | 28 ++++ kemonoio/config.h | 25 +++ kemonoio/kemonoio.c | 104 +++++++++++++ kemonoio/kemonoio.h | 53 +++++++ kemonoio/meson.build | 13 ++ mai2hook/dllmain.c | 2 +- meson.build | 2 + mu3hook/dllmain.c | 2 +- platform/vfs.c | 12 +- unityhook/hook.c | 9 +- unityhook/hook.h | 4 +- 29 files changed, 1307 insertions(+), 154 deletions(-) create mode 100644 dist/kemono/segatools.ini create mode 100644 dist/kemono/start.bat create mode 100644 kemonohook/config.c create mode 100644 kemonohook/config.h create mode 100644 kemonohook/dllmain.c create mode 100644 kemonohook/hooks.c create mode 100644 kemonohook/hooks.h create mode 100644 kemonohook/jvs.c create mode 100644 kemonohook/jvs.h create mode 100644 kemonohook/kemono-dll.c create mode 100644 kemonohook/kemono-dll.h create mode 100644 kemonohook/kemonohook.def create mode 100644 kemonohook/meson.build create mode 100644 kemonoio/config.c create mode 100644 kemonoio/config.h create mode 100644 kemonoio/kemonoio.c create mode 100644 kemonoio/kemonoio.h create mode 100644 kemonoio/meson.build diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index 604783b..08923fd 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -11,10 +11,10 @@ enum { SG_NFC_CMD_RADIO_OFF = 0x41, SG_NFC_CMD_POLL = 0x42, SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, - SG_NFC_CMD_MIFARE_SET_KEY_A = 0x50, + SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50, SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51, SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_B = 0x54, + SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55, SG_NFC_CMD_TO_UPDATE_MODE = 0x60, SG_NFC_CMD_SEND_HEX_DATA = 0x61, diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 19a6ad6..49309f8 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -189,7 +189,7 @@ static HRESULT sg_nfc_dispatch( &req->felica_encap, &res->felica_encap); - case SG_NFC_CMD_MIFARE_AUTHENTICATE: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_A: case SG_NFC_CMD_SEND_HEX_DATA: return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index ac54a9d..7020f75 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -101,7 +101,7 @@ static DWORD CALLBACK cm_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `cmhook` initialization. */ - unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod); + unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod, NULL); /* Initialize debug helpers */ diff --git a/dist/kemono/segatools.ini b/dist/kemono/segatools.ini new file mode 100644 index 0000000..7bb293e --- /dev/null +++ b/dist/kemono/segatools.ini @@ -0,0 +1,145 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + +[dns] +; Insert the hostname or IP address of the server you wish to use here. +; Note that 127.0.0.1, localhost etc are specifically rejected. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about its LAN environment, so leaving this +; setting enabled is recommended. +enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + +[keychip] +; The /24 LAN subnet that the emulated keychip will tell the game to expect. +; If you disable netenv then you must set this to your LAN's IP subnet, and +; that subnet must start with 192.168. +subnet=192.168.172.0 + +[gpio] +; Emulated Nu DIP switch for Distribution Server setting. +; +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. +dipsw1=1 + +; Chassis Test button virtual-key code. Default is the 4 key. +test=0x34 +; Chassis Service button virtual-key code. Default is the 5 key. +service=0x35 + +; ----------------------------------------------------------------------------- +; Misc. hook settings +; ----------------------------------------------------------------------------- + +[unity] +; Enable Unity hook. This will allow you to run custom .NET code before the game +enable=1 + +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + +[printer] +; Sinfonia CHC-C300 printer emulation setting. +enable=1 +; Change the printer serial number here. +serial_no="5A-A123" +; Insert the path to the image output directory here. +printerOutPath="DEVICE\print" + +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15093] +; 837-15093-06 LED board emulation setting. +enable=1 + +; ----------------------------------------------------------------------------- +; Custom IO settings +; ----------------------------------------------------------------------------- + +[aimeio] +; To use a custom card reader IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +[kemonoio] +; To use a custom Kemono IO DLL enter its path here. +; Leave empty if you want to use Segatools built-in keyboard input. +path= + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io3] +; Test button virtual-key code. Default is the 1 key. +test=0x31 +; Service button virtual-key code. Default is the 2 key. +service=0x32 +; Keyboard button to increment coin counter. Default is the 3 key. +coin=0x33 + +; Analog lever (which is actually just four buttons, and not real analog input, default: Arrow keys) +left=0x25 +right=0x27 +up=0x26 +down=0x28 + +; Controller face buttons (default A, S, D) +red=0x41 +green=0x53 +blue=0x44 + +; Menu confirmation key (default RETURN) +start=0x0D \ No newline at end of file diff --git a/dist/kemono/start.bat b/dist/kemono/start.bat new file mode 100644 index 0000000..7f3bfa9 --- /dev/null +++ b/dist/kemono/start.bat @@ -0,0 +1,12 @@ +@echo off + +pushd %~dp0 + +start "AM Daemon" /min cmd /C timeout 10 ^& inject_x64 -d -k kemonohook_x64.dll ../amdaemon.exe -f -c ../config.json" +inject_x86 -d -k kemonohook_x86.dll Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes + +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/hooklib/printer.c b/hooklib/printer.c index 7ce0ee0..3ea4e70 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -11,6 +11,7 @@ #include "hooklib/printer.h" +#include #include #include #include @@ -60,44 +61,44 @@ static uint8_t STATUS = 0; /* C3XXFWDLusb API hooks */ -int fwdlusb_open(uint16_t *rResult); -void fwdlusb_close(); -int fwdlusb_listupPrinter(uint8_t *rIdArray); -int fwdlusb_listupPrinterSN(uint64_t *rSerialArray); -int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); -int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); -int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); -int fwdlusb_status(uint16_t *rResult); -int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); -int fwdlusb_resetPrinter(uint16_t *rResult); -int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); -int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); -int fwdlusb_MakeThread(uint16_t maxCount); -int fwdlusb_ReleaseThread(uint16_t *rResult); -int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); -int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); +__stdcall int fwdlusb_open(uint16_t *rResult); +__stdcall void fwdlusb_close(); +__stdcall int fwdlusb_listupPrinter(uint8_t *rIdArray); +__stdcall int fwdlusb_listupPrinterSN(uint64_t *rSerialArray); +__stdcall int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +__stdcall int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +__stdcall int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +__stdcall int fwdlusb_status(uint16_t *rResult); +__stdcall int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +__stdcall int fwdlusb_resetPrinter(uint16_t *rResult); +__stdcall int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); +__stdcall int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +__stdcall int fwdlusb_MakeThread(uint16_t maxCount); +__stdcall int fwdlusb_ReleaseThread(uint16_t *rResult); +__stdcall int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +__stdcall int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); /* C3XXusb API hooks */ -int chcusb_MakeThread(uint16_t maxCount); -int chcusb_open(uint16_t *rResult); -void chcusb_close(); -int chcusb_ReleaseThread(uint16_t *rResult); -int chcusb_listupPrinter(uint8_t *rIdArray); -int chcusb_listupPrinterSN(uint64_t *rSerialArray); -int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); -int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); -int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); -int chcusb_imageformat( +__stdcall int chcusb_MakeThread(uint16_t maxCount); +__stdcall int chcusb_open(uint16_t *rResult); +__stdcall void chcusb_close(); +__stdcall int chcusb_ReleaseThread(uint16_t *rResult); +__stdcall int chcusb_listupPrinter(uint8_t *rIdArray); +__stdcall int chcusb_listupPrinterSN(uint64_t *rSerialArray); +__stdcall int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +__stdcall int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +__stdcall int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +__stdcall int chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint16_t *rResult); -int chcusb_setmtf(int32_t *mtf); -int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); -int chcusb_setIcctable( +__thiscall int chcusb_setmtf(int32_t *mtf); +__stdcall int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); +__stdcall int chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, @@ -108,40 +109,42 @@ int chcusb_setIcctable( uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult); -int chcusb_copies(uint16_t copies, uint16_t *rResult); -int chcusb_status(uint16_t *rResult); -int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); -int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); -int chcusb_endpage(uint16_t *rResult); -int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); -int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); -int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); -int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); -int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); -int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); -int chcusb_blinkLED(uint16_t *rResult); -int chcusb_resetPrinter(uint16_t *rResult); -int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); -int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); -int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); -int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); -int chcusb_exitCard(uint16_t *rResult); -int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); -int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); -int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); -int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); -int chcusb_getErrorStatus(uint16_t *rBuffer); -int chcusb_setCutList(uint8_t *rData, uint16_t *rResult); -int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); -int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); -int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); -int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); -int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); -int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); -int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); +__stdcall int chcusb_copies(uint16_t copies, uint16_t *rResult); +__stdcall int chcusb_status(uint16_t *rResult); +__stdcall int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +__stdcall int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); +__stdcall int chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult); +__stdcall int chcusb_endpage(uint16_t *rResult); +__stdcall int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +__stdcall int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +__stdcall int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +__stdcall int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +__stdcall int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); +__stdcall int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); +__stdcall int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); +__stdcall int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +__stdcall int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +__stdcall int chcusb_blinkLED(uint16_t *rResult); +__stdcall int chcusb_resetPrinter(uint16_t *rResult); +__stdcall int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +__stdcall int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); +__stdcall int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); +__stdcall int chcusb_setPrintStandby_300(uint16_t *rResult); +__stdcall int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); +__stdcall int chcusb_exitCard(uint16_t *rResult); +__stdcall int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); +__stdcall int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); +__stdcall int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); +__stdcall int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); +__stdcall int chcusb_getErrorStatus(uint16_t *rBuffer); +__stdcall int chcusb_setCutList(uint8_t *rData, uint16_t *rResult); +__stdcall int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); +__stdcall int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +__stdcall int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +__stdcall int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); +__stdcall int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); +__stdcall int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); +__stdcall int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); /* PrintDLL API hooks */ @@ -491,7 +494,7 @@ static const struct hook_symbol C300usb_hooks[] = { }, { .name = "chcusb_startpage", .ordinal = 0x0011, - .patch = chcusb_startpage, + .patch = chcusb_startpage_300, .link = NULL }, { .name = "chcusb_endpage", @@ -561,7 +564,7 @@ static const struct hook_symbol C300usb_hooks[] = { }, { .name = "chcusb_setPrintStandby", .ordinal = 0x001f, - .patch = chcusb_setPrintStandby, + .patch = chcusb_setPrintStandby_300, .link = NULL }, { .name = "chcusb_testCardFeed", @@ -1619,7 +1622,7 @@ static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte) { // C3XXFWDLusb stubs -int fwdlusb_open(uint16_t *rResult) { +__stdcall int fwdlusb_open(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; @@ -1627,33 +1630,33 @@ int fwdlusb_open(uint16_t *rResult) { void fwdlusb_close() {} -int fwdlusb_listupPrinter(uint8_t *rIdArray) { +__stdcall int fwdlusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } -int fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { +__stdcall int fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } -int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { +__stdcall int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { +__stdcall int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { +__stdcall int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); switch (tagNumber) { case 0: // getPaperInfo @@ -1734,13 +1737,13 @@ int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) return 1; } -int fwdlusb_status(uint16_t *rResult) { +__stdcall int fwdlusb_status(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { +__stdcall int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { *(uint16_t *)(rResultArray + 2 * i) = 0; @@ -1749,13 +1752,13 @@ int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { return 1; } -int fwdlusb_resetPrinter(uint16_t *rResult) { +__stdcall int fwdlusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { +__stdcall int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { int8_t a; uint32_t b = 0; for (int32_t i = 0; i < size; ++i) { @@ -1776,7 +1779,7 @@ int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { return b; } -int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { +__stdcall int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1825,7 +1828,7 @@ int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResu return result; } -int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { +__stdcall int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1874,7 +1877,7 @@ int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResul return result; } -int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { +__stdcall int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1923,7 +1926,7 @@ int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rRes return result; } -int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { +__stdcall int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); if (update == 1) { return fwdlusb_updateFirmware_main(update, filename, rResult); @@ -1937,7 +1940,7 @@ int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { } } -int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +__stdcall int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -1973,7 +1976,7 @@ int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rL return result; } -int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +__stdcall int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -2009,7 +2012,7 @@ int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLe return result; } -int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +__stdcall int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -2045,7 +2048,7 @@ int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *r return result; } -int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +__stdcall int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s(update: %d, filename: %s)\n", __func__, update, filename); if (!rBuffer) { *rLen = 38; @@ -2064,25 +2067,25 @@ int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, u } } -int fwdlusb_MakeThread(uint16_t maxCount) { +__stdcall int fwdlusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); return 1; } -int fwdlusb_ReleaseThread(uint16_t *rResult) { +__stdcall int fwdlusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { +__stdcall int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } -int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { +__stdcall int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; @@ -2090,12 +2093,12 @@ int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { // C3XXusb stubs -int chcusb_MakeThread(uint16_t maxCount) { +__stdcall int chcusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } -int chcusb_open(uint16_t *rResult) { +__stdcall int chcusb_open(uint16_t *rResult) { // Seed random for card id generation srand(time(NULL)); generate_rfid(); @@ -2109,38 +2112,38 @@ void chcusb_close() { dprintf("Printer: C3XXusb: %s\n", __func__); } -int chcusb_ReleaseThread(uint16_t *rResult) { +__stdcall int chcusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } -int chcusb_listupPrinter(uint8_t *rIdArray) { +__stdcall int chcusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } -int chcusb_listupPrinterSN(uint64_t *rSerialArray) { +__stdcall int chcusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } -int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { +__stdcall int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { +__stdcall int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { +__stdcall int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { // dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { @@ -2239,6 +2242,8 @@ int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) *rLen = 1; if (awaitingCardExit) *rBuffer = 0xF0; + else if (STATUS == 1) + *rBuffer = 1; else *rBuffer = 0; break; @@ -2294,7 +2299,7 @@ int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) return 1; } -int chcusb_imageformat( +__stdcall int chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, @@ -2310,14 +2315,14 @@ int chcusb_imageformat( return 1; } -int chcusb_setmtf(int32_t *mtf) { +__thiscall int chcusb_setmtf(int32_t *mtf) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(MTF, mtf, sizeof(MTF)); return 1; } -int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { +__stdcall int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { dprintf("Printer: C3XXusb: %s\n", __func__); uint8_t tone; @@ -2348,7 +2353,7 @@ int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *in return 1; } -int chcusb_setIcctable( +__stdcall int chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, @@ -2361,32 +2366,34 @@ int chcusb_setIcctable( uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); - for (int i = 0; i < 256; ++i) { - intoneR[i] = i; - intoneG[i] = i; - intoneB[i] = i; - outtoneR[i] = i; - outtoneG[i] = i; - outtoneB[i] = i; + if (intoneR != NULL && intoneG != NULL && intoneB != NULL && outtoneR != NULL && outtoneG != NULL && outtoneB != NULL) { + for (int i = 0; i < 256; ++i) { + intoneR[i] = i; + intoneG[i] = i; + intoneB[i] = i; + outtoneR[i] = i; + outtoneG[i] = i; + outtoneB[i] = i; + } } *rResult = 0; return 1; } -int chcusb_copies(uint16_t copies, uint16_t *rResult) { +__stdcall int chcusb_copies(uint16_t copies, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_status(uint16_t *rResult) { +__stdcall int chcusb_status(uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { +__stdcall int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { @@ -2396,7 +2403,7 @@ int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { return 1; } -int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { +__stdcall int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); STATUS = 2; @@ -2406,7 +2413,16 @@ int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult return 1; } -int chcusb_endpage(uint16_t *rResult) { +__stdcall int chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult) { + dprintf("Printer: C300usb: %s\n", __func__); + + STATUS = 2; + + *rResult = 0; + return 1; +} + +__stdcall int chcusb_endpage(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = true; @@ -2415,7 +2431,7 @@ int chcusb_endpage(uint16_t *rResult) { return 1; } -int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +__stdcall int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2439,7 +2455,7 @@ int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { return 1; } -int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +__stdcall int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2458,7 +2474,7 @@ int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) return 1; } -int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +__stdcall int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2477,7 +2493,7 @@ int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { return 1; } -int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +__stdcall int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { @@ -2495,7 +2511,7 @@ int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, return 1; } -int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { +__stdcall int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; i < 256; ++i) { @@ -2508,7 +2524,7 @@ int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_ return 1; } -int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { +__stdcall int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -2545,13 +2561,13 @@ int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { return 1; } -int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { +__stdcall int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { +__stdcall int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { CURVE[type][number] = *data; @@ -2560,7 +2576,7 @@ int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, u return 1; } -int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { +__stdcall int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { *data = CURVE[type][number]; @@ -2569,26 +2585,26 @@ int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, u return 1; } -int chcusb_blinkLED(uint16_t *rResult) { +__stdcall int chcusb_blinkLED(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_resetPrinter(uint16_t *rResult) { +__stdcall int chcusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { +__stdcall int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } -int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { +__stdcall int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 8); @@ -2606,7 +2622,7 @@ int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult return 1; } -int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { +__stdcall int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if (STATUS == 0) @@ -2622,13 +2638,29 @@ int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { return 1; } -int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { +__stdcall int chcusb_setPrintStandby_300(uint16_t *rResult) { + dprintf("Printer: C300usb: %s\n", __func__); + + *rResult = 0; + if (awaitingCardExit){ // 300 does not use exitCard, so reset this for getPrinterInfo. + awaitingCardExit = false; + STATUS = 1; + } + if (STATUS == 0) + { + STATUS = 1; + } + + return 1; +} + +__stdcall int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_exitCard(uint16_t *rResult) { +__stdcall int chcusb_exitCard(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = false; @@ -2638,7 +2670,7 @@ int chcusb_exitCard(uint16_t *rResult) { return 1; } -int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { +__stdcall int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(rCardTID, cardRFID, sizeof(cardRFID)); @@ -2646,7 +2678,7 @@ int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { return 1; } -int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { +__stdcall int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { uint8_t off; dprintf("Printer: C3XXusb: %s\n", __func__); @@ -2709,67 +2741,67 @@ int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t se return 1; } -int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { +__stdcall int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { +__stdcall int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_getErrorStatus(uint16_t *rBuffer) { +__stdcall int chcusb_getErrorStatus(uint16_t *rBuffer) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 0x80); return 1; } -int chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { +__stdcall int chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { +__stdcall int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { +__stdcall int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { +__stdcall int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { +__stdcall int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { +__stdcall int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { +__stdcall int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { +__stdcall int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; @@ -3282,3 +3314,8 @@ DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSi #endif } + +void printer_set_dimensions(int width, int height){ + WIDTH = width; + HEIGHT = height; +} \ No newline at end of file diff --git a/hooklib/printer.h b/hooklib/printer.h index 229cff7..1a39fe8 100644 --- a/hooklib/printer.h +++ b/hooklib/printer.h @@ -15,3 +15,4 @@ struct printer_config { void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self); void printer_hook_insert_hooks(HMODULE target); +void printer_set_dimensions(int width, int height); \ No newline at end of file diff --git a/kemonohook/config.c b/kemonohook/config.c new file mode 100644 index 0000000..d1097be --- /dev/null +++ b/kemonohook/config.c @@ -0,0 +1,105 @@ +#include +#include + +#include "amex/config.h" + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "kemonohook/config.h" + +#include "platform/config.h" + +void kemono_dll_config_load( + struct kemono_dll_config *cfg, + const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"kemonoio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); + memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-04", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6704 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); + for (int i = n; i < sizeof(cfg->chip_number); i++) + { + cfg->chip_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6704 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } +} + +void kemono_hook_config_load( + struct kemono_hook_config *cfg, + const wchar_t *filename) { + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + vfd_config_load(&cfg->vfd, filename); + kemono_dll_config_load(&cfg->dll, filename); + unity_config_load(&cfg->unity, filename); + printer_config_load(&cfg->printer, filename); + amex_config_load(&cfg->amex, filename); + led15093_config_load(&cfg->led15093, filename); +} diff --git a/kemonohook/config.h b/kemonohook/config.h new file mode 100644 index 0000000..bf76cff --- /dev/null +++ b/kemonohook/config.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "amex/amex.h" + +#include "board/config.h" +#include "board/led15093.h" + +#include "hooklib/dvd.h" + +#include "kemonohook/kemono-dll.h" + +#include "platform/config.h" + +#include "unityhook/config.h" + +struct kemono_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct vfd_config vfd; + struct kemono_dll_config dll; + struct unity_config unity; + struct printer_config printer; + struct amex_config amex; + struct led15093_config led15093; +}; + +void kemono_dll_config_load( + struct kemono_dll_config *cfg, + const wchar_t *filename); + +void kemono_hook_config_load( + struct kemono_hook_config *cfg, + const wchar_t *filename); diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c new file mode 100644 index 0000000..736da4e --- /dev/null +++ b/kemonohook/dllmain.c @@ -0,0 +1,121 @@ +#include + +#include "board/io4.h" +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "hook/process.h" +#include "hook/table.h" +#include "hook/iohook.h" + +#include "hooklib/printer.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "kemonohook/config.h" +#include "kemonohook/hooks.h" +#include "kemonohook/jvs.h" +#include "kemonohook/kemono-dll.h" + +#include "platform/platform.h" + +#include "unityhook/hook.h" + +#include "util/dprintf.h" + +static HMODULE kemono_hook_mod; +static process_entry_t kemono_startup; +static struct kemono_hook_config kemono_hook_cfg; + +static DWORD CALLBACK kemono_pre_startup(void) { + HRESULT hr; + + dprintf("--- Begin kemono_pre_startup ---\n"); + + /* Load config */ + + kemono_hook_config_load(&kemono_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&kemono_hook_cfg.dvd, kemono_hook_mod); + serial_hook_init(); + printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod); + printer_set_dimensions(720, 1028); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &kemono_hook_cfg.platform, + "SDFL", + "AAW1", + kemono_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&kemono_hook_cfg.aime, 1, 1, kemono_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = kemono_dll_init(&kemono_hook_cfg.dll, kemono_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = amex_hook_init(&kemono_hook_cfg.amex, kemono_jvs_init); + + if (FAILED(hr)) { + goto fail; + } + + hr = led15093_hook_init(&kemono_hook_cfg.led15093, kemono_dll.led_init, kemono_dll.led_set_leds, 10, 1, 1, 2); + + if (FAILED(hr)) { + goto fail; + } + + kemono_extra_hooks_init(); + + /* Initialize Unity native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the `kemonohook` initialization. */ + + unity_hook_init(&kemono_hook_cfg.unity, kemono_hook_mod, kemono_extra_hooks_load); + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End kemono_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return kemono_startup(); + + fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) { + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + kemono_hook_mod = mod; + + hr = process_hijack_startup(kemono_pre_startup, &kemono_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/kemonohook/hooks.c b/kemonohook/hooks.c new file mode 100644 index 0000000..51fc0d0 --- /dev/null +++ b/kemonohook/hooks.c @@ -0,0 +1,59 @@ +#include "hook/iohook.h" +#include "hook/procaddr.h" +#include "hook/table.h" + +#include "hooklib/serial.h" + +#include "kemonohook/hooks.h" + +#include "util/dprintf.h" + +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); + +static int (WINAPI *next_GetVersionExW)(LPOSVERSIONINFOW lpVersionInformation); + +static const struct hook_symbol kemono_kernel32_syms[] = { + { + .name = "GetVersionExW", + .patch = hook_GetVersionExW, + .link = (void **) &next_GetVersionExW, + } +}; + +void kemono_extra_hooks_init(){ +} + +void kemono_extra_hooks_load(HMODULE mod, const wchar_t* target_module) { + + // Workaround for AmManager.checkTarget:Environment.GetEnvironmentVariable("USERNAME") + SetEnvironmentVariableA("USERNAME", "AppUser"); + + // Workaround for AmManager.checkTarget, expects OS version to be 6.2 or 6.3 + hook_table_apply( + mod, + "kernel32.dll", + kemono_kernel32_syms, + _countof(kemono_kernel32_syms)); + + // needed for LED COM port + // FIXME: SerialPortAPI.dll seems to be loaded twice? this causes a crash + /*if (_wcsicmp(L"SerialPortAPI.dll", target_module) == 0) { + iohook_apply_hooks(mod); + serial_hook_apply_hooks(mod); + dprintf("Kemono: Loaded I/O hooks for serial port\n"); + }*/ + +} + +static BOOL WINAPI hook_GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) { + int result = next_GetVersionExW(lpVersionInformation); + + if (result) { + lpVersionInformation->dwMajorVersion = 6; + lpVersionInformation->dwMinorVersion = 2; + lpVersionInformation->dwBuildNumber = 0; + dprintf("Kemono: GetVersionExW hook hit\n"); + } + + return result; +} \ No newline at end of file diff --git a/kemonohook/hooks.h b/kemonohook/hooks.h new file mode 100644 index 0000000..a778e5b --- /dev/null +++ b/kemonohook/hooks.h @@ -0,0 +1,5 @@ +#pragma once + +void kemono_extra_hooks_init(); + +void kemono_extra_hooks_load(HMODULE mod, const wchar_t* target_module); \ No newline at end of file diff --git a/kemonohook/jvs.c b/kemonohook/jvs.c new file mode 100644 index 0000000..ae9f0f8 --- /dev/null +++ b/kemonohook/jvs.c @@ -0,0 +1,133 @@ +#include + +#include +#include +#include +#include + +#include "amex/jvs.h" + +#include "board/io3.h" + +#include "kemonohook/kemono-dll.h" + +#include "jvs/jvs-bus.h" + +#include "util/dprintf.h" + +struct kemono_jvs_ir_mask { + uint16_t p1; + uint16_t p2; +}; + +static void kemono_jvs_read_switches(void *ctx, struct io3_switch_state *out); +static void kemono_jvs_read_coin_counter( + void *ctx, + uint8_t slot_no, + uint16_t *out); + +static const struct io3_ops kemono_jvs_io3_ops = { + .read_switches = kemono_jvs_read_switches, + .read_coin_counter = kemono_jvs_read_coin_counter, +}; + +static struct io3 kemono_jvs_io3; + +HRESULT kemono_jvs_init(struct jvs_node **out) +{ + HRESULT hr; + + assert(out != NULL); + assert(kemono_dll.init != NULL); + + dprintf("JVS I/O: Starting IO backend\n"); + hr = kemono_dll.init(); + + if (FAILED(hr)) { + dprintf("JVS I/O: Backend error, I/O disconnected: %x\n", (int) hr); + + return hr; + } + + io3_init(&kemono_jvs_io3, NULL, &kemono_jvs_io3_ops, NULL); + *out = io3_to_jvs_node(&kemono_jvs_io3); + + return S_OK; +} + +static void kemono_jvs_read_switches(void *ctx, struct io3_switch_state *out) +{ + const struct kemono_jvs_ir_mask *masks; + uint16_t opbtn; + uint16_t pbtn; + size_t i; + + assert(out != NULL); + assert(kemono_dll.poll != NULL); + + opbtn = 0; + pbtn = 0; + + kemono_dll.poll(&opbtn, &pbtn); + + out->system = 0x00; + out->p1 = 0x0000; + out->p2 = 0x0000; + + if (opbtn & KEMONO_IO_OPBTN_TEST) { + out->system |= 1 << 7; + } + + if (opbtn & KEMONO_IO_OPBTN_SERVICE) { + out->p1 |= 1 << 14; + } + + if (pbtn & KEMONO_IO_GAMEBTN_UP) { + out->p1 |= 1 << 13; + } + + if (pbtn & KEMONO_IO_GAMEBTN_DOWN) { + out->p1 |= 1 << 12; + } + + if (pbtn & KEMONO_IO_GAMEBTN_LEFT) { + out->p1 |= 1 << 11; + } + + if (pbtn & KEMONO_IO_GAMEBTN_RIGHT) { + out->p1 |= 1 << 10; + } + + if (pbtn & KEMONO_IO_GAMEBTN_R) { + out->p1 |= 1 << 9; + } + + if (pbtn & KEMONO_IO_GAMEBTN_G) { + out->p1 |= 1 << 7; + } + + if (pbtn & KEMONO_IO_GAMEBTN_B) { + out->p1 |= 1 << 8; + } + + if (pbtn & KEMONO_IO_GAMEBTN_START) { + out->p1 |= 1 << 15; + } + + +} + +static void kemono_jvs_read_coin_counter( + void *ctx, + uint8_t slot_no, + uint16_t *out) +{ + assert(out != NULL); + assert(kemono_dll.jvs_read_coin_counter != NULL); + + if (slot_no > 0) { + return; + } + + kemono_dll.jvs_read_coin_counter(out); +} diff --git a/kemonohook/jvs.h b/kemonohook/jvs.h new file mode 100644 index 0000000..359138b --- /dev/null +++ b/kemonohook/jvs.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "jvs/jvs-bus.h" + +HRESULT kemono_jvs_init(struct jvs_node **root); diff --git a/kemonohook/kemono-dll.c b/kemonohook/kemono-dll.c new file mode 100644 index 0000000..8fbb447 --- /dev/null +++ b/kemonohook/kemono-dll.c @@ -0,0 +1,115 @@ +#include + +#include +#include + +#include "kemonohook/kemono-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym kemono_dll_syms[] = { + { + .sym = "kemono_io_init", + .off = offsetof(struct kemono_dll, init), + }, + { + .sym = "kemono_io_poll", + .off = offsetof(struct kemono_dll, poll), + }, + { + .sym = "kemono_io_jvs_read_coin_counter", + .off = offsetof(struct kemono_dll, jvs_read_coin_counter), + }, + { + .sym = "kemono_io_led_init", + .off = offsetof(struct kemono_dll, led_init), + }, + { + .sym = "kemono_io_led_set_colors", + .off = offsetof(struct kemono_dll, led_set_leds), + } +}; + +struct kemono_dll kemono_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT kemono_dll_init(const struct kemono_dll_config *cfg, HINSTANCE self) { + uint16_t (*get_api_version)(void); + const struct dll_bind_sym *sym; + HINSTANCE owned; + HINSTANCE src; + HRESULT hr; + + assert(cfg != NULL); + assert(self != NULL); + + if (cfg->path[0] != L'\0') { + owned = LoadLibraryW(cfg->path); + + if (owned == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Kemono IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("Kemono IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "kemono_io_get_api_version"); + + if (get_api_version != NULL) { + kemono_dll.api_version = get_api_version(); + } else { + kemono_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose kemono_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (kemono_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("Kemono IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + kemono_dll.api_version); + + goto end; + } + + sym = kemono_dll_syms; + hr = dll_bind(&kemono_dll, src, &sym, _countof(kemono_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("Kemono IO: Custom IO DLL does not provide function " + "\"%s\". Please contact your IO DLL's developer for " + "further assistance.\n", + sym->sym); + + goto end; + } else { + dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); + } + } + + owned = NULL; + + end: + if (owned != NULL) { + FreeLibrary(owned); + } + + return hr; +} diff --git a/kemonohook/kemono-dll.h b/kemonohook/kemono-dll.h new file mode 100644 index 0000000..3ab7506 --- /dev/null +++ b/kemonohook/kemono-dll.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "kemonoio/kemonoio.h" + +struct kemono_dll { + uint16_t api_version; + + HRESULT (*init)(void); + + HRESULT (*poll)(uint16_t *ops, uint16_t *player); + + void (*jvs_read_coin_counter)(uint16_t *coins); + + HRESULT (*led_init)(void); + + void (*led_set_leds)(uint8_t board, uint8_t *rgb); +}; + +struct kemono_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct kemono_dll kemono_dll; + +HRESULT kemono_dll_init(const struct kemono_dll_config *cfg, HINSTANCE self); diff --git a/kemonohook/kemonohook.def b/kemonohook/kemonohook.def new file mode 100644 index 0000000..c28d512 --- /dev/null +++ b/kemonohook/kemonohook.def @@ -0,0 +1,82 @@ +LIBRARY kemonohook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + kemono_io_get_api_version + kemono_io_jvs_read_coin_counter + kemono_io_init + kemono_io_poll + kemono_io_led_init + kemono_io_led_set_colors + fwdlusb_open + fwdlusb_close + fwdlusb_listupPrinter + fwdlusb_listupPrinterSN + fwdlusb_selectPrinter + fwdlusb_selectPrinterSN + fwdlusb_getPrinterInfo + fwdlusb_status + fwdlusb_statusAll + fwdlusb_resetPrinter + fwdlusb_updateFirmware + fwdlusb_getFirmwareInfo + fwdlusb_MakeThread + fwdlusb_ReleaseThread + fwdlusb_AttachThreadCount + fwdlusb_getErrorLog + chcusb_MakeThread + chcusb_open + chcusb_close + chcusb_ReleaseThread + chcusb_listupPrinter + chcusb_listupPrinterSN + chcusb_selectPrinter + chcusb_selectPrinterSN + chcusb_getPrinterInfo + chcusb_imageformat + chcusb_setmtf + chcusb_makeGamma + chcusb_setIcctable + chcusb_copies + chcusb_status + chcusb_statusAll + chcusb_startpage + chcusb_endpage + chcusb_write + chcusb_writeLaminate + chcusb_writeHolo + chcusb_setPrinterInfo + chcusb_getGamma + chcusb_getMtf + chcusb_cancelCopies + chcusb_setPrinterToneCurve + chcusb_getPrinterToneCurve + chcusb_blinkLED + chcusb_resetPrinter + chcusb_AttachThreadCount + chcusb_getPrintIDStatus + chcusb_setPrintStandby + chcusb_testCardFeed + chcusb_exitCard + chcusb_getCardRfidTID + chcusb_commCardRfidReader + chcusb_updateCardRfidReader + chcusb_getErrorLog + chcusb_getErrorStatus + chcusb_setCutList + chcusb_setLaminatePattern + chcusb_color_adjustment + chcusb_color_adjustmentEx + chcusb_getEEPROM + chcusb_setParameter + chcusb_getParameter + chcusb_universal_command diff --git a/kemonohook/meson.build b/kemonohook/meson.build new file mode 100644 index 0000000..78538dd --- /dev/null +++ b/kemonohook/meson.build @@ -0,0 +1,34 @@ +shared_library( + 'kemonohook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'kemonohook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + ], + link_with : [ + aimeio_lib, + amex_lib, + board_lib, + hooklib_lib, + jvs_lib, + kemonoio_lib, + platform_lib, + unityhook_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'hooks.c', + 'hooks.h', + 'jvs.c', + 'jvs.h', + 'kemono-dll.c', + 'kemono-dll.h', + ], +) diff --git a/kemonoio/config.c b/kemonoio/config.c new file mode 100644 index 0000000..88afa5d --- /dev/null +++ b/kemonoio/config.c @@ -0,0 +1,28 @@ +#include + +#include +#include +#include + +#include "kemonoio/config.h" + +void kemono_io_config_load( + struct kemono_io_config *cfg, + const wchar_t *filename) { + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + + cfg->vk_left = GetPrivateProfileIntW(L"io3", L"left", VK_LEFT, filename); + cfg->vk_right = GetPrivateProfileIntW(L"io3", L"right", VK_RIGHT, filename); + cfg->vk_up = GetPrivateProfileIntW(L"io3", L"up", VK_UP, filename); + cfg->vk_down = GetPrivateProfileIntW(L"io3", L"down", VK_DOWN, filename); + cfg->vk_red = GetPrivateProfileIntW(L"io3", L"red", 'A', filename); + cfg->vk_green = GetPrivateProfileIntW(L"io3", L"green", 'S', filename); + cfg->vk_blue = GetPrivateProfileIntW(L"io3", L"blue", 'D', filename); + cfg->vk_start = GetPrivateProfileIntW(L"io3", L"start", VK_RETURN, filename); +} diff --git a/kemonoio/config.h b/kemonoio/config.h new file mode 100644 index 0000000..f2c36f3 --- /dev/null +++ b/kemonoio/config.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include + +struct kemono_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + + uint8_t vk_left; + uint8_t vk_right; + uint8_t vk_up; + uint8_t vk_down; + uint8_t vk_red; + uint8_t vk_green; + uint8_t vk_blue; + uint8_t vk_start; +}; + +void kemono_io_config_load( + struct kemono_io_config *cfg, + const wchar_t *filename); diff --git a/kemonoio/kemonoio.c b/kemonoio/kemonoio.c new file mode 100644 index 0000000..8d4033c --- /dev/null +++ b/kemonoio/kemonoio.c @@ -0,0 +1,104 @@ +#include + +#include +#include +#include + +#include "kemonoio/kemonoio.h" +#include "kemonoio/config.h" + +static uint8_t kemono_opbtn; +static uint16_t kemono_pbtn; +static uint16_t kemono_io_coins; +static struct kemono_io_config kemono_io_cfg; +static bool kemono_io_coin; + +uint16_t kemono_io_get_api_version(void) { + return 0x0100; +} + +HRESULT kemono_io_init(void) { + kemono_io_config_load(&kemono_io_cfg, L".\\segatools.ini"); + + kemono_io_coins = 0; + + return S_OK; +} + +HRESULT kemono_io_poll(uint16_t *ops, uint16_t *player) { + kemono_opbtn = 0; + kemono_pbtn = 0; + + if (GetAsyncKeyState(kemono_io_cfg.vk_test) & 0x8000) { + kemono_opbtn |= KEMONO_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_service) & 0x8000) { + kemono_opbtn |= KEMONO_IO_OPBTN_SERVICE; + } + + if (kemono_io_cfg.vk_coin && + (GetAsyncKeyState(kemono_io_cfg.vk_coin) & 0x8000)) { + if (!kemono_io_coin) { + kemono_io_coin = true; + kemono_io_coins++; + } + } else { + kemono_io_coin = false; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_up)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_UP; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_down)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_DOWN; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_left)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_LEFT; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_right)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_RIGHT; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_red)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_R; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_green)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_G; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_blue)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_B; + } + + if (GetAsyncKeyState(kemono_io_cfg.vk_start)) { + kemono_pbtn |= KEMONO_IO_GAMEBTN_START; + } + + if (ops != NULL) { + *ops = kemono_opbtn; + } + if (player != NULL) { + *player = kemono_pbtn; + } + + return S_OK; +} + +void kemono_io_jvs_read_coin_counter(uint16_t *out) { + assert(out != NULL); + + *out = kemono_io_coins; +} + +HRESULT kemono_io_led_init(void) { + return S_OK; +} + +void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb) { + +} \ No newline at end of file diff --git a/kemonoio/kemonoio.h b/kemonoio/kemonoio.h new file mode 100644 index 0000000..c014857 --- /dev/null +++ b/kemonoio/kemonoio.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include + +enum { + KEMONO_IO_OPBTN_TEST = 0x01, + KEMONO_IO_OPBTN_SERVICE = 0x02 +}; + +enum { + KEMONO_IO_GAMEBTN_UP = 0x01, + KEMONO_IO_GAMEBTN_DOWN = 0x02, + KEMONO_IO_GAMEBTN_LEFT = 0x04, + KEMONO_IO_GAMEBTN_RIGHT = 0x08, + KEMONO_IO_GAMEBTN_R = 0x10, + KEMONO_IO_GAMEBTN_G = 0x20, + KEMONO_IO_GAMEBTN_B = 0x40, + KEMONO_IO_GAMEBTN_START = 0x80 +}; + +/* Get the version of the Kemono IO API that this DLL supports. This + function should return a positive 16-bit integer, where the high byte is + the major version and the low byte is the minor version (as defined by the + Semantic Versioning standard). + + The latest API version as of this writing is 0x0100. */ + +uint16_t kemono_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after kemono_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT kemono_io_init(void); + +/* Send any queued outputs (of which there are currently none, though this may + change in subsequent API versions) and retrieve any new inputs. + + Minimum API version: 0x0100 */ + +HRESULT kemono_io_poll(uint16_t* ops, uint16_t* player); + +/* 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. + + Minimum API version: 0x0100 */ +void kemono_io_jvs_read_coin_counter(uint16_t *out); diff --git a/kemonoio/meson.build b/kemonoio/meson.build new file mode 100644 index 0000000..3dcc27c --- /dev/null +++ b/kemonoio/meson.build @@ -0,0 +1,13 @@ +kemonoio_lib = static_library( + 'kemonoio_lib', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + sources : [ + 'kemonoio.c', + 'kemonoio.h', + 'config.c', + 'config.h', + ], +) diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 02f32a4..ac14649 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -102,7 +102,7 @@ static DWORD CALLBACK mai2_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `mai2hook` initialization. */ - unity_hook_init(&mai2_hook_cfg.unity, mai2_hook_mod); + unity_hook_init(&mai2_hook_cfg.unity, mai2_hook_mod, NULL); /* Initialize debug helpers */ diff --git a/meson.build b/meson.build index c5b3d40..129a387 100644 --- a/meson.build +++ b/meson.build @@ -110,6 +110,7 @@ subdir('mercuryio') subdir('cxbio') subdir('tokyoio') subdir('fgoio') +subdir('kemonoio') subdir('chunihook') subdir('divahook') @@ -126,3 +127,4 @@ subdir('mercuryhook') subdir('cxbhook') subdir('tokyohook') subdir('fgohook') +subdir('kemonohook') diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index bab6c0b..e991b40 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -110,7 +110,7 @@ static DWORD CALLBACK mu3_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `mu3hook` initialization. */ - unity_hook_init(&mu3_hook_cfg.unity, mu3_hook_mod); + unity_hook_init(&mu3_hook_cfg.unity, mu3_hook_mod, NULL); /* Initialize debug helpers */ diff --git a/platform/vfs.c b/platform/vfs.c index 26e4d34..e49ad5b 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -34,11 +34,11 @@ static HRESULT vfs_path_hook_option( static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); -static wchar_t* hook_System_getAppRootPath(); -static wchar_t* (*next_System_getAppRootPath)(); +static __thiscall wchar_t* hook_System_getAppRootPath(); +static __thiscall wchar_t* (*next_System_getAppRootPath)(); -static wchar_t* hook_AppImage_getOptionMountRootPath(); -static wchar_t* (*next_AppImage_getOptionMountRootPath)(); +static __thiscall wchar_t* hook_AppImage_getOptionMountRootPath(); +static __thiscall wchar_t* (*next_AppImage_getOptionMountRootPath)(); static const struct hook_symbol amdaemon_syms[] = { { @@ -510,7 +510,7 @@ static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) return reg_hook_read_wstr(bytes, nbytes, L"Y:\\"); } -static wchar_t* hook_System_getAppRootPath() +static __thiscall wchar_t* hook_System_getAppRootPath() { wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); wcscpy_s(path, MAX_PATH, vfs_config.appdata); @@ -520,7 +520,7 @@ static wchar_t* hook_System_getAppRootPath() return path; } -static wchar_t* hook_AppImage_getOptionMountRootPath() +static __thiscall wchar_t* hook_AppImage_getOptionMountRootPath() { wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); wcscpy_s(path, MAX_PATH, vfs_config.option); diff --git a/unityhook/hook.c b/unityhook/hook.c index 0058ec1..63816f3 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -39,6 +39,8 @@ static const size_t target_modules_len = _countof(target_modules); static void dll_hook_insert_hooks(HMODULE target); +static unity_hook_callback_func hook_load_callback; + static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name); static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags); @@ -57,7 +59,7 @@ static const struct hook_symbol unity_kernel32_syms[] = { }; -void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback) { assert(cfg != NULL); if (!cfg->enable) { @@ -71,6 +73,8 @@ void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { memcpy(&unity_config, cfg, sizeof(*cfg)); dll_hook_insert_hooks(NULL); + hook_load_callback = callback; + unity_hook_initted = true; dprintf("Unity: Hook enabled.\n"); } @@ -144,6 +148,9 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name) reg_hook_insert_hooks(result); clock_hook_insert_hooks(result); proc_addr_insert_hooks(result); + if (hook_load_callback != NULL){ + hook_load_callback(result, target_module); + } // Not needed? // serial_hook_apply_hooks(result); diff --git a/unityhook/hook.h b/unityhook/hook.h index 684868c..7be6044 100644 --- a/unityhook/hook.h +++ b/unityhook/hook.h @@ -4,4 +4,6 @@ #include "config.h" -void unity_hook_init(const struct unity_config *cfg, HINSTANCE self); +typedef void (*unity_hook_callback_func)(HMODULE, const wchar_t*); + +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback); From 70ac873d117fdd56e76918558354b86a148c3494 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:39:42 +0200 Subject: [PATCH 134/204] kemono: add to package creation --- Package.mk | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Package.mk b/Package.mk index f85d86f..31f43a2 100644 --- a/Package.mk +++ b/Package.mk @@ -219,6 +219,27 @@ $(BUILD_DIR_ZIP)/tokyo.zip: $(V)strip $(BUILD_DIR_ZIP)/tokyo/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/tokyo ; zip -r ../tokyo.zip * +$(BUILD_DIR_ZIP)/kemono.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/kemono + $(V)mkdir -p $(BUILD_DIR_ZIP)/kemono/DEVICE + $(V)cp $(DIST_DIR)/kemono/segatools.ini \ + $(DIST_DIR)/kemono/start.bat \ + $(BUILD_DIR_ZIP)/kemono + $(V)cp $(BUILD_DIR_32)/kemonohook/kemonohook.dll \ + $(BUILD_DIR_ZIP)/kemono/kemonohook_x86.dll + $(V)cp $(BUILD_DIR_64)/kemonohook/kemonohook.dll \ + $(BUILD_DIR_ZIP)/kemono/kemonohook_x64.dll + $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_ZIP)/kemono/inject_x86.exe + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_ZIP)/kemono/inject_x64.exe + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/kemono/DEVICE + for x in exe dll; do strip $(BUILD_DIR_ZIP)/kemono/*.$$x; done + $(V)cd $(BUILD_DIR_ZIP)/kemono ; zip -r ../kemono.zip * + $(BUILD_DIR_ZIP)/doc.zip: \ $(DOC_DIR)/config \ $(DOC_DIR)/chunihook.md \ From d4bb7b6e0eefe9b58f81e5132d43669a1393ee2d Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:40:10 +0200 Subject: [PATCH 135/204] kemono: correct keychip IP range --- dist/kemono/segatools.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/kemono/segatools.ini b/dist/kemono/segatools.ini index 7bb293e..bb4d153 100644 --- a/dist/kemono/segatools.ini +++ b/dist/kemono/segatools.ini @@ -54,7 +54,7 @@ addrSuffix=11 ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and ; that subnet must start with 192.168. -subnet=192.168.172.0 +subnet=192.168.179.0 [gpio] ; Emulated Nu DIP switch for Distribution Server setting. From 96bdacfa7c598e1bb4c7e22bec6ac433ddee3660 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:40:57 +0200 Subject: [PATCH 136/204] kemono: remove old amdaemon workaround --- dist/kemono/start.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/kemono/start.bat b/dist/kemono/start.bat index 7f3bfa9..cee8384 100644 --- a/dist/kemono/start.bat +++ b/dist/kemono/start.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start "AM Daemon" /min cmd /C timeout 10 ^& inject_x64 -d -k kemonohook_x64.dll ../amdaemon.exe -f -c ../config.json" +start "AM Daemon" /min inject_x64 -d -k kemonohook.dll ../amdaemon.exe -f -c ../config.json inject_x86 -d -k kemonohook_x86.dll Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes taskkill /f /im amdaemon.exe > nul 2>&1 From 6bd1bce419c836b79af50a1fa048d32d5f92db91 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:50:51 +0200 Subject: [PATCH 137/204] kemono: mention in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ad64f5f..1be0546 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo * SEGA World Drivers Championship 2019 * WACCA * starting from WACCA +* Kemono Friends + * Kemono Friends 3: Planet Tours ## End-users From f18d074c5f13606a87e6b22a5c6d30e087fff88a Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:50:57 +0200 Subject: [PATCH 138/204] kemono: add missed declarations --- kemonoio/kemonoio.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kemonoio/kemonoio.h b/kemonoio/kemonoio.h index c014857..5969158 100644 --- a/kemonoio/kemonoio.h +++ b/kemonoio/kemonoio.h @@ -51,3 +51,16 @@ HRESULT kemono_io_poll(uint16_t* ops, uint16_t* player); Minimum API version: 0x0100 */ void kemono_io_jvs_read_coin_counter(uint16_t *out); + +/* Initialize LED emulation. This function will be called before any + other fgo_io_led_*() function calls. + + 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 kemono_io_led_init(void); + +/* Update the RGB LEDs. + + Exact layout is TBD. */ +void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb); \ No newline at end of file From 599d5e321162b0f68916ac1b6ac2d0b0493ef2e5 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:25:19 +0200 Subject: [PATCH 139/204] kemono: fix LED hooking, add button LEDs --- kemonohook/hooks.c | 6 ++++++ kemonohook/jvs.c | 6 ++++++ kemonohook/kemono-dll.c | 4 ++++ kemonohook/kemono-dll.h | 2 ++ kemonohook/kemonohook.def | 1 + kemonoio/kemonoio.c | 5 +++++ kemonoio/kemonoio.h | 21 ++++++++++++++++++--- 7 files changed, 42 insertions(+), 3 deletions(-) diff --git a/kemonohook/hooks.c b/kemonohook/hooks.c index 51fc0d0..bdce643 100644 --- a/kemonohook/hooks.c +++ b/kemonohook/hooks.c @@ -21,6 +21,12 @@ static const struct hook_symbol kemono_kernel32_syms[] = { }; void kemono_extra_hooks_init(){ + HMODULE serialportapi = LoadLibraryA("Parade_Data/Plugins/SerialPortAPI.dll"); // HACK?? + if (serialportapi != NULL){ + iohook_apply_hooks(serialportapi); + serial_hook_apply_hooks(serialportapi); + dprintf("Kemono: Successfully pre-loaded SerialPortAPI\n"); + } } void kemono_extra_hooks_load(HMODULE mod, const wchar_t* target_module) { diff --git a/kemonohook/jvs.c b/kemonohook/jvs.c index ae9f0f8..0b10d3c 100644 --- a/kemonohook/jvs.c +++ b/kemonohook/jvs.c @@ -25,10 +25,12 @@ static void kemono_jvs_read_coin_counter( void *ctx, uint8_t slot_no, uint16_t *out); +static void kemono_jvs_write_gpio(void *ctx, uint32_t state); static const struct io3_ops kemono_jvs_io3_ops = { .read_switches = kemono_jvs_read_switches, .read_coin_counter = kemono_jvs_read_coin_counter, + .write_gpio = kemono_jvs_write_gpio }; static struct io3 kemono_jvs_io3; @@ -131,3 +133,7 @@ static void kemono_jvs_read_coin_counter( kemono_dll.jvs_read_coin_counter(out); } + +static void kemono_jvs_write_gpio(void *ctx, uint32_t state){ + kemono_dll.jvs_write_gpio(state); +} \ No newline at end of file diff --git a/kemonohook/kemono-dll.c b/kemonohook/kemono-dll.c index 8fbb447..004cf50 100644 --- a/kemonohook/kemono-dll.c +++ b/kemonohook/kemono-dll.c @@ -28,6 +28,10 @@ const struct dll_bind_sym kemono_dll_syms[] = { { .sym = "kemono_io_led_set_colors", .off = offsetof(struct kemono_dll, led_set_leds), + }, + { + .sym = "kemono_io_jvs_write_gpio", + .off = offsetof(struct kemono_dll, jvs_write_gpio), } }; diff --git a/kemonohook/kemono-dll.h b/kemonohook/kemono-dll.h index 3ab7506..df676f0 100644 --- a/kemonohook/kemono-dll.h +++ b/kemonohook/kemono-dll.h @@ -16,6 +16,8 @@ struct kemono_dll { HRESULT (*led_init)(void); void (*led_set_leds)(uint8_t board, uint8_t *rgb); + + void (*jvs_write_gpio)(uint32_t state); }; struct kemono_dll_config { diff --git a/kemonohook/kemonohook.def b/kemonohook/kemonohook.def index c28d512..601a00b 100644 --- a/kemonohook/kemonohook.def +++ b/kemonohook/kemonohook.def @@ -17,6 +17,7 @@ EXPORTS kemono_io_poll kemono_io_led_init kemono_io_led_set_colors + kemono_io_jvs_write_gpio fwdlusb_open fwdlusb_close fwdlusb_listupPrinter diff --git a/kemonoio/kemonoio.c b/kemonoio/kemonoio.c index 8d4033c..5b24c28 100644 --- a/kemonoio/kemonoio.c +++ b/kemonoio/kemonoio.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "kemonoio/kemonoio.h" #include "kemonoio/config.h" @@ -101,4 +102,8 @@ HRESULT kemono_io_led_init(void) { void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb) { +} + +void kemono_io_jvs_write_gpio(uint32_t state){ + } \ No newline at end of file diff --git a/kemonoio/kemonoio.h b/kemonoio/kemonoio.h index 5969158..3b180e2 100644 --- a/kemonoio/kemonoio.h +++ b/kemonoio/kemonoio.h @@ -57,10 +57,25 @@ void kemono_io_jvs_read_coin_counter(uint16_t *out); All subsequent calls may originate from arbitrary threads and some may overlap with each other. Ensuring synchronization inside your IO DLL is - your responsibility. */ + your responsibility. + + Minimum API version: 0x0100 */ HRESULT kemono_io_led_init(void); /* Update the RGB LEDs. - Exact layout is TBD. */ -void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb); \ No newline at end of file + The left side LED bar are indices 0 to 32. + The right side LED bar are indices 33 to 65. + + Minimum API version: 0x0100 */ +void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb); + +/* Update the button LEDs. + + Button R: Bit 15 + Button G: Bit 1 + Button B: Bit 13 + Start Button: Bit 11 + + Minimum API version: 0x0100 */ +void kemono_io_jvs_write_gpio(uint32_t state); \ No newline at end of file From 3eef5dd209af369ea2e8c1a817b50a349d228e3f Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:25:38 +0200 Subject: [PATCH 140/204] kemono: fix LED board check error --- board/led15093-cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/led15093-cmd.h b/board/led15093-cmd.h index 5648de6..0cd5d8d 100644 --- a/board/led15093-cmd.h +++ b/board/led15093-cmd.h @@ -199,7 +199,7 @@ struct led15093_resp_board_info { char chip_num[5]; uint8_t endcode; // Always 0xFF uint8_t fw_ver; - uint8_t rx_buf; + uint16_t rx_buf; }; struct led15093_resp_protocol_ver { From d257887f6ec354b176fb42ec0ad0bf90dbddbcf9 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:29:17 +0200 Subject: [PATCH 141/204] kemono: fix packagefile again --- Package.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.mk b/Package.mk index 31f43a2..9d907b1 100644 --- a/Package.mk +++ b/Package.mk @@ -264,6 +264,7 @@ $(BUILD_DIR_ZIP)/segatools.zip: \ $(BUILD_DIR_ZIP)/cm.zip \ $(BUILD_DIR_ZIP)/tokyo.zip \ $(BUILD_DIR_ZIP)/fgo.zip \ + $(BUILD_DIR_ZIP)/kemono.zip \ CHANGELOG.md \ README.md \ From 9de48dd6ce3a7df0bfc72f0177d997273a7b5c83 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:52:55 +0200 Subject: [PATCH 142/204] kemono: flip declarations --- hooklib/printer.c | 268 +++++++++++++++++++++++----------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/hooklib/printer.c b/hooklib/printer.c index 3ea4e70..642acdb 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -61,44 +61,44 @@ static uint8_t STATUS = 0; /* C3XXFWDLusb API hooks */ -__stdcall int fwdlusb_open(uint16_t *rResult); -__stdcall void fwdlusb_close(); -__stdcall int fwdlusb_listupPrinter(uint8_t *rIdArray); -__stdcall int fwdlusb_listupPrinterSN(uint64_t *rSerialArray); -__stdcall int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); -__stdcall int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); -__stdcall int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); -__stdcall int fwdlusb_status(uint16_t *rResult); -__stdcall int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); -__stdcall int fwdlusb_resetPrinter(uint16_t *rResult); -__stdcall int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); -__stdcall int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); -__stdcall int fwdlusb_MakeThread(uint16_t maxCount); -__stdcall int fwdlusb_ReleaseThread(uint16_t *rResult); -__stdcall int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); -__stdcall int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); +int WINAPI fwdlusb_open(uint16_t *rResult); +void WINAPI fwdlusb_close(); +int WINAPI fwdlusb_listupPrinter(uint8_t *rIdArray); +int WINAPI fwdlusb_listupPrinterSN(uint64_t *rSerialArray); +int WINAPI fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +int WINAPI fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +int WINAPI fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int WINAPI fwdlusb_status(uint16_t *rResult); +int WINAPI fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +int WINAPI fwdlusb_resetPrinter(uint16_t *rResult); +int WINAPI fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); +int WINAPI fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int WINAPI fwdlusb_MakeThread(uint16_t maxCount); +int WINAPI fwdlusb_ReleaseThread(uint16_t *rResult); +int WINAPI fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +int WINAPI fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); /* C3XXusb API hooks */ -__stdcall int chcusb_MakeThread(uint16_t maxCount); -__stdcall int chcusb_open(uint16_t *rResult); +int WINAPI chcusb_MakeThread(uint16_t maxCount); +int WINAPI chcusb_open(uint16_t *rResult); __stdcall void chcusb_close(); -__stdcall int chcusb_ReleaseThread(uint16_t *rResult); -__stdcall int chcusb_listupPrinter(uint8_t *rIdArray); -__stdcall int chcusb_listupPrinterSN(uint64_t *rSerialArray); -__stdcall int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); -__stdcall int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); -__stdcall int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); -__stdcall int chcusb_imageformat( +int WINAPI chcusb_ReleaseThread(uint16_t *rResult); +int WINAPI chcusb_listupPrinter(uint8_t *rIdArray); +int WINAPI chcusb_listupPrinterSN(uint64_t *rSerialArray); +int WINAPI chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); +int WINAPI chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); +int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); +int WINAPI chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint16_t *rResult); -__thiscall int chcusb_setmtf(int32_t *mtf); -__stdcall int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); -__stdcall int chcusb_setIcctable( +int __thiscall chcusb_setmtf(int32_t *mtf); +int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); +int WINAPI chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, @@ -109,42 +109,42 @@ __stdcall int chcusb_setIcctable( uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult); -__stdcall int chcusb_copies(uint16_t copies, uint16_t *rResult); -__stdcall int chcusb_status(uint16_t *rResult); -__stdcall int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); -__stdcall int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); -__stdcall int chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult); -__stdcall int chcusb_endpage(uint16_t *rResult); -__stdcall int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -__stdcall int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -__stdcall int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); -__stdcall int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); -__stdcall int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); -__stdcall int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); -__stdcall int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); -__stdcall int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); -__stdcall int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); -__stdcall int chcusb_blinkLED(uint16_t *rResult); -__stdcall int chcusb_resetPrinter(uint16_t *rResult); -__stdcall int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); -__stdcall int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); -__stdcall int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); -__stdcall int chcusb_setPrintStandby_300(uint16_t *rResult); -__stdcall int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); -__stdcall int chcusb_exitCard(uint16_t *rResult); -__stdcall int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); -__stdcall int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); -__stdcall int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); -__stdcall int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); -__stdcall int chcusb_getErrorStatus(uint16_t *rBuffer); -__stdcall int chcusb_setCutList(uint8_t *rData, uint16_t *rResult); -__stdcall int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); -__stdcall int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); -__stdcall int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); -__stdcall int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); -__stdcall int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); -__stdcall int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); -__stdcall int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); +int WINAPI chcusb_copies(uint16_t copies, uint16_t *rResult); +int WINAPI chcusb_status(uint16_t *rResult); +int WINAPI chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); +int WINAPI chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); +int WINAPI chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult); +int WINAPI chcusb_endpage(uint16_t *rResult); +int WINAPI chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int WINAPI chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int WINAPI chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); +int WINAPI chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); +int WINAPI chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); +int WINAPI chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); +int WINAPI chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); +int WINAPI chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int WINAPI chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); +int WINAPI chcusb_blinkLED(uint16_t *rResult); +int WINAPI chcusb_resetPrinter(uint16_t *rResult); +int WINAPI chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); +int WINAPI chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); +int WINAPI chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); +int WINAPI chcusb_setPrintStandby_300(uint16_t *rResult); +int WINAPI chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); +int WINAPI chcusb_exitCard(uint16_t *rResult); +int WINAPI chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); +int WINAPI chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); +int WINAPI chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); +int WINAPI chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); +int WINAPI chcusb_getErrorStatus(uint16_t *rBuffer); +int WINAPI chcusb_setCutList(uint8_t *rData, uint16_t *rResult); +int WINAPI chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); +int WINAPI chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +int WINAPI chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); +int WINAPI chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); +int WINAPI chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); +int WINAPI chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); +int WINAPI chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); /* PrintDLL API hooks */ @@ -1622,7 +1622,7 @@ static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte) { // C3XXFWDLusb stubs -__stdcall int fwdlusb_open(uint16_t *rResult) { +int WINAPI fwdlusb_open(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; @@ -1630,33 +1630,33 @@ __stdcall int fwdlusb_open(uint16_t *rResult) { void fwdlusb_close() {} -__stdcall int fwdlusb_listupPrinter(uint8_t *rIdArray) { +int WINAPI fwdlusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } -__stdcall int fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { +int WINAPI fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } -__stdcall int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { +int WINAPI fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { +int WINAPI fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { +int WINAPI fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); switch (tagNumber) { case 0: // getPaperInfo @@ -1737,13 +1737,13 @@ __stdcall int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint3 return 1; } -__stdcall int fwdlusb_status(uint16_t *rResult) { +int WINAPI fwdlusb_status(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { +int WINAPI fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { *(uint16_t *)(rResultArray + 2 * i) = 0; @@ -1752,13 +1752,13 @@ __stdcall int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { return 1; } -__stdcall int fwdlusb_resetPrinter(uint16_t *rResult) { +int WINAPI fwdlusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { +int WINAPI fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { int8_t a; uint32_t b = 0; for (int32_t i = 0; i < size; ++i) { @@ -1779,7 +1779,7 @@ __stdcall int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { return b; } -__stdcall int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { +int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1828,7 +1828,7 @@ __stdcall int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint1 return result; } -__stdcall int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { +int WINAPI fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1877,7 +1877,7 @@ __stdcall int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16 return result; } -__stdcall int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { +int WINAPI fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; @@ -1926,7 +1926,7 @@ __stdcall int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint return result; } -__stdcall int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { +int WINAPI fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); if (update == 1) { return fwdlusb_updateFirmware_main(update, filename, rResult); @@ -1940,7 +1940,7 @@ __stdcall int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t * } } -__stdcall int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +int WINAPI fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -1976,7 +1976,7 @@ __stdcall int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, ui return result; } -__stdcall int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +int WINAPI fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -2012,7 +2012,7 @@ __stdcall int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uin return result; } -__stdcall int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +int WINAPI fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { @@ -2048,7 +2048,7 @@ __stdcall int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, u return result; } -__stdcall int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +int WINAPI fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s(update: %d, filename: %s)\n", __func__, update, filename); if (!rBuffer) { *rLen = 38; @@ -2067,25 +2067,25 @@ __stdcall int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t * } } -__stdcall int fwdlusb_MakeThread(uint16_t maxCount) { +int WINAPI fwdlusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); return 1; } -__stdcall int fwdlusb_ReleaseThread(uint16_t *rResult) { +int WINAPI fwdlusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { +int WINAPI fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } -__stdcall int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { +int WINAPI fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; @@ -2093,12 +2093,12 @@ __stdcall int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rRes // C3XXusb stubs -__stdcall int chcusb_MakeThread(uint16_t maxCount) { +int WINAPI chcusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } -__stdcall int chcusb_open(uint16_t *rResult) { +int WINAPI chcusb_open(uint16_t *rResult) { // Seed random for card id generation srand(time(NULL)); generate_rfid(); @@ -2112,38 +2112,38 @@ void chcusb_close() { dprintf("Printer: C3XXusb: %s\n", __func__); } -__stdcall int chcusb_ReleaseThread(uint16_t *rResult) { +int WINAPI chcusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } -__stdcall int chcusb_listupPrinter(uint8_t *rIdArray) { +int WINAPI chcusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } -__stdcall int chcusb_listupPrinterSN(uint64_t *rSerialArray) { +int WINAPI chcusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } -__stdcall int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { +int WINAPI chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { +int WINAPI chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { +int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { // dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { @@ -2299,7 +2299,7 @@ __stdcall int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32 return 1; } -__stdcall int chcusb_imageformat( +int WINAPI chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, @@ -2315,14 +2315,14 @@ __stdcall int chcusb_imageformat( return 1; } -__thiscall int chcusb_setmtf(int32_t *mtf) { +int __thiscall chcusb_setmtf(int32_t *mtf) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(MTF, mtf, sizeof(MTF)); return 1; } -__stdcall int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { +int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { dprintf("Printer: C3XXusb: %s\n", __func__); uint8_t tone; @@ -2353,7 +2353,7 @@ __stdcall int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, u return 1; } -__stdcall int chcusb_setIcctable( +int WINAPI chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, @@ -2381,19 +2381,19 @@ __stdcall int chcusb_setIcctable( return 1; } -__stdcall int chcusb_copies(uint16_t copies, uint16_t *rResult) { +int WINAPI chcusb_copies(uint16_t copies, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_status(uint16_t *rResult) { +int WINAPI chcusb_status(uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { +int WINAPI chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { @@ -2403,7 +2403,7 @@ __stdcall int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { return 1; } -__stdcall int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { +int WINAPI chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); STATUS = 2; @@ -2413,7 +2413,7 @@ __stdcall int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_ return 1; } -__stdcall int chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult) { +int WINAPI chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult) { dprintf("Printer: C300usb: %s\n", __func__); STATUS = 2; @@ -2422,7 +2422,7 @@ __stdcall int chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult) { return 1; } -__stdcall int chcusb_endpage(uint16_t *rResult) { +int WINAPI chcusb_endpage(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = true; @@ -2431,7 +2431,7 @@ __stdcall int chcusb_endpage(uint16_t *rResult) { return 1; } -__stdcall int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +int WINAPI chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2455,7 +2455,7 @@ __stdcall int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult return 1; } -__stdcall int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +int WINAPI chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2474,7 +2474,7 @@ __stdcall int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t return 1; } -__stdcall int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { +int WINAPI chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); @@ -2493,7 +2493,7 @@ __stdcall int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rRe return 1; } -__stdcall int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { +int WINAPI chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { @@ -2511,7 +2511,7 @@ __stdcall int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32 return 1; } -__stdcall int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { +int WINAPI chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; i < 256; ++i) { @@ -2524,7 +2524,7 @@ __stdcall int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t * return 1; } -__stdcall int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { +int WINAPI chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -2561,13 +2561,13 @@ __stdcall int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { return 1; } -__stdcall int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { +int WINAPI chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { +int WINAPI chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { CURVE[type][number] = *data; @@ -2576,7 +2576,7 @@ __stdcall int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_ return 1; } -__stdcall int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { +int WINAPI chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { *data = CURVE[type][number]; @@ -2585,26 +2585,26 @@ __stdcall int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_ return 1; } -__stdcall int chcusb_blinkLED(uint16_t *rResult) { +int WINAPI chcusb_blinkLED(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_resetPrinter(uint16_t *rResult) { +int WINAPI chcusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { +int WINAPI chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } -__stdcall int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { +int WINAPI chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 8); @@ -2622,7 +2622,7 @@ __stdcall int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_ return 1; } -__stdcall int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { +int WINAPI chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if (STATUS == 0) @@ -2638,7 +2638,7 @@ __stdcall int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { return 1; } -__stdcall int chcusb_setPrintStandby_300(uint16_t *rResult) { +int WINAPI chcusb_setPrintStandby_300(uint16_t *rResult) { dprintf("Printer: C300usb: %s\n", __func__); *rResult = 0; @@ -2654,13 +2654,13 @@ __stdcall int chcusb_setPrintStandby_300(uint16_t *rResult) { return 1; } -__stdcall int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { +int WINAPI chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_exitCard(uint16_t *rResult) { +int WINAPI chcusb_exitCard(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = false; @@ -2670,7 +2670,7 @@ __stdcall int chcusb_exitCard(uint16_t *rResult) { return 1; } -__stdcall int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { +int WINAPI chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(rCardTID, cardRFID, sizeof(cardRFID)); @@ -2678,7 +2678,7 @@ __stdcall int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { return 1; } -__stdcall int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { +int WINAPI chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { uint8_t off; dprintf("Printer: C3XXusb: %s\n", __func__); @@ -2741,67 +2741,67 @@ __stdcall int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, u return 1; } -__stdcall int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { +int WINAPI chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { +int WINAPI chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_getErrorStatus(uint16_t *rBuffer) { +int WINAPI chcusb_getErrorStatus(uint16_t *rBuffer) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 0x80); return 1; } -__stdcall int chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { +int WINAPI chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { +int WINAPI chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { +int WINAPI chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { +int WINAPI chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { +int WINAPI chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { +int WINAPI chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { +int WINAPI chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } -__stdcall int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { +int WINAPI chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; From 86556ed2c87e8bb9dd3551c4a8510cc7262f4061 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:29:49 +0200 Subject: [PATCH 143/204] kemono: Update start.bat --- dist/kemono/segatools.ini | 2 ++ dist/kemono/start.bat | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dist/kemono/segatools.ini b/dist/kemono/segatools.ini index bb4d153..2da65aa 100644 --- a/dist/kemono/segatools.ini +++ b/dist/kemono/segatools.ini @@ -78,6 +78,8 @@ enable=1 ; Path to a .NET DLL that should run before the game. Useful for loading ; modding frameworks such as BepInEx. +; +; NOTE: For Kemono Friends, BepInEx (or similar) should be installed to the main folder, not the "UnityApp" folder. targetAssembly= [printer] diff --git a/dist/kemono/start.bat b/dist/kemono/start.bat index cee8384..eb4b106 100644 --- a/dist/kemono/start.bat +++ b/dist/kemono/start.bat @@ -2,11 +2,11 @@ pushd %~dp0 -start "AM Daemon" /min inject_x64 -d -k kemonohook.dll ../amdaemon.exe -f -c ../config.json -inject_x86 -d -k kemonohook_x86.dll Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes +start "AM Daemon" /min inject_x64 -d -k kemonohook_x64.dll amdaemon.exe -c config.json +inject_x86 -d -k kemonohook_x86.dll UnityApp\Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes taskkill /f /im amdaemon.exe > nul 2>&1 echo. echo Game processes have terminated -pause \ No newline at end of file +pause From f6c12fd23041260f1130943ed905866f1ba1f26b Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:46:49 +0200 Subject: [PATCH 144/204] kemono: Pre-generate printer firmware files --- hooklib/printer.c | 2 ++ hooklib/printer.h | 7 ++++++- kemonohook/dllmain.c | 18 +++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hooklib/printer.c b/hooklib/printer.c index 642acdb..121ee3d 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -1667,6 +1667,7 @@ int WINAPI fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t if (*rLen != 0x99) *rLen = 0x99; if (rBuffer) { memset(rBuffer, 0, *rLen); + rBuffer[0] = 4; // firmware count // bootFirmware int i = 1; memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); @@ -2157,6 +2158,7 @@ int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t if (*rLen != 0x99) *rLen = 0x99; if (rBuffer) { memset(rBuffer, 0, *rLen); + rBuffer[0] = 4; // firmware count // bootFirmware int i = 1; memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); diff --git a/hooklib/printer.h b/hooklib/printer.h index 1a39fe8..d376964 100644 --- a/hooklib/printer.h +++ b/hooklib/printer.h @@ -2,6 +2,7 @@ #include #include +#include struct printer_config { bool enable; @@ -15,4 +16,8 @@ struct printer_config { void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self); void printer_hook_insert_hooks(HMODULE target); -void printer_set_dimensions(int width, int height); \ No newline at end of file + +void printer_set_dimensions(int width, int height); +int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult); +int WINAPI fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult); +int WINAPI fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult); \ No newline at end of file diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c index 736da4e..42b2b68 100644 --- a/kemonohook/dllmain.c +++ b/kemonohook/dllmain.c @@ -40,8 +40,24 @@ static DWORD CALLBACK kemono_pre_startup(void) { dvd_hook_init(&kemono_hook_cfg.dvd, kemono_hook_mod); serial_hook_init(); + + // 2.02 does not call printer update functions + uint16_t ret; + fwdlusb_updateFirmware_main(1, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223100-014E-C300-MAINAPP.BIN", &ret); + if (ret != 0){ + goto fail; + } + fwdlusb_updateFirmware_dsp(2, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223200-0101-C300-DSPAPP.BIN", &ret); + if (ret != 0){ + goto fail; + } + fwdlusb_updateFirmware_param(3, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\D0460700-0101-C300-PARAM.BIN", &ret); + if (ret != 0){ + goto fail; + } + printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod); - printer_set_dimensions(720, 1028); + printer_set_dimensions(720, 1028); // printer doesn't call setimageformat /* Initialize emulation hooks */ From cdfd3bf655a829f50ee78c0d33874ef6c2f3bad2 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:09:21 +0200 Subject: [PATCH 145/204] kemono: not sure why that went missing --- board/sg-nfc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 49309f8..571be60 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -190,6 +190,7 @@ static HRESULT sg_nfc_dispatch( &res->felica_encap); case SG_NFC_CMD_MIFARE_AUTHENTICATE_A: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_B: case SG_NFC_CMD_SEND_HEX_DATA: return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); From 79592514ba8f826a807da064d0c52e50d7c80370 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:14:41 +0200 Subject: [PATCH 146/204] fgo: fix printer --- fgohook/dllmain.c | 3 +++ fgohook/fgohook.def | 2 +- hooklib/printer.c | 28 ++++++++++++++++++++-------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index dfbbdb5..1604a8d 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -26,6 +26,7 @@ #include "hook/process.h" +#include "hooklib/dll.h" #include "hooklib/dvd.h" #include "hooklib/touch.h" #include "hooklib/printer.h" @@ -65,6 +66,8 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Hook external DLL APIs */ printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod); + dll_hook_push(fgo_hook_mod, L"C330Ausb.dll"); + dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll"); /* Initialize emulation hooks */ diff --git a/fgohook/fgohook.def b/fgohook/fgohook.def index 4f769fe..3e77ccc 100644 --- a/fgohook/fgohook.def +++ b/fgohook/fgohook.def @@ -44,7 +44,7 @@ EXPORTS chcusb_selectPrinter chcusb_selectPrinterSN chcusb_getPrinterInfo - chcusb_imageformat + chcusb_imageformat=chcusb_imageformat_330 chcusb_setmtf chcusb_makeGamma chcusb_setIcctable diff --git a/hooklib/printer.c b/hooklib/printer.c index 121ee3d..010e75a 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -89,13 +89,14 @@ int WINAPI chcusb_listupPrinterSN(uint64_t *rSerialArray); int WINAPI chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); int WINAPI chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); -int WINAPI chcusb_imageformat( - uint16_t format, - uint16_t ncomp, - uint16_t depth, - uint16_t width, - uint16_t height, - uint16_t *rResult); +int WINAPI chcusb_imageformat(uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint8_t * image, uint16_t* rResult); +int WINAPI chcusb_imageformat_330( + uint16_t format, + uint16_t ncomp, + uint16_t depth, + uint16_t width, + uint16_t height, + uint16_t *rResult); int __thiscall chcusb_setmtf(int32_t *mtf); int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); int WINAPI chcusb_setIcctable( @@ -2302,6 +2303,17 @@ int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t } int WINAPI chcusb_imageformat( + uint16_t format, + uint16_t ncomp, + uint16_t depth, + uint16_t width, + uint16_t height, + uint8_t *image, + uint16_t *rResult) { + return chcusb_imageformat_330(format, ncomp, depth, width, height, rResult); +} + +int WINAPI chcusb_imageformat_330( uint16_t format, uint16_t ncomp, uint16_t depth, @@ -2994,7 +3006,7 @@ int CHCUSB_getPrinterToneCurve(const void *handle, uint16_t type, uint16_t numbe int CHCUSB_imageformat(const void *handle, uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint8_t *inputImage, uint16_t *rResult) { - return chcusb_imageformat(format, ncomp, depth, width, height, rResult); + return chcusb_imageformat(format, ncomp, depth, width, height, inputImage, rResult); } int CHCUSB_init(LPCSTR dllpath) From 88a5bdcd14bac85e8f151f1f98dee9a46ca71c94 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:57:37 +0200 Subject: [PATCH 147/204] kemono: only load I/O dll inside amdaemon --- kemonohook/config.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/kemonohook/config.c b/kemonohook/config.c index d1097be..3eb85c8 100644 --- a/kemonohook/config.c +++ b/kemonohook/config.c @@ -12,19 +12,44 @@ #include "platform/config.h" +// Check windows +#if _WIN32 || _WIN64 + #if _WIN64 + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + +// Check GCC +#if __GNUC__ + #if __x86_64__ || __ppc64__ + #define ENV64BIT + #else + #define ENV32BIT + #endif +#endif + void kemono_dll_config_load( struct kemono_dll_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"kemonoio", - L"path", - L"", - cfg->path, - _countof(cfg->path), - filename); + #if defined(ENV32BIT) + // Always empty, due to amdaemon being 64 bit in 32 bit mode + memset(cfg->path, 0, sizeof(cfg->path)); + #elif defined(ENV64BIT) + GetPrivateProfileStringW( + L"kemonoio", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); + #else + #error "Unknown environment" + #endif } void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) From 4fa9abffe80332d77b85c3b5fa05609c5b49105e Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:57:35 +0200 Subject: [PATCH 148/204] printer: add ability to delay printing --- hooklib/config.c | 2 ++ hooklib/printer.c | 35 +++++++++++++++++++++++++++-------- hooklib/printer.h | 1 + 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/hooklib/config.c b/hooklib/config.c index 584d146..d9db805 100644 --- a/hooklib/config.c +++ b/hooklib/config.c @@ -80,4 +80,6 @@ void printer_config_load(struct printer_config *cfg, const wchar_t *filename) cfg->printer_out_path, _countof(cfg->printer_out_path), filename); + + cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename); } diff --git a/hooklib/printer.c b/hooklib/printer.c index 010e75a..cc3070d 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -58,6 +58,7 @@ static int32_t MTF[9]; /* Printer status */ static uint8_t STATUS = 0; +static ULONGLONG finishTime = 0; /* C3XXFWDLusb API hooks */ @@ -1244,6 +1245,10 @@ void printer_hook_insert_hooks(HMODULE target) { proc_addr_table_push(target, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); } +static inline bool check_for_wait_time(){ + return finishTime > 0 && GetTickCount64() < finishTime; +} + static void generate_rfid(void) { for (int i = 0; i < sizeof(cardRFID); i++) cardRFID[i] = rand(); @@ -2403,7 +2408,11 @@ int WINAPI chcusb_copies(uint16_t copies, uint16_t *rResult) { int WINAPI chcusb_status(uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); - *rResult = 0; + if (check_for_wait_time()) { + *rResult = 2203; + } else { + *rResult = 0; + } return 1; } @@ -2439,6 +2448,10 @@ int WINAPI chcusb_startpage_300(uint16_t postCardState, uint16_t *rResult) { int WINAPI chcusb_endpage(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); + if (printer_config.wait_time > 0){ + finishTime = GetTickCount64() + printer_config.wait_time; + dprintf("Printer: Waiting for %dms...\n", printer_config.wait_time); + } awaitingCardExit = true; *rResult = 0; @@ -2622,13 +2635,12 @@ int WINAPI chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t * // dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 8); - if (STATUS > 1) - { + if (check_for_wait_time()) { + *((uint16_t*)(rBuffer + 6)) = 2203; + } else if (STATUS > 1) { STATUS = 0; *((uint16_t*)(rBuffer + 6)) = 2212; - } - else - { + } else { *((uint16_t*)(rBuffer + 6)) = 2300; } @@ -2658,6 +2670,7 @@ int WINAPI chcusb_setPrintStandby_300(uint16_t *rResult) { *rResult = 0; if (awaitingCardExit){ // 300 does not use exitCard, so reset this for getPrinterInfo. awaitingCardExit = false; + finishTime = 0; STATUS = 1; } if (STATUS == 0) @@ -2677,8 +2690,14 @@ int WINAPI chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) int WINAPI chcusb_exitCard(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); - awaitingCardExit = false; - generate_rfid(); + if (check_for_wait_time()) { + *rResult = 2203; + return 0; + } else { + awaitingCardExit = false; + finishTime = 0; + generate_rfid(); + } *rResult = 0; return 1; diff --git a/hooklib/printer.h b/hooklib/printer.h index d376964..3e451d1 100644 --- a/hooklib/printer.h +++ b/hooklib/printer.h @@ -12,6 +12,7 @@ struct printer_config { wchar_t dsp_fw_path[MAX_PATH]; wchar_t param_fw_path[MAX_PATH]; wchar_t printer_out_path[MAX_PATH]; + uint32_t wait_time; }; void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self); From 33452394e63397543214add35e5e0bb7d8d280a2 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:09:52 +0200 Subject: [PATCH 149/204] kemono: also only load aimeio dll in x64 process --- kemonohook/dllmain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c index 42b2b68..5eac13d 100644 --- a/kemonohook/dllmain.c +++ b/kemonohook/dllmain.c @@ -34,6 +34,7 @@ static DWORD CALLBACK kemono_pre_startup(void) { /* Load config */ + kemono_hook_cfg.aime.dll.path64 = true; kemono_hook_config_load(&kemono_hook_cfg, L".\\segatools.ini"); /* Hook Win32 APIs */ From c06bb408e74e9364fcc83bf5e7a7d3151b1796cd Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 30 Sep 2024 18:50:46 +0200 Subject: [PATCH 150/204] idac: add ffb emulation --- board/config.c | 8 + board/config.h | 2 + board/ffb.c | 234 +++++++++++++++++++++ board/ffb.h | 20 ++ board/meson.build | 2 + dist/idac/segatools.ini | 26 ++- hooklib/printer.c | 2 +- idachook/config.c | 1 + idachook/config.h | 1 + idachook/dllmain.c | 7 + idachook/ffb.c | 59 ++++++ idachook/ffb.h | 7 + idachook/idac-dll.c | 17 +- idachook/idac-dll.h | 5 + idachook/idachook.def | 5 + idachook/meson.build | 2 + idacio/backend.h | 5 + idacio/config.c | 26 ++- idacio/config.h | 6 +- idacio/di-dev.c | 446 +++++++++++++++++++++++++++++----------- idacio/di-dev.h | 13 +- idacio/di.c | 37 ++-- idacio/dllmain.c | 39 +++- idacio/idacio.def | 5 + idacio/idacio.h | 49 +++++ idacio/xi.c | 55 ++++- 26 files changed, 930 insertions(+), 149 deletions(-) create mode 100644 board/ffb.c create mode 100644 board/ffb.h create mode 100644 idachook/ffb.c create mode 100644 idachook/ffb.h diff --git a/board/config.c b/board/config.c index c1cd713..95eeecf 100644 --- a/board/config.c +++ b/board/config.c @@ -93,3 +93,11 @@ void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename); cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename); } + +void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"ffb", L"enable", 1, filename); +} diff --git a/board/config.h b/board/config.h index 37b5b14..34977dc 100644 --- a/board/config.h +++ b/board/config.h @@ -6,7 +6,9 @@ #include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" +#include "board/ffb.h" void aime_config_load(struct aime_config *cfg, const wchar_t *filename); void io4_config_load(struct io4_config *cfg, const wchar_t *filename); void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename); +void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename); diff --git a/board/ffb.c b/board/ffb.c new file mode 100644 index 0000000..48e15ad --- /dev/null +++ b/board/ffb.c @@ -0,0 +1,234 @@ +/* + Force Feedback Board (FFB) + + This board is used by many SEGA games to provide force feedback to the player. + It is driven by the game software over a serial connection and is used by many + games such as SEGA World Drivers Championship, Initial D Arcade, ... + + Part number in schematics is "838-15069 MOTOR DRIVE BD RS232/422 Board". + + Some observations: + The maximal strength for any effect is 127, except Damper which maxes out at 40. + The period for rumble effects is in the range 0-40. +*/ + +#include "board/ffb.h" + +#include +#include +#include + +#include "hook/iohook.h" +#include "hooklib/uart.h" +#include "util/dprintf.h" +#include "util/dump.h" + + +// request format: +// 0x?? - sync + command +// 0x?? - direction/additional command +// 0x?? - strength +// 0x?? - checksum (sum of everything except the sync byte) + +enum { + FFB_CMD_TOGGLE = 0x80, + FFB_CMD_CONSTANT_FORCE = 0x84, + FFB_CMD_RUMBLE = 0x85, + FFB_CMD_DAMPER = 0x86, +}; + +struct ffb_hdr { + uint8_t cmd; +}; + +union ffb_req_any { + struct ffb_hdr hdr; + uint8_t bytes[3]; +}; + +static HRESULT ffb_handle_irp(struct irp *irp); + +static HRESULT ffb_req_dispatch(const union ffb_req_any *req); +static HRESULT ffb_req_toggle(const uint8_t *bytes); +static HRESULT ffb_req_constant_force(const uint8_t *bytes); +static HRESULT ffb_req_rumble(const uint8_t *bytes); +static HRESULT ffb_req_damper(const uint8_t *bytes); + +static const struct ffb_ops *ffb_ops; +static struct uart ffb_uart; + +static bool ffb_started; +static HRESULT ffb_start_hr; +static uint8_t ffb_written[4]; +static uint8_t ffb_readable[4]; + +/* Static variables to store maximum strength values */ +static uint8_t max_constant_force = 0; +static uint8_t max_rumble = 0; +static uint8_t max_period = 0; +static uint8_t max_damper = 0; + +HRESULT ffb_hook_init( + const struct ffb_config *cfg, + const struct ffb_ops *ops, + unsigned int port_no) +{ + assert(cfg != NULL); + assert(ops != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + ffb_ops = ops; + + uart_init(&ffb_uart, port_no); + ffb_uart.written.bytes = ffb_written; + ffb_uart.written.nbytes = sizeof(ffb_written); + ffb_uart.readable.bytes = ffb_readable; + ffb_uart.readable.nbytes = sizeof(ffb_readable); + + dprintf("FFB: hook enabled.\n"); + + return iohook_push_handler(ffb_handle_irp); +} + +static HRESULT ffb_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + if (!uart_match_irp(&ffb_uart, irp)) { + return iohook_invoke_next(irp); + } + + hr = uart_handle_irp(&ffb_uart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + assert(&ffb_uart.written != NULL); + assert(ffb_uart.written.bytes != NULL || ffb_uart.written.nbytes == 0); + assert(ffb_uart.written.pos <= ffb_uart.written.nbytes); + + // dprintf("FFB TX:\n"); + + hr = ffb_req_dispatch((const union ffb_req_any *) ffb_uart.written.bytes); + + if (FAILED(hr)) { + dprintf("FFB: Processing error: %x\n", (int)hr); + } + + // dump_iobuf(&ffb_uart.written); + ffb_uart.written.pos = 0; + + return hr; +} + +static HRESULT ffb_req_dispatch(const union ffb_req_any *req) +{ + switch (req->hdr.cmd) { + case FFB_CMD_TOGGLE: + return ffb_req_toggle(req->bytes); + case FFB_CMD_CONSTANT_FORCE: + return ffb_req_constant_force(req->bytes); + case FFB_CMD_RUMBLE: + return ffb_req_rumble(req->bytes); + case FFB_CMD_DAMPER: + return ffb_req_damper(req->bytes); + /* There are some test mode specfic commands which doesn't seem to be used in + game at all. The same is true for the initialization phase. */ + + default: + dprintf("FFB: Unhandled command %02x\n", req->hdr.cmd); + + return S_OK; + } +} + +static HRESULT ffb_req_toggle(const uint8_t *bytes) +{ + uint8_t activate = bytes[2]; + + if (activate == 0x01) { + dprintf("FFB: Activated\n"); + } else { + dprintf("FFB: Deactivated\n"); + } + + if (ffb_ops->toggle != NULL) { + ffb_ops->toggle(activate == 0x01); + } + + return S_OK; +} + +static HRESULT ffb_req_constant_force(const uint8_t *bytes) +{ + // dprintf("FFB: Constant force\n"); + + uint8_t direction = bytes[1]; + uint8_t force = bytes[2]; + + if (direction == 0x0) { + // Right + force = 128 - force; + } + + // Update max strength if the current force is greater + if (force > max_constant_force) { + max_constant_force = force; + } + + // dprintf("FFB: Constant Force Strength: %d (Max: %d)\n", force, max_constant_force); + if (ffb_ops->constant_force != NULL) { + ffb_ops->constant_force(direction, force); + } + + return S_OK; +} + +static HRESULT ffb_req_rumble(const uint8_t *bytes) +{ + // dprintf("FFB: Rumble\n"); + + uint8_t force = bytes[1]; + uint8_t period = bytes[2]; + + // Update max strength if the current force is greater + if (force > max_rumble) { + max_rumble = force; + } + + if (period > max_period) { + max_period = period; + } + + // dprintf("FFB: Rumble Period: %d (Min %d, Max %d), Strength: %d (Max: %d)\n", period, min_period, max_period, force, max_rumble); + if (ffb_ops->rumble != NULL) { + ffb_ops->rumble(force, period); + } + + return S_OK; +} + +static HRESULT ffb_req_damper(const uint8_t *bytes) +{ + // dprintf("FFB: Damper\n"); + + uint8_t force = bytes[2]; + + // Update max strength if the current force is greater + if (force > max_damper) { + max_damper = force; + } + + // dprintf("FFB: Damper Strength: %d (Max: %d)\n", force, max_damper); + if (ffb_ops->damper != NULL) { + ffb_ops->damper(force); + } + + return S_OK; +} diff --git a/board/ffb.h b/board/ffb.h new file mode 100644 index 0000000..af46fe3 --- /dev/null +++ b/board/ffb.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +struct ffb_config { + bool enable; +}; + +struct ffb_ops { + void (*toggle)(bool active); + void (*constant_force)(uint8_t direction, uint8_t force); + void (*rumble)(uint8_t force, uint8_t period); + void (*damper)(uint8_t force); +}; + +HRESULT ffb_hook_init( + const struct ffb_config *cfg, + const struct ffb_ops *ops, + unsigned int port_no); diff --git a/board/meson.build b/board/meson.build index b26851f..2a6cf70 100644 --- a/board/meson.build +++ b/board/meson.build @@ -50,5 +50,7 @@ board_lib = static_library( 'vfd-cmd.h', 'vfd-frame.c', 'vfd-frame.h', + 'ffb.c', + 'ffb.h' ], ) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index d4c828c..da94d64 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -75,6 +75,11 @@ dipsw3=0 dipsw4=0 dipsw5=0 +[ffb] +; Enable force feedback (838-15069) board emulation. This is required for +; both DirectInput and XInput steering wheel effects. +enable=1 + ; ----------------------------------------------------------------------------- ; LED settings ; ----------------------------------------------------------------------------- @@ -231,6 +236,21 @@ reverseAccelAxis=0 reverseBrakeAxis=0 ; Force feedback settings. -; Strength of the force feedback spring effect in percent. Possible values -; are 0-100. -centerSpringStrength=30 +; Only works when FFB board emulation is enabled! +; +; It is recommended to change the strength inside the Game Test Mode! +; +; These settings are only used when using DirectInput for the wheel. +; The values are in the range 0%-100%, where 0 disables the effect and +; 100 is the maximum. + +; Constant force strength, used for centering spring effect. +constantForceStrength=100 +; Damper strength, used for steering wheel damper effect. +damperStrength=100 + +; Rumble strength, used for road surface effects. +; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! +rumbleStrength=100 +; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. +rumbleDuration=1000 diff --git a/hooklib/printer.c b/hooklib/printer.c index 010e75a..31362dd 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -82,7 +82,7 @@ int WINAPI fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult int WINAPI chcusb_MakeThread(uint16_t maxCount); int WINAPI chcusb_open(uint16_t *rResult); -__stdcall void chcusb_close(); +void WINAPI chcusb_close(); int WINAPI chcusb_ReleaseThread(uint16_t *rResult); int WINAPI chcusb_listupPrinter(uint8_t *rIdArray); int WINAPI chcusb_listupPrinterSN(uint64_t *rSerialArray); diff --git a/idachook/config.c b/idachook/config.c index a4fe392..43455ae 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -89,6 +89,7 @@ void idac_hook_config_load( zinput_config_load(&cfg->zinput, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); + ffb_config_load(&cfg->ffb, filename); led15070_config_load(&cfg->led15070, filename); indrun_config_load(&cfg->indrun, filename); } diff --git a/idachook/config.h b/idachook/config.h index b7ca6d3..baae2e5 100644 --- a/idachook/config.h +++ b/idachook/config.h @@ -19,6 +19,7 @@ struct idac_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct ffb_config ffb; struct idac_dll_config dll; struct zinput_config zinput; struct led15070_config led15070; diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 63b0954..3336690 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -28,6 +28,7 @@ #include "idachook/config.h" #include "idachook/idac-dll.h" #include "idachook/io4.h" +#include "idachook/ffb.h" #include "idachook/zinput.h" #include "platform/platform.h" @@ -84,6 +85,12 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } + hr = idac_ffb_hook_init(&idac_hook_cfg.ffb, 1); + + if (FAILED(hr)) { + goto fail; + } + hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init, idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1); diff --git a/idachook/ffb.c b/idachook/ffb.c new file mode 100644 index 0000000..8befaa6 --- /dev/null +++ b/idachook/ffb.c @@ -0,0 +1,59 @@ +#include + +#include +#include +#include +#include + +#include "board/ffb.h" + +#include "idachook/idac-dll.h" + +#include "util/dprintf.h" + +static void idac_ffb_toggle(bool active); +static void idac_ffb_constant_force(uint8_t direction, uint8_t force); +static void idac_ffb_rumble(uint8_t force, uint8_t period); +static void idac_ffb_damper(uint8_t force); + +static const struct ffb_ops idac_ffb_ops = { + .toggle = idac_ffb_toggle, + .constant_force = idac_ffb_constant_force, + .rumble = idac_ffb_rumble, + .damper = idac_ffb_damper +}; + +HRESULT idac_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no) +{ + HRESULT hr; + + assert(idac_dll.init != NULL); + + hr = ffb_hook_init(cfg, &idac_ffb_ops, port_no); + + if (FAILED(hr)) { + return hr; + } + + return idac_dll.ffb_init(); +} + +static void idac_ffb_toggle(bool active) +{ + idac_dll.ffb_toggle(active); +} + +static void idac_ffb_constant_force(uint8_t direction, uint8_t force) +{ + idac_dll.ffb_constant_force(direction, force); +} + +static void idac_ffb_rumble(uint8_t force, uint8_t period) +{ + idac_dll.ffb_rumble(force, period); +} + +static void idac_ffb_damper(uint8_t force) +{ + idac_dll.ffb_damper(force); +} diff --git a/idachook/ffb.h b/idachook/ffb.h new file mode 100644 index 0000000..aff0d2d --- /dev/null +++ b/idachook/ffb.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/ffb.h" + +HRESULT idac_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no); diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c index 3019608..5b09d91 100644 --- a/idachook/idac-dll.c +++ b/idachook/idac-dll.c @@ -36,7 +36,22 @@ const struct dll_bind_sym idac_dll_syms[] = { }, { .sym = "idac_io_led_set_leds", .off = offsetof(struct idac_dll, led_set_leds), - } + }, { + .sym = "idac_io_ffb_init", + .off = offsetof(struct idac_dll, ffb_init), + }, { + .sym = "idac_io_ffb_toggle", + .off = offsetof(struct idac_dll, ffb_toggle), + }, { + .sym = "idac_io_ffb_constant_force", + .off = offsetof(struct idac_dll, ffb_constant_force), + }, { + .sym = "idac_io_ffb_rumble", + .off = offsetof(struct idac_dll, ffb_rumble), + }, { + .sym = "idac_io_ffb_damper", + .off = offsetof(struct idac_dll, ffb_damper), + }, }; struct idac_dll idac_dll; diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h index acdce35..88ac299 100644 --- a/idachook/idac-dll.h +++ b/idachook/idac-dll.h @@ -15,6 +15,11 @@ struct idac_dll { void (*led_set_fet_output)(const uint8_t *rgb); void (*led_gs_update)(const uint8_t *rgb); void (*led_set_leds)(const uint8_t *rgb); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; struct idac_dll_config { diff --git a/idachook/idachook.def b/idachook/idachook.def index 32cdffc..4653c37 100644 --- a/idachook/idachook.def +++ b/idachook/idachook.def @@ -21,3 +21,8 @@ EXPORTS idac_io_led_set_fet_output idac_io_led_gs_update idac_io_led_set_leds + idac_io_ffb_init + idac_io_ffb_toggle + idac_io_ffb_constant_force + idac_io_ffb_rumble + idac_io_ffb_damper diff --git a/idachook/meson.build b/idachook/meson.build index 8de655e..66e8602 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -30,5 +30,7 @@ shared_library( 'zinput.h', 'indrun.c', 'indrun.h', + 'ffb.c', + 'ffb.h', ], ) diff --git a/idacio/backend.h b/idacio/backend.h index b9833a1..ee65fae 100644 --- a/idacio/backend.h +++ b/idacio/backend.h @@ -9,4 +9,9 @@ struct idac_io_backend { void (*get_gamebtns)(uint8_t *gamebtn); void (*get_shifter)(uint8_t *gear); void (*get_analogs)(struct idac_io_analog_state *state); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; diff --git a/idacio/config.c b/idacio/config.c index 6bf6996..f862840 100644 --- a/idacio/config.c +++ b/idacio/config.c @@ -80,13 +80,29 @@ void idac_di_config_load(struct idac_di_config *cfg, const wchar_t *filename) } // FFB configuration + cfg->ffb_constant_force_strength = GetPrivateProfileIntW( + L"dinput", + L"constantForceStrength", + 100, + filename); - cfg->center_spring_strength = GetPrivateProfileIntW( - L"dinput", - L"centerSpringStrength", - 30, - filename); + cfg->ffb_rumble_strength = GetPrivateProfileIntW( + L"dinput", + L"rumbleStrength", + 100, + filename); + cfg->ffb_damper_strength = GetPrivateProfileIntW( + L"dinput", + L"damperStrength", + 100, + filename); + + cfg->ffb_rumble_duration = GetPrivateProfileIntW( + L"dinput", + L"rumbleDuration", + 1000, + filename); } void idac_xi_config_load(struct idac_xi_config *cfg, const wchar_t *filename) diff --git a/idacio/config.h b/idacio/config.h index bbf568d..88a1d6a 100644 --- a/idacio/config.h +++ b/idacio/config.h @@ -25,7 +25,11 @@ struct idac_di_config { bool reverse_accel_axis; // FFB configuration - uint16_t center_spring_strength; + uint8_t ffb_constant_force_strength; + uint8_t ffb_rumble_strength; + uint8_t ffb_damper_strength; + + uint32_t ffb_rumble_duration; }; struct idac_xi_config { diff --git a/idacio/di-dev.c b/idacio/di-dev.c index 62cab2f..a8b6e0b 100644 --- a/idacio/di-dev.c +++ b/idacio/di-dev.c @@ -1,134 +1,39 @@ #include #include - +#include #include #include "idacio/di-dev.h" #include "util/dprintf.h" -HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +const struct idac_di_config *idac_di_cfg; +static HWND idac_di_wnd; +static IDirectInputDevice8W *idac_di_dev; + +/* Individual DI Effects */ +static IDirectInputEffect *idac_di_fx; +static IDirectInputEffect *idac_di_fx_rumble; +static IDirectInputEffect *idac_di_fx_damper; + +/* Max FFB Board value is 127 */ +static const double idac_di_ffb_scale = 127.0; + +HRESULT idac_di_dev_init( + const struct idac_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd) { HRESULT hr; assert(dev != NULL); assert(wnd != NULL); - hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + idac_di_cfg = cfg; + idac_di_dev = dev; + idac_di_wnd = wnd; - if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); - - if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_Acquire(dev); - - if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - - return hr; - } - - return hr; -} - -void idac_di_dev_start_fx( - IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) -{ - /* Set up force-feedback on devices that support it. This is just a stub - for the time being, since we don't yet know how the serial port force - feedback protocol works. - - I'm currently developing with an Xbox One Thrustmaster TMX wheel, if - we don't perform at least some perfunctory FFB initialization of this - nature (or indeed if no DirectInput application is running) then the - wheel exhibits considerable resistance, similar to that of a stationary - car. Changing cf.lMagnitude to a nonzero value does cause the wheel to - continuously turn in the given direction with the given force as one - would expect (max magnitude per DirectInput docs is +/- 10000). - - Failure here is non-fatal, we log any errors and move on. - - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) - */ - - IDirectInputEffect *obj; - DWORD axis; - LONG direction; - DIEFFECT fx; - DICONDITION cond; - HRESULT hr; - - assert(dev != NULL); - assert(out != NULL); - - *out = NULL; - - dprintf("DirectInput: Starting force feedback (may take a sec)\n"); - - // Auto-centering effect - axis = DIJOFS_X; - direction = 0; - - memset(&cond, 0, sizeof(cond)); - cond.lOffset = 0; - cond.lPositiveCoefficient = strength; - cond.lNegativeCoefficient = strength; - cond.dwPositiveSaturation = strength; // For FG920? - cond.dwNegativeSaturation = strength; // For FG920? - cond.lDeadBand = 0; - - memset(&fx, 0, sizeof(fx)); - fx.dwSize = sizeof(fx); - fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = INFINITE; - fx.dwGain = DI_FFNOMINALMAX; - fx.dwTriggerButton = DIEB_NOTRIGGER; - fx.dwTriggerRepeatInterval = INFINITE; - fx.cAxes = 1; - fx.rgdwAxes = &axis; - fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cond); - fx.lpvTypeSpecificParams = &cond; - - hr = IDirectInputDevice8_CreateEffect( - dev, - &GUID_Spring, - &fx, - &obj, - NULL); - - if (FAILED(hr)) { - dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", - (int) hr); - return; - } - - hr = IDirectInputEffect_Start(obj, INFINITE, 0); - - if (FAILED(hr)) { - IDirectInputEffect_Release(obj); - dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", - (int) hr); - return; - } - - *out = obj; - - dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", - strength / 100); + return S_OK; } HRESULT idac_di_dev_poll( @@ -167,3 +72,312 @@ HRESULT idac_di_dev_poll( return hr; } + +HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +HRESULT idac_di_ffb_init(void) +{ + HRESULT hr; + + hr = idac_di_dev_start(idac_di_dev, idac_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +void idac_di_ffb_toggle(bool active) +{ + if (active) { + return; + } + + /* Stop and release all effects */ + /* I never programmed DirectInput Effects, so this might be bad practice. */ + if (idac_di_fx != NULL) { + IDirectInputEffect_Stop(idac_di_fx); + IDirectInputEffect_Release(idac_di_fx); + idac_di_fx = NULL; + } + + if (idac_di_fx_rumble != NULL) { + IDirectInputEffect_Stop(idac_di_fx_rumble); + IDirectInputEffect_Release(idac_di_fx_rumble); + idac_di_fx_rumble = NULL; + } + + if (idac_di_fx_damper != NULL) { + IDirectInputEffect_Stop(idac_di_fx_damper); + IDirectInputEffect_Release(idac_di_fx_damper); + idac_di_fx_damper = NULL; + } +} + +void idac_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idac_di_cfg->ffb_constant_force_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + /* Direction 0: move to the right, 1: move to the left */ + LONG magnitude = (LONG)(((double)force / idac_di_ffb_scale) * ffb_strength); + cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; + + axis = DIJOFS_X; + /* Irrelevant as magnitude descripbes the direction */ + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + if (idac_di_fx != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idac_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idac_di_fx); + IDirectInputEffect_Release(idac_di_fx); + idac_di_fx = NULL; + } + } + + // Create a new constant force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idac_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idac_di_fx = obj; +} + +void idac_di_ffb_rumble(uint8_t force, uint8_t period) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idac_di_cfg->ffb_rumble_strength * 100; + if (ffb_strength == 0) { + return; + } + + uint32_t ffb_duration = idac_di_cfg->ffb_rumble_duration; + + DWORD axis; + LONG direction; + DIEFFECT fx; + DIPERIODIC pe; + HRESULT hr; + + /* Duration in microseconds, + Might be totally wrong as especially on FANATEC wheels as this code will + crash the game. TODO: Figure out why this effect will crash on FANATEC! */ + DWORD duration = (DWORD)((double)force * ffb_duration); + + memset(&pe, 0, sizeof(pe)); + pe.dwMagnitude = (DWORD)(((double)force / idac_di_ffb_scale) * ffb_strength); + pe.lOffset = 0; + pe.dwPhase = 0; + pe.dwPeriod = duration; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = duration; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(pe); + fx.lpvTypeSpecificParams = &pe; + + if (idac_di_fx_rumble != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idac_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idac_di_fx_rumble); + IDirectInputEffect_Release(idac_di_fx_rumble); + idac_di_fx_rumble = NULL; + } + } + + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idac_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idac_di_fx_rumble = obj; +} + +void idac_di_ffb_damper(uint8_t force) +{ + /* DI expects a coefficient in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idac_di_cfg->ffb_damper_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONDITION cond; + HRESULT hr; + + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = (LONG)(((double)force / idac_di_ffb_scale) * ffb_strength); + cond.lNegativeCoefficient = (LONG)(((double)force / idac_di_ffb_scale) * ffb_strength); + /* Not sure on this one */ + cond.dwPositiveSaturation = DI_FFNOMINALMAX; + cond.dwNegativeSaturation = DI_FFNOMINALMAX; + cond.lDeadBand = 0; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; + + if (idac_di_fx_damper != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idac_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idac_di_fx_damper); + IDirectInputEffect_Release(idac_di_fx_damper); + idac_di_fx_damper = NULL; + } + } + + // Create a new damper force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idac_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idac_di_fx_damper = obj; +} diff --git a/idacio/di-dev.h b/idacio/di-dev.h index b1559e3..f26b802 100644 --- a/idacio/di-dev.h +++ b/idacio/di-dev.h @@ -5,15 +5,26 @@ #include +#include "idacio/config.h" + union idac_di_state { DIJOYSTATE st; uint8_t bytes[sizeof(DIJOYSTATE)]; }; +HRESULT idac_di_dev_init( + const struct idac_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd); + HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void idac_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT idac_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, union idac_di_state *out); +HRESULT idac_di_ffb_init(void); +void idac_di_ffb_toggle(bool active); +void idac_di_ffb_constant_force(uint8_t direction, uint8_t force); +void idac_di_ffb_rumble(uint8_t force, uint8_t period); +void idac_di_ffb_damper(uint8_t force); diff --git a/idacio/di.c b/idacio/di.c index 55018e8..fb50ed1 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -52,9 +52,14 @@ static const struct idac_di_axis idac_di_axes[] = { }; static const struct idac_io_backend idac_di_backend = { - .get_gamebtns = idac_di_get_buttons, - .get_shifter = idac_di_get_shifter, - .get_analogs = idac_di_get_analogs, + .get_gamebtns = idac_di_get_buttons, + .get_shifter = idac_di_get_shifter, + .get_analogs = idac_di_get_analogs, + .ffb_init = idac_di_ffb_init, + .ffb_toggle = idac_di_ffb_toggle, + .ffb_constant_force = idac_di_ffb_constant_force, + .ffb_rumble = idac_di_ffb_rumble, + .ffb_damper = idac_di_ffb_damper }; static HWND idac_di_wnd; @@ -62,7 +67,6 @@ static IDirectInput8W *idac_di_api; static IDirectInputDevice8W *idac_di_dev; static IDirectInputDevice8W *idac_di_pedals; static IDirectInputDevice8W *idac_di_shifter; -static IDirectInputEffect *idac_di_fx; static size_t idac_di_off_brake; static size_t idac_di_off_accel; static uint8_t idac_di_shift_dn; @@ -105,7 +109,7 @@ HRESULT idac_di_init( return hr; } - /* Initial D Zero has some built-in DirectInput support that is not + /* Initial D THE ARCADE has some built-in DirectInput support that is not particularly useful. idachook shorts this out by redirecting dinput8.dll to a no-op implementation of DirectInput. However, idacio does need to talk to the real operating system implementation of DirectInput without @@ -168,16 +172,12 @@ HRESULT idac_di_init( return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } - hr = idac_di_dev_start(idac_di_dev, idac_di_wnd); + hr = idac_di_dev_init(cfg, idac_di_dev, idac_di_wnd); if (FAILED(hr)) { return hr; } - // Convert the strength from 0-100 to 0-10000 for DirectInput - idac_di_dev_start_fx(idac_di_dev, &idac_di_fx, - idac_di_center_spring_strength * 100); - if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( idac_di_api, @@ -367,15 +367,24 @@ static HRESULT idac_di_config_apply(const struct idac_di_config *cfg) idac_di_gear[i] = cfg->gear[i]; } - // FFB configuration + /* FFB configuration */ + if (cfg->ffb_constant_force_strength < 0 || cfg->ffb_constant_force_strength > 100) { + dprintf("Wheel: Invalid constant force strength: %i\n", cfg->ffb_constant_force_strength); - if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { - dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + return E_INVALIDARG; + } + + if (cfg->ffb_rumble_strength < 0 || cfg->ffb_rumble_strength > 100) { + dprintf("Wheel: Invalid rumble strength: %i\n", cfg->ffb_rumble_strength); return E_INVALIDARG; } - idac_di_center_spring_strength = cfg->center_spring_strength; + if (cfg->ffb_damper_strength < 0 || cfg->ffb_damper_strength > 100) { + dprintf("Wheel: Invalid damper strength: %i\n", cfg->ffb_damper_strength); + + return E_INVALIDARG; + } return S_OK; } diff --git a/idacio/dllmain.c b/idacio/dllmain.c index fbdc7d8..f295f90 100644 --- a/idacio/dllmain.c +++ b/idacio/dllmain.c @@ -19,7 +19,7 @@ static bool idac_io_coin; uint16_t idac_io_get_api_version(void) { - return 0x0101; + return 0x0102; } HRESULT idac_io_init(void) @@ -62,6 +62,8 @@ void idac_io_get_opbtns(uint8_t *opbtn_out) opbtn = 0; + /* Common operator buttons, not backend-specific */ + if (GetAsyncKeyState(idac_io_cfg.vk_test) & 0x8000) { opbtn |= IDAC_IO_OPBTN_TEST; } @@ -159,3 +161,38 @@ void idac_io_led_set_leds(const uint8_t *rgb) return; } + +HRESULT idac_io_ffb_init(void) +{ + assert(idac_io_backend != NULL); + + return idac_io_backend->ffb_init(); +} + +void idac_io_ffb_toggle(bool active) +{ + assert(idac_io_backend != NULL); + + idac_io_backend->ffb_toggle(active); +} + +void idac_io_ffb_constant_force(uint8_t direction, uint8_t force) +{ + assert(idac_io_backend != NULL); + + idac_io_backend->ffb_constant_force(direction, force); +} + +void idac_io_ffb_rumble(uint8_t period, uint8_t force) +{ + assert(idac_io_backend != NULL); + + idac_io_backend->ffb_rumble(period, force); +} + +void idac_io_ffb_damper(uint8_t force) +{ + assert(idac_io_backend != NULL); + + idac_io_backend->ffb_damper(force); +} diff --git a/idacio/idacio.def b/idacio/idacio.def index 6b447ac..f60bacf 100644 --- a/idacio/idacio.def +++ b/idacio/idacio.def @@ -10,3 +10,8 @@ EXPORTS idac_io_led_set_fet_output idac_io_led_gs_update idac_io_led_set_leds + idac_io_ffb_init + idac_io_ffb_toggle + idac_io_ffb_constant_force + idac_io_ffb_rumble + idac_io_ffb_damper diff --git a/idacio/idacio.h b/idacio/idacio.h index 5e36b5b..513c9d1 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -2,6 +2,7 @@ #include +#include #include enum { @@ -160,3 +161,51 @@ void idac_io_led_gs_update(const uint8_t *rgb); Minimum API version: 0x0101 */ void idac_io_led_set_leds(const uint8_t *rgb); + +/* Initialize FFB emulation. This function will be called before any + other idac_io_ffb_*() function calls. + + This will always be called even if FFB board emulation is disabled to allow + the IO DLL to initialize any necessary resources. + + Minimum API version: 0x0102 */ + +HRESULT idac_io_ffb_init(void); + +/* Toggle FFB emulation. If active is true, FFB emulation should be enabled. + If active is false, FFB emulation should be disabled and all FFB effects + should be stopped and released. + + Minimum API version: 0x0102 */ + +void idac_io_ffb_toggle(bool active); + +/* Set a constant force FFB effect. + + Direction is 0 for right and 1 for left. + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force in a given direction. + + Minimum API version: 0x0102 */ + +void idac_io_ffb_constant_force(uint8_t direction, uint8_t force); + +/* Set a (sine) periodic force FFB effect. + + Period is the period of the effect in milliseconds (not sure). + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force. + + Minimum API version: 0x0102 */ + +void idac_io_ffb_rumble(uint8_t period, uint8_t force); + +/* Set a damper FFB effect. + + Force is the magnitude of the force, where 0 is no force and 40 is the + maximum force. Theoretically the maximum force is 127, but the game only + uses a maximum of 40. + + Minimum API version: 0x0102 */ + +void idac_io_ffb_damper(uint8_t force); diff --git a/idacio/xi.c b/idacio/xi.c index c924153..e695561 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -1,5 +1,3 @@ -#include "idacio/xi.h" - #include #include #include @@ -7,22 +5,35 @@ #include #include +#include "idacio/xi.h" #include "idacio/backend.h" #include "idacio/config.h" #include "idacio/idacio.h" #include "idacio/shifter.h" + #include "util/dprintf.h" static void idac_xi_get_gamebtns(uint8_t *gamebtn_out); static void idac_xi_get_shifter(uint8_t *gear); static void idac_xi_get_analogs(struct idac_io_analog_state *out); +static HRESULT idac_xi_ffb_init(void); +static void idac_xi_ffb_toggle(bool active); +static void idac_xi_ffb_constant_force(uint8_t direction, uint8_t force); +static void idac_xi_ffb_rumble(uint8_t force, uint8_t period); +static void idac_xi_ffb_damper(uint8_t force); + static HRESULT idac_xi_config_apply(const struct idac_xi_config *cfg); static const struct idac_io_backend idac_xi_backend = { - .get_gamebtns = idac_xi_get_gamebtns, - .get_shifter = idac_xi_get_shifter, - .get_analogs = idac_xi_get_analogs, + .get_gamebtns = idac_xi_get_gamebtns, + .get_shifter = idac_xi_get_shifter, + .get_analogs = idac_xi_get_analogs, + .ffb_init = idac_xi_ffb_init, + .ffb_toggle = idac_xi_ffb_toggle, + .ffb_constant_force = idac_xi_ffb_constant_force, + .ffb_rumble = idac_xi_ffb_rumble, + .ffb_damper = idac_xi_ffb_damper }; static bool idac_xi_single_stick_steering; @@ -46,7 +57,7 @@ HRESULT idac_xi_init(const struct idac_xi_config *cfg, const struct idac_io_back return hr; } - dprintf("XInput: Using XInput controller\n"); + dprintf("IDACIO: Using XInput controller\n"); *backend = &idac_xi_backend; return S_OK; @@ -205,3 +216,35 @@ static void idac_xi_get_analogs(struct idac_io_analog_state *out) { out->accel = xi.Gamepad.bRightTrigger << 8; out->brake = xi.Gamepad.bLeftTrigger << 8; } + +static HRESULT idac_xi_ffb_init(void) { + return S_OK; +} + +static void idac_xi_ffb_toggle(bool active) { + XINPUT_VIBRATION vibration; + + memset(&vibration, 0, sizeof(vibration)); + + XInputSetState(0, &vibration); +} + +static void idac_xi_ffb_constant_force(uint8_t direction, uint8_t force) { + return; +} + +static void idac_xi_ffb_rumble(uint8_t force, uint8_t period) { + XINPUT_VIBRATION vibration; + /* XInput max strength is 65.535, so multiply the 127.0 by 516. */ + uint16_t strength = force * 516; + + memset(&vibration, 0, sizeof(vibration)); + vibration.wLeftMotorSpeed = strength; + vibration.wRightMotorSpeed = strength; + + XInputSetState(0, &vibration); +} + +static void idac_xi_ffb_damper(uint8_t force) { + return; +} From 2251585ef026da34e054b0d17238d266b7612ff2 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 30 Sep 2024 20:23:28 +0200 Subject: [PATCH 151/204] swdc: add ffb and led emulation --- dist/swdc/segatools.ini | 26 ++- idachook/idac-dll.c | 2 +- idachook/io4.c | 2 +- idacio/di.c | 1 - swdchook/config.c | 38 ++++ swdchook/config.h | 3 + swdchook/dllmain.c | 14 ++ swdchook/ffb.c | 59 ++++++ swdchook/ffb.h | 7 + swdchook/io4.c | 35 +++- swdchook/meson.build | 2 + swdchook/swdc-dll.c | 27 +++ swdchook/swdc-dll.h | 9 + swdchook/swdchook.def | 9 + swdcio/backend.h | 5 + swdcio/config.c | 27 ++- swdcio/config.h | 6 +- swdcio/di-dev.c | 446 +++++++++++++++++++++++++++++----------- swdcio/di-dev.h | 13 +- swdcio/di.c | 33 +-- swdcio/dllmain.c | 80 ++++++- swdcio/swdcio.def | 9 + swdcio/swdcio.h | 118 ++++++++++- swdcio/xi.c | 47 ++++- 24 files changed, 872 insertions(+), 146 deletions(-) create mode 100644 swdchook/ffb.c create mode 100644 swdchook/ffb.h diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 72ea69d..b6b15b8 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -65,6 +65,11 @@ enable=1 ; allow you to start a game in freeplay mode. freeplay=0 +[ffb] +; Enable force feedback (838-15069) board emulation. This is required for +; both DirectInput and XInput steering wheel effects. +enable=1 + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- @@ -181,6 +186,21 @@ reverseAccelAxis=0 reverseBrakeAxis=0 ; Force feedback settings. -; Strength of the force feedback spring effect in percent. Possible values -; are 0-100. -centerSpringStrength=30 +; Only works when FFB board emulation is enabled! +; +; It is recommended to change the strength inside the Game Test Mode! +; +; These settings are only used when using DirectInput for the wheel. +; The values are in the range 0%-100%, where 0 disables the effect and +; 100 is the maximum. + +; Constant force strength, used for centering spring effect. +constantForceStrength=100 +; Damper strength, used for steering wheel damper effect. +damperStrength=100 + +; Rumble strength, used for road surface effects. +; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! +rumbleStrength=100 +; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. +rumbleDuration=1000 diff --git a/idachook/idac-dll.c b/idachook/idac-dll.c index 5b09d91..224bca6 100644 --- a/idachook/idac-dll.c +++ b/idachook/idac-dll.c @@ -51,7 +51,7 @@ const struct dll_bind_sym idac_dll_syms[] = { }, { .sym = "idac_io_ffb_damper", .off = offsetof(struct idac_dll, ffb_damper), - }, + } }; struct idac_dll idac_dll; diff --git a/idachook/io4.c b/idachook/io4.c index 5340f5a..c13e7a5 100644 --- a/idachook/io4.c +++ b/idachook/io4.c @@ -15,7 +15,7 @@ static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len); static uint16_t coins; static const struct io4_ops idac_io4_ops = { - .poll = idac_io4_poll, + .poll = idac_io4_poll, .write_gpio = idac_io4_write_gpio }; diff --git a/idacio/di.c b/idacio/di.c index fb50ed1..5310774 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -79,7 +79,6 @@ static uint8_t idac_di_gear[6]; static bool idac_di_use_pedals; static bool idac_di_reverse_brake_axis; static bool idac_di_reverse_accel_axis; -static uint16_t idac_di_center_spring_strength; HRESULT idac_di_init( const struct idac_di_config *cfg, diff --git a/swdchook/config.c b/swdchook/config.c index 4513fd8..62115fa 100644 --- a/swdchook/config.c +++ b/swdchook/config.c @@ -13,6 +13,43 @@ #include "platform/config.h" #include "platform/platform.h" + +void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); + /* TODO: Unknown, no firmware file available */ + cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0xdead, filename); + + GetPrivateProfileStringW( + L"led15070", + L"boardNumber", + L"15070-02", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15070", + L"eepromPath", + L"DEVICE", + cfg->eeprom_path, + _countof(cfg->eeprom_path), + filename); +} + void swdc_dll_config_load( struct swdc_dll_config *cfg, const wchar_t *filename) @@ -43,6 +80,7 @@ void swdc_hook_config_load( dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); + led15070_config_load(&cfg->led15070, filename); } void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) diff --git a/swdchook/config.h b/swdchook/config.h index 587ab66..976285a 100644 --- a/swdchook/config.h +++ b/swdchook/config.h @@ -4,6 +4,7 @@ #include #include "board/config.h" +#include "board/led15070.h" #include "hooklib/dvd.h" @@ -17,7 +18,9 @@ struct swdc_hook_config { struct aime_config aime; struct dvd_config dvd; struct io4_config io4; + struct ffb_config ffb; struct vfd_config vfd; + struct led15070_config led15070; struct swdc_dll_config dll; struct zinput_config zinput; }; diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index 94d68ea..f9c6081 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -31,6 +31,7 @@ #include "swdchook/config.h" #include "swdchook/swdc-dll.h" #include "swdchook/io4.h" +#include "swdchook/ffb.h" #include "platform/platform.h" @@ -91,6 +92,19 @@ static DWORD CALLBACK swdc_pre_startup(void) goto fail; } + hr = swdc_ffb_hook_init(&swdc_hook_cfg.ffb, 1); + + if (FAILED(hr)) { + goto fail; + } + + hr = led15070_hook_init(&swdc_hook_cfg.led15070, swdc_dll.led_init, + swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, 2, 1); + + if (FAILED(hr)) { + goto fail; + } + /* Hook external DLL APIs */ zinput_hook_init(&swdc_hook_cfg.zinput); diff --git a/swdchook/ffb.c b/swdchook/ffb.c new file mode 100644 index 0000000..07c6dea --- /dev/null +++ b/swdchook/ffb.c @@ -0,0 +1,59 @@ +#include + +#include +#include +#include +#include + +#include "board/ffb.h" + +#include "swdchook/swdc-dll.h" + +#include "util/dprintf.h" + +static void swdc_ffb_toggle(bool active); +static void swdc_ffb_constant_force(uint8_t direction, uint8_t force); +static void swdc_ffb_rumble(uint8_t force, uint8_t period); +static void swdc_ffb_damper(uint8_t force); + +static const struct ffb_ops swdc_ffb_ops = { + .toggle = swdc_ffb_toggle, + .constant_force = swdc_ffb_constant_force, + .rumble = swdc_ffb_rumble, + .damper = swdc_ffb_damper +}; + +HRESULT swdc_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no) +{ + HRESULT hr; + + assert(swdc_dll.init != NULL); + + hr = ffb_hook_init(cfg, &swdc_ffb_ops, port_no); + + if (FAILED(hr)) { + return hr; + } + + return swdc_dll.ffb_init(); +} + +static void swdc_ffb_toggle(bool active) +{ + swdc_dll.ffb_toggle(active); +} + +static void swdc_ffb_constant_force(uint8_t direction, uint8_t force) +{ + swdc_dll.ffb_constant_force(direction, force); +} + +static void swdc_ffb_rumble(uint8_t force, uint8_t period) +{ + swdc_dll.ffb_rumble(force, period); +} + +static void swdc_ffb_damper(uint8_t force) +{ + swdc_dll.ffb_damper(force); +} diff --git a/swdchook/ffb.h b/swdchook/ffb.h new file mode 100644 index 0000000..53a47a4 --- /dev/null +++ b/swdchook/ffb.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/ffb.h" + +HRESULT swdc_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no); diff --git a/swdchook/io4.c b/swdchook/io4.c index d9f2198..5221f63 100644 --- a/swdchook/io4.c +++ b/swdchook/io4.c @@ -15,10 +15,12 @@ static HRESULT init_mmf(void); static void swdc_set_gamebtns(uint16_t value); static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state); +static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len); static uint16_t coins; static const struct io4_ops swdc_io4_ops = { - .poll = swdc_io4_poll, + .poll = swdc_io4_poll, + .write_gpio = swdc_io4_write_gpio }; HRESULT swdc_io4_hook_init(const struct io4_config *cfg) { @@ -172,3 +174,34 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { return S_OK; } + +static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) +{ + // Just fast fail if there aren't enough bytes in the payload + if (len < 3) + return S_OK; + + // This command is used for lights in SWDC, but it only contains button lights, + // and only in the first 3 bytes of the payload; everything else is padding to + // make the payload 62 bytes. The rest of the cabinet lights and the side button + // lights are handled separately, by the 15070 lights controller. + uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); + + // Since Sega uses an odd ordering for the first part of the bitfield, + // let's normalize the data and just send over bytes for the receiver + // to interpret as ON/OFF values. + uint8_t rgb_out[6] = { + lights_data & SWDC_IO_LED_START ? 0xFF : 0x00, + lights_data & SWDC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00, + lights_data & SWDC_IO_LED_UP ? 0xFF : 0x00, + lights_data & SWDC_IO_LED_DOWN ? 0xFF : 0x00, + lights_data & SWDC_IO_LED_RIGHT ? 0xFF : 0x00, + lights_data & SWDC_IO_LED_LEFT ? 0xFF : 0x00, + }; + + swdc_dll.led_set_leds(rgb_out); + + return S_OK; +} diff --git a/swdchook/meson.build b/swdchook/meson.build index c312ed4..786c936 100644 --- a/swdchook/meson.build +++ b/swdchook/meson.build @@ -28,5 +28,7 @@ shared_library( 'io4.h', 'zinput.c', 'zinput.h', + 'ffb.c', + 'ffb.h' ], ) diff --git a/swdchook/swdc-dll.c b/swdchook/swdc-dll.c index 80d4526..0897b73 100644 --- a/swdchook/swdc-dll.c +++ b/swdchook/swdc-dll.c @@ -21,6 +21,33 @@ const struct dll_bind_sym swdc_dll_syms[] = { }, { .sym = "swdc_io_get_analogs", .off = offsetof(struct swdc_dll, get_analogs), + }, { + .sym = "swdc_io_led_init", + .off = offsetof(struct swdc_dll, led_init), + }, { + .sym = "swdc_io_led_set_fet_output", + .off = offsetof(struct swdc_dll, led_set_fet_output), + }, { + .sym = "swdc_io_led_gs_update", + .off = offsetof(struct swdc_dll, led_gs_update), + }, { + .sym = "swdc_io_led_set_leds", + .off = offsetof(struct swdc_dll, led_set_leds), + }, { + .sym = "swdc_io_ffb_init", + .off = offsetof(struct swdc_dll, ffb_init), + }, { + .sym = "swdc_io_ffb_toggle", + .off = offsetof(struct swdc_dll, ffb_toggle), + }, { + .sym = "swdc_io_ffb_constant_force", + .off = offsetof(struct swdc_dll, ffb_constant_force), + }, { + .sym = "swdc_io_ffb_rumble", + .off = offsetof(struct swdc_dll, ffb_rumble), + }, { + .sym = "swdc_io_ffb_damper", + .off = offsetof(struct swdc_dll, ffb_damper), } }; diff --git a/swdchook/swdc-dll.h b/swdchook/swdc-dll.h index 87781c8..1b81e26 100644 --- a/swdchook/swdc-dll.h +++ b/swdchook/swdc-dll.h @@ -10,6 +10,15 @@ struct swdc_dll { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint16_t *gamebtn); void (*get_analogs)(struct swdc_io_analog_state *out); + HRESULT (*led_init)(void); + void (*led_set_fet_output)(const uint8_t *rgb); + void (*led_gs_update)(const uint8_t *rgb); + void (*led_set_leds)(const uint8_t *rgb); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; struct swdc_dll_config { diff --git a/swdchook/swdchook.def b/swdchook/swdchook.def index 160cb7d..ad4f93e 100644 --- a/swdchook/swdchook.def +++ b/swdchook/swdchook.def @@ -16,3 +16,12 @@ EXPORTS swdc_io_get_opbtns swdc_io_get_gamebtns swdc_io_get_analogs + swdc_io_led_init + swdc_io_led_set_fet_output + swdc_io_led_gs_update + swdc_io_led_set_leds + swdc_io_ffb_init + swdc_io_ffb_toggle + swdc_io_ffb_constant_force + swdc_io_ffb_rumble + swdc_io_ffb_damper diff --git a/swdcio/backend.h b/swdcio/backend.h index d30645b..85517a4 100644 --- a/swdcio/backend.h +++ b/swdcio/backend.h @@ -8,4 +8,9 @@ struct swdc_io_backend { void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint16_t *gamebtn); void (*get_analogs)(struct swdc_io_analog_state *state); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; diff --git a/swdcio/config.c b/swdcio/config.c index 131b403..4f095ce 100644 --- a/swdcio/config.c +++ b/swdcio/config.c @@ -69,12 +69,29 @@ void swdc_di_config_load(struct swdc_di_config *cfg, const wchar_t *filename) filename); // FFB configuration + cfg->ffb_constant_force_strength = GetPrivateProfileIntW( + L"dinput", + L"constantForceStrength", + 100, + filename); - cfg->center_spring_strength = GetPrivateProfileIntW( - L"dinput", - L"centerSpringStrength", - 30, - filename); + cfg->ffb_rumble_strength = GetPrivateProfileIntW( + L"dinput", + L"rumbleStrength", + 100, + filename); + + cfg->ffb_damper_strength = GetPrivateProfileIntW( + L"dinput", + L"damperStrength", + 100, + filename); + + cfg->ffb_rumble_duration = GetPrivateProfileIntW( + L"dinput", + L"rumbleDuration", + 1000, + filename); } void swdc_xi_config_load(struct swdc_xi_config *cfg, const wchar_t *filename) diff --git a/swdcio/config.h b/swdcio/config.h index ba3240c..9a630a2 100644 --- a/swdcio/config.h +++ b/swdcio/config.h @@ -21,7 +21,11 @@ struct swdc_di_config { bool reverse_accel_axis; // FFB configuration - uint16_t center_spring_strength; + uint8_t ffb_constant_force_strength; + uint8_t ffb_rumble_strength; + uint8_t ffb_damper_strength; + + uint32_t ffb_rumble_duration; }; struct swdc_xi_config { diff --git a/swdcio/di-dev.c b/swdcio/di-dev.c index 254596a..85db2fb 100644 --- a/swdcio/di-dev.c +++ b/swdcio/di-dev.c @@ -1,134 +1,39 @@ #include #include - +#include #include #include "swdcio/di-dev.h" #include "util/dprintf.h" -HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +const struct swdc_di_config *swdc_di_cfg; +static HWND swdc_di_wnd; +static IDirectInputDevice8W *swdc_di_dev; + +/* Individual DI Effects */ +static IDirectInputEffect *swdc_di_fx; +static IDirectInputEffect *swdc_di_fx_rumble; +static IDirectInputEffect *swdc_di_fx_damper; + +/* Max FFB Board value is 127 */ +static const double swdc_di_ffb_scale = 127.0; + +HRESULT swdc_di_dev_init( + const struct swdc_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd) { HRESULT hr; assert(dev != NULL); assert(wnd != NULL); - hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + swdc_di_cfg = cfg; + swdc_di_dev = dev; + swdc_di_wnd = wnd; - if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); - - if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_Acquire(dev); - - if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - - return hr; - } - - return hr; -} - -void swdc_di_dev_start_fx( - IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) -{ - /* Set up force-feedback on devices that support it. This is just a stub - for the time being, since we don't yet know how the serial port force - feedback protocol works. - - I'm currently developing with an Xbox One Thrustmaster TMX wheel, if - we don't perform at least some perfunctory FFB initialization of this - nature (or indeed if no DirectInput application is running) then the - wheel exhibits considerable resistance, similar to that of a stationary - car. Changing cf.lMagnitude to a nonzero value does cause the wheel to - continuously turn in the given direction with the given force as one - would expect (max magnitude per DirectInput docs is +/- 10000). - - Failure here is non-fatal, we log any errors and move on. - - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) - */ - - IDirectInputEffect *obj; - DWORD axis; - LONG direction; - DIEFFECT fx; - DICONDITION cond; - HRESULT hr; - - assert(dev != NULL); - assert(out != NULL); - - *out = NULL; - - dprintf("DirectInput: Starting force feedback (may take a sec)\n"); - - // Auto-centering effect - axis = DIJOFS_X; - direction = 0; - - memset(&cond, 0, sizeof(cond)); - cond.lOffset = 0; - cond.lPositiveCoefficient = strength; - cond.lNegativeCoefficient = strength; - cond.dwPositiveSaturation = strength; // For FG920? - cond.dwNegativeSaturation = strength; // For FG920? - cond.lDeadBand = 0; - - memset(&fx, 0, sizeof(fx)); - fx.dwSize = sizeof(fx); - fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = INFINITE; - fx.dwGain = DI_FFNOMINALMAX; - fx.dwTriggerButton = DIEB_NOTRIGGER; - fx.dwTriggerRepeatInterval = INFINITE; - fx.cAxes = 1; - fx.rgdwAxes = &axis; - fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cond); - fx.lpvTypeSpecificParams = &cond; - - hr = IDirectInputDevice8_CreateEffect( - dev, - &GUID_Spring, - &fx, - &obj, - NULL); - - if (FAILED(hr)) { - dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", - (int) hr); - return; - } - - hr = IDirectInputEffect_Start(obj, INFINITE, 0); - - if (FAILED(hr)) { - IDirectInputEffect_Release(obj); - dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", - (int) hr); - return; - } - - *out = obj; - - dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", - strength / 100); + return S_OK; } HRESULT swdc_di_dev_poll( @@ -167,3 +72,312 @@ HRESULT swdc_di_dev_poll( return hr; } + +HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +HRESULT swdc_di_ffb_init(void) +{ + HRESULT hr; + + hr = swdc_di_dev_start(swdc_di_dev, swdc_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +void swdc_di_ffb_toggle(bool active) +{ + if (active) { + return; + } + + /* Stop and release all effects */ + /* I never programmed DirectInput Effects, so this might be bad practice. */ + if (swdc_di_fx != NULL) { + IDirectInputEffect_Stop(swdc_di_fx); + IDirectInputEffect_Release(swdc_di_fx); + swdc_di_fx = NULL; + } + + if (swdc_di_fx_rumble != NULL) { + IDirectInputEffect_Stop(swdc_di_fx_rumble); + IDirectInputEffect_Release(swdc_di_fx_rumble); + swdc_di_fx_rumble = NULL; + } + + if (swdc_di_fx_damper != NULL) { + IDirectInputEffect_Stop(swdc_di_fx_damper); + IDirectInputEffect_Release(swdc_di_fx_damper); + swdc_di_fx_damper = NULL; + } +} + +void swdc_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = swdc_di_cfg->ffb_constant_force_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + /* Direction 0: move to the right, 1: move to the left */ + LONG magnitude = (LONG)(((double)force / swdc_di_ffb_scale) * ffb_strength); + cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; + + axis = DIJOFS_X; + /* Irrelevant as magnitude descripbes the direction */ + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + if (swdc_di_fx != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(swdc_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(swdc_di_fx); + IDirectInputEffect_Release(swdc_di_fx); + swdc_di_fx = NULL; + } + } + + // Create a new constant force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + swdc_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + swdc_di_fx = obj; +} + +void swdc_di_ffb_rumble(uint8_t force, uint8_t period) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = swdc_di_cfg->ffb_rumble_strength * 100; + if (ffb_strength == 0) { + return; + } + + uint32_t ffb_duration = swdc_di_cfg->ffb_rumble_duration; + + DWORD axis; + LONG direction; + DIEFFECT fx; + DIPERIODIC pe; + HRESULT hr; + + /* Duration in microseconds, + Might be totally wrong as especially on FANATEC wheels as this code will + crash the game. TODO: Figure out why this effect will crash on FANATEC! */ + DWORD duration = (DWORD)((double)force * ffb_duration); + + memset(&pe, 0, sizeof(pe)); + pe.dwMagnitude = (DWORD)(((double)force / swdc_di_ffb_scale) * ffb_strength); + pe.lOffset = 0; + pe.dwPhase = 0; + pe.dwPeriod = duration; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = duration; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(pe); + fx.lpvTypeSpecificParams = &pe; + + if (swdc_di_fx_rumble != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(swdc_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(swdc_di_fx_rumble); + IDirectInputEffect_Release(swdc_di_fx_rumble); + swdc_di_fx_rumble = NULL; + } + } + + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + swdc_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + swdc_di_fx_rumble = obj; +} + +void swdc_di_ffb_damper(uint8_t force) +{ + /* DI expects a coefficient in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = swdc_di_cfg->ffb_damper_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONDITION cond; + HRESULT hr; + + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = (LONG)(((double)force / swdc_di_ffb_scale) * ffb_strength); + cond.lNegativeCoefficient = (LONG)(((double)force / swdc_di_ffb_scale) * ffb_strength); + /* Not sure on this one */ + cond.dwPositiveSaturation = DI_FFNOMINALMAX; + cond.dwNegativeSaturation = DI_FFNOMINALMAX; + cond.lDeadBand = 0; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; + + if (swdc_di_fx_damper != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(swdc_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(swdc_di_fx_damper); + IDirectInputEffect_Release(swdc_di_fx_damper); + swdc_di_fx_damper = NULL; + } + } + + // Create a new damper force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + swdc_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + swdc_di_fx_damper = obj; +} diff --git a/swdcio/di-dev.h b/swdcio/di-dev.h index 06ac036..d28afdb 100644 --- a/swdcio/di-dev.h +++ b/swdcio/di-dev.h @@ -5,15 +5,26 @@ #include +#include "swdcio/config.h" + union swdc_di_state { DIJOYSTATE st; uint8_t bytes[sizeof(DIJOYSTATE)]; }; +HRESULT swdc_di_dev_init( + const struct swdc_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd); + HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void swdc_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT swdc_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, union swdc_di_state *out); +HRESULT swdc_di_ffb_init(void); +void swdc_di_ffb_toggle(bool active); +void swdc_di_ffb_constant_force(uint8_t direction, uint8_t force); +void swdc_di_ffb_rumble(uint8_t force, uint8_t period); +void swdc_di_ffb_damper(uint8_t force); diff --git a/swdcio/di.c b/swdcio/di.c index 7639a4e..db952a0 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -45,8 +45,13 @@ static const struct swdc_di_axis swdc_di_axes[] = { }; static const struct swdc_io_backend swdc_di_backend = { - .get_gamebtns = swdc_di_get_buttons, - .get_analogs = swdc_di_get_analogs, + .get_gamebtns = swdc_di_get_buttons, + .get_analogs = swdc_di_get_analogs, + .ffb_init = swdc_di_ffb_init, + .ffb_toggle = swdc_di_ffb_toggle, + .ffb_constant_force = swdc_di_ffb_constant_force, + .ffb_rumble = swdc_di_ffb_rumble, + .ffb_damper = swdc_di_ffb_damper }; static HWND swdc_di_wnd; @@ -67,7 +72,6 @@ static uint8_t swdc_di_wheel_yellow; static bool swdc_di_use_pedals; static bool swdc_di_reverse_brake_axis; static bool swdc_di_reverse_accel_axis; -static uint16_t swdc_di_center_spring_strength; HRESULT swdc_di_init( const struct swdc_di_config *cfg, @@ -160,16 +164,12 @@ HRESULT swdc_di_init( return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } - hr = swdc_di_dev_start(swdc_di_dev, swdc_di_wnd); + hr = swdc_di_dev_init(cfg, swdc_di_dev, swdc_di_wnd); if (FAILED(hr)) { return hr; } - // Convert the strength from 0-100 to 0-10000 for DirectInput - swdc_di_dev_start_fx(swdc_di_dev, &swdc_di_fx, - swdc_di_center_spring_strength * 100); - if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( swdc_di_api, @@ -320,15 +320,24 @@ static HRESULT swdc_di_config_apply(const struct swdc_di_config *cfg) swdc_di_reverse_brake_axis = cfg->reverse_brake_axis; swdc_di_reverse_accel_axis = cfg->reverse_accel_axis; - // FFB configuration + /* FFB configuration */ + if (cfg->ffb_constant_force_strength < 0 || cfg->ffb_constant_force_strength > 100) { + dprintf("Wheel: Invalid constant force strength: %i\n", cfg->ffb_constant_force_strength); - if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { - dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + return E_INVALIDARG; + } + + if (cfg->ffb_rumble_strength < 0 || cfg->ffb_rumble_strength > 100) { + dprintf("Wheel: Invalid rumble strength: %i\n", cfg->ffb_rumble_strength); return E_INVALIDARG; } - swdc_di_center_spring_strength = cfg->center_spring_strength; + if (cfg->ffb_damper_strength < 0 || cfg->ffb_damper_strength > 100) { + dprintf("Wheel: Invalid damper strength: %i\n", cfg->ffb_damper_strength); + + return E_INVALIDARG; + } return S_OK; } diff --git a/swdcio/dllmain.c b/swdcio/dllmain.c index ead174c..c2c5078 100644 --- a/swdcio/dllmain.c +++ b/swdcio/dllmain.c @@ -19,7 +19,7 @@ static bool swdc_io_coin; uint16_t swdc_io_get_api_version(void) { - return 0x0100; + return 0x0102; } HRESULT swdc_io_init(void) @@ -62,6 +62,8 @@ void swdc_io_get_opbtns(uint8_t *opbtn_out) opbtn = 0; + /* Common operator buttons, not backend-specific */ + if (GetAsyncKeyState(swdc_io_cfg.vk_test) & 0x8000) { opbtn |= SWDC_IO_OPBTN_TEST; } @@ -110,3 +112,79 @@ void swdc_io_get_analogs(struct swdc_io_analog_state *out) out->accel = tmp.accel; out->brake = tmp.brake; } + +HRESULT swdc_io_led_init(void) +{ + return S_OK; +} + +void swdc_io_led_set_fet_output(const uint8_t *rgb) +{ +#if 0 + dprintf("SWDC LED: LEFT SEAT LED: %02X\n", rgb[0]); + dprintf("SWDC LED: RIGHT SEAT LED: %02X\n", rgb[1]); +#endif + + return; +} + +void swdc_io_led_gs_update(const uint8_t *rgb) +{ +#if 0 + for (int i = 0; i < 9; i++) { + dprintf("SWDC LED: LED %d: %02X %02X %02X Speed: %02X\n", + i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + } +#endif + + return; +} + +void swdc_io_led_set_leds(const uint8_t *rgb) +{ +#if 0 + dprintf("SWDC LED: START: %02X\n", rgb[0]); + dprintf("SWDC LED: VIEW CHANGE: %02X\n", rgb[1]); + dprintf("SWDC LED: UP: %02X\n", rgb[2]); + dprintf("SWDC LED: DOWN: %02X\n", rgb[3]); + dprintf("SWDC LED: RIGHT: %02X\n", rgb[4]); + dprintf("SWDC LED: LEFT: %02X\n", rgb[5]); +#endif + + return; +} + +HRESULT swdc_io_ffb_init(void) +{ + assert(swdc_io_backend != NULL); + + return swdc_io_backend->ffb_init(); +} + +void swdc_io_ffb_toggle(bool active) +{ + assert(swdc_io_backend != NULL); + + swdc_io_backend->ffb_toggle(active); +} + +void swdc_io_ffb_constant_force(uint8_t direction, uint8_t force) +{ + assert(swdc_io_backend != NULL); + + swdc_io_backend->ffb_constant_force(direction, force); +} + +void swdc_io_ffb_rumble(uint8_t period, uint8_t force) +{ + assert(swdc_io_backend != NULL); + + swdc_io_backend->ffb_rumble(period, force); +} + +void swdc_io_ffb_damper(uint8_t force) +{ + assert(swdc_io_backend != NULL); + + swdc_io_backend->ffb_damper(force); +} diff --git a/swdcio/swdcio.def b/swdcio/swdcio.def index ca63aca..b90faba 100644 --- a/swdcio/swdcio.def +++ b/swdcio/swdcio.def @@ -5,3 +5,12 @@ EXPORTS swdc_io_get_opbtns swdc_io_get_gamebtns swdc_io_get_analogs + swdc_io_led_init + swdc_io_led_set_fet_output + swdc_io_led_gs_update + swdc_io_led_set_leds + swdc_io_ffb_init + swdc_io_ffb_toggle + swdc_io_ffb_constant_force + swdc_io_ffb_rumble + swdc_io_ffb_damper diff --git a/swdcio/swdcio.h b/swdcio/swdcio.h index 7155273..6843634 100644 --- a/swdcio/swdcio.h +++ b/swdcio/swdcio.h @@ -2,6 +2,7 @@ #include +#include #include enum { @@ -26,6 +27,17 @@ enum { SWDC_IO_GAMEBTN_STEERING_PADDLE_RIGHT = 0x800, }; +enum { + /* These are the bitmasks to use when checking which + lights are triggered on incoming IO4 GPIO writes. */ + SWDC_IO_LED_START = 1 << 31, + SWDC_IO_LED_VIEW_CHANGE = 1 << 30, + SWDC_IO_LED_UP = 1 << 25, + SWDC_IO_LED_DOWN = 1 << 24, + SWDC_IO_LED_LEFT = 1 << 23, + SWDC_IO_LED_RIGHT = 1 << 22, +}; + struct swdc_io_analog_state { /* Current steering wheel position, where zero is the centered position. @@ -45,7 +57,7 @@ struct swdc_io_analog_state { uint16_t brake; }; -/* Get the version of the IDAC IO API that this DLL supports. This +/* Get the version of the SWDC IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the Semantic Versioning standard). @@ -89,3 +101,107 @@ void swdc_io_get_gamebtns(uint16_t *gamebtn); Minimum API version: 0x0100 */ void swdc_io_get_analogs(struct swdc_io_analog_state *out); + +/* Initialize LED emulation. This function will be called before any + other swdc_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0101 */ + +HRESULT swdc_io_led_init(void); + +/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes. + + The following bits are used to control the FET outputs: + [0]: LEFT SEAT LED + [1]: RIGHT SEAT LED + + The LED is truned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void swdc_io_led_set_fet_output(const uint8_t *rgb); + +/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. + + The LEDs are laid out as follows: + [0]: LEFT UP LED + [1-2]: LEFT CENTER LED + [3]: LEFT DOWN LED + [5]: RIGHT UP LED + [6-7]: RIGHT CENTER LED + [8]: RIGHT DOWN LED + + Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed. + Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest. + + Minimum API version: 0x0101 */ + +void swdc_io_led_gs_update(const uint8_t *rgb); + +/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. + + The LEDs are laid out as follows: + [0]: START LED + [1]: VIEW CHANGE LED + [2]: UP LED + [3]: DOWN LED + [4]: RIGHT LED + [5]: LEFT LED + + The LED is turned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void swdc_io_led_set_leds(const uint8_t *rgb); + +/* Initialize FFB emulation. This function will be called before any + other swdc_io_ffb_*() function calls. + + This will always be called even if FFB board emulation is disabled to allow + the IO DLL to initialize any necessary resources. + + Minimum API version: 0x0102 */ + +HRESULT swdc_io_ffb_init(void); + +/* Toggle FFB emulation. If active is true, FFB emulation should be enabled. + If active is false, FFB emulation should be disabled and all FFB effects + should be stopped and released. + + Minimum API version: 0x0102 */ + +void swdc_io_ffb_toggle(bool active); + +/* Set a constant force FFB effect. + + Direction is 0 for right and 1 for left. + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force in a given direction. + + Minimum API version: 0x0102 */ + +void swdc_io_ffb_constant_force(uint8_t direction, uint8_t force); + +/* Set a (sine) periodic force FFB effect. + + Period is the period of the effect in milliseconds (not sure). + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force. + + Minimum API version: 0x0102 */ + +void swdc_io_ffb_rumble(uint8_t period, uint8_t force); + +/* Set a damper FFB effect. + + Force is the magnitude of the force, where 0 is no force and 40 is the + maximum force. Theoretically the maximum force is 127, but the game only + uses a maximum of 40. + + Minimum API version: 0x0102 */ + +void swdc_io_ffb_damper(uint8_t force); diff --git a/swdcio/xi.c b/swdcio/xi.c index eb59ce6..3c4ab9c 100644 --- a/swdcio/xi.c +++ b/swdcio/xi.c @@ -16,11 +16,22 @@ static void swdc_xi_get_gamebtns(uint16_t *gamebtn_out); static void swdc_xi_get_analogs(struct swdc_io_analog_state *out); +static HRESULT swdc_xi_ffb_init(void); +static void swdc_xi_ffb_toggle(bool active); +static void swdc_xi_ffb_constant_force(uint8_t direction, uint8_t force); +static void swdc_xi_ffb_rumble(uint8_t force, uint8_t period); +static void swdc_xi_ffb_damper(uint8_t force); + static HRESULT swdc_xi_config_apply(const struct swdc_xi_config *cfg); static const struct swdc_io_backend swdc_xi_backend = { - .get_gamebtns = swdc_xi_get_gamebtns, - .get_analogs = swdc_xi_get_analogs, + .get_gamebtns = swdc_xi_get_gamebtns, + .get_analogs = swdc_xi_get_analogs, + .ffb_init = swdc_xi_ffb_init, + .ffb_toggle = swdc_xi_ffb_toggle, + .ffb_constant_force = swdc_xi_ffb_constant_force, + .ffb_rumble = swdc_xi_ffb_rumble, + .ffb_damper = swdc_xi_ffb_damper }; static bool swdc_xi_single_stick_steering; @@ -210,3 +221,35 @@ static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) out->accel = xi.Gamepad.bRightTrigger << 8; out->brake = xi.Gamepad.bLeftTrigger << 8; } + +static HRESULT swdc_xi_ffb_init(void) { + return S_OK; +} + +static void swdc_xi_ffb_toggle(bool active) { + XINPUT_VIBRATION vibration; + + memset(&vibration, 0, sizeof(vibration)); + + XInputSetState(0, &vibration); +} + +static void swdc_xi_ffb_constant_force(uint8_t direction, uint8_t force) { + return; +} + +static void swdc_xi_ffb_rumble(uint8_t force, uint8_t period) { + XINPUT_VIBRATION vibration; + /* XInput max strength is 65.535, so multiply the 127.0 by 516. */ + uint16_t strength = force * 516; + + memset(&vibration, 0, sizeof(vibration)); + vibration.wLeftMotorSpeed = strength; + vibration.wRightMotorSpeed = strength; + + XInputSetState(0, &vibration); +} + +static void swdc_xi_ffb_damper(uint8_t force) { + return; +} From 259b763a13e4efec5ecf5f1ef67e08c4ea8aff86 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 30 Sep 2024 23:10:16 +0200 Subject: [PATCH 152/204] idz: add ffb and led emulation --- board/ffb.c | 3 +- dist/idz/segatools.ini | 35 +++- dist/idz/start.bat | 5 +- idachook/dllmain.c | 4 +- idachook/io4.c | 2 + idzhook/config.c | 38 ++++ idzhook/config.h | 5 +- idzhook/dllmain.c | 20 ++ idzhook/ffb.c | 59 ++++++ idzhook/ffb.h | 7 + idzhook/idz-dll.c | 27 +++ idzhook/idz-dll.h | 9 + idzhook/idzhook.def | 9 + idzhook/jvs.c | 39 +++- idzhook/jvs.h | 2 + idzhook/meson.build | 2 + idzio/backend.h | 5 + idzio/config.c | 27 ++- idzio/config.h | 6 +- idzio/di-dev.c | 446 ++++++++++++++++++++++++++++++----------- idzio/di-dev.h | 13 +- idzio/di.c | 29 ++- idzio/dllmain.c | 78 ++++++- idzio/idzio.def | 9 + idzio/idzio.h | 116 +++++++++++ idzio/xi.c | 43 ++++ 26 files changed, 886 insertions(+), 152 deletions(-) create mode 100644 idzhook/ffb.c create mode 100644 idzhook/ffb.h diff --git a/board/ffb.c b/board/ffb.c index 48e15ad..e7a11f7 100644 --- a/board/ffb.c +++ b/board/ffb.c @@ -138,6 +138,7 @@ static HRESULT ffb_req_dispatch(const union ffb_req_any *req) return ffb_req_rumble(req->bytes); case FFB_CMD_DAMPER: return ffb_req_damper(req->bytes); + /* There are some test mode specfic commands which doesn't seem to be used in game at all. The same is true for the initialization phase. */ @@ -206,7 +207,7 @@ static HRESULT ffb_req_rumble(const uint8_t *bytes) max_period = period; } - // dprintf("FFB: Rumble Period: %d (Min %d, Max %d), Strength: %d (Max: %d)\n", period, min_period, max_period, force, max_rumble); + // dprintf("FFB: Rumble Period: %d (Max %d), Strength: %d (Max: %d)\n", period, max_period, force, max_rumble); if (ffb_ops->rumble != NULL) { ffb_ops->rumble(force, period); } diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index c37bab6..126a5b7 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -69,6 +69,20 @@ region=4 ; exactly one machine and set this to 0 on all others. dipsw1=1 +[ffb] +; Enable force feedback (838-15069) board emulation. This is required for +; both DirectInput and XInput steering wheel effects. +enable=1 + +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15070] +; Enable emulation of the 837-15070-02 controlled lights, which handle the +; cabinet and seat LEDs. +enable=1 + ; ----------------------------------------------------------------------------- ; Misc. hooks settings ; ----------------------------------------------------------------------------- @@ -212,6 +226,21 @@ reverseAccelAxis=0 reverseBrakeAxis=0 ; Force feedback settings. -; Strength of the force feedback spring effect in percent. Possible values -; are 0-100. -centerSpringStrength=30 +; Only works when FFB board emulation is enabled! +; +; It is recommended to change the strength inside the Game Test Mode! +; +; These settings are only used when using DirectInput for the wheel. +; The values are in the range 0%-100%, where 0 disables the effect and +; 100 is the maximum. + +; Constant force strength, used for centering spring effect. +constantForceStrength=100 +; Damper strength, used for steering wheel damper effect. +damperStrength=100 + +; Rumble strength, used for road surface effects. +; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! +rumbleStrength=100 +; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. +rumbleDuration=1000 \ No newline at end of file diff --git a/dist/idz/start.bat b/dist/idz/start.bat index 2d3d9c3..d64aa9b 100644 --- a/dist/idz/start.bat +++ b/dist/idz/start.bat @@ -2,10 +2,11 @@ pushd %~dp0 -inject -k idzhook.dll InitialD0_DX11_Nu.exe +start /min "AM Daemon" inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json + rem Set dipsw1=0 and uncomment the ServerBox for in store battle? rem inject -k idzhook.dll ServerBoxD8_Nu_x64.exe -inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json +inject -d -k idzhook.dll InitialD0_DX11_Nu.exe taskkill /im ServerBoxD8_Nu_x64.exe > nul 2>&1 diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 3336690..2e82882 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -5,7 +5,9 @@ USB: 837-15257 "Type 4" I/O Board COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board - COM2: 837-15070-02 IC BD LED Controller Board + COM2: 837-15070-02 IC BD LED Controller Board (DIPSW2 OFF) + OR + 837-15070-04 IC BD LED Controller Board (DIPSW2 ON) COM3: 837-15286 "Gen 2" Aime Reader (DIPSW2 OFF) OR 837-15396 "Gen 3" Aime Reader (DIPSW2 ON) diff --git a/idachook/io4.c b/idachook/io4.c index c13e7a5..1e4d990 100644 --- a/idachook/io4.c +++ b/idachook/io4.c @@ -133,6 +133,8 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) { + assert(idac_dll.led_set_leds != NULL); + // Just fast fail if there aren't enough bytes in the payload if (len < 3) return S_OK; diff --git a/idzhook/config.c b/idzhook/config.c index db83b9f..7948c84 100644 --- a/idzhook/config.c +++ b/idzhook/config.c @@ -18,6 +18,42 @@ #include "platform/config.h" #include "platform/platform.h" +void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); + /* TODO: Unknown, no firmware file available */ + cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename); + + GetPrivateProfileStringW( + L"led15070", + L"boardNumber", + L"15070-02", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15070", + L"eepromPath", + L"DEVICE", + cfg->eeprom_path, + _countof(cfg->eeprom_path), + filename); +} + void idz_dll_config_load( struct idz_dll_config *cfg, const wchar_t *filename) @@ -47,6 +83,8 @@ void idz_hook_config_load( dvd_config_load(&cfg->dvd, filename); gfx_config_load(&cfg->gfx, filename); idz_dll_config_load(&cfg->dll, filename); + ffb_config_load(&cfg->ffb, filename); + led15070_config_load(&cfg->led15070, filename); zinput_config_load(&cfg->zinput, filename); } diff --git a/idzhook/config.h b/idzhook/config.h index 0684949..47174ad 100644 --- a/idzhook/config.h +++ b/idzhook/config.h @@ -5,7 +5,8 @@ #include "amex/amex.h" -#include "board/sg-reader.h" +#include "board/config.h" +#include "board/led15070.h" #include "gfxhook/gfx.h" @@ -23,6 +24,8 @@ struct idz_hook_config { struct dvd_config dvd; struct gfx_config gfx; struct idz_dll_config dll; + struct ffb_config ffb; + struct led15070_config led15070; struct zinput_config zinput; }; diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index cb2fdde..e9d807a 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -33,6 +33,7 @@ #include "idzhook/config.h" #include "idzhook/idz-dll.h" #include "idzhook/jvs.h" +#include "idzhook/ffb.h" #include "idzhook/zinput.h" #include "platform/platform.h" @@ -102,6 +103,12 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } + hr = idz_jvs_hook_init(); + + if (FAILED(hr)) { + goto fail; + } + hr = amex_hook_init(&idz_hook_cfg.amex, idz_jvs_init); if (FAILED(hr)) { @@ -114,6 +121,19 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } + hr = idz_ffb_hook_init(&idz_hook_cfg.ffb, 1); + + if (FAILED(hr)) { + goto fail; + } + + hr = led15070_hook_init(&idz_hook_cfg.led15070, idz_dll.led_init, + idz_dll.led_set_fet_output, NULL, idz_dll.led_gs_update, 11, 1); + + if (FAILED(hr)) { + goto fail; + } + /* Initialize debug helpers */ spike_hook_init(L".\\segatools.ini"); diff --git a/idzhook/ffb.c b/idzhook/ffb.c new file mode 100644 index 0000000..7ac1086 --- /dev/null +++ b/idzhook/ffb.c @@ -0,0 +1,59 @@ +#include + +#include +#include +#include +#include + +#include "board/ffb.h" + +#include "idzhook/idz-dll.h" + +#include "util/dprintf.h" + +static void idz_ffb_toggle(bool active); +static void idz_ffb_constant_force(uint8_t direction, uint8_t force); +static void idz_ffb_rumble(uint8_t force, uint8_t period); +static void idz_ffb_damper(uint8_t force); + +static const struct ffb_ops idz_ffb_ops = { + .toggle = idz_ffb_toggle, + .constant_force = idz_ffb_constant_force, + .rumble = idz_ffb_rumble, + .damper = idz_ffb_damper +}; + +HRESULT idz_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no) +{ + HRESULT hr; + + assert(idz_dll.jvs_init != NULL); + + hr = ffb_hook_init(cfg, &idz_ffb_ops, port_no); + + if (FAILED(hr)) { + return hr; + } + + return idz_dll.ffb_init(); +} + +static void idz_ffb_toggle(bool active) +{ + idz_dll.ffb_toggle(active); +} + +static void idz_ffb_constant_force(uint8_t direction, uint8_t force) +{ + idz_dll.ffb_constant_force(direction, force); +} + +static void idz_ffb_rumble(uint8_t force, uint8_t period) +{ + idz_dll.ffb_rumble(force, period); +} + +static void idz_ffb_damper(uint8_t force) +{ + idz_dll.ffb_damper(force); +} diff --git a/idzhook/ffb.h b/idzhook/ffb.h new file mode 100644 index 0000000..eaee98c --- /dev/null +++ b/idzhook/ffb.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/ffb.h" + +HRESULT idz_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no); diff --git a/idzhook/idz-dll.c b/idzhook/idz-dll.c index eb1b6e1..a497319 100644 --- a/idzhook/idz-dll.c +++ b/idzhook/idz-dll.c @@ -24,6 +24,33 @@ const struct dll_bind_sym idz_dll_syms[] = { }, { .sym = "idz_io_jvs_read_coin_counter", .off = offsetof(struct idz_dll, jvs_read_coin_counter), + }, { + .sym = "idz_io_led_init", + .off = offsetof(struct idz_dll, led_init), + }, { + .sym = "idz_io_led_set_fet_output", + .off = offsetof(struct idz_dll, led_set_fet_output), + }, { + .sym = "idz_io_led_gs_update", + .off = offsetof(struct idz_dll, led_gs_update), + }, { + .sym = "idz_io_led_set_leds", + .off = offsetof(struct idz_dll, led_set_leds), + }, { + .sym = "idz_io_ffb_init", + .off = offsetof(struct idz_dll, ffb_init), + }, { + .sym = "idz_io_ffb_toggle", + .off = offsetof(struct idz_dll, ffb_toggle), + }, { + .sym = "idz_io_ffb_constant_force", + .off = offsetof(struct idz_dll, ffb_constant_force), + }, { + .sym = "idz_io_ffb_rumble", + .off = offsetof(struct idz_dll, ffb_rumble), + }, { + .sym = "idz_io_ffb_damper", + .off = offsetof(struct idz_dll, ffb_damper), } }; diff --git a/idzhook/idz-dll.h b/idzhook/idz-dll.h index e67cb45..e827f8e 100644 --- a/idzhook/idz-dll.h +++ b/idzhook/idz-dll.h @@ -11,6 +11,15 @@ struct idz_dll { void (*jvs_read_buttons)(uint8_t *opbtn, uint8_t *gamebtn); void (*jvs_read_shifter)(uint8_t *gear); void (*jvs_read_coin_counter)(uint16_t *total); + HRESULT (*led_init)(void); + void (*led_set_fet_output)(const uint8_t *rgb); + void (*led_gs_update)(const uint8_t *rgb); + void (*led_set_leds)(const uint8_t *rgb); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; struct idz_dll_config { diff --git a/idzhook/idzhook.def b/idzhook/idzhook.def index d8db3b0..53e01c6 100644 --- a/idzhook/idzhook.def +++ b/idzhook/idzhook.def @@ -22,3 +22,12 @@ EXPORTS idz_io_jvs_read_buttons idz_io_jvs_read_coin_counter idz_io_jvs_read_shifter + idz_io_led_init + idz_io_led_set_fet_output + idz_io_led_gs_update + idz_io_led_set_leds + idz_io_ffb_init + idz_io_ffb_toggle + idz_io_ffb_constant_force + idz_io_ffb_rumble + idz_io_ffb_damper diff --git a/idzhook/jvs.c b/idzhook/jvs.c index ab2f6aa..3531d55 100644 --- a/idzhook/jvs.c +++ b/idzhook/jvs.c @@ -24,11 +24,13 @@ static void idz_jvs_read_coin_counter( void *ctx, uint8_t slot_no, uint16_t *out); +static void idz_jvs_write_gpio(void *ctx, uint32_t state); static const struct io3_ops idz_jvs_io3_ops = { .read_switches = idz_jvs_read_switches, .read_analogs = idz_jvs_read_analogs, .read_coin_counter = idz_jvs_read_coin_counter, + .write_gpio = idz_jvs_write_gpio }; static const uint16_t idz_jvs_gear_signals[] = { @@ -50,21 +52,20 @@ static const uint16_t idz_jvs_gear_signals[] = { static struct io3 idz_jvs_io3; +HRESULT idz_jvs_hook_init(void) +{ + HRESULT hr; + + assert(idz_dll.jvs_init != NULL); + + return idz_dll.jvs_init(); +} + HRESULT idz_jvs_init(struct jvs_node **out) { HRESULT hr; assert(out != NULL); - assert(idz_dll.jvs_init != NULL); - - dprintf("JVS I/O: Starting Initial D Zero backend DLL\n"); - hr = idz_dll.jvs_init(); - - if (FAILED(hr)) { - dprintf("JVS I/O: Backend error, I/O disconnected; %x\n", (int) hr); - - return hr; - } io3_init(&idz_jvs_io3, NULL, &idz_jvs_io3_ops, NULL); *out = io3_to_jvs_node(&idz_jvs_io3); @@ -175,3 +176,21 @@ static void idz_jvs_read_coin_counter( idz_dll.jvs_read_coin_counter(out); } +static void idz_jvs_write_gpio(void *ctx, uint32_t state) +{ + assert(idz_dll.led_set_leds != NULL); + + // Since Sega uses an odd ordering for the first part of the bitfield, + // let's normalize the data and just send over bytes for the receiver + // to interpret as ON/OFF values. + uint8_t rgb_out[6] = { + state & IDZ_IO_LED_START ? 0xFF : 0x00, + state & IDZ_IO_LED_VIEW_CHANGE ? 0xFF : 0x00, + state & IDZ_IO_LED_UP ? 0xFF : 0x00, + state & IDZ_IO_LED_DOWN ? 0xFF : 0x00, + state & IDZ_IO_LED_RIGHT ? 0xFF : 0x00, + state & IDZ_IO_LED_LEFT ? 0xFF : 0x00, + }; + + idz_dll.led_set_leds(rgb_out); +} diff --git a/idzhook/jvs.h b/idzhook/jvs.h index 6a7c72a..82de143 100644 --- a/idzhook/jvs.h +++ b/idzhook/jvs.h @@ -4,4 +4,6 @@ #include "jvs/jvs-bus.h" +HRESULT idz_jvs_hook_init(void); + HRESULT idz_jvs_init(struct jvs_node **root); diff --git a/idzhook/meson.build b/idzhook/meson.build index ab90815..eb9ba6c 100644 --- a/idzhook/meson.build +++ b/idzhook/meson.build @@ -32,5 +32,7 @@ shared_library( 'jvs.h', 'zinput.c', 'zinput.h', + 'ffb.c', + 'ffb.h', ], ) diff --git a/idzio/backend.h b/idzio/backend.h index e0a958f..1993076 100644 --- a/idzio/backend.h +++ b/idzio/backend.h @@ -8,4 +8,9 @@ struct idz_io_backend { void (*jvs_read_buttons)(uint8_t *gamebtn); void (*jvs_read_shifter)(uint8_t *gear); void (*jvs_read_analogs)(struct idz_io_analog_state *state); + HRESULT (*ffb_init)(void); + void (*ffb_toggle)(bool active); + void (*ffb_constant_force)(uint8_t direction, uint8_t force); + void (*ffb_rumble)(uint8_t period, uint8_t force); + void (*ffb_damper)(uint8_t force); }; diff --git a/idzio/config.c b/idzio/config.c index aec8261..369a4c5 100644 --- a/idzio/config.c +++ b/idzio/config.c @@ -78,12 +78,29 @@ void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename) } // FFB configuration + cfg->ffb_constant_force_strength = GetPrivateProfileIntW( + L"dinput", + L"constantForceStrength", + 100, + filename); - cfg->center_spring_strength = GetPrivateProfileIntW( - L"dinput", - L"centerSpringStrength", - 30, - filename); + cfg->ffb_rumble_strength = GetPrivateProfileIntW( + L"dinput", + L"rumbleStrength", + 100, + filename); + + cfg->ffb_damper_strength = GetPrivateProfileIntW( + L"dinput", + L"damperStrength", + 100, + filename); + + cfg->ffb_rumble_duration = GetPrivateProfileIntW( + L"dinput", + L"rumbleDuration", + 1000, + filename); } void idz_xi_config_load(struct idz_xi_config *cfg, const wchar_t *filename) diff --git a/idzio/config.h b/idzio/config.h index 155f797..7a17f00 100644 --- a/idzio/config.h +++ b/idzio/config.h @@ -23,7 +23,11 @@ struct idz_di_config { bool reverse_accel_axis; // FFB configuration - uint16_t center_spring_strength; + uint8_t ffb_constant_force_strength; + uint8_t ffb_rumble_strength; + uint8_t ffb_damper_strength; + + uint32_t ffb_rumble_duration; }; struct idz_xi_config { diff --git a/idzio/di-dev.c b/idzio/di-dev.c index 26cf6e3..053eb9c 100644 --- a/idzio/di-dev.c +++ b/idzio/di-dev.c @@ -1,134 +1,39 @@ #include #include - +#include #include #include "idzio/di-dev.h" #include "util/dprintf.h" -HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +const struct idz_di_config *idz_di_cfg; +static HWND idz_di_wnd; +static IDirectInputDevice8W *idz_di_dev; + +/* Individual DI Effects */ +static IDirectInputEffect *idz_di_fx; +static IDirectInputEffect *idz_di_fx_rumble; +static IDirectInputEffect *idz_di_fx_damper; + +/* Max FFB Board value is 127 */ +static const double idz_di_ffb_scale = 127.0; + +HRESULT idz_di_dev_init( + const struct idz_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd) { HRESULT hr; assert(dev != NULL); assert(wnd != NULL); - hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + idz_di_cfg = cfg; + idz_di_dev = dev; + idz_di_wnd = wnd; - if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); - - if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - - return hr; - } - - hr = IDirectInputDevice8_Acquire(dev); - - if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - - return hr; - } - - return hr; -} - -void idz_di_dev_start_fx( - IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength) -{ - /* Set up force-feedback on devices that support it. This is just a stub - for the time being, since we don't yet know how the serial port force - feedback protocol works. - - I'm currently developing with an Xbox One Thrustmaster TMX wheel, if - we don't perform at least some perfunctory FFB initialization of this - nature (or indeed if no DirectInput application is running) then the - wheel exhibits considerable resistance, similar to that of a stationary - car. Changing cf.lMagnitude to a nonzero value does cause the wheel to - continuously turn in the given direction with the given force as one - would expect (max magnitude per DirectInput docs is +/- 10000). - - Failure here is non-fatal, we log any errors and move on. - - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) - */ - - IDirectInputEffect *obj; - DWORD axis; - LONG direction; - DIEFFECT fx; - DICONDITION cond; - HRESULT hr; - - assert(dev != NULL); - assert(out != NULL); - - *out = NULL; - - dprintf("DirectInput: Starting force feedback (may take a sec)\n"); - - // Auto-centering effect - axis = DIJOFS_X; - direction = 0; - - memset(&cond, 0, sizeof(cond)); - cond.lOffset = 0; - cond.lPositiveCoefficient = strength; - cond.lNegativeCoefficient = strength; - cond.dwPositiveSaturation = strength; // For FG920? - cond.dwNegativeSaturation = strength; // For FG920? - cond.lDeadBand = 0; - - memset(&fx, 0, sizeof(fx)); - fx.dwSize = sizeof(fx); - fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = INFINITE; - fx.dwGain = DI_FFNOMINALMAX; - fx.dwTriggerButton = DIEB_NOTRIGGER; - fx.dwTriggerRepeatInterval = INFINITE; - fx.cAxes = 1; - fx.rgdwAxes = &axis; - fx.rglDirection = &direction; - fx.cbTypeSpecificParams = sizeof(cond); - fx.lpvTypeSpecificParams = &cond; - - hr = IDirectInputDevice8_CreateEffect( - dev, - &GUID_Spring, - &fx, - &obj, - NULL); - - if (FAILED(hr)) { - dprintf("DirectInput: Centering spring force feedback unavailable: %08x\n", - (int) hr); - return; - } - - hr = IDirectInputEffect_Start(obj, INFINITE, 0); - - if (FAILED(hr)) { - IDirectInputEffect_Release(obj); - dprintf("DirectInput: Centering spring force feedback start failed: %08x\n", - (int) hr); - return; - } - - *out = obj; - - dprintf("DirectInput: Centering spring effects initialized with strength %d%%\n", - strength / 100); + return S_OK; } HRESULT idz_di_dev_poll( @@ -167,3 +72,312 @@ HRESULT idz_di_dev_poll( return hr; } + +HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +HRESULT idz_di_ffb_init(void) +{ + HRESULT hr; + + hr = idz_di_dev_start(idz_di_dev, idz_di_wnd); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +void idz_di_ffb_toggle(bool active) +{ + if (active) { + return; + } + + /* Stop and release all effects */ + /* I never programmed DirectInput Effects, so this might be bad practice. */ + if (idz_di_fx != NULL) { + IDirectInputEffect_Stop(idz_di_fx); + IDirectInputEffect_Release(idz_di_fx); + idz_di_fx = NULL; + } + + if (idz_di_fx_rumble != NULL) { + IDirectInputEffect_Stop(idz_di_fx_rumble); + IDirectInputEffect_Release(idz_di_fx_rumble); + idz_di_fx_rumble = NULL; + } + + if (idz_di_fx_damper != NULL) { + IDirectInputEffect_Stop(idz_di_fx_damper); + IDirectInputEffect_Release(idz_di_fx_damper); + idz_di_fx_damper = NULL; + } +} + +void idz_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idz_di_cfg->ffb_constant_force_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + /* Direction 0: move to the right, 1: move to the left */ + LONG magnitude = (LONG)(((double)force / idz_di_ffb_scale) * ffb_strength); + cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; + + axis = DIJOFS_X; + /* Irrelevant as magnitude descripbes the direction */ + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + if (idz_di_fx != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idz_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idz_di_fx); + IDirectInputEffect_Release(idz_di_fx); + idz_di_fx = NULL; + } + } + + // Create a new constant force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idz_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idz_di_fx = obj; +} + +void idz_di_ffb_rumble(uint8_t force, uint8_t period) +{ + /* DI expects a magnitude in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idz_di_cfg->ffb_rumble_strength * 100; + if (ffb_strength == 0) { + return; + } + + uint32_t ffb_duration = idz_di_cfg->ffb_rumble_duration; + + DWORD axis; + LONG direction; + DIEFFECT fx; + DIPERIODIC pe; + HRESULT hr; + + /* Duration in microseconds, + Might be totally wrong as especially on FANATEC wheels as this code will + crash the game. TODO: Figure out why this effect will crash on FANATEC! */ + DWORD duration = (DWORD)((double)force * ffb_duration); + + memset(&pe, 0, sizeof(pe)); + pe.dwMagnitude = (DWORD)(((double)force / idz_di_ffb_scale) * ffb_strength); + pe.lOffset = 0; + pe.dwPhase = 0; + pe.dwPeriod = duration; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = duration; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(pe); + fx.lpvTypeSpecificParams = &pe; + + if (idz_di_fx_rumble != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idz_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idz_di_fx_rumble); + IDirectInputEffect_Release(idz_di_fx_rumble); + idz_di_fx_rumble = NULL; + } + } + + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idz_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idz_di_fx_rumble = obj; +} + +void idz_di_ffb_damper(uint8_t force) +{ + /* DI expects a coefficient in the range of -10.000 to 10.000 */ + uint16_t ffb_strength = idz_di_cfg->ffb_damper_strength * 100; + if (ffb_strength == 0) { + return; + } + + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONDITION cond; + HRESULT hr; + + memset(&cond, 0, sizeof(cond)); + cond.lOffset = 0; + cond.lPositiveCoefficient = (LONG)(((double)force / idz_di_ffb_scale) * ffb_strength); + cond.lNegativeCoefficient = (LONG)(((double)force / idz_di_ffb_scale) * ffb_strength); + /* Not sure on this one */ + cond.dwPositiveSaturation = DI_FFNOMINALMAX; + cond.dwNegativeSaturation = DI_FFNOMINALMAX; + cond.lDeadBand = 0; + + axis = DIJOFS_X; + direction = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cond); + fx.lpvTypeSpecificParams = &cond; + + if (idz_di_fx_damper != NULL) { + // Try to update the existing effect + hr = IDirectInputEffect_SetParameters(idz_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); + + if (SUCCEEDED(hr)) { + return; + } else { + dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); + // Stop and release the current effect if updating fails + IDirectInputEffect_Stop(idz_di_fx_damper); + IDirectInputEffect_Release(idz_di_fx_damper); + idz_di_fx_damper = NULL; + } + } + + // Create a new damper force effect + IDirectInputEffect *obj; + hr = IDirectInputDevice8_CreateEffect( + idz_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + if (FAILED(hr)) { + dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); + IDirectInputEffect_Release(obj); + return; + } + + idz_di_fx_damper = obj; +} diff --git a/idzio/di-dev.h b/idzio/di-dev.h index 9b3d03f..783ec66 100644 --- a/idzio/di-dev.h +++ b/idzio/di-dev.h @@ -5,15 +5,26 @@ #include +#include "idzio/config.h" + union idz_di_state { DIJOYSTATE st; uint8_t bytes[sizeof(DIJOYSTATE)]; }; +HRESULT idz_di_dev_init( + const struct idz_di_config *cfg, + IDirectInputDevice8W *dev, + HWND wnd); + HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); -void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out, uint16_t strength); HRESULT idz_di_dev_poll( IDirectInputDevice8W *dev, HWND wnd, union idz_di_state *out); +HRESULT idz_di_ffb_init(void); +void idz_di_ffb_toggle(bool active); +void idz_di_ffb_constant_force(uint8_t direction, uint8_t force); +void idz_di_ffb_rumble(uint8_t force, uint8_t period); +void idz_di_ffb_damper(uint8_t force); diff --git a/idzio/di.c b/idzio/di.c index e0cb4c6..8d8be41 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -55,6 +55,11 @@ static const struct idz_io_backend idz_di_backend = { .jvs_read_buttons = idz_di_jvs_read_buttons, .jvs_read_shifter = idz_di_jvs_read_shifter, .jvs_read_analogs = idz_di_jvs_read_analogs, + .ffb_init = idz_di_ffb_init, + .ffb_toggle = idz_di_ffb_toggle, + .ffb_constant_force = idz_di_ffb_constant_force, + .ffb_rumble = idz_di_ffb_rumble, + .ffb_damper = idz_di_ffb_damper }; static HWND idz_di_wnd; @@ -73,7 +78,6 @@ static uint8_t idz_di_gear[6]; static bool idz_di_use_pedals; static bool idz_di_reverse_brake_axis; static bool idz_di_reverse_accel_axis; -static uint16_t idz_di_center_spring_strength; HRESULT idz_di_init( const struct idz_di_config *cfg, @@ -166,16 +170,12 @@ HRESULT idz_di_init( return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } - hr = idz_di_dev_start(idz_di_dev, idz_di_wnd); + hr = idz_di_dev_init(cfg, idz_di_dev, idz_di_wnd); if (FAILED(hr)) { return hr; } - // Convert the strength from 0-100 to 0-10000 for DirectInput - idz_di_dev_start_fx(idz_di_dev, &idz_di_fx, - idz_di_center_spring_strength * 100); - if (cfg->pedals_name[0] != L'\0') { hr = IDirectInput8_EnumDevices( idz_di_api, @@ -349,15 +349,24 @@ static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) idz_di_gear[i] = cfg->gear[i]; } - // FFB configuration + /* FFB configuration */ + if (cfg->ffb_constant_force_strength < 0 || cfg->ffb_constant_force_strength > 100) { + dprintf("Wheel: Invalid constant force strength: %i\n", cfg->ffb_constant_force_strength); - if (cfg->center_spring_strength < 0 || cfg->center_spring_strength > 100) { - dprintf("Wheel: Invalid center spring strength: %i\n", cfg->center_spring_strength); + return E_INVALIDARG; + } + + if (cfg->ffb_rumble_strength < 0 || cfg->ffb_rumble_strength > 100) { + dprintf("Wheel: Invalid rumble strength: %i\n", cfg->ffb_rumble_strength); return E_INVALIDARG; } - idz_di_center_spring_strength = cfg->center_spring_strength; + if (cfg->ffb_damper_strength < 0 || cfg->ffb_damper_strength > 100) { + dprintf("Wheel: Invalid damper strength: %i\n", cfg->ffb_damper_strength); + + return E_INVALIDARG; + } return S_OK; } diff --git a/idzio/dllmain.c b/idzio/dllmain.c index ad94747..5c8592d 100644 --- a/idzio/dllmain.c +++ b/idzio/dllmain.c @@ -20,7 +20,7 @@ static uint16_t idz_io_coins; uint16_t idz_io_get_api_version(void) { - return 0x0100; + return 0x0102; } HRESULT idz_io_jvs_init(void) @@ -123,3 +123,79 @@ void idz_io_jvs_read_coin_counter(uint16_t *out) *out = idz_io_coins; } + +HRESULT idz_io_led_init(void) +{ + return S_OK; +} + +void idz_io_led_set_fet_output(const uint8_t *rgb) +{ +#if 0 + dprintf("IDZ LED: LEFT SEAT LED: %02X\n", rgb[0]); + dprintf("IDZ LED: RIGHT SEAT LED: %02X\n", rgb[1]); +#endif + + return; +} + +void idz_io_led_gs_update(const uint8_t *rgb) +{ +#if 0 + for (int i = 0; i < 9; i++) { + dprintf("IDZ LED: LED %d: %02X %02X %02X Speed: %02X\n", + i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + } +#endif + + return; +} + +void idz_io_led_set_leds(const uint8_t *rgb) +{ +#if 0 + dprintf("IDZ LED: START: %02X\n", rgb[0]); + dprintf("IDZ LED: VIEW CHANGE: %02X\n", rgb[1]); + dprintf("IDZ LED: UP: %02X\n", rgb[2]); + dprintf("IDZ LED: DOWN: %02X\n", rgb[3]); + dprintf("IDZ LED: RIGHT: %02X\n", rgb[4]); + dprintf("IDZ LED: LEFT: %02X\n", rgb[5]); +#endif + + return; +} + +HRESULT idz_io_ffb_init(void) +{ + assert(idz_io_backend != NULL); + + return idz_io_backend->ffb_init(); +} + +void idz_io_ffb_toggle(bool active) +{ + assert(idz_io_backend != NULL); + + idz_io_backend->ffb_toggle(active); +} + +void idz_io_ffb_constant_force(uint8_t direction, uint8_t force) +{ + assert(idz_io_backend != NULL); + + idz_io_backend->ffb_constant_force(direction, force); +} + +void idz_io_ffb_rumble(uint8_t period, uint8_t force) +{ + assert(idz_io_backend != NULL); + + idz_io_backend->ffb_rumble(period, force); +} + +void idz_io_ffb_damper(uint8_t force) +{ + assert(idz_io_backend != NULL); + + idz_io_backend->ffb_damper(force); +} diff --git a/idzio/idzio.def b/idzio/idzio.def index b177000..4d66148 100644 --- a/idzio/idzio.def +++ b/idzio/idzio.def @@ -6,3 +6,12 @@ EXPORTS idz_io_jvs_read_buttons idz_io_jvs_read_coin_counter idz_io_jvs_read_shifter + idz_io_led_init + idz_io_led_set_fet_output + idz_io_led_gs_update + idz_io_led_set_leds + idz_io_ffb_init + idz_io_ffb_toggle + idz_io_ffb_constant_force + idz_io_ffb_rumble + idz_io_ffb_damper diff --git a/idzio/idzio.h b/idzio/idzio.h index 395b012..8fd01d8 100644 --- a/idzio/idzio.h +++ b/idzio/idzio.h @@ -14,6 +14,7 @@ #include +#include #include enum { @@ -30,6 +31,17 @@ enum { IDZ_IO_GAMEBTN_VIEW_CHANGE = 0x20, }; +enum { + /* These are the bitmasks to use when checking which + lights are triggered on incoming IO4 GPIO writes. */ + IDZ_IO_LED_START = 1 << 7, + IDZ_IO_LED_VIEW_CHANGE = 1 << 6, + IDZ_IO_LED_UP = 1 << 1, + IDZ_IO_LED_DOWN = 1 << 0, + IDZ_IO_LED_RIGHT = 1 << 14, + IDZ_IO_LED_LEFT = 1 << 15 +}; + struct idz_io_analog_state { /* Current steering wheel position, where zero is the centered position. @@ -104,3 +116,107 @@ void idz_io_jvs_read_shifter(uint8_t *gear); Minimum API version: 0x0100 */ void idz_io_jvs_read_coin_counter(uint16_t *total); + +/* Initialize LED emulation. This function will be called before any + other idz_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0101 */ + +HRESULT idz_io_led_init(void); + +/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes. + + The following bits are used to control the FET outputs: + [0]: LEFT SEAT LED + [1]: RIGHT SEAT LED + + The LED is truned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void idz_io_led_set_fet_output(const uint8_t *rgb); + +/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. + + The LEDs are laid out as follows: + [0]: LEFT UP LED + [1-2]: LEFT CENTER LED + [3]: LEFT DOWN LED + [5]: RIGHT UP LED + [6-7]: RIGHT CENTER LED + [8]: RIGHT DOWN LED + + Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed. + Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest. + + Minimum API version: 0x0101 */ + +void idz_io_led_gs_update(const uint8_t *rgb); + +/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. + + The LEDs are laid out as follows: + [0]: START LED + [1]: VIEW CHANGE LED + [2]: UP LED + [3]: DOWN LED + [4]: RIGHT LED + [5]: LEFT LED + + The LED is turned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void idz_io_led_set_leds(const uint8_t *rgb); + +/* Initialize FFB emulation. This function will be called before any + other idz_io_ffb_*() function calls. + + This will always be called even if FFB board emulation is disabled to allow + the IO DLL to initialize any necessary resources. + + Minimum API version: 0x0102 */ + +HRESULT idz_io_ffb_init(void); + +/* Toggle FFB emulation. If active is true, FFB emulation should be enabled. + If active is false, FFB emulation should be disabled and all FFB effects + should be stopped and released. + + Minimum API version: 0x0102 */ + +void idz_io_ffb_toggle(bool active); + +/* Set a constant force FFB effect. + + Direction is 0 for right and 1 for left. + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force in a given direction. + + Minimum API version: 0x0102 */ + +void idz_io_ffb_constant_force(uint8_t direction, uint8_t force); + +/* Set a (sine) periodic force FFB effect. + + Period is the period of the effect in milliseconds (not sure). + Force is the magnitude of the force, where 0 is no force and 127 is the + maximum force. + + Minimum API version: 0x0102 */ + +void idz_io_ffb_rumble(uint8_t period, uint8_t force); + +/* Set a damper FFB effect. + + Force is the magnitude of the force, where 0 is no force and 40 is the + maximum force. Theoretically the maximum force is 127, but the game only + uses a maximum of 40. + + Minimum API version: 0x0102 */ + +void idz_io_ffb_damper(uint8_t force); diff --git a/idzio/xi.c b/idzio/xi.c index 4a8391d..db3a94d 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -18,12 +18,23 @@ static void idz_xi_jvs_read_buttons(uint8_t *gamebtn_out); static void idz_xi_jvs_read_shifter(uint8_t *gear); static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out); +static HRESULT idz_xi_ffb_init(void); +static void idz_xi_ffb_toggle(bool active); +static void idz_xi_ffb_constant_force(uint8_t direction, uint8_t force); +static void idz_xi_ffb_rumble(uint8_t force, uint8_t period); +static void idz_xi_ffb_damper(uint8_t force); + static HRESULT idz_xi_config_apply(const struct idz_xi_config *cfg); static const struct idz_io_backend idz_xi_backend = { .jvs_read_buttons = idz_xi_jvs_read_buttons, .jvs_read_shifter = idz_xi_jvs_read_shifter, .jvs_read_analogs = idz_xi_jvs_read_analogs, + .ffb_init = idz_xi_ffb_init, + .ffb_toggle = idz_xi_ffb_toggle, + .ffb_constant_force = idz_xi_ffb_constant_force, + .ffb_rumble = idz_xi_ffb_rumble, + .ffb_damper = idz_xi_ffb_damper }; static bool idz_xi_single_stick_steering; @@ -210,3 +221,35 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) out->accel = xi.Gamepad.bRightTrigger << 8; out->brake = xi.Gamepad.bLeftTrigger << 8; } + +static HRESULT idz_xi_ffb_init(void) { + return S_OK; +} + +static void idz_xi_ffb_toggle(bool active) { + XINPUT_VIBRATION vibration; + + memset(&vibration, 0, sizeof(vibration)); + + XInputSetState(0, &vibration); +} + +static void idz_xi_ffb_constant_force(uint8_t direction, uint8_t force) { + return; +} + +static void idz_xi_ffb_rumble(uint8_t force, uint8_t period) { + XINPUT_VIBRATION vibration; + /* XInput max strength is 65.535, so multiply the 127.0 by 516. */ + uint16_t strength = force * 516; + + memset(&vibration, 0, sizeof(vibration)); + vibration.wLeftMotorSpeed = strength; + vibration.wRightMotorSpeed = strength; + + XInputSetState(0, &vibration); +} + +static void idz_xi_ffb_damper(uint8_t force) { + return; +} From 5f817c8a36a187e6ba349c1aa7650bcd5b9df2ec Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 30 Sep 2024 23:17:37 +0200 Subject: [PATCH 153/204] swdc: minor improvements --- swdchook/config.c | 21 +++++++++++---------- swdchook/dllmain.c | 7 ++++--- swdchook/io4.c | 2 ++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/swdchook/config.c b/swdchook/config.c index 62115fa..269a450 100644 --- a/swdchook/config.c +++ b/swdchook/config.c @@ -30,7 +30,7 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) GetPrivateProfileStringW( L"led15070", L"boardNumber", - L"15070-02", + L"15070-04", tmpstr, _countof(tmpstr), filename); @@ -66,6 +66,14 @@ void swdc_dll_config_load( filename); } +void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename); +} + void swdc_hook_config_load( struct swdc_hook_config *cfg, const wchar_t *filename) @@ -79,14 +87,7 @@ void swdc_hook_config_load( zinput_config_load(&cfg->zinput, filename); dvd_config_load(&cfg->dvd, filename); io4_config_load(&cfg->io4, filename); - vfd_config_load(&cfg->vfd, filename); + ffb_config_load(&cfg->ffb, filename); led15070_config_load(&cfg->led15070, filename); -} - -void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename) -{ - assert(cfg != NULL); - assert(filename != NULL); - - cfg->enable = GetPrivateProfileIntW(L"zinput", L"enable", 1, filename); + vfd_config_load(&cfg->vfd, filename); } diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index f9c6081..bd6a1b3 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -8,8 +8,8 @@ WITH 838-15416 Indicator BD LED Board COM1: 838-15069 MOTOR DRIVE BD RS232/422 board - COM2: 837-15396 "Gen 3" Aime reader - COM3: 837-15070-04 IC BD LED controller board + COM2: 837-15070-04 IC BD LED controller board + COM3: 837-15396 "Gen 3" Aime reader COM4: 200-6275 VFD GP1232A02A FUTABA board */ @@ -97,7 +97,8 @@ static DWORD CALLBACK swdc_pre_startup(void) if (FAILED(hr)) { goto fail; } - + + /* Not working, different board -04 instead of -02? */ hr = led15070_hook_init(&swdc_hook_cfg.led15070, swdc_dll.led_init, swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, 2, 1); diff --git a/swdchook/io4.c b/swdchook/io4.c index 5221f63..be1d4b9 100644 --- a/swdchook/io4.c +++ b/swdchook/io4.c @@ -177,6 +177,8 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) { + assert(swdc_dll.led_set_leds != NULL); + // Just fast fail if there aren't enough bytes in the payload if (len < 3) return S_OK; From 3bb9404a38d865f4d6e139e5a88b656a182e5956 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:43:34 +0200 Subject: [PATCH 154/204] printer: add the default waitTime setting to config --- dist/kemono/segatools.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/kemono/segatools.ini b/dist/kemono/segatools.ini index 2da65aa..5f6186e 100644 --- a/dist/kemono/segatools.ini +++ b/dist/kemono/segatools.ini @@ -89,6 +89,9 @@ enable=1 serial_no="5A-A123" ; Insert the path to the image output directory here. printerOutPath="DEVICE\print" +; The length in milliseconds the printer should be busy printing. +; Set to 0 to instantly finish printing. +waitTime=20000 ; ----------------------------------------------------------------------------- ; LED settings From 66317a0054de3149b185e7efcb16f07ec1c90a02 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 11 Oct 2024 07:32:22 +0200 Subject: [PATCH 155/204] bump capnhook rev to include serial fixes --- subprojects/capnhook.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index 584b4a1..01a5c57 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook url = https://github.com/Hay1tsme/capnhook -revision = 09306229f1fd09bae0e617865a26778d3537ff93 +revision = f060250e1b92dcb06946eb77742f0ab51755e158 From 243bb778d1dca2e0fb0b61204466deeddb017581 Mon Sep 17 00:00:00 2001 From: Kagamine Haku Date: Wed, 16 Oct 2024 04:08:54 +0700 Subject: [PATCH 156/204] Add automatically apply OpenSSL patch for Intel Gen 10+ CPUs --- platform/meson.build | 2 + platform/opensslpatch.c | 101 ++++++++++++++++++++++++++++++++++++++++ platform/opensslpatch.h | 8 ++++ platform/platform.c | 3 ++ platform/platform.h | 1 + 5 files changed, 115 insertions(+) create mode 100644 platform/opensslpatch.c create mode 100644 platform/opensslpatch.h diff --git a/platform/meson.build b/platform/meson.build index aa0d362..a00df6b 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -36,5 +36,7 @@ platform_lib = static_library( 'vfs.h', 'system.c', 'system.h', + 'opensslpatch.c', + 'opensslpatch.h', ], ) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c new file mode 100644 index 0000000..c2ca13b --- /dev/null +++ b/platform/opensslpatch.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include "util/dprintf.h" +#include "platform/opensslpatch.h" + +int ChecknPatch(void) { + char* cpuname = GetCpuName(); + if (cpuname == NULL) { + dprintf("Error: Unable to detect CPU.\n"); + return 1; + } + + //dprintf("CPU Detected: %s\n", cpuname); + + if (CheckCpu(cpuname)) { + OpenSSLPatch(); + dprintf("OpenSSL Patch applied successfully.\n"); + } else { + dprintf("Info: OpenSSL Patch is not required (AMD or Intel < 10th gen or older CPU detected).\n"); + } + + free(cpuname); + return 0; +} + +char* GetCpuName() { + FILE* fp; + char buffer[128]; + char* cpu_info = NULL; + + fp = _popen("wmic cpu get Name", "r"); + + if (fp == NULL) { + return NULL; + } + + fgets(buffer, sizeof(buffer), fp); + + if (fgets(buffer, sizeof(buffer), fp) != NULL) { + cpu_info = (char*)malloc(strlen(buffer) + 1); + strcpy(cpu_info, buffer); + } + _pclose(fp); + + if (cpu_info != NULL) { + cpu_info[strcspn(cpu_info, "\r\n")] = 0; + } + + return cpu_info; +} + +int CheckCpu(char* cpuname) { + if (strstr(cpuname, "Core 2 Duo") || strstr(cpuname, "Core 2 Quad") || + (strstr(cpuname, "Pentium") && !strstr(cpuname, "G")) || strstr(cpuname, "Celeron")) { + //dprintf("Trash detected. No patch needed.\n"); + return 0; + } + + if (strstr(cpuname, "Intel")) { + char* part = strtok(cpuname, " "); + while (part != NULL) { + if (part[0] == 'i' && strlen(part) >= 4) { + int gen = atoi(part + 1); + if (gen >= 10) { + dprintf("Intel Gen 10+ CPU Detected: %s\n", cpuname); + return 1; + } + } else if (part[0] == 'G' && strlen(part) >= 4) { + int pentium = atoi(part + 1); + if (pentium / 1000 >= 6) { + dprintf("Intel Gen 10+ CPU Detected: %s\n", cpuname); + return 1; + } + } + part = strtok(NULL, " "); + } + } + + return 0; +} + +void OpenSSLPatch(void) { + const char* variablename = "OPENSSL_ia32cap"; + const char* variablevalue = "~0x20000000"; + + HKEY hKey; + if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { + if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { + dprintf("Successfully set the user environment variable %s to %s\n", variablename, variablevalue); + } else { + dprintf("Error: Failed to set the user environment variable.\n"); + } + + RegCloseKey(hKey); + + SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); + } else { + dprintf("Error: Failed to open the user environment registry key.\n"); + } +} diff --git a/platform/opensslpatch.h b/platform/opensslpatch.h new file mode 100644 index 0000000..5def7d5 --- /dev/null +++ b/platform/opensslpatch.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +int ChecknPatch(void); +void OpenSSLPatch(void); +char* GetCpuName(void); +int CheckCpu(char* cpuname); diff --git a/platform/platform.c b/platform/platform.c index a769c97..5dbebc7 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -14,6 +14,7 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/opensslpatch.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -28,6 +29,8 @@ HRESULT platform_hook_init( assert(platform_id != NULL); assert(redir_mod != NULL); + ChecknPatch(); + hr = amvideo_hook_init(&cfg->amvideo, redir_mod); if (FAILED(hr)) { diff --git a/platform/platform.h b/platform/platform.h index 0b69f12..b9bf7fd 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -14,6 +14,7 @@ #include "platform/pcbid.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/opensslpatch.h" struct platform_config { struct amvideo_config amvideo; From f39b9ce3a0fbb15d4e3e0c938c0f42c91b878bc8 Mon Sep 17 00:00:00 2001 From: Kagamine Haku Date: Wed, 16 Oct 2024 15:01:39 +0700 Subject: [PATCH 157/204] resolve dniel97 comments --- platform/opensslpatch.c | 51 ++++++++++++++++++----------------------- platform/opensslpatch.h | 7 +----- platform/platform.c | 2 +- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index c2ca13b..afb5fd6 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -4,27 +4,7 @@ #include "util/dprintf.h" #include "platform/opensslpatch.h" -int ChecknPatch(void) { - char* cpuname = GetCpuName(); - if (cpuname == NULL) { - dprintf("Error: Unable to detect CPU.\n"); - return 1; - } - - //dprintf("CPU Detected: %s\n", cpuname); - - if (CheckCpu(cpuname)) { - OpenSSLPatch(); - dprintf("OpenSSL Patch applied successfully.\n"); - } else { - dprintf("Info: OpenSSL Patch is not required (AMD or Intel < 10th gen or older CPU detected).\n"); - } - - free(cpuname); - return 0; -} - -char* GetCpuName() { +static char* GetCpuName() { FILE* fp; char buffer[128]; char* cpu_info = NULL; @@ -50,10 +30,9 @@ char* GetCpuName() { return cpu_info; } -int CheckCpu(char* cpuname) { +static int CheckCpu(char* cpuname) { if (strstr(cpuname, "Core 2 Duo") || strstr(cpuname, "Core 2 Quad") || (strstr(cpuname, "Pentium") && !strstr(cpuname, "G")) || strstr(cpuname, "Celeron")) { - //dprintf("Trash detected. No patch needed.\n"); return 0; } @@ -63,13 +42,13 @@ int CheckCpu(char* cpuname) { if (part[0] == 'i' && strlen(part) >= 4) { int gen = atoi(part + 1); if (gen >= 10) { - dprintf("Intel Gen 10+ CPU Detected: %s\n", cpuname); + dprintf("OpenSSL Patch: Intel Gen 10+ CPU Detected: %s\n", cpuname); return 1; } } else if (part[0] == 'G' && strlen(part) >= 4) { int pentium = atoi(part + 1); if (pentium / 1000 >= 6) { - dprintf("Intel Gen 10+ CPU Detected: %s\n", cpuname); + dprintf("OpenSSL Patch: Intel Gen 10+ CPU Detected: %s\n", cpuname); return 1; } } @@ -80,22 +59,36 @@ int CheckCpu(char* cpuname) { return 0; } -void OpenSSLPatch(void) { +static void OpenSSLPatch(void) { const char* variablename = "OPENSSL_ia32cap"; const char* variablevalue = "~0x20000000"; HKEY hKey; if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { - dprintf("Successfully set the user environment variable %s to %s\n", variablename, variablevalue); + dprintf("OpenSSL Patch: Applied successfully : Set the user environment variable %s to %s\n", variablename, variablevalue); } else { - dprintf("Error: Failed to set the user environment variable.\n"); + dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); } RegCloseKey(hKey); SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); } else { - dprintf("Error: Failed to open the user environment registry key.\n"); + dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); } } + +int openssl_patch_apply(void) { + char* cpuname = GetCpuName(); + if (cpuname == NULL) { + dprintf("OpenSSL Patch: Error: Unable to detect CPU.\n"); + return 1; + } + + if (CheckCpu(cpuname)) { + OpenSSLPatch(); + } + free(cpuname); + return 0; +} \ No newline at end of file diff --git a/platform/opensslpatch.h b/platform/opensslpatch.h index 5def7d5..fe665a5 100644 --- a/platform/opensslpatch.h +++ b/platform/opensslpatch.h @@ -1,8 +1,3 @@ #pragma once -#include - -int ChecknPatch(void); -void OpenSSLPatch(void); -char* GetCpuName(void); -int CheckCpu(char* cpuname); +int openssl_patch_apply(void); diff --git a/platform/platform.c b/platform/platform.c index 5dbebc7..4f663bc 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -29,7 +29,7 @@ HRESULT platform_hook_init( assert(platform_id != NULL); assert(redir_mod != NULL); - ChecknPatch(); + openssl_patch_apply(); hr = amvideo_hook_init(&cfg->amvideo, redir_mod); From 97d2d6b9bc96072cb3726c0efc784c8902476e84 Mon Sep 17 00:00:00 2001 From: Kagamine Haku Date: Wed, 16 Oct 2024 15:53:52 +0700 Subject: [PATCH 158/204] resolved camelCase and the " :" problem --- platform/opensslpatch.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index afb5fd6..4537195 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -4,7 +4,7 @@ #include "util/dprintf.h" #include "platform/opensslpatch.h" -static char* GetCpuName() { +static char* get_cpu_name() { FILE* fp; char buffer[128]; char* cpu_info = NULL; @@ -30,7 +30,7 @@ static char* GetCpuName() { return cpu_info; } -static int CheckCpu(char* cpuname) { +static int check_cpu(char* cpuname) { if (strstr(cpuname, "Core 2 Duo") || strstr(cpuname, "Core 2 Quad") || (strstr(cpuname, "Pentium") && !strstr(cpuname, "G")) || strstr(cpuname, "Celeron")) { return 0; @@ -59,14 +59,14 @@ static int CheckCpu(char* cpuname) { return 0; } -static void OpenSSLPatch(void) { +static void openssl_patch(void) { const char* variablename = "OPENSSL_ia32cap"; const char* variablevalue = "~0x20000000"; HKEY hKey; if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { - dprintf("OpenSSL Patch: Applied successfully : Set the user environment variable %s to %s\n", variablename, variablevalue); + dprintf("OpenSSL Patch: Applied successfully, set the user environment variable %s to %s\n", variablename, variablevalue); } else { dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); } @@ -80,14 +80,14 @@ static void OpenSSLPatch(void) { } int openssl_patch_apply(void) { - char* cpuname = GetCpuName(); + char* cpuname = get_cpu_name(); if (cpuname == NULL) { dprintf("OpenSSL Patch: Error: Unable to detect CPU.\n"); return 1; } - if (CheckCpu(cpuname)) { - OpenSSLPatch(); + if (check_cpu(cpuname)) { + openssl_patch(); } free(cpuname); return 0; From cef3406691891a0065f970d436e038ab9f9a380e Mon Sep 17 00:00:00 2001 From: Kagamine Haku Date: Fri, 18 Oct 2024 13:34:25 +0700 Subject: [PATCH 159/204] Add switch for openssl patch in segatools.ini --- platform/config.c | 17 +++++++++++++++++ platform/config.h | 1 + platform/opensslpatch.c | 15 ++++++++++++--- platform/opensslpatch.h | 6 +++++- platform/platform.c | 6 +++++- platform/platform.h | 1 + 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/platform/config.c b/platform/config.c index ad97905..98b67b6 100644 --- a/platform/config.c +++ b/platform/config.c @@ -23,6 +23,7 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/opensslpatch.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -41,6 +42,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); system_config_load(&cfg->system, filename); + openssl_patch_config_load(&cfg->openssl, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -355,3 +357,18 @@ void epay_config_load(struct epay_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); } + +void openssl_patch_config_load(struct openssl_patch_config *cfg, const wchar_t *filename) +{ + // Ensure the config structure and filename are valid + assert(cfg != NULL); + assert(filename != NULL); + + // Read the "enable" key from the "[openssl]" section of the configuration file + cfg->enable = GetPrivateProfileIntW( + L"openssl", // Section name + L"enable", // Key name + 1, // Default value if the key is not found (disabled by default) + filename // INI file name + ); +} diff --git a/platform/config.h b/platform/config.h index e945378..9f1f7f4 100644 --- a/platform/config.h +++ b/platform/config.h @@ -36,3 +36,4 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); void system_config_load(struct system_config *cfg, const wchar_t *filename); +void openssl_patch_config_load(struct openssl_patch_config *cfg, const wchar_t *filename); \ No newline at end of file diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index 4537195..bebbaf9 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -79,16 +79,25 @@ static void openssl_patch(void) { } } -int openssl_patch_apply(void) { +HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg) { + HRESULT hr; + + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + char* cpuname = get_cpu_name(); if (cpuname == NULL) { dprintf("OpenSSL Patch: Error: Unable to detect CPU.\n"); - return 1; + return S_FALSE; } if (check_cpu(cpuname)) { openssl_patch(); } + free(cpuname); - return 0; + return S_OK; } \ No newline at end of file diff --git a/platform/opensslpatch.h b/platform/opensslpatch.h index fe665a5..f97d9b7 100644 --- a/platform/opensslpatch.h +++ b/platform/opensslpatch.h @@ -1,3 +1,7 @@ #pragma once -int openssl_patch_apply(void); +struct openssl_patch_config { + int enable; +}; + +HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg); diff --git a/platform/platform.c b/platform/platform.c index 4f663bc..c61c031 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -29,7 +29,11 @@ HRESULT platform_hook_init( assert(platform_id != NULL); assert(redir_mod != NULL); - openssl_patch_apply(); + hr = openssl_patch_apply(&cfg->openssl); + + if (FAILED(hr)) { + return hr; + } hr = amvideo_hook_init(&cfg->amvideo, redir_mod); diff --git a/platform/platform.h b/platform/platform.h index b9bf7fd..4972bfe 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -29,6 +29,7 @@ struct platform_config { struct nusec_config nusec; struct vfs_config vfs; struct system_config system; + struct openssl_patch_config openssl; }; HRESULT platform_hook_init( From b80b9fbc19673f63d49831ce69459cc23954c5d2 Mon Sep 17 00:00:00 2001 From: Kagamine Haku Date: Fri, 18 Oct 2024 13:44:47 +0700 Subject: [PATCH 160/204] Delete useless comment --- platform/config.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/platform/config.c b/platform/config.c index 98b67b6..f2eea12 100644 --- a/platform/config.c +++ b/platform/config.c @@ -360,15 +360,13 @@ void epay_config_load(struct epay_config *cfg, const wchar_t *filename) void openssl_patch_config_load(struct openssl_patch_config *cfg, const wchar_t *filename) { - // Ensure the config structure and filename are valid assert(cfg != NULL); assert(filename != NULL); - // Read the "enable" key from the "[openssl]" section of the configuration file cfg->enable = GetPrivateProfileIntW( - L"openssl", // Section name - L"enable", // Key name - 1, // Default value if the key is not found (disabled by default) - filename // INI file name + L"openssl", + L"enable", + 1, + filename ); } From 892eb2b859849daae1ca6df3535c77278fe36861 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 29 Oct 2024 22:06:07 +0100 Subject: [PATCH 161/204] idz, idac, swdc: fixed rumble effect --- dist/idac/segatools.ini | 1 - dist/idz/segatools.ini | 1 - dist/swdc/segatools.ini | 1 - idacio/di-dev.c | 116 ++++++++++++++++++---------------------- idzio/di-dev.c | 116 ++++++++++++++++++---------------------- swdcio/di-dev.c | 116 ++++++++++++++++++---------------------- 6 files changed, 156 insertions(+), 195 deletions(-) diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index da94d64..a2387af 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -250,7 +250,6 @@ constantForceStrength=100 damperStrength=100 ; Rumble strength, used for road surface effects. -; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! rumbleStrength=100 ; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. rumbleDuration=1000 diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index 126a5b7..e617de2 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -240,7 +240,6 @@ constantForceStrength=100 damperStrength=100 ; Rumble strength, used for road surface effects. -; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! rumbleStrength=100 ; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. rumbleDuration=1000 \ No newline at end of file diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index b6b15b8..1b24a74 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -200,7 +200,6 @@ constantForceStrength=100 damperStrength=100 ; Rumble strength, used for road surface effects. -; WARNING: THIS WILL CRASH ON FANATEC (maybe even more) WHEELS! rumbleStrength=100 ; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect. rumbleDuration=1000 diff --git a/idacio/di-dev.c b/idacio/di-dev.c index a8b6e0b..5f959f6 100644 --- a/idacio/di-dev.c +++ b/idacio/di-dev.c @@ -37,9 +37,9 @@ HRESULT idac_di_dev_init( } HRESULT idac_di_dev_poll( - IDirectInputDevice8W *dev, - HWND wnd, - union idac_di_state *out) + IDirectInputDevice8W *dev, + HWND wnd, + union idac_di_state *out) { HRESULT hr; MSG msg; @@ -59,17 +59,14 @@ HRESULT idac_di_dev_poll( } hr = IDirectInputDevice8_GetDeviceState( - dev, - sizeof(out->st), - &out->st); + dev, + sizeof(out->st), + &out->st); if (FAILED(hr)) { - dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } - /* JVS lacks a protocol for reporting hardware errors from poll command - responses, so this ends up returning zeroed input state instead. */ - return hr; } @@ -80,29 +77,26 @@ HRESULT idac_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { assert(wnd != NULL); hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_Acquire(dev); if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - + dprintf("DirectInput: Acquire failed: %08x\n", (int)hr); return hr; } @@ -168,7 +162,6 @@ void idac_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; axis = DIJOFS_X; - /* Irrelevant as magnitude descripbes the direction */ direction = 0; memset(&fx, 0, sizeof(fx)); @@ -184,38 +177,38 @@ void idac_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) fx.cbTypeSpecificParams = sizeof(cf); fx.lpvTypeSpecificParams = &cf; + /* Check if the effect already exists */ if (idac_di_fx != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idac_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { - return; - } else { + return; // Successfully updated existing effect + } + else { dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails IDirectInputEffect_Stop(idac_di_fx); IDirectInputEffect_Release(idac_di_fx); - idac_di_fx = NULL; + idac_di_fx = NULL; // Reset the pointer } } - // Create a new constant force effect + /* Create a new constant force effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idac_di_dev, - &GUID_ConstantForce, - &fx, - &obj, - NULL); + idac_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -239,9 +232,6 @@ void idac_di_ffb_rumble(uint8_t force, uint8_t period) DIPERIODIC pe; HRESULT hr; - /* Duration in microseconds, - Might be totally wrong as especially on FANATEC wheels as this code will - crash the game. TODO: Figure out why this effect will crash on FANATEC! */ DWORD duration = (DWORD)((double)force * ffb_duration); memset(&pe, 0, sizeof(pe)); @@ -256,7 +246,7 @@ void idac_di_ffb_rumble(uint8_t force, uint8_t period) memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = duration; + fx.dwDuration = INFINITE; fx.dwGain = DI_FFNOMINALMAX; fx.dwTriggerButton = DIEB_NOTRIGGER; fx.dwTriggerRepeatInterval = INFINITE; @@ -266,37 +256,38 @@ void idac_di_ffb_rumble(uint8_t force, uint8_t period) fx.cbTypeSpecificParams = sizeof(pe); fx.lpvTypeSpecificParams = &pe; + /* Check if the effect already exists */ if (idac_di_fx_rumble != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idac_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { + dprintf("DirectInput: Failed to update rumble feedback, recreating effect: %08x\n", (int)hr); IDirectInputEffect_Stop(idac_di_fx_rumble); IDirectInputEffect_Release(idac_di_fx_rumble); idac_di_fx_rumble = NULL; } } + /* Create a new rumble effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idac_di_dev, - &GUID_Sine, - &fx, - &obj, - NULL); + idac_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -343,38 +334,35 @@ void idac_di_ffb_damper(uint8_t force) fx.cbTypeSpecificParams = sizeof(cond); fx.lpvTypeSpecificParams = &cond; + /* Check if the damper effect already exists */ if (idac_di_fx_damper != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idac_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { IDirectInputEffect_Stop(idac_di_fx_damper); IDirectInputEffect_Release(idac_di_fx_damper); idac_di_fx_damper = NULL; } } - // Create a new damper force effect + /* Create a new damper effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idac_di_dev, - &GUID_Damper, - &fx, - &obj, - NULL); + idac_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); return; } - hr = IDirectInputEffect_Start(obj, INFINITE, 0); + /* Start the effect */ + hr = IDirectInputEffect_Start(obj, fx.dwDuration, 0); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); IDirectInputEffect_Release(obj); return; } diff --git a/idzio/di-dev.c b/idzio/di-dev.c index 053eb9c..10b67d6 100644 --- a/idzio/di-dev.c +++ b/idzio/di-dev.c @@ -37,9 +37,9 @@ HRESULT idz_di_dev_init( } HRESULT idz_di_dev_poll( - IDirectInputDevice8W *dev, - HWND wnd, - union idz_di_state *out) + IDirectInputDevice8W *dev, + HWND wnd, + union idz_di_state *out) { HRESULT hr; MSG msg; @@ -59,17 +59,14 @@ HRESULT idz_di_dev_poll( } hr = IDirectInputDevice8_GetDeviceState( - dev, - sizeof(out->st), - &out->st); + dev, + sizeof(out->st), + &out->st); if (FAILED(hr)) { - dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } - /* JVS lacks a protocol for reporting hardware errors from poll command - responses, so this ends up returning zeroed input state instead. */ - return hr; } @@ -80,29 +77,26 @@ HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { assert(wnd != NULL); hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_Acquire(dev); if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - + dprintf("DirectInput: Acquire failed: %08x\n", (int)hr); return hr; } @@ -168,7 +162,6 @@ void idz_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; axis = DIJOFS_X; - /* Irrelevant as magnitude descripbes the direction */ direction = 0; memset(&fx, 0, sizeof(fx)); @@ -184,38 +177,38 @@ void idz_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) fx.cbTypeSpecificParams = sizeof(cf); fx.lpvTypeSpecificParams = &cf; + /* Check if the effect already exists */ if (idz_di_fx != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idz_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { - return; - } else { + return; // Successfully updated existing effect + } + else { dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails IDirectInputEffect_Stop(idz_di_fx); IDirectInputEffect_Release(idz_di_fx); - idz_di_fx = NULL; + idz_di_fx = NULL; // Reset the pointer } } - // Create a new constant force effect + /* Create a new constant force effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idz_di_dev, - &GUID_ConstantForce, - &fx, - &obj, - NULL); + idz_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -239,9 +232,6 @@ void idz_di_ffb_rumble(uint8_t force, uint8_t period) DIPERIODIC pe; HRESULT hr; - /* Duration in microseconds, - Might be totally wrong as especially on FANATEC wheels as this code will - crash the game. TODO: Figure out why this effect will crash on FANATEC! */ DWORD duration = (DWORD)((double)force * ffb_duration); memset(&pe, 0, sizeof(pe)); @@ -256,7 +246,7 @@ void idz_di_ffb_rumble(uint8_t force, uint8_t period) memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = duration; + fx.dwDuration = INFINITE; fx.dwGain = DI_FFNOMINALMAX; fx.dwTriggerButton = DIEB_NOTRIGGER; fx.dwTriggerRepeatInterval = INFINITE; @@ -266,37 +256,38 @@ void idz_di_ffb_rumble(uint8_t force, uint8_t period) fx.cbTypeSpecificParams = sizeof(pe); fx.lpvTypeSpecificParams = &pe; + /* Check if the effect already exists */ if (idz_di_fx_rumble != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idz_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { + dprintf("DirectInput: Failed to update rumble feedback, recreating effect: %08x\n", (int)hr); IDirectInputEffect_Stop(idz_di_fx_rumble); IDirectInputEffect_Release(idz_di_fx_rumble); idz_di_fx_rumble = NULL; } } + /* Create a new rumble effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idz_di_dev, - &GUID_Sine, - &fx, - &obj, - NULL); + idz_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -343,38 +334,35 @@ void idz_di_ffb_damper(uint8_t force) fx.cbTypeSpecificParams = sizeof(cond); fx.lpvTypeSpecificParams = &cond; + /* Check if the damper effect already exists */ if (idz_di_fx_damper != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(idz_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { IDirectInputEffect_Stop(idz_di_fx_damper); IDirectInputEffect_Release(idz_di_fx_damper); idz_di_fx_damper = NULL; } } - // Create a new damper force effect + /* Create a new damper effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - idz_di_dev, - &GUID_Damper, - &fx, - &obj, - NULL); + idz_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); return; } - hr = IDirectInputEffect_Start(obj, INFINITE, 0); + /* Start the effect */ + hr = IDirectInputEffect_Start(obj, fx.dwDuration, 0); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); IDirectInputEffect_Release(obj); return; } diff --git a/swdcio/di-dev.c b/swdcio/di-dev.c index 85db2fb..4f099cc 100644 --- a/swdcio/di-dev.c +++ b/swdcio/di-dev.c @@ -37,9 +37,9 @@ HRESULT swdc_di_dev_init( } HRESULT swdc_di_dev_poll( - IDirectInputDevice8W *dev, - HWND wnd, - union swdc_di_state *out) + IDirectInputDevice8W *dev, + HWND wnd, + union swdc_di_state *out) { HRESULT hr; MSG msg; @@ -59,17 +59,14 @@ HRESULT swdc_di_dev_poll( } hr = IDirectInputDevice8_GetDeviceState( - dev, - sizeof(out->st), - &out->st); + dev, + sizeof(out->st), + &out->st); if (FAILED(hr)) { - dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } - /* JVS lacks a protocol for reporting hardware errors from poll command - responses, so this ends up returning zeroed input state instead. */ - return hr; } @@ -80,29 +77,26 @@ HRESULT swdc_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) { assert(wnd != NULL); hr = IDirectInputDevice8_SetCooperativeLevel( - dev, - wnd, - DISCL_BACKGROUND | DISCL_EXCLUSIVE); + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); if (FAILED(hr)) { - dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); if (FAILED(hr)) { - dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); - + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int)hr); return hr; } hr = IDirectInputDevice8_Acquire(dev); if (FAILED(hr)) { - dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); - + dprintf("DirectInput: Acquire failed: %08x\n", (int)hr); return hr; } @@ -168,7 +162,6 @@ void swdc_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) cf.lMagnitude = (direction_ffb == 0) ? -magnitude : magnitude; axis = DIJOFS_X; - /* Irrelevant as magnitude descripbes the direction */ direction = 0; memset(&fx, 0, sizeof(fx)); @@ -184,38 +177,38 @@ void swdc_di_ffb_constant_force(uint8_t direction_ffb, uint8_t force) fx.cbTypeSpecificParams = sizeof(cf); fx.lpvTypeSpecificParams = &cf; + /* Check if the effect already exists */ if (swdc_di_fx != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(swdc_di_fx, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { - return; - } else { + return; // Successfully updated existing effect + } + else { dprintf("DirectInput: Failed to update constant force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails IDirectInputEffect_Stop(swdc_di_fx); IDirectInputEffect_Release(swdc_di_fx); - swdc_di_fx = NULL; + swdc_di_fx = NULL; // Reset the pointer } } - // Create a new constant force effect + /* Create a new constant force effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - swdc_di_dev, - &GUID_ConstantForce, - &fx, - &obj, - NULL); + swdc_di_dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Constant force feedback start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -239,9 +232,6 @@ void swdc_di_ffb_rumble(uint8_t force, uint8_t period) DIPERIODIC pe; HRESULT hr; - /* Duration in microseconds, - Might be totally wrong as especially on FANATEC wheels as this code will - crash the game. TODO: Figure out why this effect will crash on FANATEC! */ DWORD duration = (DWORD)((double)force * ffb_duration); memset(&pe, 0, sizeof(pe)); @@ -256,7 +246,7 @@ void swdc_di_ffb_rumble(uint8_t force, uint8_t period) memset(&fx, 0, sizeof(fx)); fx.dwSize = sizeof(fx); fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - fx.dwDuration = duration; + fx.dwDuration = INFINITE; fx.dwGain = DI_FFNOMINALMAX; fx.dwTriggerButton = DIEB_NOTRIGGER; fx.dwTriggerRepeatInterval = INFINITE; @@ -266,37 +256,38 @@ void swdc_di_ffb_rumble(uint8_t force, uint8_t period) fx.cbTypeSpecificParams = sizeof(pe); fx.lpvTypeSpecificParams = &pe; + /* Check if the effect already exists */ if (swdc_di_fx_rumble != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(swdc_di_fx_rumble, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update periodic force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { + dprintf("DirectInput: Failed to update rumble feedback, recreating effect: %08x\n", (int)hr); IDirectInputEffect_Stop(swdc_di_fx_rumble); IDirectInputEffect_Release(swdc_di_fx_rumble); swdc_di_fx_rumble = NULL; } } + /* Create a new rumble effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - swdc_di_dev, - &GUID_Sine, - &fx, - &obj, - NULL); + swdc_di_dev, + &GUID_Sine, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback creation failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect creation failed: %08x\n", (int)hr); return; } + /* Start the effect */ hr = IDirectInputEffect_Start(obj, INFINITE, 0); if (FAILED(hr)) { - dprintf("DirectInput: Periodic force feedback start failed: %08x\n", (int) hr); + dprintf("DirectInput: Rumble effect start failed: %08x\n", (int)hr); IDirectInputEffect_Release(obj); return; } @@ -343,38 +334,35 @@ void swdc_di_ffb_damper(uint8_t force) fx.cbTypeSpecificParams = sizeof(cond); fx.lpvTypeSpecificParams = &cond; + /* Check if the damper effect already exists */ if (swdc_di_fx_damper != NULL) { - // Try to update the existing effect hr = IDirectInputEffect_SetParameters(swdc_di_fx_damper, &fx, DIEP_TYPESPECIFICPARAMS); - if (SUCCEEDED(hr)) { return; - } else { - dprintf("DirectInput: Failed to update damper force feedback, recreating effect: %08x\n", (int)hr); - // Stop and release the current effect if updating fails + } + else { IDirectInputEffect_Stop(swdc_di_fx_damper); IDirectInputEffect_Release(swdc_di_fx_damper); swdc_di_fx_damper = NULL; } } - // Create a new damper force effect + /* Create a new damper effect */ IDirectInputEffect *obj; hr = IDirectInputDevice8_CreateEffect( - swdc_di_dev, - &GUID_Damper, - &fx, - &obj, - NULL); + swdc_di_dev, + &GUID_Damper, + &fx, + &obj, + NULL); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback creation failed: %08x\n", (int) hr); return; } - hr = IDirectInputEffect_Start(obj, INFINITE, 0); + /* Start the effect */ + hr = IDirectInputEffect_Start(obj, fx.dwDuration, 0); if (FAILED(hr)) { - dprintf("DirectInput: Damper force feedback start failed: %08x\n", (int) hr); IDirectInputEffect_Release(obj); return; } From ebf0f0b4288529acae393ee91f2e84605404de76 Mon Sep 17 00:00:00 2001 From: KagamineHaku Date: Sat, 2 Nov 2024 00:26:31 +0700 Subject: [PATCH 162/204] Develop a new/better method to detect cpu using intrinsic functions (__cpuid and __cpuidex) --- platform/opensslpatch.c | 72 +++++++++-------------------------------- 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index bebbaf9..4db287c 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -1,59 +1,26 @@ #include #include #include +#include #include "util/dprintf.h" #include "platform/opensslpatch.h" -static char* get_cpu_name() { - FILE* fp; - char buffer[128]; - char* cpu_info = NULL; +int check_cpu() { + int cpui[4] = {0}; - fp = _popen("wmic cpu get Name", "r"); + __cpuid(cpui, 0); + int nIds_ = cpui[0]; - if (fp == NULL) { - return NULL; - } + char vendor[0x20] = {0}; + *((int*)vendor) = cpui[1]; + *((int*)(vendor + 4)) = cpui[3]; + *((int*)(vendor + 8)) = cpui[2]; - fgets(buffer, sizeof(buffer), fp); + int isIntel = (strcmp(vendor, "GenuineIntel") == 0); - if (fgets(buffer, sizeof(buffer), fp) != NULL) { - cpu_info = (char*)malloc(strlen(buffer) + 1); - strcpy(cpu_info, buffer); - } - _pclose(fp); - - if (cpu_info != NULL) { - cpu_info[strcspn(cpu_info, "\r\n")] = 0; - } - - return cpu_info; -} - -static int check_cpu(char* cpuname) { - if (strstr(cpuname, "Core 2 Duo") || strstr(cpuname, "Core 2 Quad") || - (strstr(cpuname, "Pentium") && !strstr(cpuname, "G")) || strstr(cpuname, "Celeron")) { - return 0; - } - - if (strstr(cpuname, "Intel")) { - char* part = strtok(cpuname, " "); - while (part != NULL) { - if (part[0] == 'i' && strlen(part) >= 4) { - int gen = atoi(part + 1); - if (gen >= 10) { - dprintf("OpenSSL Patch: Intel Gen 10+ CPU Detected: %s\n", cpuname); - return 1; - } - } else if (part[0] == 'G' && strlen(part) >= 4) { - int pentium = atoi(part + 1); - if (pentium / 1000 >= 6) { - dprintf("OpenSSL Patch: Intel Gen 10+ CPU Detected: %s\n", cpuname); - return 1; - } - } - part = strtok(NULL, " "); - } + if (isIntel && nIds_ >= 7) { + __cpuidex(cpui, 7, 0); + return (cpui[1] & (1 << 29)) != 0; } return 0; @@ -88,16 +55,9 @@ HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg) { return S_FALSE; } - char* cpuname = get_cpu_name(); - if (cpuname == NULL) { - dprintf("OpenSSL Patch: Error: Unable to detect CPU.\n"); - return S_FALSE; + if (check_cpu()) { + openssl_patch(); } - if (check_cpu(cpuname)) { - openssl_patch(); - } - - free(cpuname); return S_OK; -} \ No newline at end of file +} From 8fc24503c853a470c60f1a8c9640a6c642018168 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 3 Nov 2024 23:00:43 +0100 Subject: [PATCH 163/204] diva, fgo: added gfx, close #46 --- dist/carol/segatools.ini | 2 + dist/chuni/segatools.ini | 2 + dist/chusan/segatools.ini | 2 + dist/cxb/segatools.ini | 2 + dist/diva/segatools.ini | 18 ++++++++- dist/fgo/segatools.ini | 8 ++++ dist/mercury/segatools.ini | 1 + dist/mu3/segatools.ini | 1 + divahook/config.c | 5 +++ divahook/config.h | 14 ++++++- divahook/dllmain.c | 18 +++++++++ divahook/jvs.c | 14 +++---- divahook/meson.build | 1 + divaio/divaio.c | 4 +- divaio/divaio.h | 13 ++++++ fgohook/config.c | 1 + fgohook/config.h | 3 ++ fgohook/dllmain.c | 15 +++++++ fgohook/meson.build | 1 + gfxhook/gfx.c | 81 +++++++++++++++++++++++++++++++++++++- gfxhook/gl.c | 77 ++++++++++++++++++++++++++++++++++++ gfxhook/gl.h | 3 ++ gfxhook/meson.build | 2 + 23 files changed, 274 insertions(+), 14 deletions(-) create mode 100644 gfxhook/gl.c create mode 100644 gfxhook/gl.h diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index e79cf13..e75f1cd 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -64,6 +64,8 @@ subnet=192.168.126.0 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 5b8af0c..3e87cb0 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -56,6 +56,8 @@ subnet=192.168.139.0 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index ee3af18..7ff4d0a 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -82,6 +82,8 @@ dipsw3=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 6d9e5e0..1fe70c8 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -75,6 +75,8 @@ path=../DEVICE/sram.bin ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index 000f5c8..e8db667 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -5,7 +5,7 @@ [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains Axxx directories) +; Insert the path to the game Option (mdata) directory here (contains Mxxx directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. @@ -36,6 +36,10 @@ default=127.0.0.1 ; Chunithm is extremely picky about its LAN environment, so leaving this ; setting enabled is strongly recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 ; ----------------------------------------------------------------------------- ; Board settings @@ -54,6 +58,18 @@ dipsw1=1 ; that subnet must start with 192.168. subnet=192.168.78.0 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[gfx] +; Enables the graphics hook. +enable=1 +; Force the game to run windowed. +windowed=1 +; Add a frame to the game window if running windowed. +framed=0 + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 790de88..e9c7c20 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -85,6 +85,14 @@ freeplay=0 ; Misc. hook settings ; ----------------------------------------------------------------------------- +[gfx] +; Enables the graphics hook. +enable=1 +; Force the game to run windowed. +windowed=0 +; Add a frame to the game window if running windowed. +framed=0 + [touch] ; WinTouch emulation setting. enable=1 diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 0755bac..4e24489 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -74,6 +74,7 @@ dipsw1=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. enable=1 ; Hooks related to the touch boards diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 59ec0d2..43fef6e 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -70,6 +70,7 @@ dipsw1=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. enable=1 [unity] diff --git a/divahook/config.c b/divahook/config.c index 29ca5c8..142cf73 100644 --- a/divahook/config.c +++ b/divahook/config.c @@ -8,6 +8,9 @@ #include "board/config.h" #include "board/sg-reader.h" +#include "hooklib/config.h" +#include "hooklib/dvd.h" + #include "divahook/config.h" #include "platform/config.h" @@ -47,6 +50,8 @@ void diva_hook_config_load( platform_config_load(&cfg->platform, filename); amex_config_load(&cfg->amex, filename); aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + gfx_config_load(&cfg->gfx, filename); diva_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); } diff --git a/divahook/config.h b/divahook/config.h index a327f47..3b3f1ea 100644 --- a/divahook/config.h +++ b/divahook/config.h @@ -6,15 +6,25 @@ #include "board/sg-reader.h" +#include "hooklib/dvd.h" +#include "hooklib/touch.h" + +#include "gfxhook/config.h" + +#include "platform/config.h" + +#include "divahook/3mpxsc.h" #include "divahook/diva-dll.h" #include "divahook/slider.h" -#include "platform/platform.h" - struct diva_hook_config { struct platform_config platform; struct amex_config amex; struct aime_config aime; + struct dvd_config dvd; + struct gfx_config gfx; + struct touch3mpxsc_config touch3mpxsc; + struct touch_screen_config touch; struct diva_dll_config dll; struct slider_config slider; }; diff --git a/divahook/dllmain.c b/divahook/dllmain.c index 412fe9c..337eff5 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -22,6 +22,9 @@ #include "divahook/jvs.h" #include "divahook/slider.h" +#include "gfxhook/gfx.h" +#include "gfxhook/gl.h" + #include "hook/process.h" #include "hooklib/serial.h" @@ -38,15 +41,30 @@ static struct diva_hook_config diva_hook_cfg; static DWORD CALLBACK diva_pre_startup(void) { HRESULT hr; + HMODULE dbghelp; dprintf("--- Begin diva_pre_startup ---\n"); + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } + else { + dprintf("Failed to load debug helper library!\n"); + } + /* Config load */ diva_hook_config_load(&diva_hook_cfg, L".\\segatools.ini"); /* Hook Win32 APIs */ + dvd_hook_init(&diva_hook_cfg.dvd, diva_hook_mod); + gfx_hook_init(&diva_hook_cfg.gfx); + gfx_gl_hook_init(&diva_hook_cfg.gfx, diva_hook_mod); serial_hook_init(); /* Initialize emulation hooks */ diff --git a/divahook/jvs.c b/divahook/jvs.c index 14d222d..f718438 100644 --- a/divahook/jvs.c +++ b/divahook/jvs.c @@ -63,33 +63,33 @@ static void diva_jvs_read_switches(void *ctx, struct io3_switch_state *out) diva_dll.jvs_poll(&opbtn, &gamebtn); - if (gamebtn & 0x01) { + if (gamebtn & DIVA_IO_GAMEBTN_CIRCLE) { out->p1 |= 1 << 6; } - if (gamebtn & 0x02) { + if (gamebtn & DIVA_IO_GAMEBTN_CROSS) { out->p1 |= 1 << 7; } - if (gamebtn & 0x04) { + if (gamebtn & DIVA_IO_GAMEBTN_SQUARE) { out->p1 |= 1 << 8; } - if (gamebtn & 0x08) { + if (gamebtn & DIVA_IO_GAMEBTN_TRIANGLE) { out->p1 |= 1 << 9; } - if (gamebtn & 0x10) { + if (gamebtn & DIVA_IO_GAMEBTN_START) { out->p1 |= 1 << 15; } - if (opbtn & 0x01) { + if (opbtn & DIVA_IO_OPBTN_TEST) { out->system = 0x80; } else { out->system = 0; } - if (opbtn & 0x02) { + if (opbtn & DIVA_IO_OPBTN_SERVICE) { out->p1 |= 1 << 14; } } diff --git a/divahook/meson.build b/divahook/meson.build index 20c1ff2..e291f3e 100644 --- a/divahook/meson.build +++ b/divahook/meson.build @@ -14,6 +14,7 @@ shared_library( amex_lib, board_lib, divaio_lib, + gfxhook_lib, hooklib_lib, jvs_lib, platform_lib, diff --git a/divaio/divaio.c b/divaio/divaio.c index 760e198..9976cb7 100644 --- a/divaio/divaio.c +++ b/divaio/divaio.c @@ -37,11 +37,11 @@ void diva_io_jvs_poll(uint8_t *opbtn_out, uint8_t *gamebtn_out) opbtn = 0; if (GetAsyncKeyState(diva_io_cfg.vk_test) & 0x8000) { - opbtn |= 1; + opbtn |= DIVA_IO_OPBTN_TEST; } if (GetAsyncKeyState(diva_io_cfg.vk_service) & 0x8000) { - opbtn |= 2; + opbtn |= DIVA_IO_OPBTN_SERVICE; } for (i = 0 ; i < _countof(diva_io_cfg.vk_buttons) ; i++) { diff --git a/divaio/divaio.h b/divaio/divaio.h index bac3627..7dd13b8 100644 --- a/divaio/divaio.h +++ b/divaio/divaio.h @@ -5,6 +5,19 @@ #include #include +enum { + DIVA_IO_OPBTN_TEST = 0x01, + DIVA_IO_OPBTN_SERVICE = 0x02 +}; + +enum { + DIVA_IO_GAMEBTN_CIRCLE = 0x01, + DIVA_IO_GAMEBTN_CROSS = 0x02, + DIVA_IO_GAMEBTN_SQUARE = 0x04, + DIVA_IO_GAMEBTN_TRIANGLE = 0x08, + DIVA_IO_GAMEBTN_START = 0x10, +}; + /* Get the version of the Project Diva IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the diff --git a/fgohook/config.c b/fgohook/config.c index 5442b32..b2bb7f5 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -122,5 +122,6 @@ void fgo_hook_config_load( fgo_deck_config_load(&cfg->deck, filename); ftdi_config_load(&cfg->ftdi, filename); led15093_config_load(&cfg->led15093, filename); + gfx_config_load(&cfg->gfx, filename); fgo_dll_config_load(&cfg->dll, filename); } diff --git a/fgohook/config.h b/fgohook/config.h index ffffc25..ca8895a 100644 --- a/fgohook/config.h +++ b/fgohook/config.h @@ -9,6 +9,8 @@ #include "hooklib/touch.h" #include "hooklib/printer.h" +#include "gfxhook/config.h" + #include "fgohook/deck.h" #include "fgohook/ftdi.h" #include "fgohook/fgo-dll.h" @@ -26,6 +28,7 @@ struct fgo_hook_config { struct deck_config deck; struct ftdi_config ftdi; struct led15093_config led15093; + struct gfx_config gfx; struct fgo_dll_config dll; }; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 1604a8d..9bc3694 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -34,6 +34,8 @@ #include "hooklib/serial.h" #include "hooklib/spike.h" +#include "gfxhook/gfx.h" + #include "fgohook/config.h" #include "fgohook/io4.h" #include "fgohook/fgo-dll.h" @@ -50,9 +52,21 @@ static struct fgo_hook_config fgo_hook_cfg; static DWORD CALLBACK fgo_pre_startup(void) { HRESULT hr; + HMODULE dbghelp; dprintf("--- Begin fgo_pre_startup ---\n"); + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } + else { + dprintf("Failed to load debug helper library!\n"); + } + /* Load config */ fgo_hook_config_load(&fgo_hook_cfg, L".\\segatools.ini"); @@ -60,6 +74,7 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Hook Win32 APIs */ dvd_hook_init(&fgo_hook_cfg.dvd, fgo_hook_mod); + gfx_hook_init(&fgo_hook_cfg.gfx); touch_screen_hook_init(&fgo_hook_cfg.touch, fgo_hook_mod); serial_hook_init(); diff --git a/fgohook/meson.build b/fgohook/meson.build index 2e9772f..257048b 100644 --- a/fgohook/meson.build +++ b/fgohook/meson.build @@ -13,6 +13,7 @@ shared_library( link_with : [ aimeio_lib, board_lib, + gfxhook_lib, hooklib_lib, fgoio_lib, platform_lib, diff --git a/gfxhook/gfx.c b/gfxhook/gfx.c index 1af3647..af844a3 100644 --- a/gfxhook/gfx.c +++ b/gfxhook/gfx.c @@ -9,18 +9,53 @@ #include "util/dprintf.h" -typedef BOOL (WINAPI *ShowWindow_t)(HWND hWnd, int nCmdShow); +/* Hook functions */ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow); +static BOOL WINAPI hook_CreateWindowExA( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +); + +/* Link pointers */ + +static BOOL (WINAPI *next_ShowWindow)(HWND hWnd, int nCmdShow); +static BOOL (WINAPI *next_CreateWindowExA)( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +); static struct gfx_config gfx_config; -static ShowWindow_t next_ShowWindow; static const struct hook_symbol gfx_hooks[] = { { .name = "ShowWindow", .patch = hook_ShowWindow, .link = (void **) &next_ShowWindow, + }, { + .name = "CreateWindowExA", + .patch = hook_CreateWindowExA, + .link = (void **) &next_CreateWindowExA, }, }; @@ -46,3 +81,45 @@ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow) return next_ShowWindow(hWnd, nCmdShow); } + +static BOOL WINAPI hook_CreateWindowExA( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +) +{ + dprintf("Gfx: CreateWindowExA hook hit\n"); + + // Set to WS_OVERLAPPEDWINDOW to enable a window with a border and windowed style + if (gfx_config.windowed) { + dwStyle = WS_OVERLAPPEDWINDOW; + + if (!gfx_config.framed) { + dwStyle = WS_POPUP; + } + } + + return next_CreateWindowExA( + dwExStyle, + lpClassName, + lpWindowName, + dwStyle, + X, + Y, + nWidth, + nHeight, + hWndParent, + hMenu, + hInstance, + lpParam + ); +} diff --git a/gfxhook/gl.c b/gfxhook/gl.c new file mode 100644 index 0000000..67812ab --- /dev/null +++ b/gfxhook/gl.c @@ -0,0 +1,77 @@ +#include + +#include +#include + +#include "gfxhook/gfx.h" +#include "gfxhook/gl.h" + +#include "hook/table.h" + +#include "hooklib/dll.h" + +#include "util/dprintf.h" + +/* Hook functions */ + +static void WINAPI hook_glutFullScreen(void); +static void WINAPI hook_glutInitDisplayMode(unsigned int mode); + +/* Link pointers */ + +static void (WINAPI *next_glutFullScreen)(void); +static void (WINAPI *next_glutInitDisplayMode)(unsigned int mode); + +static struct gfx_config gfx_config; + +static const struct hook_symbol glut_hooks[] = { + { + .name = "glutFullScreen", + .patch = hook_glutFullScreen, + .link = (void **) &next_glutFullScreen, + }, { + .name = "glutInitDisplayMode", + .patch = hook_glutInitDisplayMode, + .link = (void **) &next_glutInitDisplayMode, + }, +}; + +void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + memcpy(&gfx_config, cfg, sizeof(*cfg)); + hook_table_apply(NULL, "glut32.dll", glut_hooks, _countof(glut_hooks)); + + if (self != NULL) { + dll_hook_push(self, L"glut32.dll"); + } +} + +static void WINAPI hook_glutFullScreen(void) +{ + dprintf("Gfx: glutFullScreen hook hit\n"); + + if (gfx_config.windowed) { + return; + } + + return next_glutFullScreen(); +} + +static void WINAPI hook_glutInitDisplayMode(unsigned int mode) +{ + dprintf("Gfx: glutInitDisplayMode hook hit\n"); + + // GLUT adds a frame when going windowed + if (gfx_config.windowed && !gfx_config.framed) { + // GLUT_BORDERLESS + mode |= 0x0800; + } + + return next_glutInitDisplayMode(mode); +} diff --git a/gfxhook/gl.h b/gfxhook/gl.h new file mode 100644 index 0000000..033840d --- /dev/null +++ b/gfxhook/gl.h @@ -0,0 +1,3 @@ +#pragma once + +void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self); diff --git a/gfxhook/meson.build b/gfxhook/meson.build index b973ddd..1cf8df3 100644 --- a/gfxhook/meson.build +++ b/gfxhook/meson.build @@ -22,6 +22,8 @@ gfxhook_lib = static_library( 'dxgi.h', 'gfx.c', 'gfx.h', + 'gl.c', + 'gl.h', 'util.c', 'util.h', ], From 8aef1cfa79f1f04bf2cf036ec20b45b5fb5ea1b7 Mon Sep 17 00:00:00 2001 From: KagamineHaku Date: Tue, 5 Nov 2024 00:48:21 +0700 Subject: [PATCH 164/204] Change method set environment variable to current process only using "SetEnvironmentVariableW" --- platform/opensslpatch.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index 4db287c..2447a0a 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -26,23 +26,36 @@ int check_cpu() { return 0; } +//Set User's Environment variable via registry +// static void openssl_patch(void) { +// const char* variablename = "OPENSSL_ia32cap"; +// const char* variablevalue = "~0x20000000"; + +// HKEY hKey; +// if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { +// if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { +// dprintf("OpenSSL Patch: Applied successfully, set the user environment variable %s to %s\n", variablename, variablevalue); +// } else { +// dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); +// } + +// RegCloseKey(hKey); + +// SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); +// } else { +// dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); +// } +// } + +//Set environment variable for current process static void openssl_patch(void) { - const char* variablename = "OPENSSL_ia32cap"; - const char* variablevalue = "~0x20000000"; + const wchar_t* variablename = L"OPENSSL_ia32cap"; + const wchar_t* variablevalue = L"~0x20000000"; - HKEY hKey; - if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { - if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { - dprintf("OpenSSL Patch: Applied successfully, set the user environment variable %s to %s\n", variablename, variablevalue); - } else { - dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); - } - - RegCloseKey(hKey); - - SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); + if (SetEnvironmentVariableW(variablename, variablevalue)) { + dprintf("OpenSSL Patch: Applied successfully, set the environment variable %ls to %ls\n", variablename, variablevalue); } else { - dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); + dprintf("OpenSSL Patch: Error: Failed to set the environment variable.\n"); } } From e1a47cf3655a8020ad0772131fd83b0a55b5f78f Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Mon, 4 Nov 2024 22:53:20 +0000 Subject: [PATCH 165/204] Throw fatal when vfs option configured but invalid --- platform/vfs.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/platform/vfs.c b/platform/vfs.c index e49ad5b..649c7cb 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -107,6 +107,20 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id) if (config->option[0] == L'\0') { dprintf("Vfs: WARNING: OPTION path not specified in INI file\n"); + } else if (!PathFileExistsW(config->option)) { + dprintf("Vfs: FATAL: OPTION path does not exist\n"); + dprintf(" Configured: \"%ls\"\n", config->option); + GetFullPathNameW(config->option, _countof(temp), temp, NULL); + dprintf(" Expanded: \"%ls\"\n", temp); + + return E_FAIL; + } else if (!(GetFileAttributesW(config->option) & FILE_ATTRIBUTE_DIRECTORY)) { + dprintf("Vfs: FATAL: OPTION path doesn't point to a directory\n"); + dprintf(" Configured: \"%ls\"\n", config->option); + GetFullPathNameW(config->option, _countof(temp), temp, NULL); + dprintf(" Expanded: \"%ls\"\n", temp); + + return E_FAIL; } home_ok = GetEnvironmentVariableW( @@ -516,7 +530,7 @@ static __thiscall wchar_t* hook_System_getAppRootPath() wcscpy_s(path, MAX_PATH, vfs_config.appdata); wcscat_s(path, MAX_PATH, game); wcscat_s(path, MAX_PATH, L"\\"); - + return path; } From 83840e0a87597fd9cea788571bc6fa9d3f097a1a Mon Sep 17 00:00:00 2001 From: zaphkito Date: Sun, 10 Nov 2024 20:47:40 +0000 Subject: [PATCH 166/204] dns: add new WAHLAP url blocked (#49) Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/49 Co-authored-by: zaphkito Co-committed-by: zaphkito --- platform/dns.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/platform/dns.c b/platform/dns.c index ab7574a..5fe9262 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -116,6 +116,12 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + hr = dns_hook_push(L"at.sys-allnet.cn", cfg->startup); + + if (FAILED(hr)) { + return hr; + } + // WAHLAP WeChat AimeDB Server hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb); @@ -123,8 +129,20 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + hr = dns_hook_push(L"ai.sys-allnet.cn", cfg->aimedb); + + if (FAILED(hr)) { + return hr; + } + // WAHLAP Billing - hr = dns_hook_push(L"ib.sys-all.cn", cfg->billing); + hr = dns_hook_push(L"bl.sys-all.cn", cfg->billing); + + if (FAILED(hr)) { + return hr; + } + + hr = dns_hook_push(L"bl.sys-allnet.cn", cfg->billing); if (FAILED(hr)) { return hr; From ceb2b63e8b6d49097231934f411fd9ffe1fad15d Mon Sep 17 00:00:00 2001 From: Sanhei Date: Mon, 11 Nov 2024 16:24:33 +0000 Subject: [PATCH 167/204] Modify host header in HTTP requests to bypass domain censorship in China. (#34) Co-authored-by: Sanheiii <35133371+Sanheiii@users.noreply.github.com> Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/34 Co-authored-by: Sanhei Co-committed-by: Sanhei --- doc/config/common.md | 6 +++ hooklib/dns.c | 82 ++++++++++++++++++++++++++++++++++++- hooklib/dns.h | 2 +- meson.build | 1 + platform/config.c | 2 + platform/dns.c | 4 ++ platform/dns.h | 1 + util/get_function_ordinal.c | 34 +++++++++++++++ util/get_function_ordinal.h | 6 +++ util/meson.build | 3 ++ 10 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 util/get_function_ordinal.c create mode 100644 util/get_function_ordinal.h diff --git a/doc/config/common.md b/doc/config/common.md index e778a8a..3c86751 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -197,6 +197,12 @@ Default: Empty string (i.e. use value from `default` setting) Overrides the target of the `aime.naominet.jp` host lookup. +### `replaceHost` + +Default: `0` + +Replace the HOST field in HTTP request headers with the settings above. This may help bypass network restrictions in some regions. + ## `[ds]` Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX diff --git a/hooklib/dns.c b/hooklib/dns.c index d7f0c4a..c3b95fb 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -14,6 +14,7 @@ #include "hook/table.h" #include "util/dprintf.h" +#include "util/get_function_ordinal.h" #include "hooklib/dns.h" @@ -81,6 +82,12 @@ static bool WINAPI hook_WinHttpCrackUrl( DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); +static DWORD WINAPI hook_send( + SOCKET s, + const char* buf, + int len, + int flags); + /* Link pointers */ static DNS_STATUS (WINAPI *next_DnsQuery_A)( @@ -122,6 +129,12 @@ static bool (WINAPI *next_WinHttpCrackUrl)( DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); +static DWORD (WINAPI *next_send)( + SOCKET s, + const char* buf, + int len, + int flags); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -144,7 +157,7 @@ static const struct hook_symbol dns_hook_syms_ws2[] = { .ordinal = 176, .patch = hook_getaddrinfo, .link = (void **) &next_getaddrinfo, - } + }, }; static const struct hook_symbol dns_hook_syms_winhttp[] = { @@ -157,7 +170,14 @@ static const struct hook_symbol dns_hook_syms_winhttp[] = { .patch = hook_WinHttpCrackUrl, .link = (void **) &next_WinHttpCrackUrl, } +}; +static struct hook_symbol http_hook_syms_ws2[] = { + { + .name = "send", + .patch = hook_send, + .link = (void **) &next_send + }, }; static bool dns_hook_initted; @@ -186,7 +206,7 @@ static void dns_hook_init(void) "ws2_32.dll", dns_hook_syms_ws2, _countof(dns_hook_syms_ws2)); - + hook_table_apply( NULL, "winhttp.dll", @@ -194,6 +214,18 @@ static void dns_hook_init(void) _countof(dns_hook_syms_winhttp)); } +void http_hook_init(){ + for (size_t i = 0; i < _countof(http_hook_syms_ws2); ++i) { + http_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", http_hook_syms_ws2[i].name); + } + + hook_table_apply( + NULL, + "ws2_32.dll", + http_hook_syms_ws2, + _countof(http_hook_syms_ws2)); +} + // This function match domain and subdomains like *.naominet.jp. bool match_domain(const wchar_t* target, const wchar_t* pattern) { if (_wcsicmp(pattern, target) == 0) { @@ -618,3 +650,49 @@ static bool WINAPI hook_WinHttpCrackUrl( lpUrlComponents ); } + +DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { + if (strstr(buf, "HTTP/") != NULL) { + char *new_buf = malloc(len + 1); + if (new_buf == NULL) return SOCKET_ERROR; + + memcpy(new_buf, buf, len); + new_buf[len] = '\0'; + + char *host_start = strstr(new_buf, "Host: "); + if (host_start != NULL) { + char *host_end = strstr(host_start, "\r\n"); + if (host_end != NULL) { + host_end += 2; + int host_len = host_end - host_start; + + char *host_value_start = host_start + 6; + char *host_value_end = strstr(host_value_start, "\r\n"); + if (host_value_end != NULL) { + int value_len = host_value_end - host_value_start; + char host_value[value_len + 1]; + strncpy(host_value, host_value_start, value_len); + host_value[value_len] = '\0'; + + for (struct dns_hook_entry *entry = dns_hook_entries; entry && entry->from; entry++) { + char from_value[256]; + wcstombs(from_value, entry->from, sizeof(from_value)); + + if (strcmp(host_value, from_value) == 0) { + char to_value[256]; + wcstombs(to_value, entry->to, sizeof(to_value)); + snprintf(host_start, len - (host_start - new_buf), "Host: %s\r\n", to_value); + break; + } + } + } + len = (int)strlen(new_buf); + } + } + DWORD result = next_send(s, new_buf, len, flags); + free(new_buf); + return result; + } + + return next_send(s, buf, len, flags); +} \ No newline at end of file diff --git a/hooklib/dns.h b/hooklib/dns.h index 1f93b0f..ed46959 100644 --- a/hooklib/dns.h +++ b/hooklib/dns.h @@ -3,7 +3,7 @@ #include #include - +void http_hook_init(); // if to_src is NULL, all lookups for from_src will fail HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src); diff --git a/meson.build b/meson.build index 129a387..12df35a 100644 --- a/meson.build +++ b/meson.build @@ -81,6 +81,7 @@ dinput8_lib = cc.find_library('dinput8') dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') pathcch_lib = cc.find_library('pathcch') +imagehlp_lib = cc.find_library('imagehlp') inc = include_directories('.') capnhook = subproject('capnhook') diff --git a/platform/config.c b/platform/config.c index ad97905..a4362a3 100644 --- a/platform/config.c +++ b/platform/config.c @@ -121,6 +121,8 @@ void dns_config_load(struct dns_config *cfg, const wchar_t *filename) cfg->title, _countof(cfg->title), filename); + + cfg->replaceHost = GetPrivateProfileIntW(L"dns", L"replaceHost", 0, filename); } void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename) diff --git a/platform/dns.c b/platform/dns.c index 5fe9262..9ca8a5b 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -16,6 +16,10 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return S_FALSE; } + if(cfg->replaceHost){ + http_hook_init(); + } + hr = dns_hook_push(L"tenporouter.loc", cfg->router); if (FAILED(hr)) { diff --git a/platform/dns.h b/platform/dns.h index e822ff3..0a2c2bc 100644 --- a/platform/dns.h +++ b/platform/dns.h @@ -12,6 +12,7 @@ struct dns_config { wchar_t billing[128]; wchar_t aimedb[128]; wchar_t title[128]; + bool replaceHost; }; HRESULT dns_platform_hook_init(const struct dns_config *cfg); diff --git a/util/get_function_ordinal.c b/util/get_function_ordinal.c new file mode 100644 index 0000000..470bf7f --- /dev/null +++ b/util/get_function_ordinal.c @@ -0,0 +1,34 @@ +#include "get_function_ordinal.h" + +DWORD get_function_ordinal(const char* dllName, const char* functionName) { + HMODULE hModule = LoadLibraryA(dllName); + if (!hModule) { + dprintf("Failed to load DLL: %s\n", dllName); + return 0; + } + + ULONG size; + PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData( + hModule, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size); + if (!exportDir) { + dprintf("Failed to get export table\n"); + FreeLibrary(hModule); + return 0; + } + + DWORD* functionNames = (DWORD*)((BYTE*)hModule + exportDir->AddressOfNames); + WORD* ordinals = (WORD*)((BYTE*)hModule + exportDir->AddressOfNameOrdinals); + + for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) { + char* name = (char*)((BYTE*)hModule + functionNames[i]); + if (strcmp(name, functionName) == 0) { + DWORD ordinal = ordinals[i] + exportDir->Base; + FreeLibrary(hModule); + return ordinal; + } + } + + dprintf("Function not found: %s\n", functionName); + FreeLibrary(hModule); + return 0; +} \ No newline at end of file diff --git a/util/get_function_ordinal.h b/util/get_function_ordinal.h new file mode 100644 index 0000000..6bc4b9e --- /dev/null +++ b/util/get_function_ordinal.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "dprintf.h" + +DWORD get_function_ordinal(const char* dllName, const char* functionName); \ No newline at end of file diff --git a/util/meson.build b/util/meson.build index 575d123..2c29609 100644 --- a/util/meson.build +++ b/util/meson.build @@ -5,6 +5,7 @@ util_lib = static_library( c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), + imagehlp_lib, ], sources : [ 'async.c', @@ -17,6 +18,8 @@ util_lib = static_library( 'dprintf.h', 'dump.c', 'dump.h', + 'get_function_ordinal.c', + 'get_function_ordinal.h', 'lib.c', 'lib.h', 'str.c', From c80f903cf8132d51de9d773f1057500bd230cad8 Mon Sep 17 00:00:00 2001 From: GEEKiDoS Date: Mon, 11 Nov 2024 16:28:24 +0000 Subject: [PATCH 168/204] Fix build with Microsoft Visual C++, Fix gfxhook and felica issue (#48) I just wanna say that It is a SHAME that a Windows ONLY project was not able to build without MINGW Also where's the missing `3mpxsc.h` in diva hook? This also fixes the window size issue from hook_CreateWindowExA in gfxhook And Fixes felica issue as described in #45 Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/48 Reviewed-by: Dniel97 Co-authored-by: GEEKiDoS Co-committed-by: GEEKiDoS --- board/led15093-cmd.h | 2 +- board/sg-nfc.c | 6 +- divahook/config.h | 2 - fgohook/ftdi.c | 2 +- fgoio/fgoio.c | 4 +- gfxhook/gfx.c | 34 +++++--- gfxhook/gl.c | 4 +- hooklib/printer.c | 10 +-- iccard/felica.c | 162 +++++++++++++++++++++++++++++++++++--- iccard/felica.h | 10 ++- idacio/xi.c | 4 +- idzio/xi.c | 4 +- meson.build | 2 +- msvc-build.bat | 128 ++++++++++++++++++++++++++++++ package.ps1 | 96 ++++++++++++++++++++++ platform/vfs.c | 12 +-- subprojects/capnhook.wrap | 2 +- swdcio/xi.c | 6 +- 18 files changed, 432 insertions(+), 58 deletions(-) create mode 100644 msvc-build.bat create mode 100644 package.ps1 diff --git a/board/led15093-cmd.h b/board/led15093-cmd.h index 0cd5d8d..44bddf9 100644 --- a/board/led15093-cmd.h +++ b/board/led15093-cmd.h @@ -88,7 +88,7 @@ struct led15093_req_reset { struct led15093_req_set_timeout { struct led15093_req_hdr hdr; uint8_t cmd; - uint8_t count; + uint16_t count; }; struct led15093_req_set_disable_response { diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 571be60..eac0984 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -354,13 +354,13 @@ static HRESULT sg_nfc_poll_felica( felica->type = 0x20; felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm); felica->IDm = _byteswap_uint64(IDm); - felica->PMm = _byteswap_uint64(felica_get_generic_PMm()); + felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm()); /* Initialize FeliCa IC emulator */ nfc->felica.IDm = IDm; - nfc->felica.PMm = felica_get_generic_PMm(); - nfc->felica.system_code = 0x0000; + nfc->felica.PMm = felica_get_amusement_ic_PMm(); + nfc->felica.system_code = 0x88b4; return S_OK; } diff --git a/divahook/config.h b/divahook/config.h index 3b3f1ea..694b055 100644 --- a/divahook/config.h +++ b/divahook/config.h @@ -13,7 +13,6 @@ #include "platform/config.h" -#include "divahook/3mpxsc.h" #include "divahook/diva-dll.h" #include "divahook/slider.h" @@ -23,7 +22,6 @@ struct diva_hook_config { struct aime_config aime; struct dvd_config dvd; struct gfx_config gfx; - struct touch3mpxsc_config touch3mpxsc; struct touch_screen_config touch; struct diva_dll_config dll; struct slider_config slider; diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index 91aea04..9a04b71 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -116,7 +116,7 @@ static const struct hook_symbol reg_syms[] = { } }; -#define device_fake_key 0xDEADBEEF +const size_t device_fake_key = 0xDEADBEEF; static HANDLE ftdi_fd; static char port_name[8]; diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index faba36c..61f7d77 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -109,8 +109,8 @@ HRESULT fgo_io_poll(void) normalizedMagnitude = 0.0; } - fgo_stick_x = normalizedLX * normalizedMagnitude * 32767; - fgo_stick_y = normalizedLY * normalizedMagnitude * 32767; + fgo_stick_x = (int16_t)(normalizedLX * normalizedMagnitude * 32767); + fgo_stick_y = (int16_t)(normalizedLY * normalizedMagnitude * 32767); return S_OK; } diff --git a/gfxhook/gfx.c b/gfxhook/gfx.c index af844a3..0acc1ae 100644 --- a/gfxhook/gfx.c +++ b/gfxhook/gfx.c @@ -12,7 +12,7 @@ /* Hook functions */ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow); -static BOOL WINAPI hook_CreateWindowExA( +static HWND WINAPI hook_CreateWindowExA( DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, @@ -30,7 +30,7 @@ static BOOL WINAPI hook_CreateWindowExA( /* Link pointers */ static BOOL (WINAPI *next_ShowWindow)(HWND hWnd, int nCmdShow); -static BOOL (WINAPI *next_CreateWindowExA)( +static HWND (WINAPI *next_CreateWindowExA)( DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, @@ -82,7 +82,7 @@ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow) return next_ShowWindow(hWnd, nCmdShow); } -static BOOL WINAPI hook_CreateWindowExA( +static HWND WINAPI hook_CreateWindowExA( DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, @@ -97,18 +97,32 @@ static BOOL WINAPI hook_CreateWindowExA( LPVOID lpParam ) { + RECT rect; + dprintf("Gfx: CreateWindowExA hook hit\n"); - // Set to WS_OVERLAPPEDWINDOW to enable a window with a border and windowed style - if (gfx_config.windowed) { - dwStyle = WS_OVERLAPPEDWINDOW; - - if (!gfx_config.framed) { + if (gfx_config.windowed) + { + if (gfx_config.framed) + dwStyle |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + else dwStyle = WS_POPUP; - } + + rect.left = ((X == CW_USEDEFAULT) ? 0 : X); + rect.top = ((Y == CW_USEDEFAULT) ? 0 : Y); + rect.right = rect.left + nWidth; + rect.bottom = rect.top + nHeight; + + // Don't care if it's ok or not, since we are creating window and we can't just return a NULL + AdjustWindowRect(&rect, dwStyle, !!hMenu); + + X = ((X == CW_USEDEFAULT) ? X : rect.left); + Y = ((Y == CW_USEDEFAULT) ? Y : rect.top); + nWidth = rect.right - rect.left; + nHeight = rect.bottom - rect.top; } - return next_CreateWindowExA( + return next_CreateWindowExA( dwExStyle, lpClassName, lpWindowName, diff --git a/gfxhook/gl.c b/gfxhook/gl.c index 67812ab..a3f0496 100644 --- a/gfxhook/gl.c +++ b/gfxhook/gl.c @@ -60,7 +60,7 @@ static void WINAPI hook_glutFullScreen(void) return; } - return next_glutFullScreen(); + next_glutFullScreen(); } static void WINAPI hook_glutInitDisplayMode(unsigned int mode) @@ -73,5 +73,5 @@ static void WINAPI hook_glutInitDisplayMode(unsigned int mode) mode |= 0x0800; } - return next_glutInitDisplayMode(mode); + next_glutInitDisplayMode(mode); } diff --git a/hooklib/printer.c b/hooklib/printer.c index 03e90bf..dbd56f9 100644 --- a/hooklib/printer.c +++ b/hooklib/printer.c @@ -98,7 +98,7 @@ int WINAPI chcusb_imageformat_330( uint16_t width, uint16_t height, uint16_t *rResult); -int __thiscall chcusb_setmtf(int32_t *mtf); +int __fastcall chcusb_setmtf(int32_t *mtf); int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); int WINAPI chcusb_setIcctable( LPCSTR icc1, @@ -1634,7 +1634,7 @@ int WINAPI fwdlusb_open(uint16_t *rResult) { return 1; } -void fwdlusb_close() {} +void WINAPI fwdlusb_close() {} int WINAPI fwdlusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); @@ -2115,7 +2115,7 @@ int WINAPI chcusb_open(uint16_t *rResult) { return 1; } -void chcusb_close() { +void WINAPI chcusb_close() { dprintf("Printer: C3XXusb: %s\n", __func__); } @@ -2334,7 +2334,7 @@ int WINAPI chcusb_imageformat_330( return 1; } -int __thiscall chcusb_setmtf(int32_t *mtf) { +int __fastcall chcusb_setmtf(int32_t *mtf) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(MTF, mtf, sizeof(MTF)); @@ -3351,4 +3351,4 @@ DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSi void printer_set_dimensions(int width, int height){ WIDTH = width; HEIGHT = height; -} \ No newline at end of file +} diff --git a/iccard/felica.c b/iccard/felica.c index b251d54..64ef897 100644 --- a/iccard/felica.c +++ b/iccard/felica.c @@ -21,21 +21,27 @@ static HRESULT felica_cmd_get_system_code( struct const_iobuf *req, struct iobuf *res); -static HRESULT felica_cmd_nda_a4( +static HRESULT felica_cmd_active( struct felica *f, struct const_iobuf *req, struct iobuf *res); -uint64_t felica_get_generic_PMm(void) +static HRESULT felica_cmd_read_without_encryption( + struct felica *f, + struct const_iobuf *req, + struct iobuf *res); + +static HRESULT felica_cmd_write_without_encryption( + struct felica* f, + struct const_iobuf* req, + struct iobuf* res); + +uint64_t felica_get_amusement_ic_PMm(void) { - /* A FeliCa PMm contains low-level protocol timing information for - communicating with a particular IC card. The exact values are not - particularly important for our purposes, so we'll just return a hard- - coded PMm. This current value has been taken from an iPhone, emulating - a Suica pass via Apple Wallet, which seems to be one of the few - universally accepted FeliCa types for these games. Certain older - Suica passes and other payment and transportation cards - do not seem to be supported anymore. */ + /* + * AIC Card PMm, if this is returned from the card, + * the aimelib will access the actual blocks for authentication. + */ return 0x00F1000000014300; } @@ -90,8 +96,14 @@ HRESULT felica_transact( case FELICA_CMD_GET_SYSTEM_CODE: return felica_cmd_get_system_code(f, req, res); - case FELICA_CMD_NDA_A4: - return felica_cmd_nda_a4(f, req, res); + case FELICA_READ_WITHOUT_ENCRYPTION: + return felica_cmd_read_without_encryption(f, req, res); + + case FELICA_WRITE_WITHOUT_ENCRYPTION: + return felica_cmd_write_without_encryption(f, req, res); + + case FELICA_CMD_ACTIVE: + return felica_cmd_active(f, req, res); default: dprintf("FeliCa: Unimplemented command %02x, payload:\n", code); @@ -184,7 +196,131 @@ static HRESULT felica_cmd_get_system_code( return S_OK; } -static HRESULT felica_cmd_nda_a4( +static HRESULT felica_cmd_read_without_encryption( + struct felica *f, + struct const_iobuf *req, + struct iobuf *res) +{ + HRESULT hr; + uint8_t system_code_count; + uint16_t* system_codes; + uint8_t read_block_count; + uint8_t* blocks; + size_t i; + + hr = iobuf_read_8(req, &system_code_count); + + if (FAILED(hr)) { + goto fail; + } + + system_codes = malloc(sizeof(uint16_t) * system_code_count); + if (!system_codes) goto fail; + + for (i = 0; i < system_code_count; i++) { + hr = iobuf_read_be16(req, system_codes + i); + + if (FAILED(hr)) { + goto fail; + } + } + + hr = iobuf_read_8(req, &read_block_count); + + if (FAILED(hr)) { + goto fail; + } + + blocks = malloc(read_block_count); + if (!system_codes) goto fail; + + for (i = 0; i < read_block_count; i++) { + // 0x80 + hr = iobuf_read_8(req, blocks + i); + + if (FAILED(hr)) { + goto fail; + } + + // actual block num + hr = iobuf_read_8(req, blocks + i); + + if (FAILED(hr)) { + goto fail; + } + } + + // status + hr = iobuf_write_be16(res, 0); + + if (FAILED(hr)) { + goto fail; + } + + // block count + hr = iobuf_write_8(res, read_block_count); + + if (FAILED(hr)) { + goto fail; + } + + // block data + for (i = 0; i < read_block_count; i++) + { + dprintf("FeliCa: Read block %x\n", blocks[i]); + + switch (blocks[i]) { + case 0x82: { + hr = iobuf_write_be64(res, f->IDm); + + if (FAILED(hr)) + { + goto fail; + } + + hr = iobuf_write_be64(res, 0x0078000000000000ull); + + if (FAILED(hr)) + { + goto fail; + } + } + default: { + hr = iobuf_write_be64(res, 0); + + if (FAILED(hr)) + { + goto fail; + } + + hr = iobuf_write_be64(res, 0); + + if (FAILED(hr)) + { + goto fail; + } + } + } + } + + hr = S_OK; + +fail: + if (system_codes) free(system_codes); + if (blocks) free(blocks); + + return hr; +} + +static HRESULT felica_cmd_write_without_encryption( + struct felica* f, + struct const_iobuf* req, + struct iobuf* res) +{ + return iobuf_write_be16(res, 0); +} + +static HRESULT felica_cmd_active( struct felica *f, struct const_iobuf *req, struct iobuf *res) diff --git a/iccard/felica.h b/iccard/felica.h index 33be201..b55cc87 100644 --- a/iccard/felica.h +++ b/iccard/felica.h @@ -8,9 +8,11 @@ #include "hook/iobuf.h" enum { - FELICA_CMD_POLL = 0x00, - FELICA_CMD_GET_SYSTEM_CODE = 0x0c, - FELICA_CMD_NDA_A4 = 0xa4, + FELICA_CMD_POLL = 0x00, + FELICA_READ_WITHOUT_ENCRYPTION = 0x06, + FELICA_WRITE_WITHOUT_ENCRYPTION = 0x08, + FELICA_CMD_GET_SYSTEM_CODE = 0x0c, + FELICA_CMD_ACTIVE = 0xa4, }; struct felica { @@ -24,4 +26,4 @@ HRESULT felica_transact( struct const_iobuf *req, struct iobuf *res); -uint64_t felica_get_generic_PMm(void); +uint64_t felica_get_amusement_ic_PMm(void); diff --git a/idacio/xi.c b/idacio/xi.c index e695561..570bf12 100644 --- a/idacio/xi.c +++ b/idacio/xi.c @@ -184,10 +184,10 @@ static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool lin // apply non-linear transform to the axis if (!linear_steering) { - return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + return (int16_t)(norm_axis * powf(norm_magnitude, 3.0f) * max_wheel_value); } - return norm_axis * norm_magnitude * max_wheel_value; + return (int16_t)(norm_axis * norm_magnitude * max_wheel_value); } static void idac_xi_get_analogs(struct idac_io_analog_state *out) { diff --git a/idzio/xi.c b/idzio/xi.c index db3a94d..515be2f 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -188,10 +188,10 @@ static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool lin // apply non-linear transform to the axis if (!linear_steering) { - return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + return (int16_t)(norm_axis * powf(norm_magnitude, 3.0f) * max_wheel_value); } - return norm_axis * norm_magnitude * max_wheel_value; + return (int16_t)(norm_axis * norm_magnitude * max_wheel_value); } static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) diff --git a/meson.build b/meson.build index 12df35a..4a962a4 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,6 @@ add_project_arguments( '-DWIN32_LEAN_AND_MEAN', '-D_WIN32_WINNT=_WIN32_WINNT_WIN7', '-DMINGW_HAS_SECURE_API=1', - '-Wno-unused', # '-ggdb', # Add debug information language: 'c', ) @@ -24,6 +23,7 @@ if cc.get_id() != 'msvc' add_project_arguments( '-ffunction-sections', '-fdata-sections', + '-Wno-unused', language: 'c', ) diff --git a/msvc-build.bat b/msvc-build.bat new file mode 100644 index 0000000..d485839 --- /dev/null +++ b/msvc-build.bat @@ -0,0 +1,128 @@ +@echo off +setlocal enabledelayedexpansion + +set BUILD_DIR=build +set BUILD_DIR_32=%BUILD_DIR%\build32 +set BUILD_DIR_64=%BUILD_DIR%\build64 +set BUILD_DIR_ZIP=%BUILD_DIR%\zip +set DIST_DIR=dist +set DOC_DIR=doc + +REM Set your Visual Studio install path if Visual Studio installation can not be detected +set VS_INSTALLATION=C:\Program Files\Microsoft Visual Studio\2022\Community + +if /I "%1"=="build" ( + call :detect-visual-studio + if ERRORLEVEL 2 exit /b + if ERRORLEVEL 1 ( + echo Failed to detect Visual Studio installation path. + echo. + echo If Visual Studio is installed then edit VS_INSTALLATION in this file + echo to manually specify Visual Studio install path. + exit /b + ) + + call :detect-meson + if ERRORLEVEL 1 ( + echo Meson is not installed. + exit /b + ) + + set VSVARSALL=!VSVARSALL! + set MESON=!MESON! + + call :build + + echo. + echo Build done! + exit /b +) +if /I "%1"=="zip" ( + powershell -NoProfile -ExecutionPolicy Bypass -Command "& './package.ps1'" + exit /b +) + +echo %~nx0 [action] +echo build: Build the for both x86 and x64 +echo zip: Make zip file +exit /b + +rem This should works for Visual Studio 2017+ +:detect-visual-studio ( + rem Who the hell on earth is still using a 32bit Windows in 2024 + if "%ProgramFiles(x86)%"=="" ( + set VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" + ) else ( + set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" + ) + + if exist %VSWHERE% ( + REM get vcvarsall by using vswhere + set VSVARSALL="" + for /f "tokens=* usebackq" %%i in (`%VSWHERE% -find VC\Auxiliary\Build\vcvarsall.bat`) do set VSVARSALL="%%i" + ) else ( + REM fallback to old method + set VSVARSALL="%VS_INSTALLATION%\VC\Auxiliary\Build\vcvarsall.bat" + ) + + :check-vcvarsall + if /i %VSVARSALL%=="" ( + echo Microsoft Visual C++ Component is not installed + echo Install it from Visual Studio Installer + exit /b 2 + ) + + rem if a path is returned by vswhere, then it's sure that the result path exists + rem if path not exists than it was assumed from VS_INSTALLATION + if not exist %VSVARSALL% ( + echo vsvarsall.bat not exists in VS_INSTALLATION, + echo either Visual C++ Component is not installed + echo or VS_INSTALLATION is wrong. + exit /b 1 + ) + + exit /b 0 +) + +:detect-meson ( + for /f "tokens=* usebackq" %%i in (`where meson`) do set MESON="%%i" + if not exist %MESON% ( + exit /b 1 + ) + + exit /b 0 +) + +:build ( + :build_x64 ( + call %VSVARSALL% x64 + + if exist %BUILD_DIR_64% ( + %MESON% setup %BUILD_DIR_64% --backend vs --buildtype release --reconfigure + ) else ( + %MESON% setup %BUILD_DIR_64% --backend vs --buildtype release + ) + + pushd %BUILD_DIR_64% + msbuild /m /p:Configuration=release /p:Platform=x64 segatools.sln + popd + ) + + :build_x86 ( + call %VSVARSALL% x86 + + if exist %BUILD_DIR_32% ( + %MESON% setup %BUILD_DIR_32% --backend vs --buildtype release --reconfigure + ) else ( + %MESON% setup %BUILD_DIR_32% --backend vs --buildtype release + ) + + pushd %BUILD_DIR_32% + msbuild /m /p:Configuration=release /p:Platform=Win32 segatools.sln + popd + ) + + :end ( + exit /b + ) +) diff --git a/package.ps1 b/package.ps1 new file mode 100644 index 0000000..bae0e6c --- /dev/null +++ b/package.ps1 @@ -0,0 +1,96 @@ +if ($null -eq $env:BUILD_DIR) { + $BUILD_DIR="build" + $BUILD_DIR_32="$BUILD_DIR\build32" + $BUILD_DIR_64="$BUILD_DIR\build64" + $BUILD_DIR_ZIP="$BUILD_DIR\zip" + $DIST_DIR="dist" + $DOC_DIR="doc" +} else { + $BUILD_DIR = $env:BUILD_DIR; + $BUILD_DIR_32 = $env:BUILD_DIR_32; + $BUILD_DIR_64 = $env:BUILD_DIR_64; + $BUILD_DIR_ZIP = $env:BUILD_DIR_ZIP; + $DIST_DIR = $env:DIST_DIR; + $DOC_DIR = $env:DOC_DIR; +} + +$target = $null; +$line = ''; +[System.Collections.ArrayList]$files = @(); +$folder = Get-Location + +cat .\Package.mk | % { + $trimmed = $_.TrimEnd('\'). + TrimStart("`t "). + Replace('$(V)', ''). + Replace('$(BUILD_DIR)', $BUILD_DIR). + Replace('$(BUILD_DIR_32)', $BUILD_DIR_32). + Replace('$(BUILD_DIR_64)', $BUILD_DIR_64). + Replace('$(BUILD_DIR_ZIP)', $BUILD_DIR_ZIP). + Replace('$(DIST_DIR)', $DIST_DIR). + Replace('$(DOC_DIR)', $DOC_DIR). + Replace('$@', $target). + Replace('/', '\'); + + if ($trimmed.EndsWith(': ') -or $trimmed.EndsWith(':')) { + $target = $trimmed.TrimEnd(': '); + $line = ''; + $files.Clear(); + cd $folder; + + return; + } + + if (-not $trimmed.StartsWith('|')) { + $line += $trimmed; + + if ($_.EndsWith('\')) { + return; + } + } + + $line.Split(';') | % { + $cmd = $_.Trim(' '); + if ($cmd.StartsWith('echo')) { + echo $cmd.TrimStart('echo ') + } elseif ($cmd.StartsWith('mkdir')) { + $cmd = $cmd.Replace('-p', '-Force') + echo " - $cmd" + Invoke-Expression $cmd | Out-Null + } elseif ($cmd.StartsWith('cp')) { + $tokens = $cmd.Replace('cp ', '').Split(' '); + $srcs = $tokens[0..($tokens.Count - 2)]; + $dest = $tokens[$tokens.Count - 1]; + echo " - cp -Path $srcs -Destination $dest"; + cp -Path $srcs -Destination $dest + } elseif ($cmd.StartsWith('cd')) { + echo " - $cmd" + Invoke-Expression $cmd | Out-Null + } elseif ($cmd.StartsWith('zip ')) { + $tokens = $cmd.Substring(4, $cmd.Length - 4).Replace('-r ', '').Replace('-j ', '').Replace('*', '.\*'); + $tokens = $tokens.Split(' '); + $target = $tokens[0] + + if (-not $tokens.Contains('$^')) { + $files.AddRange($tokens[1..($tokens.Count - 1)]); + } + + echo " - Compress-Archive -Path $files -DestinationPath $target -Force" + Compress-Archive -Path $files -DestinationPath $target -Force + } else { + $allExists = $true + $args = $cmd.Split(' '); + $args | ? { -not $_ -eq '' } | % { + if (-not (Test-Path $_)) { + $allExists = $false + } + } + + if ($allExists) { + $files.AddRange($args); + } + } + } + + $line = ''; +} diff --git a/platform/vfs.c b/platform/vfs.c index 649c7cb..e16389a 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -34,11 +34,11 @@ static HRESULT vfs_path_hook_option( static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); -static __thiscall wchar_t* hook_System_getAppRootPath(); -static __thiscall wchar_t* (*next_System_getAppRootPath)(); +static wchar_t* hook_System_getAppRootPath(); +static wchar_t* (*next_System_getAppRootPath)(); -static __thiscall wchar_t* hook_AppImage_getOptionMountRootPath(); -static __thiscall wchar_t* (*next_AppImage_getOptionMountRootPath)(); +static wchar_t* hook_AppImage_getOptionMountRootPath(); +static wchar_t* (*next_AppImage_getOptionMountRootPath)(); static const struct hook_symbol amdaemon_syms[] = { { @@ -524,7 +524,7 @@ static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes) return reg_hook_read_wstr(bytes, nbytes, L"Y:\\"); } -static __thiscall wchar_t* hook_System_getAppRootPath() +static wchar_t* hook_System_getAppRootPath() { wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); wcscpy_s(path, MAX_PATH, vfs_config.appdata); @@ -534,7 +534,7 @@ static __thiscall wchar_t* hook_System_getAppRootPath() return path; } -static __thiscall wchar_t* hook_AppImage_getOptionMountRootPath() +static wchar_t* hook_AppImage_getOptionMountRootPath() { wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH); wcscpy_s(path, MAX_PATH, vfs_config.option); diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index 01a5c57..28fab1f 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook url = https://github.com/Hay1tsme/capnhook -revision = f060250e1b92dcb06946eb77742f0ab51755e158 +revision = b595e4bf8a274ba3bdaf583e13a7ebc7efe0f48f diff --git a/swdcio/xi.c b/swdcio/xi.c index 3c4ab9c..7a6984a 100644 --- a/swdcio/xi.c +++ b/swdcio/xi.c @@ -179,7 +179,7 @@ static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool lin // optionally normalize the magnitude with respect to its expected range // giving a magnitude value of 0.0 to 1.0 - norm_magnitude = magnitude / (max_stick_value - deadzone); + norm_magnitude = (int16_t)(magnitude / (max_stick_value - deadzone)); } else // if the controller is in the deadzone zero out the magnitude { magnitude = 0.0; @@ -188,10 +188,10 @@ static int16_t calculate_norm_steering(int16_t axis, uint16_t deadzone, bool lin // apply non-linear transform to the axis if (!linear_steering) { - return norm_axis * pow(norm_magnitude, 3.0) * max_wheel_value; + return (int16_t)(norm_axis * powf(norm_magnitude, 3.0f) * max_wheel_value); } - return norm_axis * norm_magnitude * max_wheel_value; + return (int16_t)(norm_axis * norm_magnitude * max_wheel_value); } static void swdc_xi_get_analogs(struct swdc_io_analog_state *out) From 2069b1ea85de4c93419278528aea0e62599819f9 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:03:13 +0100 Subject: [PATCH 169/204] dns: fix msvc build --- hooklib/dns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hooklib/dns.c b/hooklib/dns.c index c3b95fb..8884989 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -670,7 +670,7 @@ DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { char *host_value_end = strstr(host_value_start, "\r\n"); if (host_value_end != NULL) { int value_len = host_value_end - host_value_start; - char host_value[value_len + 1]; + char* host_value = (char*)malloc(value_len + 1); strncpy(host_value, host_value_start, value_len); host_value[value_len] = '\0'; @@ -685,6 +685,7 @@ DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { break; } } + free(host_value); } len = (int)strlen(new_buf); } From 2d3d6fc2bb4c4ce6dd46c7bef273588a9ea60df2 Mon Sep 17 00:00:00 2001 From: KagamineHaku Date: Tue, 26 Nov 2024 01:40:57 +0700 Subject: [PATCH 170/204] Skip the patch when already patched --- platform/opensslpatch.c | 69 +++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index 2447a0a..d359d6c 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -26,39 +26,56 @@ int check_cpu() { return 0; } +static int is_env_variable_set(const char* variablename, const char* expectedvalue) { + char currentvalue[256]; + DWORD length = GetEnvironmentVariableA(variablename, currentvalue, sizeof(currentvalue)); + + if (length > 0 && length < sizeof(currentvalue)) { + return strcmp(currentvalue, expectedvalue) == 0; + } + return 0; +} + //Set User's Environment variable via registry -// static void openssl_patch(void) { -// const char* variablename = "OPENSSL_ia32cap"; -// const char* variablevalue = "~0x20000000"; - -// HKEY hKey; -// if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { -// if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { -// dprintf("OpenSSL Patch: Applied successfully, set the user environment variable %s to %s\n", variablename, variablevalue); -// } else { -// dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); -// } - -// RegCloseKey(hKey); - -// SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); -// } else { -// dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); -// } -// } - -//Set environment variable for current process static void openssl_patch(void) { - const wchar_t* variablename = L"OPENSSL_ia32cap"; - const wchar_t* variablevalue = L"~0x20000000"; + const char* variablename = "OPENSSL_ia32cap"; + const char* variablevalue = "~0x20000000"; - if (SetEnvironmentVariableW(variablename, variablevalue)) { - dprintf("OpenSSL Patch: Applied successfully, set the environment variable %ls to %ls\n", variablename, variablevalue); + if (is_env_variable_set(variablename, variablevalue)) { + return; + } + + HKEY hKey; + if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { + if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { + dprintf("OpenSSL Patch: Applied successfully. User environment variable %s set to %s\n", variablename, variablevalue); + SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); + dprintf( + "Please close this windows and reopen the game to enjoy.\n" + ); + ExitProcess(0); + } else { + dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); + } + + RegCloseKey(hKey); } else { - dprintf("OpenSSL Patch: Error: Failed to set the environment variable.\n"); + dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); } } +//Set environment variable for current process +// static void openssl_patch(void) { +// const wchar_t* variablename = L"OPENSSL_ia32cap"; +// const wchar_t* variablevalue = L"~0x20000000"; + +// if (SetEnvironmentVariableW(variablename, variablevalue)) { +// dprintf("OpenSSL Patch: Applied successfully, set the environment variable %ls to %ls\n", variablename, variablevalue); +// } else { +// dprintf("OpenSSL Patch: Error: Failed to set the environment variable.\n"); +// } +// } + HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg) { HRESULT hr; From d8202e1df488086690ad96676c5e3ab447e3e925 Mon Sep 17 00:00:00 2001 From: r0x5a <155115880+r0x5a@users.noreply.github.com> Date: Thu, 12 Dec 2024 02:28:02 +0800 Subject: [PATCH 171/204] dns: add port overriding support --- doc/config/common.md | 18 ++++++++++ hooklib/dns.c | 81 +++++++++++++++++++++++++++++++++++++++++++- hooklib/dns.h | 1 + meson.build | 1 + platform/config.c | 4 +++ platform/dns.c | 16 +++++---- platform/dns.h | 3 ++ 7 files changed, 117 insertions(+), 7 deletions(-) diff --git a/doc/config/common.md b/doc/config/common.md index 3c86751..f2e0380 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -203,6 +203,24 @@ Default: `0` Replace the HOST field in HTTP request headers with the settings above. This may help bypass network restrictions in some regions. +### `startupPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `startup` server. The current implementation affects every TCP connection to the port 80. + +### `billingPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `billing` server. The current implementation affects every TCP connection to the port 8443. + +### `aimedbPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `aimedb` server. The current implementation affects every TCP connection to the port 22345. + ## `[ds]` Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX diff --git a/hooklib/dns.c b/hooklib/dns.c index 8884989..7cea522 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -88,6 +88,11 @@ static DWORD WINAPI hook_send( int len, int flags); +static int WINAPI hook_connect( + SOCKET s, + const struct sockaddr *name, + int namelen); + /* Link pointers */ static DNS_STATUS (WINAPI *next_DnsQuery_A)( @@ -135,6 +140,11 @@ static DWORD (WINAPI *next_send)( int len, int flags); +static int (__stdcall *next_connect)( + SOCKET s, + const struct sockaddr *name, + int namelen); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -180,11 +190,22 @@ static struct hook_symbol http_hook_syms_ws2[] = { }, }; +static struct hook_symbol port_hook_syms_ws2[] = { + { + .name = "connect", + .patch = hook_connect, + .link = (void **) &next_connect + }, +}; + static bool dns_hook_initted; static CRITICAL_SECTION dns_hook_lock; static struct dns_hook_entry *dns_hook_entries; static size_t dns_hook_nentries; static char received_title_url[255]; +static unsigned short startup_port; +static unsigned short billing_port; +static unsigned short aimedb_port; static void dns_hook_init(void) { @@ -226,6 +247,21 @@ void http_hook_init(){ _countof(http_hook_syms_ws2)); } +void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port){ + startup_port = _startup_port; + billing_port = _billing_port; + aimedb_port = _aimedb_port; + for (size_t i = 0; i < _countof(port_hook_syms_ws2); ++i) { + port_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", port_hook_syms_ws2[i].name); + } + + hook_table_apply( + NULL, + "ws2_32.dll", + port_hook_syms_ws2, + _countof(port_hook_syms_ws2)); +} + // This function match domain and subdomains like *.naominet.jp. bool match_domain(const wchar_t* target, const wchar_t* pattern) { if (_wcsicmp(pattern, target) == 0) { @@ -624,7 +660,7 @@ static bool WINAPI hook_WinHttpCrackUrl( if (match_domain(pwszUrl, pos->from)) { wchar_t* toAddr = pos->to; wchar_t titleBuffer[255]; - + if(wcscmp(toAddr, L"title") == 0) { size_t wstr_c; mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url)); @@ -651,6 +687,49 @@ static bool WINAPI hook_WinHttpCrackUrl( ); } +int WINAPI hook_connect(SOCKET s, const struct sockaddr *name, int namelen) { + const struct sockaddr_in *n; + struct sockaddr_in new_name; + unsigned ip; + unsigned short port, new_port; + + EnterCriticalSection(&dns_hook_lock); + + n = (const struct sockaddr_in *)name; + ip = n->sin_addr.S_un.S_addr; + if (WSANtohs(s, n->sin_port, &port)) return SOCKET_ERROR; + + if (port == 80 && startup_port) { + new_port = startup_port; + } else if (port == 8443 && billing_port) { + new_port = billing_port; + } else if (port == 22345 && aimedb_port) { + new_port = aimedb_port; + } else { // No match + dprintf("TCP Connect: %u.%u.%u.%u:%hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port); + + LeaveCriticalSection(&dns_hook_lock); + return next_connect( + s, + name, + namelen + ); + } + + // matched + new_name = *n; + if (WSAHtons(s, new_port, &new_name.sin_port)) return SOCKET_ERROR; + + dprintf("TCP Connect: %u.%u.%u.%u:%hu, mapped to port %hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port, new_port); + + LeaveCriticalSection(&dns_hook_lock); + return next_connect( + s, + (const struct sockaddr *)&new_name, + sizeof(new_name) + ); +} + DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { if (strstr(buf, "HTTP/") != NULL) { char *new_buf = malloc(len + 1); diff --git a/hooklib/dns.h b/hooklib/dns.h index ed46959..9279a37 100644 --- a/hooklib/dns.h +++ b/hooklib/dns.h @@ -4,6 +4,7 @@ #include void http_hook_init(); +void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port); // if to_src is NULL, all lookups for from_src will fail HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src); diff --git a/meson.build b/meson.build index 4a962a4..41b49f4 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,7 @@ if cc.get_id() != 'msvc' '-static-libgcc', # '-ggdb', # Add debug information '-lcrypt32', # Bcrypt needed for prashook + '-lws2_32', # WSAHtons / WSANtohs needed for porthook # '-Wl,-s', # Strip debug symbols language: 'c', ) diff --git a/platform/config.c b/platform/config.c index a4362a3..2904019 100644 --- a/platform/config.c +++ b/platform/config.c @@ -123,6 +123,10 @@ void dns_config_load(struct dns_config *cfg, const wchar_t *filename) filename); cfg->replaceHost = GetPrivateProfileIntW(L"dns", L"replaceHost", 0, filename); + + cfg->startupPort = GetPrivateProfileIntW(L"dns", L"startupPort", 0, filename); + cfg->billingPort = GetPrivateProfileIntW(L"dns", L"billingPort", 0, filename); + cfg->aimedbPort = GetPrivateProfileIntW(L"dns", L"aimedbPort", 0, filename); } void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename) diff --git a/platform/dns.c b/platform/dns.c index 9ca8a5b..d87d8a4 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -20,6 +20,10 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) http_hook_init(); } + if(cfg->startupPort || cfg->billingPort || cfg->aimedbPort){ + port_hook_init(cfg->startupPort, cfg->billingPort, cfg->aimedbPort); + } + hr = dns_hook_push(L"tenporouter.loc", cfg->router); if (FAILED(hr)) { @@ -112,40 +116,40 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) if (FAILED(hr)) { return hr; } - + // WAHLAP PowerOn hr = dns_hook_push(L"at.sys-all.cn", cfg->startup); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"at.sys-allnet.cn", cfg->startup); if (FAILED(hr)) { return hr; } - + // WAHLAP WeChat AimeDB Server hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"ai.sys-allnet.cn", cfg->aimedb); if (FAILED(hr)) { return hr; } - + // WAHLAP Billing hr = dns_hook_push(L"bl.sys-all.cn", cfg->billing); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"bl.sys-allnet.cn", cfg->billing); if (FAILED(hr)) { diff --git a/platform/dns.h b/platform/dns.h index 0a2c2bc..1a19d26 100644 --- a/platform/dns.h +++ b/platform/dns.h @@ -13,6 +13,9 @@ struct dns_config { wchar_t aimedb[128]; wchar_t title[128]; bool replaceHost; + unsigned short startupPort; + unsigned short billingPort; + unsigned short aimedbPort; }; HRESULT dns_platform_hook_init(const struct dns_config *cfg); From 11556a1332e4c78201aaed72282e326147241448 Mon Sep 17 00:00:00 2001 From: GEEKi Date: Mon, 16 Dec 2024 11:09:38 +0800 Subject: [PATCH 172/204] add changeable config path --- .clang-format | 4 ++++ aimeio/aimeio.c | 3 ++- carolhook/dllmain.c | 5 +++-- carolio/carolio.c | 5 +++-- chunihook/dllmain.c | 5 +++-- chuniio/chuniio.c | 3 ++- chusanhook/dllmain.c | 5 +++-- cmhook/dllmain.c | 5 +++-- cmio/cmio.c | 3 ++- cxbhook/dllmain.c | 5 +++-- cxbio/cxbio.c | 5 +++-- divahook/dllmain.c | 5 +++-- divaio/divaio.c | 3 ++- doc/config/common.md | 11 +++++++++++ fgohook/dllmain.c | 5 +++-- fgoio/fgoio.c | 3 ++- idachook/dllmain.c | 5 +++-- idacio/dllmain.c | 3 ++- idzhook/dllmain.c | 5 +++-- idzio/dllmain.c | 3 ++- kemonohook/dllmain.c | 5 +++-- kemonoio/kemonoio.c | 5 +++-- mai2hook/dllmain.c | 5 +++-- mai2io/mai2io.c | 5 +++-- mercuryhook/dllmain.c | 5 +++-- mercuryio/mercuryio.c | 3 ++- minihook/dllmain.c | 9 +++++---- msvc-build.bat | 28 ++++++++++++++++++---------- mu3hook/dllmain.c | 5 +++-- mu3io/mu3io.c | 3 ++- swdchook/dllmain.c | 5 +++-- swdcio/dllmain.c | 3 ++- tokyohook/dllmain.c | 5 +++-- tokyoio/dllmain.c | 3 ++- util/env.c | 11 +++++++++++ util/env.h | 4 ++++ util/meson.build | 2 ++ 37 files changed, 134 insertions(+), 63 deletions(-) create mode 100644 .clang-format create mode 100644 util/env.c create mode 100644 util/env.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a8eacdb --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +--- +BasedOnStyle: Google +IndentWidth: 4 +--- diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index 17de30e..8192bae 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -12,6 +12,7 @@ #include "util/crc.h" #include "util/dprintf.h" +#include "util/env.h" struct aime_io_config { wchar_t aime_path[MAX_PATH]; @@ -222,7 +223,7 @@ uint16_t aime_io_get_api_version(void) HRESULT aime_io_init(void) { - aime_io_config_read(&aime_io_cfg, L".\\segatools.ini"); + aime_io_config_read(&aime_io_cfg, get_config_path()); return S_OK; } diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index cc422b9..762b33d 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -53,6 +53,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE carol_hook_mod; static process_entry_t carol_startup; @@ -100,7 +101,7 @@ static DWORD CALLBACK carol_pre_startup(void) /* Config load */ - carol_hook_config_load(&carol_hook_cfg, L".\\segatools.ini"); + carol_hook_config_load(&carol_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -164,7 +165,7 @@ static DWORD CALLBACK carol_pre_startup(void) } /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End carol_pre_startup ---\n"); diff --git a/carolio/carolio.c b/carolio/carolio.c index 5368da6..7582489 100644 --- a/carolio/carolio.c +++ b/carolio/carolio.c @@ -8,6 +8,7 @@ #include "carolio/carolio.h" #include "carolio/config.h" #include "util/dprintf.h" +#include "util/env.h" static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx); @@ -25,7 +26,7 @@ uint16_t carol_io_get_api_version(void) HRESULT carol_io_jvs_init(void) { - carol_io_config_load(&carol_io_cfg, L".\\segatools.ini"); + carol_io_config_load(&carol_io_cfg, get_config_path()); return S_OK; } @@ -178,4 +179,4 @@ static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx) } return 0; -} \ No newline at end of file +} diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 81c8910..d421e23 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -36,6 +36,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE chuni_hook_mod; static process_entry_t chuni_startup; @@ -71,7 +72,7 @@ static DWORD CALLBACK chuni_pre_startup(void) /* Config load */ - chuni_hook_config_load(&chuni_hook_cfg, L".\\segatools.ini"); + chuni_hook_config_load(&chuni_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -129,7 +130,7 @@ static DWORD CALLBACK chuni_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End chuni_pre_startup ---\n"); diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 27fe7b0..5d87215 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -10,6 +10,7 @@ #include "chuniio/ledoutput.h" #include "util/dprintf.h" +#include "util/env.h" static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx); @@ -27,7 +28,7 @@ uint16_t chuni_io_get_api_version(void) HRESULT chuni_io_jvs_init(void) { - chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini"); + chuni_io_config_load(&chuni_io_cfg, get_config_path()); led_init_mutex = CreateMutex( NULL, // default security attributes diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 85c6228..9a2f5da 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -49,6 +49,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE chusan_hook_mod; static process_entry_t chusan_startup; @@ -84,7 +85,7 @@ static DWORD CALLBACK chusan_pre_startup(void) /* Config load */ - chusan_hook_config_load(&chusan_hook_cfg, L".\\segatools.ini"); + chusan_hook_config_load(&chusan_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -173,7 +174,7 @@ static DWORD CALLBACK chusan_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End chusan_pre_startup ---\n"); diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 7020f75..03ace58 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -35,6 +35,7 @@ #include "unityhook/hook.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE cm_hook_mod; static process_entry_t cm_startup; @@ -48,7 +49,7 @@ static DWORD CALLBACK cm_pre_startup(void) /* Load config */ - cm_hook_config_load(&cm_hook_cfg, L".\\segatools.ini"); + cm_hook_config_load(&cm_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -105,7 +106,7 @@ static DWORD CALLBACK cm_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End cm_pre_startup ---\n"); diff --git a/cmio/cmio.c b/cmio/cmio.c index c2dbfa5..e1cacde 100644 --- a/cmio/cmio.c +++ b/cmio/cmio.c @@ -6,6 +6,7 @@ #include "cmio/cmio.h" #include "cmio/config.h" +#include "util/env.h" static uint8_t cm_opbtn; static struct cm_io_config cm_io_cfg; @@ -18,7 +19,7 @@ uint16_t cm_io_get_api_version(void) HRESULT cm_io_init(void) { - cm_io_config_load(&cm_io_cfg, L".\\segatools.ini"); + cm_io_config_load(&cm_io_cfg, get_config_path()); return S_OK; } diff --git a/cxbhook/dllmain.c b/cxbhook/dllmain.c index 18aaa7f..d644b5e 100644 --- a/cxbhook/dllmain.c +++ b/cxbhook/dllmain.c @@ -23,6 +23,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE cxb_hook_mod; static process_entry_t cxb_startup; @@ -58,7 +59,7 @@ static DWORD CALLBACK cxb_pre_startup(void) /* Config load */ - cxb_hook_config_load(&cxb_hook_cfg, L".\\segatools.ini"); + cxb_hook_config_load(&cxb_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -110,7 +111,7 @@ static DWORD CALLBACK cxb_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End cxb_pre_startup ---\n"); diff --git a/cxbio/cxbio.c b/cxbio/cxbio.c index d021d3c..fce594d 100644 --- a/cxbio/cxbio.c +++ b/cxbio/cxbio.c @@ -8,6 +8,7 @@ #include "cxbio/config.h" #include "util/dprintf.h" +#include "util/env.h" static bool cxb_io_coin; static int cxb_io_coins; @@ -21,7 +22,7 @@ uint16_t cxb_io_get_api_version(void) HRESULT cxb_io_revio_init(void) { dprintf("CXB IO: REVIO init\n"); - cxb_io_config_load(&cxb_io_cfg, L".\\segatools.ini"); + cxb_io_config_load(&cxb_io_cfg, get_config_path()); return S_OK; } @@ -75,4 +76,4 @@ HRESULT cxb_io_led_init(void) } void cxb_io_led_update(int id, int color) -{} \ No newline at end of file +{} diff --git a/divahook/dllmain.c b/divahook/dllmain.c index 337eff5..eb6e16f 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -33,6 +33,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE diva_hook_mod; static process_entry_t diva_startup; @@ -58,7 +59,7 @@ static DWORD CALLBACK diva_pre_startup(void) /* Config load */ - diva_hook_config_load(&diva_hook_cfg, L".\\segatools.ini"); + diva_hook_config_load(&diva_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -105,7 +106,7 @@ static DWORD CALLBACK diva_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End diva_pre_startup ---\n"); diff --git a/divaio/divaio.c b/divaio/divaio.c index 9976cb7..0001f2e 100644 --- a/divaio/divaio.c +++ b/divaio/divaio.c @@ -7,6 +7,7 @@ #include "divaio/divaio.h" #include "divaio/config.h" +#include "util/env.h" static unsigned int __stdcall diva_io_slider_thread_proc(void *ctx); @@ -23,7 +24,7 @@ uint16_t diva_io_get_api_version(void) HRESULT diva_io_jvs_init(void) { - diva_io_config_load(&diva_io_cfg, L".\\segatools.ini"); + diva_io_config_load(&diva_io_cfg, get_config_path()); return S_OK; } diff --git a/doc/config/common.md b/doc/config/common.md index 3c86751..0033b5e 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -6,6 +6,17 @@ all games. Keyboard binding settings use [Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). +## Config Path +The default file path for config file is `./segatools.ini`. + +You can modify environment variable `SEGATOOLS_CONFIG_PATH` to another path. + +For example, You can have a another start.bat with following code in it, +Then you can copy `segatools.ini` to `another_config.ini` but with different dns host in it +```bat +set SEGATOOLS_CONFIG_PATH=.\another_config.ini +``` + ## `[aimeio]` Controls the card reader driver. diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 9bc3694..e82423f 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -44,6 +44,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE fgo_hook_mod; static process_entry_t fgo_startup; @@ -69,7 +70,7 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Load config */ - fgo_hook_config_load(&fgo_hook_cfg, L".\\segatools.ini"); + fgo_hook_config_load(&fgo_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -147,7 +148,7 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End fgo_pre_startup ---\n"); diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index 61f7d77..4a362a0 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -8,6 +8,7 @@ #include "fgoio/fgoio.h" #include "fgoio/config.h" #include "util/dprintf.h" +#include "util/env.h" static uint8_t fgo_opbtn; static uint8_t fgo_gamebtn; @@ -23,7 +24,7 @@ uint16_t fgo_io_get_api_version(void) HRESULT fgo_io_init(void) { - fgo_io_config_load(&fgo_io_cfg, L".\\segatools.ini"); + fgo_io_config_load(&fgo_io_cfg, get_config_path()); return S_OK; } diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 2e82882..0e955e8 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -36,6 +36,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE idac_hook_mod; static process_entry_t idac_startup; @@ -49,7 +50,7 @@ static DWORD CALLBACK idac_pre_startup(void) /* Config load */ - idac_hook_config_load(&idac_hook_cfg, L".\\segatools.ini"); + idac_hook_config_load(&idac_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -109,7 +110,7 @@ static DWORD CALLBACK idac_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End idac_pre_startup ---\n"); diff --git a/idacio/dllmain.c b/idacio/dllmain.c index f295f90..6a5dba8 100644 --- a/idacio/dllmain.c +++ b/idacio/dllmain.c @@ -12,6 +12,7 @@ #include "util/dprintf.h" #include "util/str.h" +#include "util/env.h" static struct idac_io_config idac_io_cfg; static const struct idac_io_backend *idac_io_backend; @@ -38,7 +39,7 @@ HRESULT idac_io_init(void) return hr; } - idac_io_config_load(&idac_io_cfg, L".\\segatools.ini"); + idac_io_config_load(&idac_io_cfg, get_config_path()); if (wstr_ieq(idac_io_cfg.mode, L"dinput")) { hr = idac_di_init(&idac_io_cfg.di, inst, &idac_io_backend); diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index e9d807a..edf6cbb 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -40,6 +40,7 @@ #include "util/dprintf.h" #include "util/lib.h" +#include "util/env.h" static HMODULE idz_hook_mod; static process_entry_t idz_startup; @@ -55,7 +56,7 @@ static DWORD CALLBACK idz_pre_startup(void) /* Config load */ - idz_hook_config_load(&idz_hook_cfg, L".\\segatools.ini"); + idz_hook_config_load(&idz_hook_cfg, get_config_path()); module_path = module_file_name(NULL); @@ -136,7 +137,7 @@ static DWORD CALLBACK idz_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End idz_pre_startup ---\n"); diff --git a/idzio/dllmain.c b/idzio/dllmain.c index 5c8592d..39d08fc 100644 --- a/idzio/dllmain.c +++ b/idzio/dllmain.c @@ -12,6 +12,7 @@ #include "util/dprintf.h" #include "util/str.h" +#include "util/env.h" static struct idz_io_config idz_io_cfg; static const struct idz_io_backend *idz_io_backend; @@ -39,7 +40,7 @@ HRESULT idz_io_jvs_init(void) return hr; } - idz_io_config_load(&idz_io_cfg, L".\\segatools.ini"); + idz_io_config_load(&idz_io_cfg, get_config_path()); if (wstr_ieq(idz_io_cfg.mode, L"dinput")) { hr = idz_di_init(&idz_io_cfg.di, inst, &idz_io_backend); diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c index 5eac13d..0fedd5e 100644 --- a/kemonohook/dllmain.c +++ b/kemonohook/dllmain.c @@ -22,6 +22,7 @@ #include "unityhook/hook.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE kemono_hook_mod; static process_entry_t kemono_startup; @@ -35,7 +36,7 @@ static DWORD CALLBACK kemono_pre_startup(void) { /* Load config */ kemono_hook_cfg.aime.dll.path64 = true; - kemono_hook_config_load(&kemono_hook_cfg, L".\\segatools.ini"); + kemono_hook_config_load(&kemono_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -107,7 +108,7 @@ static DWORD CALLBACK kemono_pre_startup(void) { /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End kemono_pre_startup ---\n"); diff --git a/kemonoio/kemonoio.c b/kemonoio/kemonoio.c index 5b24c28..932abb1 100644 --- a/kemonoio/kemonoio.c +++ b/kemonoio/kemonoio.c @@ -7,6 +7,7 @@ #include "kemonoio/kemonoio.h" #include "kemonoio/config.h" +#include "util/env.h" static uint8_t kemono_opbtn; static uint16_t kemono_pbtn; @@ -19,7 +20,7 @@ uint16_t kemono_io_get_api_version(void) { } HRESULT kemono_io_init(void) { - kemono_io_config_load(&kemono_io_cfg, L".\\segatools.ini"); + kemono_io_config_load(&kemono_io_cfg, get_config_path()); kemono_io_coins = 0; @@ -106,4 +107,4 @@ void kemono_io_led_set_colors(uint8_t board, uint8_t *rgb) { void kemono_io_jvs_write_gpio(uint32_t state){ -} \ No newline at end of file +} diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index ac14649..0d8b20a 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -39,6 +39,7 @@ #include "unityhook/hook.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE mai2_hook_mod; static process_entry_t mai2_startup; @@ -54,7 +55,7 @@ static DWORD CALLBACK mai2_pre_startup(void) /* Load config */ - mai2_hook_config_load(&mai2_hook_cfg, L".\\segatools.ini"); + mai2_hook_config_load(&mai2_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -106,7 +107,7 @@ static DWORD CALLBACK mai2_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End mai2_pre_startup ---\n"); diff --git a/mai2io/mai2io.c b/mai2io/mai2io.c index 40d6bfb..ffdbfcf 100644 --- a/mai2io/mai2io.c +++ b/mai2io/mai2io.c @@ -5,6 +5,7 @@ #include "mai2io/mai2io.h" #include "mai2io/config.h" +#include "util/env.h" static uint8_t mai2_opbtn; static uint16_t mai2_player1_btn; @@ -19,7 +20,7 @@ uint16_t mai2_io_get_api_version(void) HRESULT mai2_io_init(void) { - mai2_io_config_load(&mai2_io_cfg, L".\\segatools.ini"); + mai2_io_config_load(&mai2_io_cfg, get_config_path()); return S_OK; } @@ -140,4 +141,4 @@ void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) if (player2 != NULL ){ *player2 = mai2_player2_btn; } -} \ No newline at end of file +} diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index ea30458..43984f9 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -34,6 +34,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE mercury_hook_mod; static process_entry_t mercury_startup; @@ -49,7 +50,7 @@ static DWORD CALLBACK mercury_pre_startup(void) /* Load config */ - mercury_hook_config_load(&mercury_hook_cfg, L".\\segatools.ini"); + mercury_hook_config_load(&mercury_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -102,7 +103,7 @@ static DWORD CALLBACK mercury_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End mercury_pre_startup ---\n"); diff --git a/mercuryio/mercuryio.c b/mercuryio/mercuryio.c index 6d38ff1..438c9e6 100644 --- a/mercuryio/mercuryio.c +++ b/mercuryio/mercuryio.c @@ -7,6 +7,7 @@ #include "mercuryio/mercuryio.h" #include "mercuryio/config.h" #include "mercuryhook/elisabeth.h" +#include "util/env.h" static unsigned int __stdcall mercury_io_touch_thread_proc(void *ctx); @@ -23,7 +24,7 @@ uint16_t mercury_io_get_api_version(void) HRESULT mercury_io_init(void) { - mercury_io_config_load(&mercury_io_cfg, L".\\segatools.ini"); + mercury_io_config_load(&mercury_io_cfg, get_config_path()); return S_OK; } diff --git a/minihook/dllmain.c b/minihook/dllmain.c index bdc45b8..c72609f 100644 --- a/minihook/dllmain.c +++ b/minihook/dllmain.c @@ -14,6 +14,7 @@ #include "platform/nusec.h" #include "util/dprintf.h" +#include "util/env.h" static process_entry_t app_startup; @@ -26,10 +27,10 @@ static DWORD CALLBACK app_pre_startup(void) dprintf("--- Begin %s ---\n", __func__); - clock_config_load(&clock_cfg, L".\\segatools.ini"); - ds_config_load(&ds_cfg, L".\\segatools.ini"); - nusec_config_load(&nusec_cfg, L".\\segatools.ini"); - spike_hook_init(L".\\segatools.ini"); + clock_config_load(&clock_cfg, get_config_path()); + ds_config_load(&ds_cfg, get_config_path()); + nusec_config_load(&nusec_cfg, get_config_path()); + spike_hook_init(get_config_path()); hr = clock_hook_init(&clock_cfg); diff --git a/msvc-build.bat b/msvc-build.bat index d485839..ae060f0 100644 --- a/msvc-build.bat +++ b/msvc-build.bat @@ -31,7 +31,7 @@ if /I "%1"=="build" ( set VSVARSALL=!VSVARSALL! set MESON=!MESON! - call :build + call :build %2 echo. echo Build done! @@ -42,9 +42,12 @@ if /I "%1"=="zip" ( exit /b ) -echo %~nx0 [action] +echo %~nx0 [action] [switch] echo build: Build the for both x86 and x64 +echo /PROJECTONLY: Only create projects +echo. echo zip: Make zip file +echo. exit /b rem This should works for Visual Studio 2017+ @@ -85,6 +88,7 @@ rem This should works for Visual Studio 2017+ ) :detect-meson ( + set MESON="" for /f "tokens=* usebackq" %%i in (`where meson`) do set MESON="%%i" if not exist %MESON% ( exit /b 1 @@ -98,28 +102,32 @@ rem This should works for Visual Studio 2017+ call %VSVARSALL% x64 if exist %BUILD_DIR_64% ( - %MESON% setup %BUILD_DIR_64% --backend vs --buildtype release --reconfigure + %MESON% setup %BUILD_DIR_64% --buildtype release --reconfigure ) else ( %MESON% setup %BUILD_DIR_64% --backend vs --buildtype release ) - pushd %BUILD_DIR_64% - msbuild /m /p:Configuration=release /p:Platform=x64 segatools.sln - popd + if /I not "%1"=="/PROJECTONLY" ( + pushd %BUILD_DIR_64% + msbuild /m /p:Configuration=release /p:Platform=x64 segatools.sln + popd + ) ) :build_x86 ( call %VSVARSALL% x86 if exist %BUILD_DIR_32% ( - %MESON% setup %BUILD_DIR_32% --backend vs --buildtype release --reconfigure + %MESON% setup %BUILD_DIR_32% --buildtype release --reconfigure ) else ( %MESON% setup %BUILD_DIR_32% --backend vs --buildtype release ) - pushd %BUILD_DIR_32% - msbuild /m /p:Configuration=release /p:Platform=Win32 segatools.sln - popd + if /I not "%1"=="/PROJECTONLY" ( + pushd %BUILD_DIR_32% + msbuild /m /p:Configuration=release /p:Platform=Win32 segatools.sln + popd + ) ) :end ( diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index e991b40..e4336e9 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -38,6 +38,7 @@ #include "unityhook/hook.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE mu3_hook_mod; static process_entry_t mu3_startup; @@ -51,7 +52,7 @@ static DWORD CALLBACK mu3_pre_startup(void) /* Load config */ - mu3_hook_config_load(&mu3_hook_cfg, L".\\segatools.ini"); + mu3_hook_config_load(&mu3_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -114,7 +115,7 @@ static DWORD CALLBACK mu3_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End mu3_pre_startup ---\n"); diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index 2658612..aaa5687 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -9,6 +9,7 @@ #include "mu3io/ledoutput.h" #include "util/dprintf.h" +#include "util/env.h" static uint8_t mu3_opbtn; static uint8_t mu3_left_btn; @@ -28,7 +29,7 @@ uint16_t mu3_io_get_api_version(void) HRESULT mu3_io_init(void) { - mu3_io_config_load(&mu3_io_cfg, L".\\segatools.ini"); + mu3_io_config_load(&mu3_io_cfg, get_config_path()); dprintf("XInput: --- Begin configuration ---\n"); dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse); diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index bd6a1b3..d83798c 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -36,6 +36,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE swdc_hook_mod; static process_entry_t swdc_startup; @@ -49,7 +50,7 @@ static DWORD CALLBACK swdc_pre_startup(void) /* Config load */ - swdc_hook_config_load(&swdc_hook_cfg, L".\\segatools.ini"); + swdc_hook_config_load(&swdc_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -112,7 +113,7 @@ static DWORD CALLBACK swdc_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End swdc_pre_startup ---\n"); diff --git a/swdcio/dllmain.c b/swdcio/dllmain.c index c2c5078..8057e23 100644 --- a/swdcio/dllmain.c +++ b/swdcio/dllmain.c @@ -12,6 +12,7 @@ #include "util/dprintf.h" #include "util/str.h" +#include "util/env.h" static struct swdc_io_config swdc_io_cfg; static const struct swdc_io_backend *swdc_io_backend; @@ -38,7 +39,7 @@ HRESULT swdc_io_init(void) return hr; } - swdc_io_config_load(&swdc_io_cfg, L".\\segatools.ini"); + swdc_io_config_load(&swdc_io_cfg, get_config_path()); if (wstr_ieq(swdc_io_cfg.mode, L"dinput")) { hr = swdc_di_init(&swdc_io_cfg.di, inst, &swdc_io_backend); diff --git a/tokyohook/dllmain.c b/tokyohook/dllmain.c index e39fcff..19a1517 100644 --- a/tokyohook/dllmain.c +++ b/tokyohook/dllmain.c @@ -26,6 +26,7 @@ #include "platform/platform.h" #include "util/dprintf.h" +#include "util/env.h" static HMODULE tokyo_hook_mod; static process_entry_t tokyo_startup; @@ -39,7 +40,7 @@ static DWORD CALLBACK tokyo_pre_startup(void) /* Load config */ - tokyo_hook_config_load(&tokyo_hook_cfg, L".\\segatools.ini"); + tokyo_hook_config_load(&tokyo_hook_cfg, get_config_path()); /* Hook Win32 APIs */ @@ -80,7 +81,7 @@ static DWORD CALLBACK tokyo_pre_startup(void) /* Initialize debug helpers */ - spike_hook_init(L".\\segatools.ini"); + spike_hook_init(get_config_path()); dprintf("--- End tokyo_pre_startup ---\n"); diff --git a/tokyoio/dllmain.c b/tokyoio/dllmain.c index 76c81ac..18d0039 100644 --- a/tokyoio/dllmain.c +++ b/tokyoio/dllmain.c @@ -12,6 +12,7 @@ #include "util/dprintf.h" #include "util/str.h" +#include "util/env.h" static struct tokyo_io_config tokyo_io_cfg; static const struct tokyo_io_backend *tokyo_io_backend; @@ -38,7 +39,7 @@ HRESULT tokyo_io_init(void) return hr; } - tokyo_io_config_load(&tokyo_io_cfg, L".\\segatools.ini"); + tokyo_io_config_load(&tokyo_io_cfg, get_config_path()); if (wstr_ieq(tokyo_io_cfg.mode, L"keyboard")) { hr = tokyo_kb_init(&tokyo_io_cfg.kb, &tokyo_io_backend); diff --git a/util/env.c b/util/env.c new file mode 100644 index 0000000..ae25a3f --- /dev/null +++ b/util/env.c @@ -0,0 +1,11 @@ +#include "env.h" + +const wchar_t* get_config_path() { + static wchar_t path[MAX_PATH]; + if (!GetEnvironmentVariableW(L"SEGATOOLS_CONFIG_PATH", path, MAX_PATH)) + { + return L".\\segatools.ini"; + } + + return path; +} diff --git a/util/env.h b/util/env.h new file mode 100644 index 0000000..c62194a --- /dev/null +++ b/util/env.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const wchar_t* get_config_path(); diff --git a/util/meson.build b/util/meson.build index 2c29609..4acae1a 100644 --- a/util/meson.build +++ b/util/meson.build @@ -24,5 +24,7 @@ util_lib = static_library( 'lib.h', 'str.c', 'str.h', + 'env.c', + 'env.h', ], ) From 21bb9653829ca227f861ba1610c361016c8d73ac Mon Sep 17 00:00:00 2001 From: GEEKi Date: Mon, 16 Dec 2024 11:14:14 +0800 Subject: [PATCH 173/204] typo --- doc/config/common.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/config/common.md b/doc/config/common.md index 0033b5e..f4e36db 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -11,7 +11,7 @@ The default file path for config file is `./segatools.ini`. You can modify environment variable `SEGATOOLS_CONFIG_PATH` to another path. -For example, You can have a another start.bat with following code in it, +For example, You can have another `start.bat` with following code in it, Then you can copy `segatools.ini` to `another_config.ini` but with different dns host in it ```bat set SEGATOOLS_CONFIG_PATH=.\another_config.ini From 047733d12260d00173090959defd9e89442d5f27 Mon Sep 17 00:00:00 2001 From: GEEKi Date: Mon, 16 Dec 2024 11:18:00 +0800 Subject: [PATCH 174/204] format code --- util/env.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/env.c b/util/env.c index ae25a3f..e88ee8a 100644 --- a/util/env.c +++ b/util/env.c @@ -2,8 +2,7 @@ const wchar_t* get_config_path() { static wchar_t path[MAX_PATH]; - if (!GetEnvironmentVariableW(L"SEGATOOLS_CONFIG_PATH", path, MAX_PATH)) - { + if (!GetEnvironmentVariableW(L"SEGATOOLS_CONFIG_PATH", path, MAX_PATH)) { return L".\\segatools.ini"; } From ff21223f06f7a063f0169d8e635134a262597856 Mon Sep 17 00:00:00 2001 From: kagaminehaku Date: Tue, 17 Dec 2024 10:06:41 +0700 Subject: [PATCH 175/204] Removed the unused lines --- platform/opensslpatch.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index d359d6c..f5532b7 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -36,7 +36,6 @@ static int is_env_variable_set(const char* variablename, const char* expectedval return 0; } -//Set User's Environment variable via registry static void openssl_patch(void) { const char* variablename = "OPENSSL_ia32cap"; const char* variablevalue = "~0x20000000"; @@ -64,18 +63,6 @@ static void openssl_patch(void) { } } -//Set environment variable for current process -// static void openssl_patch(void) { -// const wchar_t* variablename = L"OPENSSL_ia32cap"; -// const wchar_t* variablevalue = L"~0x20000000"; - -// if (SetEnvironmentVariableW(variablename, variablevalue)) { -// dprintf("OpenSSL Patch: Applied successfully, set the environment variable %ls to %ls\n", variablename, variablevalue); -// } else { -// dprintf("OpenSSL Patch: Error: Failed to set the environment variable.\n"); -// } -// } - HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg) { HRESULT hr; From 25431a9db1b7ce4dff93a573185531e2c59a81a7 Mon Sep 17 00:00:00 2001 From: KagamineHaku Date: Tue, 24 Dec 2024 02:34:44 +0700 Subject: [PATCH 176/204] Add "openssl" config key doc --- doc/config/common.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/config/common.md b/doc/config/common.md index e778a8a..f40adfd 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -565,3 +565,16 @@ Default: Empty string Configure the location of the "Option" data mount point. This mount point is optional (hence the name, probably) and contains directories which contain minor over-the-air content updates. + +## `[openssl]` + +Enable or disable the application of the OpenSSL patch for Intel Gen 10 or newer CPUs. + +### `enable` + +Default: `1` + +Enable the patch automatically sets the OPENSSL_ia32cap variable in the user's environment +table if the CPU meets the requirements. This setting must be enabled on PCs with +Intel Gen 10 or newer CPUs to ensure the game runs properly, but it's ok to leave enabled +on other CPUs since the patch will not run if the CPU requirements are not met. \ No newline at end of file From 80d4902cfceeb731eacd56d89105cb57eb9a74e8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 23 Dec 2024 21:03:35 +0100 Subject: [PATCH 177/204] remove 5gb wasted space by removing precompiled headers --- aimeio/meson.build | 1 - amex/ds.c | 1 + amex/meson.build | 1 - board/aime-dll.h | 1 + board/ffb.h | 1 + board/io3.c | 1 + board/io4.c | 1 + board/io4.h | 1 + board/led15070.c | 3 ++- board/led15093.c | 3 ++- board/meson.build | 1 - board/vfd.c | 1 + carolhook/meson.build | 1 - carolio/meson.build | 1 - chunihook/config.c | 1 + chunihook/meson.build | 1 - chuniio/chuniio.c | 3 ++- chuniio/config.c | 1 + chuniio/config.h | 1 + chuniio/leddata.h | 8 ++++---- chuniio/ledoutput.c | 8 ++++---- chuniio/ledoutput.h | 2 +- chuniio/meson.build | 1 - chuniio/serialimpl.c | 2 +- chuniio/serialimpl.h | 3 ++- chusanhook/chuni-dll.c | 1 + chusanhook/config.c | 1 + chusanhook/meson.build | 1 - cmhook/config.c | 1 + cmhook/meson.build | 1 - cmio/meson.build | 1 - cxbhook/config.c | 1 + cxbhook/led.c | 3 +++ cxbhook/meson.build | 1 - cxbhook/revio.c | 3 +++ cxbio/meson.build | 1 - divahook/meson.build | 1 - divaio/meson.build | 1 - fgohook/config.c | 1 + fgohook/ftdi.c | 4 +++- fgohook/meson.build | 1 - fgoio/meson.build | 1 - gfxhook/meson.build | 1 - hooklib/config.c | 1 + hooklib/createprocess.c | 1 + hooklib/cursor.c | 1 + hooklib/dns.c | 15 +++++++------- hooklib/meson.build | 1 - hooklib/spike.c | 1 + iccard/aime.c | 2 ++ iccard/felica.c | 1 + iccard/meson.build | 1 - idachook/config.c | 1 + idachook/indrun.c | 1 + idachook/meson.build | 1 - idachook/zinput.c | 1 + idacio/di.c | 2 ++ idacio/meson.build | 1 - idzhook/config.c | 1 + idzhook/meson.build | 1 - idzhook/zinput.c | 1 + idzio/di.c | 2 ++ idzio/meson.build | 1 - idzio/xi.c | 2 +- jvs/jvs-util.c | 1 + jvs/meson.build | 1 - kemonohook/config.c | 1 + kemonohook/dllmain.c | 2 ++ kemonohook/hooks.c | 2 ++ kemonohook/meson.build | 1 - kemonoio/meson.build | 1 - mai2hook/config.c | 1 + mai2hook/dllmain.c | 2 ++ mai2hook/meson.build | 1 - mai2io/config.c | 1 + mai2io/meson.build | 1 - mercuryhook/config.c | 1 + mercuryhook/dllmain.c | 2 ++ mercuryhook/elisabeth.h | 2 ++ mercuryhook/meson.build | 1 - mercuryio/config.c | 1 + mercuryio/mercuryio.c | 1 + mercuryio/meson.build | 1 - minihook/meson.build | 1 - mu3hook/config.c | 1 + mu3hook/meson.build | 1 - mu3io/config.c | 1 + mu3io/leddata.h | 8 ++++---- mu3io/ledoutput.c | 8 ++++---- mu3io/ledoutput.h | 2 +- mu3io/meson.build | 1 - mu3io/mu3io.c | 1 + platform/clock.c | 1 + platform/dns.c | 4 ++-- platform/epay.h | 1 + platform/meson.build | 1 - platform/misc.c | 1 + platform/netenv.c | 6 ++++++ platform/nusec.c | 1 + platform/opensslpatch.c | 3 +++ platform/system.c | 2 ++ precompiled.h | 39 ------------------------------------- swdchook/config.c | 1 + swdchook/meson.build | 1 - swdcio/di.c | 2 ++ swdcio/meson.build | 1 - tokyohook/config.c | 1 + tokyohook/meson.build | 1 - tokyoio/config.c | 1 + tokyoio/meson.build | 1 - unityhook/config.c | 2 ++ unityhook/doorstop.c | 2 ++ unityhook/hook.c | 2 ++ unityhook/meson.build | 1 - util/async.c | 2 +- util/get_function_ordinal.h | 1 + util/lib.c | 1 + util/meson.build | 1 - 118 files changed, 127 insertions(+), 114 deletions(-) delete mode 100644 precompiled.h diff --git a/aimeio/meson.build b/aimeio/meson.build index ddbb66a..46b0beb 100644 --- a/aimeio/meson.build +++ b/aimeio/meson.build @@ -3,7 +3,6 @@ aimeio_lib = static_library( name_prefix : '', include_directories: inc, implicit_include_directories : false, - c_pch : '../precompiled.h', link_with : [ util_lib, ], diff --git a/amex/ds.c b/amex/ds.c index c0f357f..74d1c85 100644 --- a/amex/ds.c +++ b/amex/ds.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "amex/ds.h" diff --git a/amex/meson.build b/amex/meson.build index 0f4d61e..7476aa4 100644 --- a/amex/meson.build +++ b/amex/meson.build @@ -2,7 +2,6 @@ amex_lib = static_library( 'amex', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/board/aime-dll.h b/board/aime-dll.h index 75dba9e..25c52f0 100644 --- a/board/aime-dll.h +++ b/board/aime-dll.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "aimeio/aimeio.h" diff --git a/board/ffb.h b/board/ffb.h index af46fe3..4dbc057 100644 --- a/board/ffb.h +++ b/board/ffb.h @@ -2,6 +2,7 @@ #include #include +#include struct ffb_config { bool enable; diff --git a/board/io3.c b/board/io3.c index 24d1b5e..d61cfdc 100644 --- a/board/io3.c +++ b/board/io3.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "board/io3.h" diff --git a/board/io4.c b/board/io4.c index 5c7d822..e1def19 100644 --- a/board/io4.c +++ b/board/io4.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "board/config.h" #include "board/guid.h" diff --git a/board/io4.h b/board/io4.h index 914c045..09a921b 100644 --- a/board/io4.h +++ b/board/io4.h @@ -3,6 +3,7 @@ #include #include +#include #define IO4_REPORT_OUT_PAYLOAD_LEN 62 diff --git a/board/led15070.c b/board/led15070.c index 6a634e8..c2d62a5 100644 --- a/board/led15070.c +++ b/board/led15070.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -242,7 +243,7 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp) dump_iobuf(&boarduart->written); #endif - req_iobuf.bytes = (byte*)&req; + req_iobuf.bytes = (uint8_t*)&req; req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); req_iobuf.pos = 0; diff --git a/board/led15093.c b/board/led15093.c index f92a6f2..a070a24 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "board/led15093-cmd.h" @@ -272,7 +273,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) dump_iobuf(&boarduart->written); #endif - req_iobuf.bytes = (byte*)&req; + req_iobuf.bytes = (uint8_t*)&req; req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.payload); req_iobuf.pos = 0; diff --git a/board/meson.build b/board/meson.build index 2a6cf70..a9c24ea 100644 --- a/board/meson.build +++ b/board/meson.build @@ -2,7 +2,6 @@ board_lib = static_library( 'board', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/board/vfd.c b/board/vfd.c index abc487a..34b89d4 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -8,6 +8,7 @@ #include #include +#include #include "board/config.h" #include "board/vfd.h" diff --git a/carolhook/meson.build b/carolhook/meson.build index cba763c..bd7fed2 100644 --- a/carolhook/meson.build +++ b/carolhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'carolhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/carolio/meson.build b/carolio/meson.build index dcb81ab..e7a7bb2 100644 --- a/carolio/meson.build +++ b/carolio/meson.build @@ -3,7 +3,6 @@ carolio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'carolio.c', 'carolio.h', diff --git a/chunihook/config.c b/chunihook/config.c index dd1497d..2ad959e 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "amex/amex.h" #include "amex/config.h" diff --git a/chunihook/meson.build b/chunihook/meson.build index 3f4a35d..b758676 100644 --- a/chunihook/meson.build +++ b/chunihook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'chunihook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 5d87215..614dc47 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "chuniio/chuniio.h" #include "chuniio/config.h" @@ -93,7 +94,7 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) } else { // Use actual AIR for (i = 0; i < 6; i++) { - if(GetAsyncKeyState(chuni_io_cfg.vk_ir[i]) & 0x8000) { + if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i]) & 0x8000) { *beams |= (1 << i); } else { *beams &= ~(1 << i); diff --git a/chuniio/config.c b/chuniio/config.c index 0f8b31b..a7b5273 100644 --- a/chuniio/config.c +++ b/chuniio/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "chuniio/config.h" diff --git a/chuniio/config.h b/chuniio/config.h index 8c5bf2c..eac6f7a 100644 --- a/chuniio/config.h +++ b/chuniio/config.h @@ -2,6 +2,7 @@ #include #include +#include struct chuni_io_config { uint8_t vk_test; diff --git a/chuniio/leddata.h b/chuniio/leddata.h index 0764c9f..564455b 100644 --- a/chuniio/leddata.h +++ b/chuniio/leddata.h @@ -13,10 +13,10 @@ // This struct is used to send data related to the slider and billboard LEDs struct _chuni_led_data_buf_t { - byte framing; // Sync byte + uint8_t framing; // Sync byte uint8_t board; // LED output the data is for (0-1: billboard, 2: slider) - byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs - byte data_len; // How many bytes to output from the buffer + uint8_t data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs + uint8_t data_len; // How many bytes to output from the buffer }; -static byte chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3}; \ No newline at end of file +static uint8_t chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3}; \ No newline at end of file diff --git a/chuniio/ledoutput.c b/chuniio/ledoutput.c index 6052e42..d4660b6 100644 --- a/chuniio/ledoutput.c +++ b/chuniio/ledoutput.c @@ -73,14 +73,14 @@ struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unes { struct _chuni_led_data_buf_t* out_struct = &led_escaped_buf[unescaped->board]; - byte* in_buf = unescaped->data; - byte* out_buf = out_struct->data; + uint8_t* in_buf = unescaped->data; + uint8_t* out_buf = out_struct->data; int i = 0; int o = 0; while (i < unescaped->data_len) { - byte b = in_buf[i++]; + uint8_t b = in_buf[i++]; if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE) { out_buf[o++] = LED_PACKET_ESCAPE; @@ -94,7 +94,7 @@ struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unes return out_struct; } -void led_output_update(uint8_t board, const byte* rgb) +void led_output_update(uint8_t board, const uint8_t* rgb) { if (board < 0 || board > 2 || !any_outputs_enabled) { diff --git a/chuniio/ledoutput.h b/chuniio/ledoutput.h index 33a4180..86642b9 100644 --- a/chuniio/ledoutput.h +++ b/chuniio/ledoutput.h @@ -16,4 +16,4 @@ extern HANDLE led_init_mutex; HRESULT led_output_init(struct chuni_io_config* const cfg); -void led_output_update(uint8_t board, const byte* rgb); +void led_output_update(uint8_t board, const uint8_t* rgb); diff --git a/chuniio/meson.build b/chuniio/meson.build index 8b03dff..eda00f0 100644 --- a/chuniio/meson.build +++ b/chuniio/meson.build @@ -3,7 +3,6 @@ chuniio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'chu2to3.c', diff --git a/chuniio/serialimpl.c b/chuniio/serialimpl.c index 7a68435..a111f93 100644 --- a/chuniio/serialimpl.c +++ b/chuniio/serialimpl.c @@ -98,7 +98,7 @@ void led_serial_update(struct _chuni_led_data_buf_t* data) ReleaseMutex(serial_write_mutex); } -void led_serial_update_openithm(const byte* rgb) +void led_serial_update_openithm(const uint8_t* rgb) { if (serial_port != INVALID_HANDLE_VALUE) { diff --git a/chuniio/serialimpl.h b/chuniio/serialimpl.h index 3f37803..b4b6f73 100644 --- a/chuniio/serialimpl.h +++ b/chuniio/serialimpl.h @@ -8,9 +8,10 @@ #pragma once #include +#include #include "chuniio/leddata.h" HRESULT led_serial_init(wchar_t led_com[12], DWORD baud); void led_serial_update(struct _chuni_led_data_buf_t* data); -void led_serial_update_openithm(const byte* rgb); \ No newline at end of file +void led_serial_update_openithm(const uint8_t* rgb); \ No newline at end of file diff --git a/chusanhook/chuni-dll.c b/chusanhook/chuni-dll.c index 0e7c634..574cbe2 100644 --- a/chusanhook/chuni-dll.c +++ b/chusanhook/chuni-dll.c @@ -2,6 +2,7 @@ #include #include +#include #include "chuniio/chu2to3.h" #include "chusanhook/chuni-dll.h" diff --git a/chusanhook/config.c b/chusanhook/config.c index fa6f19f..0ec8c61 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/chusanhook/meson.build b/chusanhook/meson.build index 69250bb..f7c622f 100644 --- a/chusanhook/meson.build +++ b/chusanhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'chusanhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/cmhook/config.c b/cmhook/config.c index c0c0bfd..47fcfa8 100644 --- a/cmhook/config.c +++ b/cmhook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/cmhook/meson.build b/cmhook/meson.build index 6c645c2..8828da9 100644 --- a/cmhook/meson.build +++ b/cmhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'cmhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/cmio/meson.build b/cmio/meson.build index 74fadda..d7a5ba6 100644 --- a/cmio/meson.build +++ b/cmio/meson.build @@ -3,7 +3,6 @@ cmio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'cmio.c', 'cmio.h', diff --git a/cxbhook/config.c b/cxbhook/config.c index c83694d..98d326d 100644 --- a/cxbhook/config.c +++ b/cxbhook/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "amex/amex.h" #include "amex/config.h" diff --git a/cxbhook/led.c b/cxbhook/led.c index b7d4f9b..662f7f9 100644 --- a/cxbhook/led.c +++ b/cxbhook/led.c @@ -1,6 +1,9 @@ #include + +#include #include #include +#include #include "cxbhook/led.h" #include "cxbhook/cxb-dll.h" diff --git a/cxbhook/meson.build b/cxbhook/meson.build index 68f8f76..e69ffff 100644 --- a/cxbhook/meson.build +++ b/cxbhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'cxbhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/cxbhook/revio.c b/cxbhook/revio.c index 7b3d25b..84ab016 100644 --- a/cxbhook/revio.c +++ b/cxbhook/revio.c @@ -1,6 +1,9 @@ #include + +#include #include #include +#include #include #include "cxbhook/revio.h" diff --git a/cxbio/meson.build b/cxbio/meson.build index 2ce52d2..5933602 100644 --- a/cxbio/meson.build +++ b/cxbio/meson.build @@ -3,7 +3,6 @@ cxbio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'cxbio.c', 'cxbio.h', diff --git a/divahook/meson.build b/divahook/meson.build index e291f3e..4c66c00 100644 --- a/divahook/meson.build +++ b/divahook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'divahook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/divaio/meson.build b/divaio/meson.build index edac3b6..3d4f611 100644 --- a/divaio/meson.build +++ b/divaio/meson.build @@ -3,7 +3,6 @@ divaio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'divaio.c', 'divaio.h', diff --git a/fgohook/config.c b/fgohook/config.c index b2bb7f5..30dbf86 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index 9a04b71..e39a7c2 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -16,8 +16,10 @@ #include #include -#include + #include +#include +#include #include #include "fgohook/ftdi.h" diff --git a/fgohook/meson.build b/fgohook/meson.build index 257048b..3d3e067 100644 --- a/fgohook/meson.build +++ b/fgohook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'fgohook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/fgoio/meson.build b/fgoio/meson.build index d8a4881..eed2fd3 100644 --- a/fgoio/meson.build +++ b/fgoio/meson.build @@ -3,7 +3,6 @@ fgoio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ xinput_lib, ], diff --git a/gfxhook/meson.build b/gfxhook/meson.build index 1cf8df3..4f7b1a5 100644 --- a/gfxhook/meson.build +++ b/gfxhook/meson.build @@ -2,7 +2,6 @@ gfxhook_lib = static_library( 'gfxhook', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), dxguid_lib, diff --git a/hooklib/config.c b/hooklib/config.c index d9db805..b7a84cf 100644 --- a/hooklib/config.c +++ b/hooklib/config.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "hooklib/config.h" diff --git a/hooklib/createprocess.c b/hooklib/createprocess.c index e44ebdb..6462394 100644 --- a/hooklib/createprocess.c +++ b/hooklib/createprocess.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "hook/table.h" diff --git a/hooklib/cursor.c b/hooklib/cursor.c index 8c66412..87e3ca8 100644 --- a/hooklib/cursor.c +++ b/hooklib/cursor.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "hook/table.h" diff --git a/hooklib/dns.c b/hooklib/dns.c index 7cea522..45b463e 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "hook/hr.h" @@ -317,7 +318,7 @@ HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src) goto end; } - if(to_src != NULL) { + if (to_src != NULL) { to = _wcsdup(to_src); if (to == NULL) { @@ -397,7 +398,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_A( pos = &dns_hook_entries[i]; if (match_domain(wstr, pos->from)) { - if(pos->to == NULL) { + if (pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); @@ -461,7 +462,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_W( pos = &dns_hook_entries[i]; if (match_domain(pszName, pos->from)) { - if(pos->to == NULL) { + if (pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); } @@ -505,7 +506,7 @@ static DNS_STATUS WINAPI hook_DnsQueryEx( pos = &dns_hook_entries[i]; if (match_domain(pRequest->QueryName, pos->from)) { - if(pos->to == NULL) { + if (pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR); } @@ -572,7 +573,7 @@ static int WSAAPI hook_getaddrinfo( pos = &dns_hook_entries[i]; if (match_domain(wstr, pos->from)) { - if(pos->to == NULL) { + if (pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); result = EAI_NONAME; @@ -626,7 +627,7 @@ static HINTERNET WINAPI hook_WinHttpConnect( pos = &dns_hook_entries[i]; if (match_domain(pwszServerName, pos->from)) { - if(pos->to == NULL) { + if (pos->to == NULL) { LeaveCriticalSection(&dns_hook_lock); return NULL; } @@ -661,7 +662,7 @@ static bool WINAPI hook_WinHttpCrackUrl( wchar_t* toAddr = pos->to; wchar_t titleBuffer[255]; - if(wcscmp(toAddr, L"title") == 0) { + if (wcscmp(toAddr, L"title") == 0) { size_t wstr_c; mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url)); toAddr = titleBuffer; diff --git a/hooklib/meson.build b/hooklib/meson.build index 4a74e05..7d5e7b8 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -2,7 +2,6 @@ hooklib_lib = static_library( 'hooklib', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/hooklib/spike.c b/hooklib/spike.c index f06166c..007c6ef 100644 --- a/hooklib/spike.c +++ b/hooklib/spike.c @@ -1,5 +1,6 @@ #include +#include #include #include #include diff --git a/iccard/aime.c b/iccard/aime.c index 5d2b1cd..bae12c1 100644 --- a/iccard/aime.c +++ b/iccard/aime.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "iccard/aime.h" #include "iccard/mifare.h" diff --git a/iccard/felica.c b/iccard/felica.c index 64ef897..392f3b2 100644 --- a/iccard/felica.c +++ b/iccard/felica.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "hook/iobuf.h" diff --git a/iccard/meson.build b/iccard/meson.build index e068ae0..72a6f78 100644 --- a/iccard/meson.build +++ b/iccard/meson.build @@ -2,7 +2,6 @@ iccard_lib = static_library( 'iccard', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/idachook/config.c b/idachook/config.c index 43455ae..279aba7 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" #include "board/sg-reader.h" diff --git a/idachook/indrun.c b/idachook/indrun.c index 1b9eb77..758a677 100644 --- a/idachook/indrun.c +++ b/idachook/indrun.c @@ -1,5 +1,6 @@ #include #include +#include #include "hook/table.h" diff --git a/idachook/meson.build b/idachook/meson.build index 66e8602..2cb6456 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'idachook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/idachook/zinput.c b/idachook/zinput.c index 59c77b5..a425307 100644 --- a/idachook/zinput.c +++ b/idachook/zinput.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include diff --git a/idacio/di.c b/idacio/di.c index 5310774..8a464ed 100644 --- a/idacio/di.c +++ b/idacio/di.c @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include "idacio/backend.h" diff --git a/idacio/meson.build b/idacio/meson.build index 7c7eddd..b095fdf 100644 --- a/idacio/meson.build +++ b/idacio/meson.build @@ -3,7 +3,6 @@ idacio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ dinput8_lib, dxguid_lib, diff --git a/idzhook/config.c b/idzhook/config.c index 7948c84..0378cbe 100644 --- a/idzhook/config.c +++ b/idzhook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "amex/amex.h" #include "amex/config.h" diff --git a/idzhook/meson.build b/idzhook/meson.build index eb9ba6c..6649489 100644 --- a/idzhook/meson.build +++ b/idzhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'idzhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/idzhook/zinput.c b/idzhook/zinput.c index dbc3b47..23e0e30 100644 --- a/idzhook/zinput.c +++ b/idzhook/zinput.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include diff --git a/idzio/di.c b/idzio/di.c index 8d8be41..00968fa 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include "idzio/backend.h" diff --git a/idzio/meson.build b/idzio/meson.build index bfab168..3a777bb 100644 --- a/idzio/meson.build +++ b/idzio/meson.build @@ -3,7 +3,6 @@ idzio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ dinput8_lib, dxguid_lib, diff --git a/idzio/xi.c b/idzio/xi.c index 515be2f..da566f0 100644 --- a/idzio/xi.c +++ b/idzio/xi.c @@ -212,7 +212,7 @@ static void idz_xi_jvs_read_analogs(struct idz_io_analog_state *out) left = calculate_norm_steering(left, idz_xi_left_stick_deadzone, idz_xi_linear_steering); right = calculate_norm_steering(right, idz_xi_right_stick_deadzone, idz_xi_linear_steering); - if(idz_xi_single_stick_steering) { + if (idz_xi_single_stick_steering) { out->wheel = left; } else { out->wheel = (left + right) / 2; diff --git a/jvs/jvs-util.c b/jvs/jvs-util.c index 5df33c7..336453e 100644 --- a/jvs/jvs-util.c +++ b/jvs/jvs-util.c @@ -10,6 +10,7 @@ #include "jvs/jvs-util.h" #include "util/dprintf.h" +#include "util/dump.h" typedef HRESULT (*jvs_dispatch_fn_t)( void *ctx, diff --git a/jvs/meson.build b/jvs/meson.build index 49737a0..14a7f66 100644 --- a/jvs/meson.build +++ b/jvs/meson.build @@ -2,7 +2,6 @@ jvs_lib = static_library( 'jvs', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/kemonohook/config.c b/kemonohook/config.c index 3eb85c8..ec00aa1 100644 --- a/kemonohook/config.c +++ b/kemonohook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "amex/config.h" diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c index 0fedd5e..83a4290 100644 --- a/kemonohook/dllmain.c +++ b/kemonohook/dllmain.c @@ -1,5 +1,7 @@ #include +#include + #include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" diff --git a/kemonohook/hooks.c b/kemonohook/hooks.c index bdce643..c34302f 100644 --- a/kemonohook/hooks.c +++ b/kemonohook/hooks.c @@ -1,3 +1,5 @@ +#include + #include "hook/iohook.h" #include "hook/procaddr.h" #include "hook/table.h" diff --git a/kemonohook/meson.build b/kemonohook/meson.build index 78538dd..63dc9e1 100644 --- a/kemonohook/meson.build +++ b/kemonohook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'kemonohook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/kemonoio/meson.build b/kemonoio/meson.build index 3dcc27c..5e5c1ac 100644 --- a/kemonoio/meson.build +++ b/kemonoio/meson.build @@ -3,7 +3,6 @@ kemonoio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'kemonoio.c', 'kemonoio.h', diff --git a/mai2hook/config.c b/mai2hook/config.c index d41a1d6..27e19ec 100644 --- a/mai2hook/config.c +++ b/mai2hook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 0d8b20a..193467f 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -19,6 +19,8 @@ #include +#include + #include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" diff --git a/mai2hook/meson.build b/mai2hook/meson.build index f43fccc..eba0c19 100644 --- a/mai2hook/meson.build +++ b/mai2hook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'mai2hook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/mai2io/config.c b/mai2io/config.c index 619b0ef..3578338 100644 --- a/mai2io/config.c +++ b/mai2io/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "mai2io/config.h" diff --git a/mai2io/meson.build b/mai2io/meson.build index c448136..cdbfd35 100644 --- a/mai2io/meson.build +++ b/mai2io/meson.build @@ -3,7 +3,6 @@ mai2io_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'mai2io.c', 'mai2io.h', diff --git a/mercuryhook/config.c b/mercuryhook/config.c index 4038129..d15c305 100644 --- a/mercuryhook/config.c +++ b/mercuryhook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index 43984f9..64b5707 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -13,6 +13,8 @@ #include +#include + #include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" diff --git a/mercuryhook/elisabeth.h b/mercuryhook/elisabeth.h index 5806c99..32512f3 100644 --- a/mercuryhook/elisabeth.h +++ b/mercuryhook/elisabeth.h @@ -1,5 +1,7 @@ #pragma once + #include +#include struct led_data { DWORD unitCount; diff --git a/mercuryhook/meson.build b/mercuryhook/meson.build index 7a676b2..fd6f46a 100644 --- a/mercuryhook/meson.build +++ b/mercuryhook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'mercuryhook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/mercuryio/config.c b/mercuryio/config.c index 853ed29..1308ac8 100644 --- a/mercuryio/config.c +++ b/mercuryio/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "mercuryio/config.h" diff --git a/mercuryio/mercuryio.c b/mercuryio/mercuryio.c index 438c9e6..880349c 100644 --- a/mercuryio/mercuryio.c +++ b/mercuryio/mercuryio.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "mercuryio/mercuryio.h" diff --git a/mercuryio/meson.build b/mercuryio/meson.build index 2970fa9..aa628fb 100644 --- a/mercuryio/meson.build +++ b/mercuryio/meson.build @@ -3,7 +3,6 @@ mercuryio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', sources : [ 'mercuryio.c', 'mercuryio.h', diff --git a/minihook/meson.build b/minihook/meson.build index 8acbf1e..7de7f6c 100644 --- a/minihook/meson.build +++ b/minihook/meson.build @@ -3,7 +3,6 @@ shared_library( name_prefix : '', include_directories: inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), ], diff --git a/mu3hook/config.c b/mu3hook/config.c index 32d4341..93957ea 100644 --- a/mu3hook/config.c +++ b/mu3hook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/mu3hook/meson.build b/mu3hook/meson.build index a722428..9f1bfcf 100644 --- a/mu3hook/meson.build +++ b/mu3hook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'mu3hook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/mu3io/config.c b/mu3io/config.c index fd4b0a7..9dbab48 100644 --- a/mu3io/config.c +++ b/mu3io/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "mu3io/config.h" diff --git a/mu3io/leddata.h b/mu3io/leddata.h index 1dcf42d..84bc8b7 100644 --- a/mu3io/leddata.h +++ b/mu3io/leddata.h @@ -14,10 +14,10 @@ // This struct is used to send data related to the button and cab LEDs struct _ongeki_led_data_buf_t { - byte framing; // Sync byte + uint8_t framing; // Sync byte uint8_t board; // LED output the data is for (0: cab, 1: control deck) - byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs - byte data_len; // How many bytes to output from the buffer + uint8_t data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs + uint8_t data_len; // How many bytes to output from the buffer }; -static byte ongeki_led_board_data_lens[LED_BOARDS_TOTAL] = {9*3, 6*3}; +static uint8_t ongeki_led_board_data_lens[LED_BOARDS_TOTAL] = {9*3, 6*3}; diff --git a/mu3io/ledoutput.c b/mu3io/ledoutput.c index 9c20d1a..83cdc26 100644 --- a/mu3io/ledoutput.c +++ b/mu3io/ledoutput.c @@ -70,14 +70,14 @@ struct _ongeki_led_data_buf_t* escape_led_data(struct _ongeki_led_data_buf_t* un { struct _ongeki_led_data_buf_t* out_struct = &mu3_led_escaped_buf[unescaped->board]; - byte* in_buf = unescaped->data; - byte* out_buf = out_struct->data; + uint8_t* in_buf = unescaped->data; + uint8_t* out_buf = out_struct->data; int i = 0; int o = 0; while (i < unescaped->data_len) { - byte b = in_buf[i++]; + uint8_t b = in_buf[i++]; if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE) { out_buf[o++] = LED_PACKET_ESCAPE; @@ -91,7 +91,7 @@ struct _ongeki_led_data_buf_t* escape_led_data(struct _ongeki_led_data_buf_t* un return out_struct; } -void mu3_led_output_update(int board, const byte* rgb) +void mu3_led_output_update(int board, const uint8_t* rgb) { if (board < 0 || board > 1 || !mu3_led_any_outputs_enabled) { diff --git a/mu3io/ledoutput.h b/mu3io/ledoutput.h index eb9e810..ab30814 100644 --- a/mu3io/ledoutput.h +++ b/mu3io/ledoutput.h @@ -17,4 +17,4 @@ extern HANDLE mu3_led_init_mutex; HRESULT mu3_led_output_init(struct mu3_io_config* const cfg); -void mu3_led_output_update(int board, const byte* rgb); +void mu3_led_output_update(int board, const uint8_t* rgb); diff --git a/mu3io/meson.build b/mu3io/meson.build index 3a2b571..67df7ca 100644 --- a/mu3io/meson.build +++ b/mu3io/meson.build @@ -3,7 +3,6 @@ mu3io_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ xinput_lib, ], diff --git a/mu3io/mu3io.c b/mu3io/mu3io.c index aaa5687..e5618d9 100644 --- a/mu3io/mu3io.c +++ b/mu3io/mu3io.c @@ -3,6 +3,7 @@ #include #include +#include #include "mu3io/mu3io.h" #include "mu3io/config.h" diff --git a/platform/clock.c b/platform/clock.c index e163961..b7249fa 100644 --- a/platform/clock.c +++ b/platform/clock.c @@ -2,6 +2,7 @@ #include #include +#include #include "hook/table.h" #include "hook/procaddr.h" diff --git a/platform/dns.c b/platform/dns.c index d87d8a4..f5745f0 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -16,11 +16,11 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return S_FALSE; } - if(cfg->replaceHost){ + if (cfg->replaceHost){ http_hook_init(); } - if(cfg->startupPort || cfg->billingPort || cfg->aimedbPort){ + if (cfg->startupPort || cfg->billingPort || cfg->aimedbPort){ port_hook_init(cfg->startupPort, cfg->billingPort, cfg->aimedbPort); } diff --git a/platform/epay.h b/platform/epay.h index c94eceb..6b5659b 100644 --- a/platform/epay.h +++ b/platform/epay.h @@ -2,6 +2,7 @@ #include #include +#include #pragma pack(push,1) struct epay_config { diff --git a/platform/meson.build b/platform/meson.build index a00df6b..af6555c 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -2,7 +2,6 @@ platform_lib = static_library( 'platform', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), shlwapi_lib, diff --git a/platform/misc.c b/platform/misc.c index 040a249..31a4d16 100644 --- a/platform/misc.c +++ b/platform/misc.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "hook/table.h" diff --git a/platform/netenv.c b/platform/netenv.c index 951c4b0..4fb77d2 100644 --- a/platform/netenv.c +++ b/platform/netenv.c @@ -1,9 +1,15 @@ #include +#include #include +#include +#include +#include +#include #include #include #include +#include #include #include diff --git a/platform/nusec.c b/platform/nusec.c index a82a99f..f455ca7 100644 --- a/platform/nusec.c +++ b/platform/nusec.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "hook/iohook.h" diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c index f5532b7..8e2ea72 100644 --- a/platform/opensslpatch.c +++ b/platform/opensslpatch.c @@ -1,7 +1,10 @@ #include + +#include #include #include #include + #include "util/dprintf.h" #include "platform/opensslpatch.h" diff --git a/platform/system.c b/platform/system.c index 49f7999..a82c326 100644 --- a/platform/system.c +++ b/platform/system.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include "platform/system.h" diff --git a/precompiled.h b/precompiled.h deleted file mode 100644 index 7c85da7..0000000 --- a/precompiled.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Making NTSTATUS available is slightly awkward. See: - https://kirkshoop.github.io/2011/09/20/ntstatus.html -*/ - -/* Win32 user-mode API */ -#define WIN32_NO_STATUS -#include -#undef WIN32_NO_STATUS -#include -#include -#include -#include -#include -#include -#include -#include - -/* Win32 kernel-mode definitions */ -#ifdef __GNUC__ -/* MinGW needs to include this for PHYSICAL_ADDRESS to be defined. - The MS SDK throws a bunch of duplicate symbol errors instead. */ -#include -#else -#include -#endif -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/swdchook/config.c b/swdchook/config.c index 269a450..fcfa251 100644 --- a/swdchook/config.c +++ b/swdchook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" #include "board/sg-reader.h" diff --git a/swdchook/meson.build b/swdchook/meson.build index 786c936..882647a 100644 --- a/swdchook/meson.build +++ b/swdchook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'swdchook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/swdcio/di.c b/swdcio/di.c index db952a0..8012454 100644 --- a/swdcio/di.c +++ b/swdcio/di.c @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include "swdcio/backend.h" diff --git a/swdcio/meson.build b/swdcio/meson.build index 71e018a..d9de43e 100644 --- a/swdcio/meson.build +++ b/swdcio/meson.build @@ -3,7 +3,6 @@ swdcio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ dinput8_lib, dxguid_lib, diff --git a/tokyohook/config.c b/tokyohook/config.c index e9735d2..304cbc2 100644 --- a/tokyohook/config.c +++ b/tokyohook/config.c @@ -1,5 +1,6 @@ #include #include +#include #include "board/config.h" diff --git a/tokyohook/meson.build b/tokyohook/meson.build index 1e4b1d8..0bbee19 100644 --- a/tokyohook/meson.build +++ b/tokyohook/meson.build @@ -4,7 +4,6 @@ shared_library( include_directories : inc, implicit_include_directories : false, vs_module_defs : 'tokyohook.def', - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), diff --git a/tokyoio/config.c b/tokyoio/config.c index 0ae2d26..2522154 100644 --- a/tokyoio/config.c +++ b/tokyoio/config.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "tokyoio/config.h" diff --git a/tokyoio/meson.build b/tokyoio/meson.build index aa4e198..9e9e9fe 100644 --- a/tokyoio/meson.build +++ b/tokyoio/meson.build @@ -3,7 +3,6 @@ tokyoio_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ xinput_lib, ], diff --git a/unityhook/config.c b/unityhook/config.c index 6f0a0cc..fe4e062 100644 --- a/unityhook/config.c +++ b/unityhook/config.c @@ -1,3 +1,5 @@ +#include + #include "config.h" void unity_config_load(struct unity_config *cfg, const wchar_t *filename) { diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index 1b94ad5..d2cbd5c 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -4,6 +4,8 @@ // SPDX-License-Identifier: CC0 // https://github.com/NeighTools/UnityDoorstop #include +#include +#include #include #include diff --git a/unityhook/hook.c b/unityhook/hook.c index 63816f3..33070a0 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "platform/clock.h" diff --git a/unityhook/meson.build b/unityhook/meson.build index 9fd7a7b..50d0488 100644 --- a/unityhook/meson.build +++ b/unityhook/meson.build @@ -2,7 +2,6 @@ unityhook_lib = static_library( 'unityhook', include_directories: inc, implicit_include_directories: false, - c_pch: '../precompiled.h', dependencies: [ capnhook.get_variable('hook_dep'), pathcch_lib diff --git a/util/async.c b/util/async.c index fd6a1cd..449550c 100644 --- a/util/async.c +++ b/util/async.c @@ -1,4 +1,4 @@ -/* NTSTATUS chicanery. See precompiled.h */ +/* NTSTATUS chicanery. */ #define WIN32_NO_STATUS #include #undef WIN32_NO_STATUS diff --git a/util/get_function_ordinal.h b/util/get_function_ordinal.h index 6bc4b9e..56779c4 100644 --- a/util/get_function_ordinal.h +++ b/util/get_function_ordinal.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "dprintf.h" diff --git a/util/lib.c b/util/lib.c index bd7a5eb..42f5c66 100644 --- a/util/lib.c +++ b/util/lib.c @@ -1,6 +1,7 @@ #include #include +#include wchar_t *module_file_name(HMODULE module) { diff --git a/util/meson.build b/util/meson.build index 4acae1a..0274ad5 100644 --- a/util/meson.build +++ b/util/meson.build @@ -2,7 +2,6 @@ util_lib = static_library( 'util', include_directories : inc, implicit_include_directories : false, - c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), imagehlp_lib, From a3120181be304f9b2a7d0a5bf721545d12b810f5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 23 Dec 2024 21:48:30 +0100 Subject: [PATCH 178/204] replace hardcoded enums with #define CTL_CODEs --- amex/ds.c | 12 +++++------- amex/eeprom.c | 6 ++---- amex/gpio.c | 11 +++++------ amex/jvs.c | 9 ++++----- amex/sram.c | 6 ++---- platform/hwmon.c | 5 ++--- platform/hwreset.c | 5 ++--- platform/nusec.c | 34 ++++++++++++++++------------------ 8 files changed, 38 insertions(+), 50 deletions(-) diff --git a/amex/ds.c b/amex/ds.c index 74d1c85..0989ac4 100644 --- a/amex/ds.c +++ b/amex/ds.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -20,13 +20,11 @@ #include "util/dprintf.h" #include "util/str.h" -#pragma pack(push, 1) +#define DS_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) +#define DS_IOCTL_SETUP CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS) +#define DS_IOCTL_READ_SECTOR CTL_CODE(0x8000, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS) -enum { - DS_IOCTL_GET_ABI_VERSION = 0x80006000, - DS_IOCTL_SETUP = 0x80006004, - DS_IOCTL_READ_SECTOR = 0x80006010, -}; +#pragma pack(push, 1) struct ds_eeprom { uint32_t crc32; diff --git a/amex/eeprom.c b/amex/eeprom.c index 84e4701..b06c4bd 100644 --- a/amex/eeprom.c +++ b/amex/eeprom.c @@ -6,7 +6,7 @@ #include #endif #include -#include +#include #include @@ -20,9 +20,7 @@ #include "util/dprintf.h" #include "util/str.h" -enum { - EEPROM_IOCTL_GET_ABI_VERSION = 0x80006000, -}; +#define EEPROM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) static HRESULT eeprom_handle_irp(struct irp *irp); static HRESULT eeprom_handle_open(struct irp *irp); diff --git a/amex/gpio.c b/amex/gpio.c index 4e18630..86eadad 100644 --- a/amex/gpio.c +++ b/amex/gpio.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -13,12 +14,10 @@ #include "util/dprintf.h" #include "util/str.h" -enum { - GPIO_IOCTL_SET_LEDS = 0x8000A004, - GPIO_IOCTL_GET_PSW = 0x80006008, - GPIO_IOCTL_GET_DIPSW = 0x8000600C, - GPIO_IOCTL_DESCRIBE = 0x80006014, -}; +#define GPIO_IOCTL_SET_LEDS CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define GPIO_IOCTL_GET_PSW CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS) +#define GPIO_IOCTL_GET_DIPSW CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS) +#define GPIO_IOCTL_DESCRIBE CTL_CODE(0x8000, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS) enum { GPIO_TYPE_NONE = 0, diff --git a/amex/jvs.c b/amex/jvs.c index dc55137..0c2dfc7 100644 --- a/amex/jvs.c +++ b/amex/jvs.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -21,11 +22,9 @@ #include "util/dump.h" #include "util/str.h" -enum { - JVS_IOCTL_HELLO = 0x80006004, - JVS_IOCTL_SENSE = 0x8000600C, - JVS_IOCTL_TRANSACT = 0x8000E008, -}; +#define JVS_IOCTL_HELLO CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS) +#define JVS_IOCTL_TRANSACT CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define JVS_IOCTL_SENSE CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS) static HRESULT jvs_handle_irp(struct irp *irp); static HRESULT jvs_handle_open(struct irp *irp); diff --git a/amex/sram.c b/amex/sram.c index c5a195a..fa4f005 100644 --- a/amex/sram.c +++ b/amex/sram.c @@ -6,7 +6,7 @@ #include #endif #include -#include +#include #include @@ -20,9 +20,7 @@ #include "util/dprintf.h" #include "util/str.h" -enum { - SRAM_IOCTL_GET_ABI_VERSION = 0x80006000, -}; +#define SRAM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) static HRESULT sram_handle_irp(struct irp *irp); static HRESULT sram_handle_open(struct irp *irp); diff --git a/platform/hwmon.c b/platform/hwmon.c index ac125d3..cc13c7a 100644 --- a/platform/hwmon.c +++ b/platform/hwmon.c @@ -1,6 +1,7 @@ #include #include +#include #include #include "hook/iohook.h" @@ -10,9 +11,7 @@ #include "util/dprintf.h" #include "util/str.h" -enum { - HWMON_IOCTL_READ_CPU_TEMP = 0x80006000, -}; +#define HWMON_IOCTL_READ_CPU_TEMP CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) static HRESULT hwmon_handle_irp(struct irp *irp); static HRESULT hwmon_handle_open(struct irp *irp); diff --git a/platform/hwreset.c b/platform/hwreset.c index 51ec337..7b37f1f 100644 --- a/platform/hwreset.c +++ b/platform/hwreset.c @@ -1,6 +1,7 @@ #include #include +#include #include #include "hook/iohook.h" @@ -10,9 +11,7 @@ #include "util/dprintf.h" #include "util/str.h" -enum { - HWRESET_IOCTL_RESTART = 0x80002000, -}; +#define HWRESET_IOCTL_RESTART CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) static HRESULT hwreset_handle_irp(struct irp *irp); static HRESULT hwreset_handle_open(struct irp *irp); diff --git a/platform/nusec.c b/platform/nusec.c index f455ca7..db275c4 100644 --- a/platform/nusec.c +++ b/platform/nusec.c @@ -14,24 +14,22 @@ #include "util/dump.h" #include "util/str.h" -enum { - NUSEC_IOCTL_PING = CTL_CODE(0x22, 0x845, METHOD_BUFFERED, FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_PLAY_COUNT = CTL_CODE(0x22, 0x854, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_ADD_PLAY_COUNT = CTL_CODE(0x22, 0x855, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_ERASE_TRACE_LOG = CTL_CODE(0x22, 0x862, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_TD_ERASE_USED = CTL_CODE(0x22, 0x863, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_PUT_TRACE_LOG_DATA = CTL_CODE(0x22, 0x864, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_TRACE_LOG_DATA = CTL_CODE(0x22, 0x865, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_TRACE_LOG_STATE = CTL_CODE(0x22, 0x866, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_NVRAM_AVAILABLE = CTL_CODE(0x22, 0x867, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_BILLING_CA_CERT = CTL_CODE(0x22, 0x871, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_BILLING_PUBKEY = CTL_CODE(0x22, 0x872, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_PLAY_LIMIT = CTL_CODE(0x22, 0x881, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_PUT_PLAY_LIMIT = CTL_CODE(0x22, 0x882, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_NEARFULL = CTL_CODE(0x22, 0x883, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_PUT_NEARFULL = CTL_CODE(0x22, 0x884, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - NUSEC_IOCTL_GET_NVRAM_GEOMETRY = CTL_CODE(0x22, 0x893, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), -}; +#define NUSEC_IOCTL_PING CTL_CODE(0x22, 0x845, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_PLAY_COUNT CTL_CODE(0x22, 0x854, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_ADD_PLAY_COUNT CTL_CODE(0x22, 0x855, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_ERASE_TRACE_LOG CTL_CODE(0x22, 0x862, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_TD_ERASE_USED CTL_CODE(0x22, 0x863, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_PUT_TRACE_LOG_DATA CTL_CODE(0x22, 0x864, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_TRACE_LOG_DATA CTL_CODE(0x22, 0x865, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_TRACE_LOG_STATE CTL_CODE(0x22, 0x866, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_NVRAM_AVAILABLE CTL_CODE(0x22, 0x867, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_BILLING_CA_CERT CTL_CODE(0x22, 0x871, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_BILLING_PUBKEY CTL_CODE(0x22, 0x872, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_PLAY_LIMIT CTL_CODE(0x22, 0x881, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_PUT_PLAY_LIMIT CTL_CODE(0x22, 0x882, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_NEARFULL CTL_CODE(0x22, 0x883, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_PUT_NEARFULL CTL_CODE(0x22, 0x884, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_GET_NVRAM_GEOMETRY CTL_CODE(0x22, 0x893, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) struct nusec_log_record { uint8_t unknown[60]; From 96bf8cab8104f13a5fd521dc9624a258289bfcc5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Mon, 23 Dec 2024 21:49:24 +0100 Subject: [PATCH 179/204] aime: add `portNo` to config --- board/config.c | 3 ++- board/sg-reader.c | 8 +++++++- board/sg-reader.h | 3 ++- board/vfd.c | 12 ++++++------ board/vfd.h | 4 ++-- doc/config/common.md | 6 ++++++ 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/board/config.c b/board/config.c index 95eeecf..19d47bc 100644 --- a/board/config.c +++ b/board/config.c @@ -72,6 +72,7 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename); cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename); } @@ -90,7 +91,7 @@ void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename); - cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename); + cfg->port_no = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename); cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename); } diff --git a/board/sg-reader.c b/board/sg-reader.c index bcbef56..bcc9701 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -47,7 +47,7 @@ static struct sg_led sg_reader_led; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no, + unsigned int default_port_no, unsigned int gen, HINSTANCE self) { @@ -66,6 +66,11 @@ HRESULT sg_reader_hook_init( return hr; } + unsigned int port_no = cfg->port_no; + if (port_no == 0){ + port_no = default_port_no; + } + if (cfg->gen != 0) { gen = cfg->gen; } @@ -85,6 +90,7 @@ HRESULT sg_reader_hook_init( sg_reader_uart.baud.BaudRate = 38400; } + dprintf("NFC Assembly: enabling (port=%d)\n", port_no); uart_init(&sg_reader_uart, port_no); sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); diff --git a/board/sg-reader.h b/board/sg-reader.h index 01eb0b3..1824e28 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -9,12 +9,13 @@ struct aime_config { struct aime_dll_config dll; bool enable; + unsigned int port_no; bool high_baudrate; unsigned int gen; }; HRESULT sg_reader_hook_init( const struct aime_config *cfg, - unsigned int port_no, + unsigned int default_port_no, unsigned int gen, HINSTANCE self); diff --git a/board/vfd.c b/board/vfd.c index 34b89d4..4cfb20b 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -51,7 +51,7 @@ HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer static bool utf_enabled; -HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port) +HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no) { if (!cfg->enable){ return S_FALSE; @@ -59,13 +59,13 @@ HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port) utf_enabled = cfg->utf_conversion; - int port = cfg->port; - if (port == 0){ - port = default_port; + unsigned int port_no = cfg->port_no; + if (port_no == 0){ + port_no = default_port_no; } - dprintf("VFD: enabling (port=%d)\n", port); - uart_init(&vfd_uart, port); + dprintf("VFD: enabling (port=%d)\n", port_no); + uart_init(&vfd_uart, port_no); vfd_uart.written.bytes = vfd_written; vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.readable.bytes = vfd_readable; diff --git a/board/vfd.h b/board/vfd.h index 3e67061..5d3664c 100644 --- a/board/vfd.h +++ b/board/vfd.h @@ -4,10 +4,10 @@ struct vfd_config { bool enable; - int port; + unsigned int port_no; bool utf_conversion; }; -HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port); +HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no); diff --git a/doc/config/common.md b/doc/config/common.md index db866b2..5368bec 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -42,6 +42,12 @@ Default: `1` Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime reader (COM port number varies by game). +### `portNo` + +Default: (game specific) + +Sets the COM port to use for the aime card reader assembly. + ### `highBaud` Default: `1` From 0c28765bddb7d29e2d15434edd0ba5e13ae1cdb0 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Fri, 27 Dec 2024 14:12:58 +0000 Subject: [PATCH 180/204] Revert: Add automatically apply OpenSSL patch for Intel Gen 10+ CPUs --- doc/config/common.md | 13 ------- platform/config.c | 15 -------- platform/config.h | 1 - platform/meson.build | 2 - platform/opensslpatch.c | 83 ----------------------------------------- platform/opensslpatch.h | 7 ---- platform/platform.c | 7 ---- platform/platform.h | 2 - 8 files changed, 130 deletions(-) delete mode 100644 platform/opensslpatch.c delete mode 100644 platform/opensslpatch.h diff --git a/doc/config/common.md b/doc/config/common.md index 5368bec..2796ded 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -606,16 +606,3 @@ Default: Empty string Configure the location of the "Option" data mount point. This mount point is optional (hence the name, probably) and contains directories which contain minor over-the-air content updates. - -## `[openssl]` - -Enable or disable the application of the OpenSSL patch for Intel Gen 10 or newer CPUs. - -### `enable` - -Default: `1` - -Enable the patch automatically sets the OPENSSL_ia32cap variable in the user's environment -table if the CPU meets the requirements. This setting must be enabled on PCs with -Intel Gen 10 or newer CPUs to ensure the game runs properly, but it's ok to leave enabled -on other CPUs since the patch will not run if the CPU requirements are not met. \ No newline at end of file diff --git a/platform/config.c b/platform/config.c index e99553f..2904019 100644 --- a/platform/config.c +++ b/platform/config.c @@ -23,7 +23,6 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" -#include "platform/opensslpatch.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -42,7 +41,6 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); system_config_load(&cfg->system, filename); - openssl_patch_config_load(&cfg->openssl, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -363,16 +361,3 @@ void epay_config_load(struct epay_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); } - -void openssl_patch_config_load(struct openssl_patch_config *cfg, const wchar_t *filename) -{ - assert(cfg != NULL); - assert(filename != NULL); - - cfg->enable = GetPrivateProfileIntW( - L"openssl", - L"enable", - 1, - filename - ); -} diff --git a/platform/config.h b/platform/config.h index 9f1f7f4..e945378 100644 --- a/platform/config.h +++ b/platform/config.h @@ -36,4 +36,3 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); void system_config_load(struct system_config *cfg, const wchar_t *filename); -void openssl_patch_config_load(struct openssl_patch_config *cfg, const wchar_t *filename); \ No newline at end of file diff --git a/platform/meson.build b/platform/meson.build index af6555c..160f8af 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -35,7 +35,5 @@ platform_lib = static_library( 'vfs.h', 'system.c', 'system.h', - 'opensslpatch.c', - 'opensslpatch.h', ], ) diff --git a/platform/opensslpatch.c b/platform/opensslpatch.c deleted file mode 100644 index 8e2ea72..0000000 --- a/platform/opensslpatch.c +++ /dev/null @@ -1,83 +0,0 @@ -#include - -#include -#include -#include -#include - -#include "util/dprintf.h" -#include "platform/opensslpatch.h" - -int check_cpu() { - int cpui[4] = {0}; - - __cpuid(cpui, 0); - int nIds_ = cpui[0]; - - char vendor[0x20] = {0}; - *((int*)vendor) = cpui[1]; - *((int*)(vendor + 4)) = cpui[3]; - *((int*)(vendor + 8)) = cpui[2]; - - int isIntel = (strcmp(vendor, "GenuineIntel") == 0); - - if (isIntel && nIds_ >= 7) { - __cpuidex(cpui, 7, 0); - return (cpui[1] & (1 << 29)) != 0; - } - - return 0; -} - -static int is_env_variable_set(const char* variablename, const char* expectedvalue) { - char currentvalue[256]; - DWORD length = GetEnvironmentVariableA(variablename, currentvalue, sizeof(currentvalue)); - - if (length > 0 && length < sizeof(currentvalue)) { - return strcmp(currentvalue, expectedvalue) == 0; - } - return 0; -} - -static void openssl_patch(void) { - const char* variablename = "OPENSSL_ia32cap"; - const char* variablevalue = "~0x20000000"; - - if (is_env_variable_set(variablename, variablevalue)) { - return; - } - - HKEY hKey; - if (RegOpenKeyExA(HKEY_CURRENT_USER, "Environment", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { - if (RegSetValueExA(hKey, variablename, 0, REG_SZ, (const BYTE*)variablevalue, strlen(variablevalue) + 1) == ERROR_SUCCESS) { - dprintf("OpenSSL Patch: Applied successfully. User environment variable %s set to %s\n", variablename, variablevalue); - SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, NULL); - dprintf( - "Please close this windows and reopen the game to enjoy.\n" - ); - ExitProcess(0); - } else { - dprintf("OpenSSL Patch: Error: Failed to set the user environment variable.\n"); - } - - RegCloseKey(hKey); - } else { - dprintf("OpenSSL Patch: Error: Failed to open the user environment registry key.\n"); - } -} - -HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg) { - HRESULT hr; - - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - if (check_cpu()) { - openssl_patch(); - } - - return S_OK; -} diff --git a/platform/opensslpatch.h b/platform/opensslpatch.h deleted file mode 100644 index f97d9b7..0000000 --- a/platform/opensslpatch.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -struct openssl_patch_config { - int enable; -}; - -HRESULT openssl_patch_apply(const struct openssl_patch_config *cfg); diff --git a/platform/platform.c b/platform/platform.c index c61c031..a769c97 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -14,7 +14,6 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" -#include "platform/opensslpatch.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -29,12 +28,6 @@ HRESULT platform_hook_init( assert(platform_id != NULL); assert(redir_mod != NULL); - hr = openssl_patch_apply(&cfg->openssl); - - if (FAILED(hr)) { - return hr; - } - hr = amvideo_hook_init(&cfg->amvideo, redir_mod); if (FAILED(hr)) { diff --git a/platform/platform.h b/platform/platform.h index 4972bfe..0b69f12 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -14,7 +14,6 @@ #include "platform/pcbid.h" #include "platform/vfs.h" #include "platform/system.h" -#include "platform/opensslpatch.h" struct platform_config { struct amvideo_config amvideo; @@ -29,7 +28,6 @@ struct platform_config { struct nusec_config nusec; struct vfs_config vfs; struct system_config system; - struct openssl_patch_config openssl; }; HRESULT platform_hook_init( From 4c20deb60a1acf56ffe9299eadb7699621e8d78c Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Mon, 27 Jan 2025 02:09:14 -0500 Subject: [PATCH 181/204] bump capnhook ver --- subprojects/capnhook.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index 28fab1f..9d45d16 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook url = https://github.com/Hay1tsme/capnhook -revision = b595e4bf8a274ba3bdaf583e13a7ebc7efe0f48f +revision = 5e44ceea2240aab0b4fcb278611dd92f47d0467a From 402bf0f24727de1e7d98b4a0f5824eeb34aeb048 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 28 Jan 2025 01:41:03 -0500 Subject: [PATCH 182/204] nusec: add full IOCTL list without handlers --- platform/nusec.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/platform/nusec.c b/platform/nusec.c index db275c4..17420f5 100644 --- a/platform/nusec.c +++ b/platform/nusec.c @@ -17,19 +17,34 @@ #define NUSEC_IOCTL_PING CTL_CODE(0x22, 0x845, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_PLAY_COUNT CTL_CODE(0x22, 0x854, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_ADD_PLAY_COUNT CTL_CODE(0x22, 0x855, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_SET_IV CTL_CODE(0x22, 0x856, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_ENCRYPT CTL_CODE(0x22, 0x857, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_DECRYPT CTL_CODE(0x22, 0x858, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_TD_RESTORE CTL_CODE(0x22, 0x861, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_ERASE_TRACE_LOG CTL_CODE(0x22, 0x862, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_TD_ERASE_USED CTL_CODE(0x22, 0x863, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_PUT_TRACE_LOG_DATA CTL_CODE(0x22, 0x864, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_TRACE_LOG_DATA CTL_CODE(0x22, 0x865, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_TRACE_LOG_STATE CTL_CODE(0x22, 0x866, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_NVRAM_AVAILABLE CTL_CODE(0x22, 0x867, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_TD_ERASE_ALL CTL_CODE(0x22, 0x869, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_BILLING_CA_CERT CTL_CODE(0x22, 0x871, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_BILLING_PUBKEY CTL_CODE(0x22, 0x872, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_PLAY_LIMIT CTL_CODE(0x22, 0x881, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_PUT_PLAY_LIMIT CTL_CODE(0x22, 0x882, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_NEARFULL CTL_CODE(0x22, 0x883, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_PUT_NEARFULL CTL_CODE(0x22, 0x884, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_NVRAM_READ CTL_CODE(0x22, 0x891, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_NVRAM_WRITE CTL_CODE(0x22, 0x892, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define NUSEC_IOCTL_GET_NVRAM_GEOMETRY CTL_CODE(0x22, 0x893, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_AL_AUTH_START CTL_CODE(0x22, 0x8B0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_AL_AUTH_PACKET CTL_CODE(0x22, 0x8B2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// Referenced in AMDaemon but seemingly not used, maybe leftovers? +#define NUSEC_IOCTL_UNK_843 CTL_CODE(0x22, 0x843, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_UNK_844 CTL_CODE(0x22, 0x844, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_UNK_894 CTL_CODE(0x22, 0x894, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define NUSEC_IOCTL_UNK_895 CTL_CODE(0x22, 0x895, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) struct nusec_log_record { uint8_t unknown[60]; From 2f54183636940665bacb668fa7ce2b359782c320 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 4 Feb 2025 11:09:23 -0500 Subject: [PATCH 183/204] bump capnhook rev --- subprojects/capnhook.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index 9d45d16..f30a334 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook url = https://github.com/Hay1tsme/capnhook -revision = 5e44ceea2240aab0b4fcb278611dd92f47d0467a +revision = 4633c51d58f7a3f714f4c0da43876376439848fe From 1d63ab24d3b0de43f4274bf37fa92e365f2ee349 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Sun, 9 Feb 2025 04:52:27 -0500 Subject: [PATCH 184/204] Move capnhook to TeamTofuShop fork, update revision --- subprojects/capnhook.wrap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/capnhook.wrap b/subprojects/capnhook.wrap index f30a334..4c349ab 100644 --- a/subprojects/capnhook.wrap +++ b/subprojects/capnhook.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = capnhook -url = https://github.com/Hay1tsme/capnhook -revision = 4633c51d58f7a3f714f4c0da43876376439848fe +url = https://gitea.tendokyu.moe/TeamTofuShop/capnhook +revision = dafd0aa336ab80ba87a82370a9dc95a3389ef5e5 From a1611afffcdbb3e83e920a870c0fe719c61be985 Mon Sep 17 00:00:00 2001 From: Mahuyo Date: Sun, 16 Feb 2025 12:49:58 +0000 Subject: [PATCH 185/204] Mai2: Add touch and led15070 hook (#55) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, I have added the `mai2` touch and `led15070` hooks to provide an example for handling custom peripherals. This change allows users to implement the touch and `led15070` logic by writing appropriate `mai2io` scripts. #### **Touch Hook**: - The touch hook simulates touch points based on keyboard combinations. For example, to trigger the A1 touch point, the user must press the A and 1 keys on the keyboard. Input for the 1p requires Caps Lock to be off, while 2p requires Caps Lock to be on. - The hook allows for independent control of whether device simulation is enabled for "1p" and "2p" and whether keyboard input mapping is enabled. - **Note**: The current touch hook is not yet functional as it requires modifications to the `capnhook` for proper completion of the `sinmai` hook. #### **LED15070 Hook**: - This hook implements basic device simulation. Peripherals requiring lighting data should complete the logic as needed. - **Note**: The LED data refresh can flood the console logs, so I’ve added a `DEBUG` flag to control whether the debug logging is enabled or not. #### **Other Changes**: - In certain versions of `sinmai`, key inputs for 1p and 2p can be directly read from the keyboard without requiring simulation via the `amdaemon io4` hook. I’ve added a switch to control this behavior to prevent redundant input. - **Benefit**: This ensures that key input is only read when `sinmai` is in the foreground. If you'd like to learn more about the touch and `led15070` features, my research findings are available here: [Mai2Touch](https://github.com/Sucareto/Mai2Touch) Co-authored-by: Sucareto <28331534+Sucareto@users.noreply.github.com> Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/55 Co-authored-by: Mahuyo Co-committed-by: Mahuyo --- board/led15070.c | 83 ++++++++++---- dist/mai2/segatools.ini | 28 ++++- hooklib/reg.c | 2 +- mai2hook/config.c | 68 +++++++++-- mai2hook/config.h | 22 +++- mai2hook/dllmain.c | 44 +++++-- mai2hook/mai2-dll.c | 25 +++- mai2hook/mai2-dll.h | 7 ++ mai2hook/mai2hook.def | 9 +- mai2hook/meson.build | 2 + mai2hook/touch.c | 248 ++++++++++++++++++++++++++++++++++++++++ mai2hook/touch.h | 43 +++++++ mai2io/config.c | 65 ++++++++--- mai2io/config.h | 5 + mai2io/mai2io.c | 163 +++++++++++++++++++++++++- mai2io/mai2io.h | 118 +++++++++++++++++++ mai2io/meson.build | 3 + meson.build | 6 + meson_options.txt | 10 ++ platform/epay.c | 2 +- 20 files changed, 877 insertions(+), 76 deletions(-) create mode 100644 mai2hook/touch.c create mode 100644 mai2hook/touch.h diff --git a/board/led15070.c b/board/led15070.c index c2d62a5..579de7c 100644 --- a/board/led15070.c +++ b/board/led15070.c @@ -238,7 +238,7 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp) } for (;;) { -#if 0 +#if defined(LOG_LED15070) dprintf("TX Buffer:\n"); dump_iobuf(&boarduart->written); #endif @@ -257,7 +257,7 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp) return hr; } -#if 0 +#if defined(LOG_LED15070) dprintf("Deframe Buffer:\n"); dump_iobuf(&req_iobuf); #endif @@ -385,7 +385,9 @@ static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req) static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set input (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -408,9 +410,10 @@ static HRESULT led15070_req_set_input(int board, const struct led15070_req_any * static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req) { uint8_t idx = req->payload[0]; - +#if defined(LOG_LED15070) dprintf("LED 15070: Set LED - Normal 12bit (board %u, index %u)\n", board, idx); +#endif // TODO: Data for this command. Seen with Carol @@ -435,9 +438,10 @@ static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_re static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req) { uint8_t idx = req->payload[0]; - - // dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n", - // board, idx); +#if defined(LOG_LED15070) + dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n", + board, idx); +#endif led15070_per_board_vars[board].gs[idx][0] = req->payload[1]; // R led15070_per_board_vars[board].gs[idx][1] = req->payload[2]; // G @@ -468,8 +472,10 @@ static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led1507 uint8_t idx_skip = req->payload[2]; // TODO: useful? - // dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n", - // board, idx_start, idx_end, idx_skip); +#if defined(LOG_LED15070) + dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n", + board, idx_start, idx_end, idx_skip); +#endif if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { idx_start += idx_skip; @@ -508,9 +514,10 @@ static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070 uint8_t idx_start = req->payload[0]; uint8_t idx_end = req->payload[1]; uint8_t idx_skip = req->payload[2]; - - // dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n", - // board, idx_start, idx_end, idx_skip); +#if defined(LOG_LED15070) + dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n", + board, idx_start, idx_end, idx_skip); +#endif if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { idx_start += idx_skip; @@ -545,7 +552,9 @@ static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070 static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set palette - 7 Normal LED (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -567,7 +576,9 @@ static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set palette - 6 Flash LED (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -589,7 +600,9 @@ static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led1 static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set 15DC out (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -611,7 +624,9 @@ static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_an static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set 15GS out (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -633,7 +648,9 @@ static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_an static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set PSC max (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -655,7 +672,9 @@ static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Set FET output (board %u)\n", board); +#endif led15070_per_board_vars[board].fet[0] = req->payload[0]; // R or FET0 intensity led15070_per_board_vars[board].fet[1] = req->payload[1]; // G or FET1 intensity @@ -685,8 +704,9 @@ static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_ static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req) { uint8_t idx = req->payload[0]; - +#if defined(LOG_LED15070) dprintf("LED 15070: Set GS palette (board %u, index %u)\n", board, idx); +#endif led15070_per_board_vars[board].gs_palette[idx][0] = req->payload[1]; // R led15070_per_board_vars[board].gs_palette[idx][1] = req->payload[2]; // G @@ -712,7 +732,9 @@ static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_ static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req) { - // dprintf("LED 15070: DC update (board %u)\n", board); +#if defined(LOG_LED15070) + dprintf("LED 15070: DC update (board %u)\n", board); +#endif if (led_dc_update) led_dc_update((const uint8_t*)led15070_per_board_vars[board].dc); @@ -737,7 +759,9 @@ static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any * static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req) { - // dprintf("LED 15070: GS update (board %u)\n", board); +#if defined(LOG_LED15070) + dprintf("LED 15070: GS update (board %u)\n", board); +#endif if (led_gs_update) led_gs_update((const uint8_t*)led15070_per_board_vars[board].gs); @@ -762,7 +786,9 @@ static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any * static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Rotate (board %u)\n", board); +#endif if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -787,9 +813,10 @@ static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any uint8_t idx_start = req->payload[0]; uint8_t idx_end = req->payload[1]; uint8_t idx_skip = req->payload[2]; - - // dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n", - // board, idx_start, idx_end, idx_skip); +#if defined(LOG_LED15070) + dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n", + board, idx_start, idx_end, idx_skip); +#endif if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) { idx_start += idx_skip; @@ -829,9 +856,10 @@ static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_an uint8_t addr = req->payload[0]; uint8_t data = req->payload[1]; - +#if defined(LOG_LED15070) dprintf("LED 15070: EEPROM write (board %u, address %02x, data %02x)\n", board, addr, data); +#endif if (addr > 0x07) { dprintf("LED 15070: Error -- Invalid EEPROM write address %02x\n", @@ -919,8 +947,9 @@ static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any uint8_t addr = req->payload[0]; uint8_t data = 0; - +#if defined(LOG_LED15070) dprintf("LED 15070: EEPROM read (board %u, address %02x)\n", board, addr); +#endif if (addr > 0x07) { dprintf("LED 15070: Error -- Invalid EEPROM read address %02x\n", @@ -1002,7 +1031,9 @@ static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Acknowledge commands ON (board %u)\n", board); +#endif led15070_per_board_vars[board].enable_response = true; @@ -1023,7 +1054,9 @@ static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req) { +#if defined(LOG_LED15070) dprintf("LED 15070: Acknowledge commands OFF (board %u)\n", board); +#endif led15070_per_board_vars[board].enable_response = false; @@ -1044,7 +1077,9 @@ static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *re static HRESULT led15070_req_board_info(int board) { +#if defined(LOG_LED15070) dprintf("LED 15070: Get board info (board %u)\n", board); +#endif struct led15070_resp_board_info resp; @@ -1067,7 +1102,9 @@ static HRESULT led15070_req_board_info(int board) static HRESULT led15070_req_board_status(int board) { +#if defined(LOG_LED15070) dprintf("LED 15070: Get board status (board %u)\n", board); +#endif struct led15070_resp_any resp; @@ -1091,7 +1128,9 @@ static HRESULT led15070_req_board_status(int board) static HRESULT led15070_req_fw_sum(int board) { +#if defined(LOG_LED15070) dprintf("LED 15070: Get firmware checksum (board %u)\n", board); +#endif struct led15070_resp_any resp; @@ -1113,7 +1152,9 @@ static HRESULT led15070_req_fw_sum(int board) static HRESULT led15070_req_protocol_ver(int board) { +#if defined(LOG_LED15070) dprintf("LED 15070: Get protocol version (board %u)\n", board); +#endif struct led15070_resp_any resp; @@ -1187,7 +1228,7 @@ static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle) HRESULT hr; BOOL ok; -#if 0 +#if defined(LOG_LED15070) dprintf("LED 15070: Opening EEPROM file '%S' handle (board %u)\n", path, board); #endif @@ -1233,7 +1274,7 @@ static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle) HRESULT hr; BOOL ok; -#if 0 +#if defined(LOG_LED15070) dprintf("LED 15070: Closing EEPROM file '%S' handle (board %u)\n", path, board); #endif diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index c253334..46fb4e5 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -126,11 +126,27 @@ coin=0x72 ; Uncomment and complete the following sequence of settings to configure a ; custom keybinding. [button] -;1p_btn1=0x53 -;1p_btn2=0x53 -;1p_btn3=0x53 +enable=1 +;p1Btn1=0x53 +;p1Btn2=0x53 +;p1Btn3=0x53 ; ... etc ... -;2p_btn1=0x53 -;2p_btn2=0x53 -;2p_btn3=0x53 +;p2Btn1=0x53 +;p2Btn2=0x53 +;p2Btn3=0x53 ; ... etc ... + +[touch] +p1Enable=1 +;p1DebugInput=0 +p2Enable=1 +;p2DebugInput=0 +;p1TouchA1=0x53 +;p1TouchA2=0x53 +; ... etc ... +;p1TouchE8=0x53 + +[led15070] +; Enable emulation of the 837-15070-02 controlled lights, which handle the +; cabinet and seat LEDs. +enable=1 \ No newline at end of file diff --git a/hooklib/reg.c b/hooklib/reg.c index bc18dbb..d4a3bc3 100644 --- a/hooklib/reg.c +++ b/hooklib/reg.c @@ -308,7 +308,7 @@ static void reg_hook_init(void) reg_hook_initted = true; InitializeCriticalSection(®_hook_lock); - dprintf("Reg hook init\n"); + dprintf("Reg: hook init.\n"); reg_hook_insert_hooks(NULL); diff --git a/mai2hook/config.c b/mai2hook/config.c index 27e19ec..48c0c6e 100644 --- a/mai2hook/config.c +++ b/mai2hook/config.c @@ -12,24 +12,70 @@ #include "platform/config.h" void mai2_dll_config_load( - struct mai2_dll_config *cfg, - const wchar_t *filename) + struct mai2_dll_config *cfg, + const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); GetPrivateProfileStringW( - L"mai2io", - L"path", - L"", - cfg->path, - _countof(cfg->path), - filename); + L"mai2io", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void touch_config_load( + struct touch_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable_1p = GetPrivateProfileIntW(L"touch", L"p1Enable", 1, filename); + cfg->enable_2p = GetPrivateProfileIntW(L"touch", L"p2Enable", 1, filename); +} + +void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + wchar_t tmpstr[16]; + + cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); + cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x00, filename); + + GetPrivateProfileStringW( + L"led15070", + L"boardNumber", + L"15070-04", + tmpstr, + _countof(tmpstr), + filename); + + size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number)); + for (int i = n; i < sizeof(cfg->board_number); i++) + { + cfg->board_number[i] = ' '; + } + + GetPrivateProfileStringW( + L"led15070", + L"eepromPath", + L"DEVICE", + cfg->eeprom_path, + _countof(cfg->eeprom_path), + filename); } void mai2_hook_config_load( - struct mai2_hook_config *cfg, - const wchar_t *filename) + struct mai2_hook_config *cfg, + const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); @@ -40,5 +86,7 @@ void mai2_hook_config_load( io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); mai2_dll_config_load(&cfg->dll, filename); + touch_config_load(&cfg->touch, filename); + led15070_config_load(&cfg->led15070, filename); unity_config_load(&cfg->unity, filename); } diff --git a/mai2hook/config.h b/mai2hook/config.h index 7e86822..1055b81 100644 --- a/mai2hook/config.h +++ b/mai2hook/config.h @@ -10,6 +10,10 @@ #include "platform/config.h" +#include "mai2hook/touch.h" + +#include "board/led15070.h" + #include "unityhook/config.h" struct mai2_hook_config { @@ -19,13 +23,23 @@ struct mai2_hook_config { struct io4_config io4; struct vfd_config vfd; struct mai2_dll_config dll; + struct touch_config touch; + struct led15070_config led15070; struct unity_config unity; }; void mai2_dll_config_load( - struct mai2_dll_config *cfg, - const wchar_t *filename); + struct mai2_dll_config *cfg, + const wchar_t *filename); + +void touch_config_load( + struct touch_config *cfg, + const wchar_t *filename); + +void led15070_config_load( + struct led15070_config *cfg, + const wchar_t *filename); void mai2_hook_config_load( - struct mai2_hook_config *cfg, - const wchar_t *filename); + struct mai2_hook_config *cfg, + const wchar_t *filename); diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index 193467f..ac0e3a1 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -67,16 +67,44 @@ static DWORD CALLBACK mai2_pre_startup(void) /* Initialize emulation hooks */ hr = platform_hook_init( - &mai2_hook_cfg.platform, - "SDEZ", - "ACA1", - mai2_hook_mod); + &mai2_hook_cfg.platform, + "SDEZ", + "ACA1", + mai2_hook_mod); if (FAILED(hr)) { goto fail; } - hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, 1, mai2_hook_mod); + /* Initialize DLLs */ + + hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + // Touch Panel uses COM3 and COM4 + + hr = touch_hook_init(&mai2_hook_cfg.touch); + + if (FAILED(hr)) { + goto fail; + } + + // LED board uses COM21 and COM23 + hr = led15070_hook_init(&mai2_hook_cfg.led15070, + mai2_dll.led_init, + mai2_dll.led_set_fet_output, + mai2_dll.led_dc_update, + mai2_dll.led_gs_update, + 21, 2); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, 3, mai2_hook_mod); if (FAILED(hr)) { goto fail; @@ -88,12 +116,6 @@ static DWORD CALLBACK mai2_pre_startup(void) goto fail; } - hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod); - - if (FAILED(hr)) { - goto fail; - } - hr = mai2_io4_hook_init(&mai2_hook_cfg.io4); if (FAILED(hr)) { diff --git a/mai2hook/mai2-dll.c b/mai2hook/mai2-dll.c index dd172c3..121750e 100644 --- a/mai2hook/mai2-dll.c +++ b/mai2hook/mai2-dll.c @@ -21,7 +21,28 @@ const struct dll_bind_sym mai2_dll_syms[] = { }, { .sym = "mai2_io_get_gamebtns", .off = offsetof(struct mai2_dll, get_gamebtns), - } + }, { + .sym = "mai2_io_touch_init", + .off = offsetof(struct mai2_dll, touch_init), + }, { + .sym = "mai2_io_touch_set_sens", + .off = offsetof(struct mai2_dll, touch_set_sens), + }, { + .sym = "mai2_io_touch_update", + .off = offsetof(struct mai2_dll, touch_update), + }, { + .sym = "mai2_io_led_init", + .off = offsetof(struct mai2_dll, led_init), + }, { + .sym = "mai2_io_led_set_fet_output", + .off = offsetof(struct mai2_dll, led_set_fet_output), + }, { + .sym = "mai2_io_led_dc_update", + .off = offsetof(struct mai2_dll, led_dc_update), + }, { + .sym = "mai2_io_led_gs_update", + .off = offsetof(struct mai2_dll, led_gs_update), + }, }; struct mai2_dll mai2_dll; @@ -67,7 +88,7 @@ HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self) if (get_api_version != NULL) { mai2_dll.api_version = get_api_version(); } else { - mai2_dll.api_version = 0x0100; + mai2_dll.api_version = 0x0101; dprintf("Custom IO DLL does not expose mai2_io_get_api_version, " "assuming API version 1.0.\n" "Please ask the developer to update their DLL.\n"); diff --git a/mai2hook/mai2-dll.h b/mai2hook/mai2-dll.h index 6e53454..6c205c8 100644 --- a/mai2hook/mai2-dll.h +++ b/mai2hook/mai2-dll.h @@ -10,6 +10,13 @@ struct mai2_dll { HRESULT (*poll)(void); void (*get_opbtns)(uint8_t *opbtn); void (*get_gamebtns)(uint16_t *player1, uint16_t *player2); + HRESULT (*touch_init)(mai2_io_touch_callback_t callback); + void (*touch_set_sens)(uint8_t *bytes); + void (*touch_update)(bool player1, bool player2); + HRESULT (*led_init)(void); + void (*led_set_fet_output)(const uint8_t *rgb); + void (*led_dc_update)(const uint8_t *rgb); + void (*led_gs_update)(const uint8_t *rgb); }; struct mai2_dll_config { diff --git a/mai2hook/mai2hook.def b/mai2hook/mai2hook.def index 2d0ac8b..50e4058 100644 --- a/mai2hook/mai2hook.def +++ b/mai2hook/mai2hook.def @@ -15,4 +15,11 @@ EXPORTS mai2_io_get_gamebtns mai2_io_get_opbtns mai2_io_init - mai2_io_poll \ No newline at end of file + mai2_io_poll + mai2_io_touch_init + mai2_io_touch_set_sens + mai2_io_touch_update + mai2_io_led_init + mai2_io_led_set_fet_output + mai2_io_led_dc_update + mai2_io_led_gs_update diff --git a/mai2hook/meson.build b/mai2hook/meson.build index eba0c19..ed47793 100644 --- a/mai2hook/meson.build +++ b/mai2hook/meson.build @@ -23,6 +23,8 @@ shared_library( 'dllmain.c', 'io4.c', 'io4.h', + 'touch.c', + 'touch.h', 'mai2-dll.c', 'mai2-dll.h', ], diff --git a/mai2hook/touch.c b/mai2hook/touch.c new file mode 100644 index 0000000..75bbded --- /dev/null +++ b/mai2hook/touch.c @@ -0,0 +1,248 @@ +#include "mai2hook/touch.h" + +static HRESULT read_reg_touch_1p(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L"COM3"); +} + +static HRESULT read_reg_touch_2p(void *bytes, uint32_t *nbytes) +{ + return reg_hook_read_wstr(bytes, nbytes, L"COM4"); +} + +static const struct reg_hook_val touch_reg_key[] = { + { + .name = L"\\Device\\RealTouchBoard0", + .read = read_reg_touch_1p, + .type = REG_SZ, + }, + { + .name = L"\\Device\\RealTouchBoard1", + .read = read_reg_touch_2p, + .type = REG_SZ, + }, +}; + +const char *sensor_map[34] = { + "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", // 0x41 - 0x48 + "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", // 0x49 - 0x50 + "C1", "C2", // 0x51 - 0x52 + "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", // 0x53 - 0x5A + "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8" // 0x5B - 0x62 +}; + +const char *sensor_to_str(uint8_t sensor) +{ + if (sensor < 0x41 || sensor > 0x62) + { + return "Invalid"; + } + + return sensor_map[sensor - 0x41]; +} + +static CRITICAL_SECTION touch_1p_lock; +static struct uart touch_1p_uart; +static uint8_t touch_1p_written_bytes[64]; +static uint8_t touch_1p_readable_bytes[64]; +static bool touch_1p_status = false; + +static CRITICAL_SECTION touch_2p_lock; +static struct uart touch_2p_uart; +static uint8_t touch_2p_written_bytes[64]; +static uint8_t touch_2p_readable_bytes[64]; +static bool touch_2p_status = false; + +HRESULT touch_hook_init(const struct touch_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable_1p && !cfg->enable_2p) + { + return S_FALSE; + } + + HRESULT hr = reg_hook_push_key(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", touch_reg_key, _countof(touch_reg_key)); + + if (FAILED(hr)) + { + return hr; + } + + if (cfg->enable_1p) + { + dprintf("Mai2 touch 1P: Init.\n"); + + InitializeCriticalSection(&touch_1p_lock); + uart_init(&touch_1p_uart, 3); + touch_1p_uart.written.bytes = touch_1p_written_bytes; + touch_1p_uart.written.nbytes = sizeof(touch_1p_written_bytes); + touch_1p_uart.readable.bytes = touch_1p_readable_bytes; + touch_1p_uart.readable.nbytes = sizeof(touch_1p_readable_bytes); + } + + if (cfg->enable_2p) + { + dprintf("Mai2 touch port 2P: Init.\n"); + + InitializeCriticalSection(&touch_2p_lock); + uart_init(&touch_2p_uart, 4); + touch_2p_uart.written.bytes = touch_2p_written_bytes; + touch_2p_uart.written.nbytes = sizeof(touch_2p_written_bytes); + touch_2p_uart.readable.bytes = touch_2p_readable_bytes; + touch_2p_uart.readable.nbytes = sizeof(touch_2p_readable_bytes); + } + + return iohook_push_handler(touch_handle_irp); +} + +static HRESULT touch_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + if (uart_match_irp(&touch_1p_uart, irp)) + { + EnterCriticalSection(&touch_1p_lock); + hr = touch_handle_irp_locked(irp, &touch_1p_uart); + LeaveCriticalSection(&touch_1p_lock); + } + else if (uart_match_irp(&touch_2p_uart, irp)) + { + EnterCriticalSection(&touch_2p_lock); + hr = touch_handle_irp_locked(irp, &touch_2p_uart); + LeaveCriticalSection(&touch_2p_lock); + } + else + { + return iohook_invoke_next(irp); + } + + return hr; +} + +static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart) +{ + HRESULT hr; + + if (irp->op == IRP_OP_OPEN) + { + dprintf("Mai2 touch port %d: Starting backend\n", uart->port_no); + hr = mai2_dll.touch_init(touch_auto_scan); + + if (FAILED(hr)) + { + dprintf("Mai2 touch port %d: Backend error: %x\n", uart->port_no, (int)hr); + return hr; + } + } + + hr = uart_handle_irp(uart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) + { + return hr; + } + +#if defined(LOG_MAI2_TOUCH) + dprintf("Mai2 touch port %d WRITE:\n", uart->port_no); + dump_iobuf(&uart->written); +#endif + uint8_t port_no = uart->port_no; + uint8_t *src = uart->written.bytes; + uint8_t *dest = uart->readable.bytes; + + switch (src[3]) + { + case commandRSET: + dprintf("Mai2 touch port %d: Reset\n", port_no); + break; + + case commandHALT: // Enter Conditioning mode and stop sending touch data. + dprintf("Mai2 touch port %d: Halt\n", port_no); + assert(mai2_dll.touch_update != NULL); + if (port_no == 3) + { + EnterCriticalSection(&touch_1p_lock); + touch_1p_status = false; + mai2_dll.touch_update(touch_1p_status, touch_2p_status); + LeaveCriticalSection(&touch_1p_lock); + } + else + { + EnterCriticalSection(&touch_2p_lock); + touch_2p_status = false; + mai2_dll.touch_update(touch_1p_status, touch_2p_status); + LeaveCriticalSection(&touch_2p_lock); + } + break; + + case commandSTAT: // Exit Conditioning mode and resume sending touch data. + dprintf("Mai2 touch port %d: Stat\n", port_no); + assert(mai2_dll.touch_update != NULL); + if (port_no == 3) + { + EnterCriticalSection(&touch_1p_lock); + touch_1p_status = true; + mai2_dll.touch_update(touch_1p_status, touch_2p_status); + LeaveCriticalSection(&touch_1p_lock); + } + else + { + EnterCriticalSection(&touch_2p_lock); + touch_2p_status = true; + mai2_dll.touch_update(touch_1p_status, touch_2p_status); + LeaveCriticalSection(&touch_2p_lock); + } + break; + + case commandRatio: +#if defined(LOG_MAI2_TOUCH) + dprintf("Mai2 touch side %c: set sensor %s ratio to %d\n", src[1], sensor_to_str(src[2]), src[4]); +#endif + dest[0] = res_start; + dest[1] = src[1]; // L,R + dest[2] = src[2]; // sensor + dest[3] = commandRatio; + dest[4] = src[4]; // Ratio + dest[5] = res_end; + uart->readable.pos = 6; + // The Ratio is fixed at 0x72 and does not need to be sent to mai2io for processing. + break; + + case commandSens: +#if defined(LOG_MAI2_TOUCH) + dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", src[1], sensor_to_str(src[2]), src[4]); +#endif + dest[0] = res_start; + dest[1] = src[1]; // L,R + dest[2] = src[2]; // sensor + dest[3] = commandSens; + dest[4] = src[4]; // Sensitivity + dest[5] = res_end; + uart->readable.pos = 6; + mai2_dll.touch_set_sens(dest); + break; + + default: + dprintf("Mai2 touch port %d: Unknow %02x\n", port_no, src[3]); + break; + } +#if defined(LOG_MAI2_TOUCH) + dprintf("Mai2 touch port %d READ:\n", uart->port_no); + dump_iobuf(&uart->readable); +#endif + uart->written.pos = 0; + + return hr; +} + +static void touch_auto_scan(const uint8_t player, const uint8_t state[7]) +{ + struct uart *touch_uart = player == 1 ? &touch_1p_uart : &touch_2p_uart; + touch_uart->readable.bytes[0] = res_start; + memcpy(&touch_uart->readable.bytes[1], state, 7); + touch_uart->readable.bytes[8] = res_end; + touch_uart->readable.pos = 9; +} \ No newline at end of file diff --git a/mai2hook/touch.h b/mai2hook/touch.h new file mode 100644 index 0000000..e25487e --- /dev/null +++ b/mai2hook/touch.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include + +#include "hooklib/fdshark.h" +#include "hooklib/reg.h" +#include "hooklib/uart.h" +#include "mai2hook/mai2-dll.h" +#include "util/dprintf.h" +#include "util/dump.h" + +struct touch_config +{ + bool enable_1p; + bool enable_2p; +}; + +enum +{ + commandRSET = 0x45, // E + commandHALT = 0x4C, // L + commandSTAT = 0x41, // A + commandRatio = 0x72, // r + commandSens = 0x6B, // k + req_start = 0x7b, // { + req_end = 0x7d, // } + res_start = 0x28, // ( + res_end = 0x29, // ) +}; + +extern const char *sensor_map[34]; +const char *sensor_to_str(uint8_t sensor); + +HRESULT touch_hook_init(const struct touch_config *cfg); +static HRESULT touch_handle_irp(struct irp *irp); +static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart); + +/* Called in mai2io to send touch data. + Similar to chuni slider_res_auto_scan, but the host does not require periodic updates. + Touch data is sent only when there is a change. */ +static void touch_auto_scan(const uint8_t player, const uint8_t state[7]); \ No newline at end of file diff --git a/mai2io/config.c b/mai2io/config.c index 3578338..c6c9913 100644 --- a/mai2io/config.c +++ b/mai2io/config.c @@ -6,6 +6,7 @@ #include #include "mai2io/config.h" +#include "mai2hook/touch.h" /* Maimai DX Default key binding @@ -15,9 +16,24 @@ Maimai DX Default key binding static const int mai2_io_1p_default[] = {'W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q', '3'}; static const int mai2_io_2p_default[] = {0x68, 0x69, 0x66, 0x63, 0x62, 0x61, 0x64, 0x67, 0x54}; +static const int mai2_io_1p_touch_default[] = { + 'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R', + 'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R', + 'G', 'G', + 'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R', + 'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R', +}; +static const int mai2_io_2p_touch_default[] = { + 'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U', + 'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U', + 'K', 'K', + 'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U', + 'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U', +}; + void mai2_io_config_load( - struct mai2_io_config *cfg, - const wchar_t *filename) + struct mai2_io_config *cfg, + const wchar_t *filename) { wchar_t key[16]; int i; @@ -28,22 +44,41 @@ void mai2_io_config_load( cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); + cfg->vk_btn_enable = GetPrivateProfileIntW(L"button", L"enable", 1, filename); - for (i = 0 ; i < 9 ; i++) { - swprintf_s(key, _countof(key), L"1p_btn%i", i + 1); + for (i = 0; i < 9; i++) + { + swprintf_s(key, _countof(key), L"p1Btn%i", i + 1); cfg->vk_1p_btn[i] = GetPrivateProfileIntW( - L"button", - key, - mai2_io_1p_default[i], - filename); + L"button", + key, + mai2_io_1p_default[i], + filename); + + swprintf_s(key, _countof(key), L"p2Btn%i", i + 1); + cfg->vk_2p_btn[i] = GetPrivateProfileIntW( + L"button", + key, + mai2_io_2p_default[i], + filename); } - for (i = 0 ; i < 9 ; i++) { - swprintf_s(key, _countof(key), L"2p_btn%i", i + 1); - cfg->vk_2p_btn[i] = GetPrivateProfileIntW( - L"button", - key, - mai2_io_2p_default[i], - filename); + cfg->debug_input_1p = GetPrivateProfileIntW(L"touch", L"p1DebugInput", 0, filename); + cfg->debug_input_2p = GetPrivateProfileIntW(L"touch", L"p2DebugInput", 0, filename); + for (i = 0; i < 34; i++) + { + swprintf_s(key, _countof(key), L"p1Touch%S", sensor_map[i]); + cfg->vk_1p_touch[i] = GetPrivateProfileIntW( + L"touch", + key, + mai2_io_1p_touch_default[i], + filename); + + swprintf_s(key, _countof(key), L"p2Touch%S", sensor_map[i]); + cfg->vk_2p_touch[i] = GetPrivateProfileIntW( + L"touch", + key, + mai2_io_2p_touch_default[i], + filename); } } diff --git a/mai2io/config.h b/mai2io/config.h index 568b832..ce765ed 100644 --- a/mai2io/config.h +++ b/mai2io/config.h @@ -9,8 +9,13 @@ struct mai2_io_config { uint8_t vk_test; uint8_t vk_service; uint8_t vk_coin; + bool vk_btn_enable; uint8_t vk_1p_btn[9]; uint8_t vk_2p_btn[9]; + bool debug_input_1p; + bool debug_input_2p; + uint8_t vk_1p_touch[34]; + uint8_t vk_2p_touch[34]; }; void mai2_io_config_load( diff --git a/mai2io/mai2io.c b/mai2io/mai2io.c index ffdbfcf..554e8dd 100644 --- a/mai2io/mai2io.c +++ b/mai2io/mai2io.c @@ -1,10 +1,9 @@ -#include - +#include #include -#include #include "mai2io/mai2io.h" #include "mai2io/config.h" +#include "mai2hook/touch.h" #include "util/env.h" static uint8_t mai2_opbtn; @@ -12,10 +11,15 @@ static uint16_t mai2_player1_btn; static uint16_t mai2_player2_btn; static struct mai2_io_config mai2_io_cfg; static bool mai2_io_coin; +mai2_io_touch_callback_t _callback; +static HANDLE mai2_io_touch_1p_thread; +static bool mai2_io_touch_1p_stop_flag; +static HANDLE mai2_io_touch_2p_thread; +static bool mai2_io_touch_2p_stop_flag; uint16_t mai2_io_get_api_version(void) { - return 0x0100; + return 0x0101; } HRESULT mai2_io_init(void) @@ -47,6 +51,10 @@ HRESULT mai2_io_poll(void) } else { mai2_io_coin = false; } + // If sinmai has enabled DebugInput, there is no need to input buttons through hook amdaemon. + if (!mai2_io_cfg.vk_btn_enable) { + return S_OK; + } //Player 1 if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[0])) { @@ -142,3 +150,150 @@ void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) *player2 = mai2_player2_btn; } } + +HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback) +{ + _callback = callback; + return S_OK; +} + +void mai2_io_touch_set_sens(uint8_t *bytes) +{ +#if 0 + dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", bytes[1], sensor_to_str(bytes[2]), bytes[4]); +#endif + return; +} + +void mai2_io_touch_update(bool player1, bool player2) +{ + if (mai2_io_cfg.debug_input_1p) + { + if (player1 && mai2_io_touch_1p_thread == NULL) + { + mai2_io_touch_1p_thread = (HANDLE)_beginthreadex( + NULL, + 0, + mai2_io_touch_1p_thread_proc, + _callback, + 0, + NULL); + } + else if (!player1 && mai2_io_touch_1p_thread != NULL) + { + mai2_io_touch_1p_stop_flag = true; + + WaitForSingleObject(mai2_io_touch_1p_thread, INFINITE); + CloseHandle(mai2_io_touch_1p_thread); + mai2_io_touch_1p_thread = NULL; + + mai2_io_touch_1p_stop_flag = false; + } + } + if (mai2_io_cfg.debug_input_2p) + { + if (player2 && mai2_io_touch_2p_thread == NULL) + { + mai2_io_touch_2p_thread = (HANDLE)_beginthreadex( + NULL, + 0, + mai2_io_touch_2p_thread_proc, + _callback, + 0, + NULL); + } + else if (!player2 && mai2_io_touch_2p_thread != NULL) + { + mai2_io_touch_2p_stop_flag = true; + + WaitForSingleObject(mai2_io_touch_2p_thread, INFINITE); + CloseHandle(mai2_io_touch_2p_thread); + mai2_io_touch_2p_thread = NULL; + + mai2_io_touch_2p_stop_flag = false; + } + } +} + +static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx) +{ + mai2_io_touch_callback_t callback = ctx; + + while (!mai2_io_touch_1p_stop_flag) + { + uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0}; + + for (int i = 0; i < 34; i++) + { + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_touch[i])) + { + int byteIndex = i / 5; + int bitIndex = i % 5; + state[byteIndex] |= (1 << bitIndex); + } + } + callback(1, state); + Sleep(1); + } + return 0; +} + +static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx) +{ + mai2_io_touch_callback_t callback = ctx; + + while (!mai2_io_touch_2p_stop_flag) + { + uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0}; + + for (int i = 0; i < 34; i++) + { + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_touch[i])) + { + int byteIndex = i / 5; + int bitIndex = i % 5; + state[byteIndex] |= (1 << bitIndex); + } + } + callback(2, state); + Sleep(1); + } + return 0; +} + +HRESULT mai2_io_led_init(void) +{ + return S_OK; +} + +void mai2_io_led_set_fet_output(const uint8_t *rgb) +{ +#if 0 + dprintf("mai2 LED: BodyLed brightness: %d%%\n", (rgb[0] * 100) / 255); + dprintf("mai2 LED: ExtLed brightness: %d%%\n", (rgb[1] * 100) / 255); + dprintf("mai2 LED: SideLed brightness: %d%%\n", (rgb[2] * 100) / 255); +#endif + return; +} + +void mai2_io_led_dc_update(const uint8_t *rgb) +{ +#if 0 + for (int i = 0; i < 10; i++) { + dprintf("mai2 LED: LED %d: %02X %02X %02X Speed: %02X\n", + i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + } +#endif + return; +} + +void mai2_io_led_gs_update(const uint8_t *rgb) +{ +#if 0 + for (int i = 0; i < 8; i++) { + dprintf("mai2 LED: LED %d: %02X %02X %02X Speed: %02X\n", + i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + } +#endif + return; +} diff --git a/mai2io/mai2io.h b/mai2io/mai2io.h index 084228c..039094b 100644 --- a/mai2io/mai2io.h +++ b/mai2io/mai2io.h @@ -3,6 +3,7 @@ #include #include +#include enum { MAI2_IO_OPBTN_TEST = 0x01, @@ -66,3 +67,120 @@ void mai2_io_get_opbtns(uint8_t *opbtn); Minimum API version: 0x0100 */ void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2); + +/* Callback function used by mai2_io_touch_1p/2p_thread_proc. + + The 'player'(1 or 2) parameter indicates which player the touch data is for. + + The 'state' represents a complete response packet. + The format of the state array is as follows: + uint8_t state[7] = { + bytes[0] - bit(0 , 0 , 0 , A5, A4, A3, A2, A1) + bytes[1] - bit(0 , 0 , 0 , B2, B1, A8, A7, A6) + bytes[2] - bit(0 , 0 , 0 , B7, B6, B5, B4, B3) + bytes[3] - bit(0 , 0 , 0 , D2, D1, C2, C1, B8) + bytes[4] - bit(0 , 0 , 0 , D7, D6, D5, D4, D3) + bytes[5] - bit(0 , 0 , 0 , E4, E3, E2, E1, D8) + bytes[6] - bit(0 , 0 , 0 , 0 , E8, E7, E6, E5) + } + The 7 bytes are the touch data, with each byte storing the touch state in the lower 5 bits. + A value of 1 indicates that the corresponding touch area is pressed. + The touch areas are ordered from A1 to E8, and the binary values are stored from low to high. */ + +typedef void (*mai2_io_touch_callback_t)(const uint8_t player, const uint8_t state[7]); + +/** + * @brief Initializes the touch input callback function + * + * This function accepts a callback function as a parameter and stores it in the global variable `_callback` + * for later handling of touch input events. + * + * @param callback The touch input callback function that takes two parameters: player number and the touch state array. + * @return HRESULT Returns the result of the operation, S_OK on success. + */ + +HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback); + +/* Send sensitivity setting data to the touch device. + Format: + bytes[0] - Header + bytes[1] - Target device, ASCII characters 'L' or 'R' + bytes[2] - Target touch point + bytes[3] - commandRatio identifier + bytes[4] - Ratio value to be set, within a fixed range + bytes[5] - Footer + + Example function, not actually used. The sensitivity range can be determined + based on the Ratio set within the game. */ + +void mai2_io_touch_set_sens(uint8_t *bytes); + +/** + * @brief Updates the touch input acceptance state + * + * This function determines whether the game is ready to accept touch input based on the states of player 1 and player 2. + * If the game is ready, it creates or stops the corresponding threads to handle touch data for each player. + * Whether or not threads are created for each player is controlled by `mai2_io_cfg.debug_input_1p` and `mai2_io_cfg.debug_input_2p` configuration. + * + * @param player1 If `true`, indicates the game is ready to accept touch data from player 1, `false` means the game is not ready. + * @param player2 If `true`, indicates the game is ready to accept touch data from player 2, `false` means the game is not ready. + */ + +void mai2_io_touch_update(bool player1, bool player2); + +/** + * @brief Player touch input handling thread + * + * This function runs in a separate thread, continuously monitoring player touch status and passing the state data + * to the main thread via a callback function. Each time a touch input is detected, it updates the `state` array and calls the callback. + * The thread stops when `mai2_io_touch_1p/2p_stop_flag` is `true`. + * + * @param ctx The callback function context, of type `mai2_io_touch_callback_t`, used to handle the touch input events. + * @return The thread's return value, typically `0`. + */ + +static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx); + +static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx); + +/* Initialize LED emulation. This function will be called before any + other mai2_io_led_*() function calls. + + All subsequent calls may originate from arbitrary threads and some may + overlap with each other. Ensuring synchronization inside your IO DLL is + your responsibility. + + Minimum API version: 0x0101 */ + +HRESULT mai2_io_led_init(void); + +/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes. + + Set the brightness of the white light on the machine's outer shell. + The program will continuously send changed values to request the blinking effect. + + [0]: BodyLed + [1]: ExtLed + [2]: SideLed + + The LED is truned on when the byte is 255 and turned off when the byte is 0. + + Minimum API version: 0x0101 */ + +void mai2_io_led_set_fet_output(const uint8_t *rgb); + +/* The effect of this command is unknown, it is triggered after LED_15070_CMD_EEPROM_READ. */ + +void mai2_io_led_dc_update(const uint8_t *rgb); + +/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. + + The LEDs are laid out as follows: + [0-7]: 8 button LED + + Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed. + Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest. + + Minimum API version: 0x0101 */ + +void mai2_io_led_gs_update(const uint8_t *rgb); diff --git a/mai2io/meson.build b/mai2io/meson.build index cdbfd35..3d06b9f 100644 --- a/mai2io/meson.build +++ b/mai2io/meson.build @@ -3,6 +3,9 @@ mai2io_lib = static_library( name_prefix : '', include_directories : inc, implicit_include_directories : false, + dependencies : [ + capnhook.get_variable('hook_dep'), + ], sources : [ 'mai2io.c', 'mai2io.h', diff --git a/meson.build b/meson.build index 41b49f4..da9b427 100644 --- a/meson.build +++ b/meson.build @@ -46,6 +46,9 @@ endif if get_option('log_all') or get_option('log_io3') add_project_arguments('-DLOG_IO3', language: 'c') endif +if get_option('log_all') or get_option('log_led15070') + add_project_arguments('-DLOG_LED15070', language: 'c') +endif if get_option('log_all') or get_option('log_led15093') add_project_arguments('-DLOG_LED15093', language: 'c') endif @@ -61,6 +64,9 @@ endif if get_option('log_all') or get_option('log_carol_touch') add_project_arguments('-DLOG_CAROL_TOUCH', language: 'c') endif +if get_option('log_all') or get_option('log_mai2_touch') + add_project_arguments('-DLOG_MAI2_TOUCH', language: 'c') +endif if get_option('log_all') or get_option('log_chuni_slider') add_project_arguments('-DLOG_CHUNI_SLIDER', language: 'c') endif diff --git a/meson_options.txt b/meson_options.txt index fb39b10..de9aefc 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -13,6 +13,11 @@ option('log_io3', value : false, description : 'Enable debug logging for JVS' ) +option('log_led15070', + type : 'boolean', + value : false, + description : 'Enable debug logging for the 15070 LED board emulation' +) option('log_led15093', type : 'boolean', value : false, @@ -38,6 +43,11 @@ option('log_carol_touch', value : false, description : 'Enable debug logging for the Carlo Touchscreen' ) +option('log_mai2_touch', + type : 'boolean', + value : false, + description : 'Enable debug logging for the mai2 TouchPanel' +) option('log_chuni_slider', type : 'boolean', value : false, diff --git a/platform/epay.c b/platform/epay.c index 0faf145..4a231c2 100644 --- a/platform/epay.c +++ b/platform/epay.c @@ -189,7 +189,7 @@ HRESULT epay_hook_init(const struct epay_config *cfg) { thinca_stub->impl1->unk220 = thinca_unk; thinca_stub->impl1->unk228 = thinca_unk; - dprintf("Epay: Init\n"); + dprintf("Epay: Init.\n"); return hr; } From 004a2f6dcdfc9b218718e690df98938350d77508 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Fri, 21 Feb 2025 19:37:54 -0500 Subject: [PATCH 186/204] docs: fix playformID and billingType config docs --- dist/cxb/segatools.ini | 2 +- doc/config/common.md | 38 ++++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 1fe70c8..40589de 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -60,7 +60,7 @@ enable=1 subnet=192.168.150.0 billingCa=../DEVICE/ca.crt billingPub=../DEVICE/billing.pub -billingType=2 +billingType=0 [eeprom] ; See above diff --git a/doc/config/common.md b/doc/config/common.md index 2796ded..a25e353 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -420,18 +420,22 @@ Default: (Varies depending on game) Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This is actually supposed to be a separate three-character `platformId` and -integer `modelType` setting, but they are combined here for convenience. Valid -values include: +integer `modelType` setting, but they are combined here for convenience. -- `AAV0`: Nu 1 (Project DIVA) -- `AAV1`: Nu 1.1 (Chunithm) -- `AAV2`: Nu 2 (Initial D Zero) -- `AAW0`: NuSX 1 -- `AAW1`: NuSX 1.1 -- `ACA0`: ALLS UX -- `ACA1`: ALLS HX -- `ACA2`: ALLS UX (without dedicated GPU) -- `ACA4`: ALLS MX +`platformId` is one of the following: +- `AAV`: Nu 1/1.1/2 +- `AAW`: NuSX 1/1.1 +- `ACA`: ALLS UX/HX/MX + +`modelType` is one of the following: +- `1`: Server (SV) +- `2`: Satalite (ST) +- `3`: Live (LV) +- `4`: Terminal (TN) + +It's safe to assume that every game you'll be playing with these tools will be a Satalite. +Some games care, others don't. Some even change how they run based on this value (Wonderland Wars +will boot into terminal mode if `modelType` is 4). ### `region` @@ -468,15 +472,9 @@ the billing transactions. Default: `1` -Set the billing "type" for the keychip. The type determins what kind of revenue share, -if any, the game maker has with SEGA. Some games may be picky and require types other -then 1 (ex. crossbeats REV. requires billing type 2), so this option is provided if this -is an issue. Billing types are: - -- 0: No billing? -- 1: Billing type A -- 2: Billing type B1 -- 3: Billing type B2 +Sets the billing type, a single bit value that flags the cabinet as a rental if set to `1`, or `0` otherwise. +Certian games that were only sold officially as full purchases (that is, non-rentals) must have this value set to 0. +NOTE: Crossbeats erroniously displays Billing modes A/B1/B2, but this value comes from the `modelType` and NOT this value! ### `systemFlag` From efe01d92a65a4f63fdc7975121e389c896653298 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:49:22 +0000 Subject: [PATCH 187/204] Fix MSVC build again, add support for standalone MSVC compiler (#59) After switching away from VS, I realized the buildscript wouldn't detect the standalone MSVC compiler, because for whatever genius reason, MS installs that in the x86 program files directory... Also fixes some duplicate definitions and a missing library that MSVC doesn't like ah compilers... Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/59 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> --- .gitignore | 3 +++ amex/gpio.c | 1 - hooklib/meson.build | 1 + meson.build | 1 + msvc-build.bat | 9 ++++----- platform/system.c | 1 - unityhook/doorstop.c | 1 + 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index d42760f..f5d9008 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ subprojects/capnhook # For enabling debug logging on local builds MesonLocalOptions.mk + +# Some meson cache thing +.meson-subproject-wrap-hash.txt diff --git a/amex/gpio.c b/amex/gpio.c index 86eadad..5d6ead1 100644 --- a/amex/gpio.c +++ b/amex/gpio.c @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/hooklib/meson.build b/hooklib/meson.build index 7d5e7b8..e6908d6 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -4,6 +4,7 @@ hooklib_lib = static_library( implicit_include_directories : false, dependencies : [ capnhook.get_variable('hook_dep'), + Ws2_32_lib ], sources : [ 'cursor.c', diff --git a/meson.build b/meson.build index 41b49f4..40a99c4 100644 --- a/meson.build +++ b/meson.build @@ -83,6 +83,7 @@ dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') pathcch_lib = cc.find_library('pathcch') imagehlp_lib = cc.find_library('imagehlp') +Ws2_32_lib = cc.find_library('Ws2_32') inc = include_directories('.') capnhook = subproject('capnhook') diff --git a/msvc-build.bat b/msvc-build.bat index ae060f0..fac3925 100644 --- a/msvc-build.bat +++ b/msvc-build.bat @@ -52,17 +52,16 @@ exit /b rem This should works for Visual Studio 2017+ :detect-visual-studio ( - rem Who the hell on earth is still using a 32bit Windows in 2024 - if "%ProgramFiles(x86)%"=="" ( - set VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" - ) else ( + rem Fall back to x86 program directory for MSVC standalone if it can't be found in x64, because even though it's x64 compilers, they install in x86 program files for whatever dumb reason + set VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" + if not exist %VSWHERE% ( set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" ) if exist %VSWHERE% ( REM get vcvarsall by using vswhere set VSVARSALL="" - for /f "tokens=* usebackq" %%i in (`%VSWHERE% -find VC\Auxiliary\Build\vcvarsall.bat`) do set VSVARSALL="%%i" + for /f "tokens=* usebackq" %%i in (`%VSWHERE% -products * -find VC\Auxiliary\Build\vcvarsall.bat`) do set VSVARSALL="%%i" ) else ( REM fallback to old method set VSVARSALL="%VS_INSTALLATION%\VC\Auxiliary\Build\vcvarsall.bat" diff --git a/platform/system.c b/platform/system.c index a82c326..dbc832f 100644 --- a/platform/system.c +++ b/platform/system.c @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index d2cbd5c..04dee02 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -5,6 +5,7 @@ // https://github.com/NeighTools/UnityDoorstop #include #include +#include #include #include From 4cb76dd1ee8682a517cf210624b4971bb47c1fda Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 2 Mar 2025 00:01:45 +0100 Subject: [PATCH 188/204] mai2: update all LED boards to use two boards --- board/led15070.c | 30 +++++---- board/led15070.h | 11 ++-- board/led15093.c | 63 +++++++------------ board/led15093.h | 4 +- chunihook/config.c | 3 +- chunihook/dllmain.c | 3 +- chuniio/chuniio.c | 16 ++++- chusanhook/config.c | 3 +- chusanhook/dllmain.c | 49 ++++++++------- dist/mai2/segatools.ini | 14 +++-- fgohook/config.c | 3 +- fgohook/dllmain.c | 3 +- idachook/config.c | 3 +- idachook/dllmain.c | 3 +- idachook/idac-dll.h | 6 +- idachook/io4.c | 2 +- idacio/dllmain.c | 6 +- idacio/idacio.h | 6 +- idzhook/config.c | 3 +- idzhook/dllmain.c | 3 +- idzhook/idz-dll.h | 6 +- idzhook/jvs.c | 2 +- idzio/dllmain.c | 6 +- idzio/idzio.h | 6 +- kemonohook/config.c | 3 +- kemonohook/dllmain.c | 55 ++++++++-------- mai2hook/config.c | 3 +- mai2hook/dllmain.c | 3 +- mai2hook/mai2-dll.h | 6 +- mai2hook/touch.c | 15 ++++- mai2hook/touch.h | 11 +--- mai2io/mai2io.c | 136 +++++++++++++++------------------------- mai2io/mai2io.h | 14 +++-- mu3hook/config.c | 3 +- mu3hook/dllmain.c | 3 +- swdchook/config.c | 3 +- swdchook/dllmain.c | 3 +- swdchook/io4.c | 2 +- swdchook/swdc-dll.h | 6 +- swdcio/dllmain.c | 6 +- swdcio/swdcio.h | 6 +- tokyohook/config.c | 3 +- tokyohook/dllmain.c | 3 +- 43 files changed, 273 insertions(+), 265 deletions(-) diff --git a/board/led15070.c b/board/led15070.c index 579de7c..43a015d 100644 --- a/board/led15070.c +++ b/board/led15070.c @@ -103,19 +103,30 @@ HRESULT led15070_hook_init( io_led_set_fet_output_t _led_set_fet_output, io_led_dc_update_t _led_dc_update, io_led_gs_update_t _led_gs_update, - unsigned int first_port, - unsigned int num_boards) + unsigned int port_no[2]) { + unsigned int num_boards = 0; + assert(cfg != NULL); + assert(_led_init != NULL); if (!cfg->enable) { return S_FALSE; } - if (cfg->port_no != 0) { - first_port = cfg->port_no; + for (int i = 0; i < led15070_nboards; i++) + { + if (cfg->port_no[i] != 0) { + port_no[i] = cfg->port_no[i]; + } + + if (port_no[i] != 0) { + num_boards++; + } } + assert(num_boards != 0); + led_init = _led_init; led_set_fet_output = _led_set_fet_output; led_dc_update = _led_dc_update; @@ -131,10 +142,7 @@ HRESULT led15070_hook_init( InitializeCriticalSection(&v->lock); - // TODO: IMPROVE! - first_port = i == 1 ? first_port + 2 : first_port; - - uart_init(&v->boarduart, first_port); + uart_init(&v->boarduart, port_no[i]); v->boarduart.baud.BaudRate = 115200; v->boarduart.written.bytes = v->written_bytes; v->boarduart.written.nbytes = sizeof(v->written_bytes); @@ -681,7 +689,7 @@ static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_ led15070_per_board_vars[board].fet[2] = req->payload[2]; // B or FET2 intensity if (led_set_fet_output) - led_set_fet_output((const uint8_t*)led15070_per_board_vars[board].fet); + led_set_fet_output(board, (const uint8_t*)led15070_per_board_vars[board].fet); if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -737,7 +745,7 @@ static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any * #endif if (led_dc_update) - led_dc_update((const uint8_t*)led15070_per_board_vars[board].dc); + led_dc_update(board, (const uint8_t*)led15070_per_board_vars[board].dc); if (!led15070_per_board_vars[board].enable_response) return S_OK; @@ -764,7 +772,7 @@ static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any * #endif if (led_gs_update) - led_gs_update((const uint8_t*)led15070_per_board_vars[board].gs); + led_gs_update(board, (const uint8_t*)led15070_per_board_vars[board].gs); if (!led15070_per_board_vars[board].enable_response) return S_OK; diff --git a/board/led15070.h b/board/led15070.h index a2ad863..ae237b4 100644 --- a/board/led15070.h +++ b/board/led15070.h @@ -7,7 +7,7 @@ struct led15070_config { bool enable; - unsigned int port_no; + unsigned int port_no[2]; char board_number[8]; uint8_t fw_ver; uint16_t fw_sum; @@ -15,9 +15,9 @@ struct led15070_config { }; typedef HRESULT (*io_led_init_t)(void); -typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb); -typedef void (*io_led_dc_update_t)(const uint8_t *rgb); -typedef void (*io_led_gs_update_t)(const uint8_t *rgb); +typedef void (*io_led_set_fet_output_t)(uint8_t board, const uint8_t *rgb); +typedef void (*io_led_dc_update_t)(uint8_t board, const uint8_t *rgb); +typedef void (*io_led_gs_update_t)(uint8_t board, const uint8_t *rgb); HRESULT led15070_hook_init( const struct led15070_config *cfg, @@ -25,5 +25,4 @@ HRESULT led15070_hook_init( io_led_set_fet_output_t _led_set_fet_output, io_led_dc_update_t _led_dc_update, io_led_gs_update_t _led_gs_update, - unsigned int first_port, - unsigned int num_boards); + unsigned int port_no[2]); diff --git a/board/led15093.c b/board/led15093.c index a070a24..31ccb4e 100644 --- a/board/led15093.c +++ b/board/led15093.c @@ -107,9 +107,13 @@ static uint8_t led15093_host_adr = 1; static io_led_init_t led_init; static io_led_set_leds_t set_leds; -HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, - io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) +HRESULT led15093_hook_init( + const struct led15093_config *cfg, + io_led_init_t _led_init, + io_led_set_leds_t _set_leds, + unsigned int port_no[2]) { + unsigned int num_boards = 0; assert(cfg != NULL); assert(_led_init != NULL); @@ -119,14 +123,24 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led return S_FALSE; } - if (cfg->port_no != 0) { - first_port = cfg->port_no; + for (int i = 0; i < led15093_nboards; i++) + { + if (cfg->port_no[i] != 0) { + port_no[i] = cfg->port_no[i]; + } + + if (port_no[i] != 0) { + num_boards++; + } } + assert(num_boards != 0); + + led15093_board_adr = num_boards; + led15093_host_adr = num_boards == 2 ? 1 : 2; + led_init = _led_init; set_leds = _set_leds; - led15093_board_adr = board_adr; - led15093_host_adr = host_adr; memcpy(led15093_board_num, cfg->board_number, sizeof(led15093_board_num)); memcpy(led15093_chip_num, cfg->chip_number, sizeof(led15093_chip_num)); @@ -140,7 +154,7 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led InitializeCriticalSection(&vb->lock); - uart_init(&vb->boarduart, first_port + i); + uart_init(&vb->boarduart, port_no[i]); if (cfg->high_baudrate) { vb->boarduart.baud.BaudRate = 460800; } else { @@ -209,7 +223,6 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) _led15093_per_board_vars *v = &led15093_per_board_vars[board]; struct uart *boarduart = &led15093_per_board_vars[board].boarduart; - /* if (irp->op == IRP_OP_OPEN) { // Unfortunately the LED board UART gets opened and closed repeatedly @@ -236,30 +249,6 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) } } } - */ - - if (irp->op == IRP_OP_OPEN) { - dprintf("LED 15093: Starting backend DLL\n"); - // int res = led_init(); - hr = led_init(); - - /* - if (res != 0) { - dprintf("LED 15093: Backend error, LED board disconnected: " - "%d\n", - res); - - return E_FAIL; - } - */ - if (FAILED(hr)) { - dprintf("LED 15093: Backend error, LED board disconnected: " - "%x\n", - (int) hr); - - return hr; - } - } hr = uart_handle_irp(boarduart, irp); @@ -688,16 +677,6 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set return E_INVALIDARG; } - /* - if (board == 0) { - dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0x96], req->data[0x97], req->data[0x98]); - } - else if (board == 1) - { - dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0xb4], req->data[0xb5], req->data[0xb6]); - } - */ - // Return the current LED data, remove const qualifier set_leds(board, (uint8_t *) req->data); diff --git a/board/led15093.h b/board/led15093.h index 869a11b..5ff930b 100644 --- a/board/led15093.h +++ b/board/led15093.h @@ -8,7 +8,7 @@ struct led15093_config { bool enable; bool high_baudrate; - unsigned int port_no; + unsigned int port_no[2]; char board_number[8]; char chip_number[5]; char boot_chip_number[5]; @@ -20,5 +20,5 @@ typedef HRESULT (*io_led_init_t)(void); typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb); HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init, - io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr); + io_led_set_leds_t _set_leds, unsigned int port_no[2]); diff --git a/chunihook/config.c b/chunihook/config.c index 2ad959e..d711fec 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -56,7 +56,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = 0; + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index d421e23..a3fa8ab 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -114,8 +114,9 @@ static DWORD CALLBACK chuni_pre_startup(void) { dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n"); } else { + unsigned int led_port_no[2] = {10, 11}; hr = led15093_hook_init(&chuni_hook_cfg.led15093, - chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1); + chuni_dll.led_init, chuni_dll.led_set_leds, led_port_no); if (FAILED(hr)) { goto fail; diff --git a/chuniio/chuniio.c b/chuniio/chuniio.c index 614dc47..a2c0336 100644 --- a/chuniio/chuniio.c +++ b/chuniio/chuniio.c @@ -174,6 +174,20 @@ HRESULT chuni_io_led_init(void) } void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb) -{ +{ +#if 0 + if (board == 0) { + dprintf("CHUNI LED: Left Air 1: red: %d, green: %d, blue: %d\n", rgb[0x96], rgb[0x97], rgb[0x98]); + dprintf("CHUNI LED: Left Air 2: red: %d, green: %d, blue: %d\n", rgb[0x99], rgb[0x9A], rgb[0x9B]); + dprintf("CHUNI LED: Left Air 3: red: %d, green: %d, blue: %d\n", rgb[0x9C], rgb[0x9D], rgb[0x9E]); + } + else if (board == 1) + { + dprintf("CHUNI LED: Right Air 1: red: %d, green: %d, blue: %d\n", rgb[0xB4], rgb[0xB5], rgb[0xB6]); + dprintf("CHUNI LED: Right Air 2: red: %d, green: %d, blue: %d\n", rgb[0xB7], rgb[0xB8], rgb[0xB9]); + dprintf("CHUNI LED: Right Air 3: red: %d, green: %d, blue: %d\n", rgb[0xBA], rgb[0xBB], rgb[0xBC]); + } +#endif + led_output_update(board, rgb); } diff --git a/chusanhook/config.c b/chusanhook/config.c index 0ec8c61..691e8f7 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -96,7 +96,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = 0; + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 9a2f5da..e29bf7f 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -22,32 +22,23 @@ COM4: 837-15396 "Gen 3" Aime Reader */ -#include - #include #include +#include #include "amex/amex.h" - #include "board/sg-reader.h" #include "board/vfd.h" - +#include "chuniio/chuniio.h" #include "chusanhook/config.h" #include "chusanhook/io4.h" #include "chusanhook/slider.h" - -#include "chuniio/chuniio.h" - -#include "hook/process.h" - #include "gfxhook/d3d9.h" #include "gfxhook/gfx.h" - +#include "hook/process.h" #include "hooklib/serial.h" #include "hooklib/spike.h" - #include "platform/platform.h" - #include "util/dprintf.h" #include "util/env.h" @@ -55,8 +46,7 @@ static HMODULE chusan_hook_mod; static process_entry_t chusan_startup; static struct chusan_hook_config chusan_hook_cfg; -static DWORD CALLBACK chusan_pre_startup(void) -{ +static DWORD CALLBACK chusan_pre_startup(void) { HMODULE d3dc; HMODULE dbghelp; HRESULT hr; @@ -88,7 +78,7 @@ static DWORD CALLBACK chusan_pre_startup(void) chusan_hook_config_load(&chusan_hook_cfg, get_config_path()); /* Hook Win32 APIs */ - + dvd_hook_init(&chusan_hook_cfg.dvd, chusan_hook_mod); gfx_hook_init(&chusan_hook_cfg.gfx); gfx_d3d9_hook_init(&chusan_hook_cfg.gfx, chusan_hook_mod); @@ -154,19 +144,31 @@ static DWORD CALLBACK chusan_pre_startup(void) } } - if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL ) - { - dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n"); + unsigned int led_port_no[2]; + + if (is_cvt) { + led_port_no[0] = 2; + led_port_no[1] = 3; } else { - hr = led15093_hook_init(&chusan_hook_cfg.led15093, - chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1); + led_port_no[0] = 20; + led_port_no[1] = 21; + } + + if (chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL) { + dprintf( + "IO DLL doesn't support led_init/led_set_leds, cannot start " + "LED15093 hook\n"); + } else { + hr = led15093_hook_init(&chusan_hook_cfg.led15093, chuni_dll.led_init, + chuni_dll.led_set_leds, led_port_no); if (FAILED(hr)) { goto fail; } } - hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod); + hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2 : 3, + chusan_hook_mod); if (FAILED(hr)) { goto fail; @@ -186,8 +188,7 @@ fail: ExitProcess(EXIT_FAILURE); } -BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) -{ +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) { HRESULT hr; if (cause != DLL_PROCESS_ATTACH) { @@ -199,7 +200,7 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) hr = process_hijack_startup(chusan_pre_startup, &chusan_startup); if (!SUCCEEDED(hr)) { - dprintf("Failed to hijack process startup: %x\n", (int) hr); + dprintf("Failed to hijack process startup: %x\n", (int)hr); } return SUCCEEDED(hr); diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index 46fb4e5..dde853f 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -69,6 +69,15 @@ freeplay=0 ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 +; ----------------------------------------------------------------------------- +; LED settings +; ----------------------------------------------------------------------------- + +[led15070] +; Enable emulation of the 837-15070-04 controlled lights, which handle the +; cabinet and button LEDs. +enable=1 + ; ----------------------------------------------------------------------------- ; Misc. hook settings ; ----------------------------------------------------------------------------- @@ -145,8 +154,3 @@ p2Enable=1 ;p1TouchA2=0x53 ; ... etc ... ;p1TouchE8=0x53 - -[led15070] -; Enable emulation of the 837-15070-02 controlled lights, which handle the -; cabinet and seat LEDs. -enable=1 \ No newline at end of file diff --git a/fgohook/config.c b/fgohook/config.c index 30dbf86..766240c 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -48,7 +48,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index e82423f..a65cbcd 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -133,8 +133,9 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } + unsigned int led_port_no[2] = {17, 0}; hr = led15093_hook_init(&fgo_hook_cfg.led15093, - fgo_dll.led_init, fgo_dll.led_set_leds, 17, 1, 1, 2); + fgo_dll.led_init, fgo_dll.led_set_leds, led_port_no); if (FAILED(hr)) { goto fail; diff --git a/idachook/config.c b/idachook/config.c index 279aba7..0e8dc88 100644 --- a/idachook/config.c +++ b/idachook/config.c @@ -23,7 +23,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) wchar_t tmpstr[16]; cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); /* TODO: Unknown, no firmware file available */ cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename); diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 0e955e8..71a4ccd 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -94,8 +94,9 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } + unsigned int led_port_no[2] = {2, 0}; hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init, - idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1); + idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, led_port_no); if (FAILED(hr)) { goto fail; diff --git a/idachook/idac-dll.h b/idachook/idac-dll.h index 88ac299..92aa664 100644 --- a/idachook/idac-dll.h +++ b/idachook/idac-dll.h @@ -12,9 +12,9 @@ struct idac_dll { void (*get_shifter)(uint8_t *gear); void (*get_analogs)(struct idac_io_analog_state *out); HRESULT (*led_init)(void); - void (*led_set_fet_output)(const uint8_t *rgb); - void (*led_gs_update)(const uint8_t *rgb); - void (*led_set_leds)(const uint8_t *rgb); + void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb); + void (*led_gs_update)(uint8_t board, const uint8_t *rgb); + void (*led_set_leds)(uint8_t board, const uint8_t *rgb); HRESULT (*ffb_init)(void); void (*ffb_toggle)(bool active); void (*ffb_constant_force)(uint8_t direction, uint8_t force); diff --git a/idachook/io4.c b/idachook/io4.c index 1e4d990..3861ef8 100644 --- a/idachook/io4.c +++ b/idachook/io4.c @@ -159,7 +159,7 @@ static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00, }; - idac_dll.led_set_leds(rgb_out); + idac_dll.led_set_leds(0, rgb_out); return S_OK; } diff --git a/idacio/dllmain.c b/idacio/dllmain.c index 6a5dba8..fe8246e 100644 --- a/idacio/dllmain.c +++ b/idacio/dllmain.c @@ -127,7 +127,7 @@ HRESULT idac_io_led_init(void) return S_OK; } -void idac_io_led_set_fet_output(const uint8_t *rgb) +void idac_io_led_set_fet_output(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]); @@ -137,7 +137,7 @@ void idac_io_led_set_fet_output(const uint8_t *rgb) return; } -void idac_io_led_gs_update(const uint8_t *rgb) +void idac_io_led_gs_update(uint8_t board, const uint8_t *rgb) { #if 0 for (int i = 0; i < 9; i++) { @@ -149,7 +149,7 @@ void idac_io_led_gs_update(const uint8_t *rgb) return; } -void idac_io_led_set_leds(const uint8_t *rgb) +void idac_io_led_set_leds(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("IDAC LED: START: %02X\n", rgb[0]); diff --git a/idacio/idacio.h b/idacio/idacio.h index 513c9d1..bc58a34 100644 --- a/idacio/idacio.h +++ b/idacio/idacio.h @@ -127,7 +127,7 @@ HRESULT idac_io_led_init(void); Minimum API version: 0x0101 */ -void idac_io_led_set_fet_output(const uint8_t *rgb); +void idac_io_led_set_fet_output(uint8_t board, const uint8_t *rgb); /* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. @@ -144,7 +144,7 @@ void idac_io_led_set_fet_output(const uint8_t *rgb); Minimum API version: 0x0101 */ -void idac_io_led_gs_update(const uint8_t *rgb); +void idac_io_led_gs_update(uint8_t board, const uint8_t *rgb); /* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. @@ -160,7 +160,7 @@ void idac_io_led_gs_update(const uint8_t *rgb); Minimum API version: 0x0101 */ -void idac_io_led_set_leds(const uint8_t *rgb); +void idac_io_led_set_leds(uint8_t board, const uint8_t *rgb); /* Initialize FFB emulation. This function will be called before any other idac_io_ffb_*() function calls. diff --git a/idzhook/config.c b/idzhook/config.c index 0378cbe..6bbc0ed 100644 --- a/idzhook/config.c +++ b/idzhook/config.c @@ -27,7 +27,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) wchar_t tmpstr[16]; cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); /* TODO: Unknown, no firmware file available */ cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename); diff --git a/idzhook/dllmain.c b/idzhook/dllmain.c index edf6cbb..534f4d0 100644 --- a/idzhook/dllmain.c +++ b/idzhook/dllmain.c @@ -128,8 +128,9 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } + unsigned int led_port_no[2] = {11, 0}; hr = led15070_hook_init(&idz_hook_cfg.led15070, idz_dll.led_init, - idz_dll.led_set_fet_output, NULL, idz_dll.led_gs_update, 11, 1); + idz_dll.led_set_fet_output, NULL, idz_dll.led_gs_update, led_port_no); if (FAILED(hr)) { goto fail; diff --git a/idzhook/idz-dll.h b/idzhook/idz-dll.h index e827f8e..4084d84 100644 --- a/idzhook/idz-dll.h +++ b/idzhook/idz-dll.h @@ -12,9 +12,9 @@ struct idz_dll { void (*jvs_read_shifter)(uint8_t *gear); void (*jvs_read_coin_counter)(uint16_t *total); HRESULT (*led_init)(void); - void (*led_set_fet_output)(const uint8_t *rgb); - void (*led_gs_update)(const uint8_t *rgb); - void (*led_set_leds)(const uint8_t *rgb); + void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb); + void (*led_gs_update)(uint8_t board, const uint8_t *rgb); + void (*led_set_leds)(uint8_t board, const uint8_t *rgb); HRESULT (*ffb_init)(void); void (*ffb_toggle)(bool active); void (*ffb_constant_force)(uint8_t direction, uint8_t force); diff --git a/idzhook/jvs.c b/idzhook/jvs.c index 3531d55..2ded71c 100644 --- a/idzhook/jvs.c +++ b/idzhook/jvs.c @@ -192,5 +192,5 @@ static void idz_jvs_write_gpio(void *ctx, uint32_t state) state & IDZ_IO_LED_LEFT ? 0xFF : 0x00, }; - idz_dll.led_set_leds(rgb_out); + idz_dll.led_set_leds(0, rgb_out); } diff --git a/idzio/dllmain.c b/idzio/dllmain.c index 39d08fc..322d194 100644 --- a/idzio/dllmain.c +++ b/idzio/dllmain.c @@ -130,7 +130,7 @@ HRESULT idz_io_led_init(void) return S_OK; } -void idz_io_led_set_fet_output(const uint8_t *rgb) +void idz_io_led_set_fet_output(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("IDZ LED: LEFT SEAT LED: %02X\n", rgb[0]); @@ -140,7 +140,7 @@ void idz_io_led_set_fet_output(const uint8_t *rgb) return; } -void idz_io_led_gs_update(const uint8_t *rgb) +void idz_io_led_gs_update(uint8_t board, const uint8_t *rgb) { #if 0 for (int i = 0; i < 9; i++) { @@ -152,7 +152,7 @@ void idz_io_led_gs_update(const uint8_t *rgb) return; } -void idz_io_led_set_leds(const uint8_t *rgb) +void idz_io_led_set_leds(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("IDZ LED: START: %02X\n", rgb[0]); diff --git a/idzio/idzio.h b/idzio/idzio.h index 8fd01d8..db64c44 100644 --- a/idzio/idzio.h +++ b/idzio/idzio.h @@ -138,7 +138,7 @@ HRESULT idz_io_led_init(void); Minimum API version: 0x0101 */ -void idz_io_led_set_fet_output(const uint8_t *rgb); +void idz_io_led_set_fet_output(uint8_t board, const uint8_t *rgb); /* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. @@ -155,7 +155,7 @@ void idz_io_led_set_fet_output(const uint8_t *rgb); Minimum API version: 0x0101 */ -void idz_io_led_gs_update(const uint8_t *rgb); +void idz_io_led_gs_update(uint8_t board, const uint8_t *rgb); /* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. @@ -171,7 +171,7 @@ void idz_io_led_gs_update(const uint8_t *rgb); Minimum API version: 0x0101 */ -void idz_io_led_set_leds(const uint8_t *rgb); +void idz_io_led_set_leds(uint8_t board, const uint8_t *rgb); /* Initialize FFB emulation. This function will be called before any other idz_io_ffb_*() function calls. diff --git a/kemonohook/config.c b/kemonohook/config.c index ec00aa1..c008d88 100644 --- a/kemonohook/config.c +++ b/kemonohook/config.c @@ -65,7 +65,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 1, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); diff --git a/kemonohook/dllmain.c b/kemonohook/dllmain.c index 83a4290..3373489 100644 --- a/kemonohook/dllmain.c +++ b/kemonohook/dllmain.c @@ -1,28 +1,21 @@ -#include - #include +#include #include "board/io4.h" #include "board/sg-reader.h" #include "board/vfd.h" - +#include "hook/iohook.h" #include "hook/process.h" #include "hook/table.h" -#include "hook/iohook.h" - #include "hooklib/printer.h" #include "hooklib/serial.h" #include "hooklib/spike.h" - #include "kemonohook/config.h" #include "kemonohook/hooks.h" #include "kemonohook/jvs.h" #include "kemonohook/kemono-dll.h" - #include "platform/platform.h" - #include "unityhook/hook.h" - #include "util/dprintf.h" #include "util/env.h" @@ -47,29 +40,38 @@ static DWORD CALLBACK kemono_pre_startup(void) { // 2.02 does not call printer update functions uint16_t ret; - fwdlusb_updateFirmware_main(1, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223100-014E-C300-MAINAPP.BIN", &ret); - if (ret != 0){ + fwdlusb_updateFirmware_main( + 1, + "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223100-014E-C300-" + "MAINAPP.BIN", + &ret); + if (ret != 0) { goto fail; } - fwdlusb_updateFirmware_dsp(2, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223200-0101-C300-DSPAPP.BIN", &ret); - if (ret != 0){ + fwdlusb_updateFirmware_dsp( + 2, + "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223200-0101-C300-" + "DSPAPP.BIN", + &ret); + if (ret != 0) { goto fail; } - fwdlusb_updateFirmware_param(3, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\D0460700-0101-C300-PARAM.BIN", &ret); - if (ret != 0){ + fwdlusb_updateFirmware_param( + 3, + "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\D0460700-0101-C300-" + "PARAM.BIN", + &ret); + if (ret != 0) { goto fail; } printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod); - printer_set_dimensions(720, 1028); // printer doesn't call setimageformat + printer_set_dimensions(720, 1028); // printer doesn't call setimageformat /* Initialize emulation hooks */ - hr = platform_hook_init( - &kemono_hook_cfg.platform, - "SDFL", - "AAW1", - kemono_hook_mod); + hr = platform_hook_init(&kemono_hook_cfg.platform, "SDFL", "AAW1", + kemono_hook_mod); if (FAILED(hr)) { goto fail; @@ -93,7 +95,9 @@ static DWORD CALLBACK kemono_pre_startup(void) { goto fail; } - hr = led15093_hook_init(&kemono_hook_cfg.led15093, kemono_dll.led_init, kemono_dll.led_set_leds, 10, 1, 1, 2); + unsigned int led_port_no[2] = {10, 0}; + hr = led15093_hook_init(&kemono_hook_cfg.led15093, kemono_dll.led_init, + kemono_dll.led_set_leds, led_port_no); if (FAILED(hr)) { goto fail; @@ -106,7 +110,8 @@ static DWORD CALLBACK kemono_pre_startup(void) { There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `kemonohook` initialization. */ - unity_hook_init(&kemono_hook_cfg.unity, kemono_hook_mod, kemono_extra_hooks_load); + unity_hook_init(&kemono_hook_cfg.unity, kemono_hook_mod, + kemono_extra_hooks_load); /* Initialize debug helpers */ @@ -118,7 +123,7 @@ static DWORD CALLBACK kemono_pre_startup(void) { return kemono_startup(); - fail: +fail: ExitProcess(EXIT_FAILURE); } @@ -134,7 +139,7 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) { hr = process_hijack_startup(kemono_pre_startup, &kemono_startup); if (!SUCCEEDED(hr)) { - dprintf("Failed to hijack process startup: %x\n", (int) hr); + dprintf("Failed to hijack process startup: %x\n", (int)hr); } return SUCCEEDED(hr); diff --git a/mai2hook/config.c b/mai2hook/config.c index 48c0c6e..5435ada 100644 --- a/mai2hook/config.c +++ b/mai2hook/config.c @@ -46,7 +46,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) wchar_t tmpstr[16]; cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x00, filename); diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index ac0e3a1..cb8a240 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -93,12 +93,13 @@ static DWORD CALLBACK mai2_pre_startup(void) } // LED board uses COM21 and COM23 + unsigned int led_port_no[2] = {21, 23}; hr = led15070_hook_init(&mai2_hook_cfg.led15070, mai2_dll.led_init, mai2_dll.led_set_fet_output, mai2_dll.led_dc_update, mai2_dll.led_gs_update, - 21, 2); + led_port_no); if (FAILED(hr)) { goto fail; diff --git a/mai2hook/mai2-dll.h b/mai2hook/mai2-dll.h index 6c205c8..599d44a 100644 --- a/mai2hook/mai2-dll.h +++ b/mai2hook/mai2-dll.h @@ -14,9 +14,9 @@ struct mai2_dll { void (*touch_set_sens)(uint8_t *bytes); void (*touch_update)(bool player1, bool player2); HRESULT (*led_init)(void); - void (*led_set_fet_output)(const uint8_t *rgb); - void (*led_dc_update)(const uint8_t *rgb); - void (*led_gs_update)(const uint8_t *rgb); + void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb); + void (*led_dc_update)(uint8_t board, const uint8_t *rgb); + void (*led_gs_update)(uint8_t board, const uint8_t *rgb); }; struct mai2_dll_config { diff --git a/mai2hook/touch.c b/mai2hook/touch.c index 75bbded..305d005 100644 --- a/mai2hook/touch.c +++ b/mai2hook/touch.c @@ -1,5 +1,16 @@ +#include +#include + +#include "hooklib/fdshark.h" +#include "hooklib/reg.h" + +#include "mai2hook/mai2-dll.h" #include "mai2hook/touch.h" +#include "util/dprintf.h" +#include "util/dump.h" + + static HRESULT read_reg_touch_1p(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, L"COM3"); @@ -83,7 +94,7 @@ HRESULT touch_hook_init(const struct touch_config *cfg) if (cfg->enable_2p) { - dprintf("Mai2 touch port 2P: Init.\n"); + dprintf("Mai2 touch 2P: Init.\n"); InitializeCriticalSection(&touch_2p_lock); uart_init(&touch_2p_uart, 4); @@ -245,4 +256,4 @@ static void touch_auto_scan(const uint8_t player, const uint8_t state[7]) memcpy(&touch_uart->readable.bytes[1], state, 7); touch_uart->readable.bytes[8] = res_end; touch_uart->readable.pos = 9; -} \ No newline at end of file +} diff --git a/mai2hook/touch.h b/mai2hook/touch.h index e25487e..f6fc72a 100644 --- a/mai2hook/touch.h +++ b/mai2hook/touch.h @@ -1,15 +1,10 @@ #pragma once -#include + +#include #include #include -#include -#include "hooklib/fdshark.h" -#include "hooklib/reg.h" #include "hooklib/uart.h" -#include "mai2hook/mai2-dll.h" -#include "util/dprintf.h" -#include "util/dump.h" struct touch_config { @@ -40,4 +35,4 @@ static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart); /* Called in mai2io to send touch data. Similar to chuni slider_res_auto_scan, but the host does not require periodic updates. Touch data is sent only when there is a change. */ -static void touch_auto_scan(const uint8_t player, const uint8_t state[7]); \ No newline at end of file +static void touch_auto_scan(const uint8_t player, const uint8_t state[7]); diff --git a/mai2io/mai2io.c b/mai2io/mai2io.c index 554e8dd..57404cb 100644 --- a/mai2io/mai2io.c +++ b/mai2io/mai2io.c @@ -1,9 +1,11 @@ -#include -#include - #include "mai2io/mai2io.h" -#include "mai2io/config.h" + +#include +#include + #include "mai2hook/touch.h" +#include "mai2io/config.h" +#include "util/dprintf.h" #include "util/env.h" static uint8_t mai2_opbtn; @@ -17,20 +19,15 @@ static bool mai2_io_touch_1p_stop_flag; static HANDLE mai2_io_touch_2p_thread; static bool mai2_io_touch_2p_stop_flag; -uint16_t mai2_io_get_api_version(void) -{ - return 0x0101; -} +uint16_t mai2_io_get_api_version(void) { return 0x0101; } -HRESULT mai2_io_init(void) -{ +HRESULT mai2_io_init(void) { mai2_io_config_load(&mai2_io_cfg, get_config_path()); return S_OK; } -HRESULT mai2_io_poll(void) -{ +HRESULT mai2_io_poll(void) { mai2_opbtn = 0; mai2_player1_btn = 0; mai2_player2_btn = 0; @@ -51,12 +48,13 @@ HRESULT mai2_io_poll(void) } else { mai2_io_coin = false; } - // If sinmai has enabled DebugInput, there is no need to input buttons through hook amdaemon. + // If sinmai has enabled DebugInput, there is no need to input buttons + // through hook amdaemon. if (!mai2_io_cfg.vk_btn_enable) { return S_OK; } - //Player 1 + // Player 1 if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[0])) { mai2_player1_btn |= MAI2_IO_GAMEBTN_1; } @@ -93,7 +91,7 @@ HRESULT mai2_io_poll(void) mai2_player1_btn |= MAI2_IO_GAMEBTN_SELECT; } - //Player 2 + // Player 2 if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[0])) { mai2_player2_btn |= MAI2_IO_GAMEBTN_1; } @@ -133,54 +131,40 @@ HRESULT mai2_io_poll(void) return S_OK; } -void mai2_io_get_opbtns(uint8_t *opbtn) -{ +void mai2_io_get_opbtns(uint8_t *opbtn) { if (opbtn != NULL) { *opbtn = mai2_opbtn; } } -void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) -{ +void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) { if (player1 != NULL) { *player1 = mai2_player1_btn; } - if (player2 != NULL ){ + if (player2 != NULL) { *player2 = mai2_player2_btn; } } -HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback) -{ +HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback) { _callback = callback; return S_OK; } -void mai2_io_touch_set_sens(uint8_t *bytes) -{ +void mai2_io_touch_set_sens(uint8_t *bytes) { #if 0 dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", bytes[1], sensor_to_str(bytes[2]), bytes[4]); #endif return; } -void mai2_io_touch_update(bool player1, bool player2) -{ - if (mai2_io_cfg.debug_input_1p) - { - if (player1 && mai2_io_touch_1p_thread == NULL) - { +void mai2_io_touch_update(bool player1, bool player2) { + if (mai2_io_cfg.debug_input_1p) { + if (player1 && mai2_io_touch_1p_thread == NULL) { mai2_io_touch_1p_thread = (HANDLE)_beginthreadex( - NULL, - 0, - mai2_io_touch_1p_thread_proc, - _callback, - 0, - NULL); - } - else if (!player1 && mai2_io_touch_1p_thread != NULL) - { + NULL, 0, mai2_io_touch_1p_thread_proc, _callback, 0, NULL); + } else if (!player1 && mai2_io_touch_1p_thread != NULL) { mai2_io_touch_1p_stop_flag = true; WaitForSingleObject(mai2_io_touch_1p_thread, INFINITE); @@ -190,20 +174,12 @@ void mai2_io_touch_update(bool player1, bool player2) mai2_io_touch_1p_stop_flag = false; } } - if (mai2_io_cfg.debug_input_2p) - { - if (player2 && mai2_io_touch_2p_thread == NULL) - { + + if (mai2_io_cfg.debug_input_2p) { + if (player2 && mai2_io_touch_2p_thread == NULL) { mai2_io_touch_2p_thread = (HANDLE)_beginthreadex( - NULL, - 0, - mai2_io_touch_2p_thread_proc, - _callback, - 0, - NULL); - } - else if (!player2 && mai2_io_touch_2p_thread != NULL) - { + NULL, 0, mai2_io_touch_2p_thread_proc, _callback, 0, NULL); + } else if (!player2 && mai2_io_touch_2p_thread != NULL) { mai2_io_touch_2p_stop_flag = true; WaitForSingleObject(mai2_io_touch_2p_thread, INFINITE); @@ -215,18 +191,14 @@ void mai2_io_touch_update(bool player1, bool player2) } } -static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx) -{ +static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx) { mai2_io_touch_callback_t callback = ctx; - while (!mai2_io_touch_1p_stop_flag) - { + while (!mai2_io_touch_1p_stop_flag) { uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0}; - for (int i = 0; i < 34; i++) - { - if (GetAsyncKeyState(mai2_io_cfg.vk_1p_touch[i])) - { + for (int i = 0; i < 34; i++) { + if (GetAsyncKeyState(mai2_io_cfg.vk_1p_touch[i])) { int byteIndex = i / 5; int bitIndex = i % 5; state[byteIndex] |= (1 << bitIndex); @@ -238,18 +210,14 @@ static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx) return 0; } -static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx) -{ +static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx) { mai2_io_touch_callback_t callback = ctx; - while (!mai2_io_touch_2p_stop_flag) - { + while (!mai2_io_touch_2p_stop_flag) { uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0}; - for (int i = 0; i < 34; i++) - { - if (GetAsyncKeyState(mai2_io_cfg.vk_2p_touch[i])) - { + for (int i = 0; i < 34; i++) { + if (GetAsyncKeyState(mai2_io_cfg.vk_2p_touch[i])) { int byteIndex = i / 5; int bitIndex = i % 5; state[byteIndex] |= (1 << bitIndex); @@ -261,38 +229,38 @@ static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx) return 0; } -HRESULT mai2_io_led_init(void) -{ - return S_OK; -} +HRESULT mai2_io_led_init(void) { return S_OK; } -void mai2_io_led_set_fet_output(const uint8_t *rgb) -{ +void mai2_io_led_set_fet_output(uint8_t board, const uint8_t *rgb) { #if 0 - dprintf("mai2 LED: BodyLed brightness: %d%%\n", (rgb[0] * 100) / 255); - dprintf("mai2 LED: ExtLed brightness: %d%%\n", (rgb[1] * 100) / 255); - dprintf("mai2 LED: SideLed brightness: %d%%\n", (rgb[2] * 100) / 255); + uint8_t player = board + 1; + dprintf("MAI2 LED %dP: BodyLed brightness: %d%%\n", player, + (rgb[0] * 100) / 255); + dprintf("MAI2 LED %dP: ExtLed brightness: %d%%\n", player, + (rgb[1] * 100) / 255); + dprintf("MAI2 LED %dP: SideLed brightness: %d%%\n", player, + (rgb[2] * 100) / 255); #endif return; } -void mai2_io_led_dc_update(const uint8_t *rgb) -{ +void mai2_io_led_dc_update(uint8_t board, const uint8_t *rgb) { #if 0 + uint8_t player = board + 1; for (int i = 0; i < 10; i++) { - dprintf("mai2 LED: LED %d: %02X %02X %02X Speed: %02X\n", + dprintf("Mai2 LED %dP: LED %d: %02X %02X %02X Speed: %02X\n", player i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); } #endif return; } -void mai2_io_led_gs_update(const uint8_t *rgb) -{ +void mai2_io_led_gs_update(uint8_t board, const uint8_t *rgb) { #if 0 + uint8_t player = board + 1; for (int i = 0; i < 8; i++) { - dprintf("mai2 LED: LED %d: %02X %02X %02X Speed: %02X\n", - i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); + dprintf("Mai2 LED %dP: LED %d: %02X %02X %02X Speed: %02X\n", player, i, + rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]); } #endif return; diff --git a/mai2io/mai2io.h b/mai2io/mai2io.h index 039094b..9c0a7f0 100644 --- a/mai2io/mai2io.h +++ b/mai2io/mai2io.h @@ -156,6 +156,9 @@ HRESULT mai2_io_led_init(void); /* Update the FET outputs. rgb is a pointer to an array up to 3 bytes. + maimai DX uses two boards. Board 0 is for the player 1 side (left) and board 1 + is for the player 2 side (right). + Set the brightness of the white light on the machine's outer shell. The program will continuously send changed values to request the blinking effect. @@ -167,13 +170,16 @@ HRESULT mai2_io_led_init(void); Minimum API version: 0x0101 */ -void mai2_io_led_set_fet_output(const uint8_t *rgb); +void mai2_io_led_set_fet_output(uint8_t board, const uint8_t *rgb); /* The effect of this command is unknown, it is triggered after LED_15070_CMD_EEPROM_READ. */ -void mai2_io_led_dc_update(const uint8_t *rgb); +void mai2_io_led_dc_update(uint8_t board, const uint8_t *rgb); -/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. +/* Update the RGB LEDs. rgb is a pointer to an array up to 8 * 4 = 32 bytes. + + maimai DX uses two boards. Board 0 is for the player 1 side (left) and board 1 + is for the player 2 side (right). The LEDs are laid out as follows: [0-7]: 8 button LED @@ -183,4 +189,4 @@ void mai2_io_led_dc_update(const uint8_t *rgb); Minimum API version: 0x0101 */ -void mai2_io_led_gs_update(const uint8_t *rgb); +void mai2_io_led_gs_update(uint8_t board, const uint8_t *rgb); diff --git a/mu3hook/config.c b/mu3hook/config.c index 93957ea..6c52446 100644 --- a/mu3hook/config.c +++ b/mu3hook/config.c @@ -41,7 +41,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename); diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index e4336e9..4b35aa3 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -81,8 +81,9 @@ static DWORD CALLBACK mu3_pre_startup(void) goto fail; } + unsigned int led_port_no[2] = {3, 0}; hr = led15093_hook_init(&mu3_hook_cfg.led15093, - mu3_dll.led_init, mu3_dll.led_set_leds, 3, 1, 1, 2); + mu3_dll.led_init, mu3_dll.led_set_leds, led_port_no); if (FAILED(hr)) { return hr; diff --git a/swdchook/config.c b/swdchook/config.c index fcfa251..e64654e 100644 --- a/swdchook/config.c +++ b/swdchook/config.c @@ -23,7 +23,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) wchar_t tmpstr[16]; cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename); /* TODO: Unknown, no firmware file available */ cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0xdead, filename); diff --git a/swdchook/dllmain.c b/swdchook/dllmain.c index d83798c..5932a69 100644 --- a/swdchook/dllmain.c +++ b/swdchook/dllmain.c @@ -100,8 +100,9 @@ static DWORD CALLBACK swdc_pre_startup(void) } /* Not working, different board -04 instead of -02? */ + unsigned int led_port_no[2] = {2, 0}; hr = led15070_hook_init(&swdc_hook_cfg.led15070, swdc_dll.led_init, - swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, 2, 1); + swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, led_port_no); if (FAILED(hr)) { goto fail; diff --git a/swdchook/io4.c b/swdchook/io4.c index be1d4b9..679a646 100644 --- a/swdchook/io4.c +++ b/swdchook/io4.c @@ -203,7 +203,7 @@ static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) lights_data & SWDC_IO_LED_LEFT ? 0xFF : 0x00, }; - swdc_dll.led_set_leds(rgb_out); + swdc_dll.led_set_leds(0, rgb_out); return S_OK; } diff --git a/swdchook/swdc-dll.h b/swdchook/swdc-dll.h index 1b81e26..7539d1c 100644 --- a/swdchook/swdc-dll.h +++ b/swdchook/swdc-dll.h @@ -11,9 +11,9 @@ struct swdc_dll { void (*get_gamebtns)(uint16_t *gamebtn); void (*get_analogs)(struct swdc_io_analog_state *out); HRESULT (*led_init)(void); - void (*led_set_fet_output)(const uint8_t *rgb); - void (*led_gs_update)(const uint8_t *rgb); - void (*led_set_leds)(const uint8_t *rgb); + void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb); + void (*led_gs_update)(uint8_t board, const uint8_t *rgb); + void (*led_set_leds)(uint8_t board, const uint8_t *rgb); HRESULT (*ffb_init)(void); void (*ffb_toggle)(bool active); void (*ffb_constant_force)(uint8_t direction, uint8_t force); diff --git a/swdcio/dllmain.c b/swdcio/dllmain.c index 8057e23..a35b8e8 100644 --- a/swdcio/dllmain.c +++ b/swdcio/dllmain.c @@ -119,7 +119,7 @@ HRESULT swdc_io_led_init(void) return S_OK; } -void swdc_io_led_set_fet_output(const uint8_t *rgb) +void swdc_io_led_set_fet_output(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("SWDC LED: LEFT SEAT LED: %02X\n", rgb[0]); @@ -129,7 +129,7 @@ void swdc_io_led_set_fet_output(const uint8_t *rgb) return; } -void swdc_io_led_gs_update(const uint8_t *rgb) +void swdc_io_led_gs_update(uint8_t board, const uint8_t *rgb) { #if 0 for (int i = 0; i < 9; i++) { @@ -141,7 +141,7 @@ void swdc_io_led_gs_update(const uint8_t *rgb) return; } -void swdc_io_led_set_leds(const uint8_t *rgb) +void swdc_io_led_set_leds(uint8_t board, const uint8_t *rgb) { #if 0 dprintf("SWDC LED: START: %02X\n", rgb[0]); diff --git a/swdcio/swdcio.h b/swdcio/swdcio.h index 6843634..9d069f3 100644 --- a/swdcio/swdcio.h +++ b/swdcio/swdcio.h @@ -123,7 +123,7 @@ HRESULT swdc_io_led_init(void); Minimum API version: 0x0101 */ -void swdc_io_led_set_fet_output(const uint8_t *rgb); +void swdc_io_led_set_fet_output(uint8_t board, const uint8_t *rgb); /* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes. @@ -140,7 +140,7 @@ void swdc_io_led_set_fet_output(const uint8_t *rgb); Minimum API version: 0x0101 */ -void swdc_io_led_gs_update(const uint8_t *rgb); +void swdc_io_led_gs_update(uint8_t board, const uint8_t *rgb); /* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes. @@ -156,7 +156,7 @@ void swdc_io_led_gs_update(const uint8_t *rgb); Minimum API version: 0x0101 */ -void swdc_io_led_set_leds(const uint8_t *rgb); +void swdc_io_led_set_leds(uint8_t board, const uint8_t *rgb); /* Initialize FFB emulation. This function will be called before any other swdc_io_ffb_*() function calls. diff --git a/tokyohook/config.c b/tokyohook/config.c index 304cbc2..3ab387a 100644 --- a/tokyohook/config.c +++ b/tokyohook/config.c @@ -40,7 +40,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAED9, filename); diff --git a/tokyohook/dllmain.c b/tokyohook/dllmain.c index 19a1517..3ba9b36 100644 --- a/tokyohook/dllmain.c +++ b/tokyohook/dllmain.c @@ -66,8 +66,9 @@ static DWORD CALLBACK tokyo_pre_startup(void) goto fail; } + unsigned int led_port_no[2] = {1, 0}; hr = led15093_hook_init(&tokyo_hook_cfg.led15093, - tokyo_dll.led_init, tokyo_dll.led_set_leds, 1, 1, 1, 2); + tokyo_dll.led_init, tokyo_dll.led_set_leds, led_port_no); if (FAILED(hr)) { return hr; From 4d0ef542792f18b64f33dd1b182763a6cbed6afc Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 2 Mar 2025 00:23:53 +0100 Subject: [PATCH 189/204] system: add dip switch label configurations --- chusanhook/dllmain.c | 39 ++++++++-------------- cmhook/dllmain.c | 8 +++++ dist/fgo/segatools.ini | 2 +- hooklib/meson.build | 2 +- idachook/dllmain.c | 12 +++++++ mai2hook/dllmain.c | 8 +++++ mercuryhook/dllmain.c | 8 +++++ meson.build | 2 +- mu3hook/dllmain.c | 8 +++++ platform/system.c | 75 +++++++++++++++++++++--------------------- platform/system.h | 10 ++++++ tokyohook/dllmain.c | 10 ++++++ 12 files changed, 117 insertions(+), 67 deletions(-) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index e29bf7f..6e3308f 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -86,11 +86,18 @@ static DWORD CALLBACK chusan_pre_startup(void) { /* Initialize emulation hooks */ - hr = platform_hook_init( - &chusan_hook_cfg.platform, - "SDHD", - "ACA2", - chusan_hook_mod); + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + {L"Monitor Type", L"60FPS", L"120FPS"}, + {L"Cabinet Type", L"CVT", L"SP"}, + }; + + // Set the system dip switch configuration + memcpy(chusan_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + + hr = platform_hook_init(&chusan_hook_cfg.platform, "SDHD", "ACA2", + chusan_hook_mod); if (FAILED(hr)) { goto fail; @@ -114,27 +121,7 @@ static DWORD CALLBACK chusan_pre_startup(void) { goto fail; } - bool *dipsw = &chusan_hook_cfg.platform.system.dipsw[0]; - bool is_cvt = dipsw[2]; - - for (int i = 0; i < 3; i++) { - switch (i) { - case 0: - dprintf("DipSw: NetInstall: %s\n", dipsw[0] ? "Server" : "Client"); - break; - - case 1: - dprintf("DipSw: Monitor Type: %dFPS\n", dipsw[1] ? 60 : 120); - break; - - case 2: - dprintf("DipSw: Cab Type: %s\n", is_cvt ? "CVT" : "SP"); - - break; - } - } - - unsigned int first_port = is_cvt ? 2 : 20; + bool is_cvt = chusan_hook_cfg.platform.system.dipsw[2]; if (!is_cvt) { hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2); diff --git a/cmhook/dllmain.c b/cmhook/dllmain.c index 03ace58..29d93af 100644 --- a/cmhook/dllmain.c +++ b/cmhook/dllmain.c @@ -63,6 +63,14 @@ static DWORD CALLBACK cm_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Client", L"Server"}, + }; + + // Set the system dip switch configuration + memcpy(cm_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &cm_hook_cfg.platform, "SDED", diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index e9c7c20..4e846ee 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -41,7 +41,7 @@ portNo=17 ; 837-15093-06 LED board emulation setting. enable=1 ; COM port number for the LED board. Has to be the same as the FTDI port. -portNo=17 +portNo1=17 ; ----------------------------------------------------------------------------- ; Network settings diff --git a/hooklib/meson.build b/hooklib/meson.build index e6908d6..b0ad6c2 100644 --- a/hooklib/meson.build +++ b/hooklib/meson.build @@ -4,7 +4,7 @@ hooklib_lib = static_library( implicit_include_directories : false, dependencies : [ capnhook.get_variable('hook_dep'), - Ws2_32_lib + ws2_32_lib ], sources : [ 'cursor.c', diff --git a/idachook/dllmain.c b/idachook/dllmain.c index 71a4ccd..a7b3c86 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -60,6 +60,18 @@ static DWORD CALLBACK idac_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + {L"Cabinet Type", L"SWDC CVT", L"DZero CVT"}, + {L"Single Seat", L"ON", L"OFF"}, + {L"Seat Setting 1", L"ON", L"OFF"}, + {L"Seat Setting 2", L"ON", L"OFF"}, + }; + + // Set the system dip switch configuration + memcpy(idac_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &idac_hook_cfg.platform, "SDGT", diff --git a/mai2hook/dllmain.c b/mai2hook/dllmain.c index cb8a240..cecc01e 100644 --- a/mai2hook/dllmain.c +++ b/mai2hook/dllmain.c @@ -66,6 +66,14 @@ static DWORD CALLBACK mai2_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + }; + + // Set the system dip switch configuration + memcpy(mai2_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &mai2_hook_cfg.platform, "SDEZ", diff --git a/mercuryhook/dllmain.c b/mercuryhook/dllmain.c index 64b5707..37030d3 100644 --- a/mercuryhook/dllmain.c +++ b/mercuryhook/dllmain.c @@ -64,6 +64,14 @@ static DWORD CALLBACK mercury_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + }; + + // Set the system dip switch configuration + memcpy(mercury_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &mercury_hook_cfg.platform, "SDFE", diff --git a/meson.build b/meson.build index 6bb86fc..aada974 100644 --- a/meson.build +++ b/meson.build @@ -89,7 +89,7 @@ dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') pathcch_lib = cc.find_library('pathcch') imagehlp_lib = cc.find_library('imagehlp') -Ws2_32_lib = cc.find_library('Ws2_32') +ws2_32_lib = cc.find_library('ws2_32') inc = include_directories('.') capnhook = subproject('capnhook') diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index 4b35aa3..1b57e5d 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -65,6 +65,14 @@ static DWORD CALLBACK mu3_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + }; + + // Set the system dip switch configuration + memcpy(mu3_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &mu3_hook_cfg.platform, "SDDT", diff --git a/platform/system.c b/platform/system.c index dbc832f..4928e05 100644 --- a/platform/system.c +++ b/platform/system.c @@ -1,40 +1,37 @@ -#include +#include "platform/system.h" #include -#include +#include #include +#include #include +#include -#include "platform/system.h" #include "platform/vfs.h" - +#include "util/crc.h" #include "util/dprintf.h" #include "util/str.h" -#include "util/crc.h" #define DATA_SIZE 503 #define BLOCK_SIZE (sizeof(uint32_t) + 4 + 1 + DATA_SIZE) #pragma pack(push, 1) -typedef struct -{ +typedef struct { uint32_t checksum; char padding[6]; uint8_t freeplay; char data[DATA_SIZE - 2]; } CreditBlock; -typedef struct -{ +typedef struct { uint32_t checksum; char padding[4]; uint8_t dip_switches; char data[DATA_SIZE]; } DipSwBlock; -typedef struct -{ +typedef struct { CreditBlock credit_block; DipSwBlock dip_switch_block; char *data; @@ -50,16 +47,15 @@ static struct vfs_config vfs_config; static void system_read_sysfile(const wchar_t *sys_file); static void system_save_sysfile(const wchar_t *sys_file); -HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg) -{ +HRESULT system_init(const struct system_config *cfg, + const struct vfs_config *vfs_cfg) { HRESULT hr; wchar_t sys_file_path[MAX_PATH]; assert(cfg != NULL); assert(vfs_cfg != NULL); - if (!cfg->enable) - { + if (!cfg->enable) { return S_FALSE; } @@ -78,13 +74,13 @@ HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vf return S_OK; } -static void system_read_sysfile(const wchar_t *sys_file) -{ +static void system_read_sysfile(const wchar_t *sys_file) { FILE *f = _wfopen(sys_file, L"r"); - if (f == NULL) - { - dprintf("System: First run detected, system settings can only be applied AFTER the first run\n"); + if (f == NULL) { + dprintf( + "System: First run detected, system settings can only be applied " + "AFTER the first run\n"); return; } @@ -92,8 +88,7 @@ static void system_read_sysfile(const wchar_t *sys_file) long file_size = ftell(f); fseek(f, 0, SEEK_SET); - if (file_size != 0x6000) - { + if (file_size != 0x6000) { dprintf("System: Invalid sysfile.dat file size\n"); fclose(f); @@ -106,11 +101,11 @@ static void system_read_sysfile(const wchar_t *sys_file) // copy the credit_block and dip_switch_block from the sysfile.dat memcpy(&system_info.credit_block, system_info.data, BLOCK_SIZE); - memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE); + memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, + BLOCK_SIZE); } -static void system_save_sysfile(const wchar_t *sys_file) -{ +static void system_save_sysfile(const wchar_t *sys_file) { char block[BLOCK_SIZE]; uint8_t system = 0; uint8_t freeplay = 0; @@ -118,24 +113,28 @@ static void system_save_sysfile(const wchar_t *sys_file) // open the sysfile.dat for writing in bytes mode FILE *f = _wfopen(sys_file, L"rb+"); - if (f == NULL) - { + if (f == NULL) { return; } // write the system_config.system to the dip_switch_block - for (int i = 0; i < 8; i++) - { - if (system_config.dipsw[i]) - { - // print which system is enabled + for (int i = 0; i < 8; i++) { + // print the dip switch configuration with labels if present + if (system_config.dipsw_config[i].label[0] != L'\0') { + dprintf("System: %ls: %ls\n", system_config.dipsw_config[i].label, + system_config.dipsw[i] ? system_config.dipsw_config[i].on + : system_config.dipsw_config[i].off); + } else if (system_config.dipsw[i]) { dprintf("System: DipSw%d=1 set\n", i + 1); + } + + // set the system variable to the dip switch configuration + if (system_config.dipsw[i]) { system |= (1 << i); } } - if (system_config.freeplay) - { + if (system_config.freeplay) { // print that freeplay is enabled dprintf("System: Freeplay enabled\n"); freeplay = 1; @@ -149,10 +148,10 @@ static void system_save_sysfile(const wchar_t *sys_file) // calculate the new checksum, skip the old crc32 value // which is at the beginning of the block, thats's why the +4 // conver the struct to chars in order for the crc32 calculation to work - system_info.credit_block.checksum = crc32( - (char *)&system_info.credit_block + 4, BLOCK_SIZE - 4, 0); - system_info.dip_switch_block.checksum = crc32( - (char *)&system_info.dip_switch_block + 4, BLOCK_SIZE - 4, 0); + system_info.credit_block.checksum = + crc32((char *)&system_info.credit_block + 4, BLOCK_SIZE - 4, 0); + system_info.dip_switch_block.checksum = + crc32((char *)&system_info.dip_switch_block + 4, BLOCK_SIZE - 4, 0); // build the new credit block memcpy(block, (char *)&system_info.credit_block, BLOCK_SIZE); diff --git a/platform/system.h b/platform/system.h index ba0f2a6..e69ce90 100644 --- a/platform/system.h +++ b/platform/system.h @@ -7,10 +7,20 @@ #include "platform/vfs.h" + +struct dipsw_config +{ + wchar_t label[MAX_PATH]; + wchar_t on[MAX_PATH]; + wchar_t off[MAX_PATH]; +}; + + struct system_config { bool enable; bool freeplay; bool dipsw[8]; + struct dipsw_config dipsw_config[8]; }; HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg); diff --git a/tokyohook/dllmain.c b/tokyohook/dllmain.c index 3ba9b36..5f46615 100644 --- a/tokyohook/dllmain.c +++ b/tokyohook/dllmain.c @@ -50,6 +50,16 @@ static DWORD CALLBACK tokyo_pre_startup(void) /* Initialize emulation hooks */ + struct dipsw_config new_dipsw_config[8] = { + {L"Delivery Server", L"Server", L"Client"}, + {L"Cabinet ID Setting", L"ON", L"OFF"}, + {L"Cabinet ID Setting", L"ON", L"OFF"}, + }; + + // Set the system dip switch configuration + memcpy(tokyo_hook_cfg.platform.system.dipsw_config, new_dipsw_config, + sizeof(new_dipsw_config)); + hr = platform_hook_init( &tokyo_hook_cfg.platform, "SDFV", From e850346b79a670e115b1cdd336393684453197ae Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 9 Feb 2025 00:13:33 +0100 Subject: [PATCH 190/204] renamed start.bat to launch.bat --- Package.mk | 30 +++++++++++++------------- dist/carol/{start.bat => launch.bat} | 4 ++-- dist/chuni/{start.bat => launch.bat} | 2 ++ dist/chusan/{start.bat => launch.bat} | 0 dist/cm/{start.bat => launch.bat} | 0 dist/cxb/{start.bat => launch.bat} | 0 dist/diva/{start.bat => launch.bat} | 0 dist/fgo/{start.bat => launch.bat} | 0 dist/idac/{start.bat => launch.bat} | 0 dist/idz/{start.bat => launch.bat} | 2 +- dist/kemono/{start.bat => launch.bat} | 0 dist/mai2/{start.bat => launch.bat} | 0 dist/mercury/{start.bat => launch.bat} | 4 +--- dist/mercury/segatools.ini | 2 +- dist/mu3/{start.bat => launch.bat} | 0 dist/swdc/{start.bat => launch.bat} | 0 dist/tokyo/{start.bat => launch.bat} | 0 doc/chunihook.md | 2 +- doc/config/common.md | 2 +- doc/idzhook.md | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) rename dist/carol/{start.bat => launch.bat} (80%) rename dist/chuni/{start.bat => launch.bat} (96%) rename dist/chusan/{start.bat => launch.bat} (100%) rename dist/cm/{start.bat => launch.bat} (100%) rename dist/cxb/{start.bat => launch.bat} (100%) rename dist/diva/{start.bat => launch.bat} (100%) rename dist/fgo/{start.bat => launch.bat} (100%) rename dist/idac/{start.bat => launch.bat} (100%) rename dist/idz/{start.bat => launch.bat} (87%) rename dist/kemono/{start.bat => launch.bat} (100%) rename dist/mai2/{start.bat => launch.bat} (100%) rename dist/mercury/{start.bat => launch.bat} (55%) rename dist/mu3/{start.bat => launch.bat} (100%) rename dist/swdc/{start.bat => launch.bat} (100%) rename dist/tokyo/{start.bat => launch.bat} (100%) diff --git a/Package.mk b/Package.mk index 9d907b1..5647e9b 100644 --- a/Package.mk +++ b/Package.mk @@ -5,7 +5,7 @@ $(BUILD_DIR_ZIP)/chuni.zip: $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_32)/chunihook/chunihook.dll \ $(DIST_DIR)/chuni/segatools.ini \ - $(DIST_DIR)/chuni/start.bat \ + $(DIST_DIR)/chuni/launch.bat \ $(BUILD_DIR_ZIP)/chuni $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -20,7 +20,7 @@ $(BUILD_DIR_ZIP)/cxb.zip: $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_32)/cxbhook/cxbhook.dll \ $(DIST_DIR)/cxb/segatools.ini \ - $(DIST_DIR)/cxb/start.bat \ + $(DIST_DIR)/cxb/launch.bat \ $(BUILD_DIR_ZIP)/cxb $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -35,7 +35,7 @@ $(BUILD_DIR_ZIP)/diva.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/divahook/divahook.dll \ $(DIST_DIR)/diva/segatools.ini \ - $(DIST_DIR)/diva/start.bat \ + $(DIST_DIR)/diva/launch.bat \ $(BUILD_DIR_ZIP)/diva $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -50,7 +50,7 @@ $(BUILD_DIR_ZIP)/carol.zip: $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_32)/carolhook/carolhook.dll \ $(DIST_DIR)/carol/segatools.ini \ - $(DIST_DIR)/carol/start.bat \ + $(DIST_DIR)/carol/launch.bat \ $(BUILD_DIR_ZIP)/carol $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -65,7 +65,7 @@ $(BUILD_DIR_ZIP)/idz.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/idzhook/idzhook.dll \ $(DIST_DIR)/idz/segatools.ini \ - $(DIST_DIR)/idz/start.bat \ + $(DIST_DIR)/idz/launch.bat \ $(BUILD_DIR_ZIP)/idz $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -80,7 +80,7 @@ $(BUILD_DIR_ZIP)/fgo.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/fgohook/fgohook.dll \ $(DIST_DIR)/fgo/segatools.ini \ - $(DIST_DIR)/fgo/start.bat \ + $(DIST_DIR)/fgo/launch.bat \ $(BUILD_DIR_ZIP)/fgo $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -96,7 +96,7 @@ $(BUILD_DIR_ZIP)/idac.zip: $(BUILD_DIR_64)/idachook/idachook.dll \ $(DIST_DIR)/idac/segatools.ini \ $(DIST_DIR)/idac/config_hook.json \ - $(DIST_DIR)/idac/start.bat \ + $(DIST_DIR)/idac/launch.bat \ $(BUILD_DIR_ZIP)/idac $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -112,7 +112,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(BUILD_DIR_64)/swdchook/swdchook.dll \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/config_hook.json \ - $(DIST_DIR)/swdc/start.bat \ + $(DIST_DIR)/swdc/launch.bat \ $(BUILD_DIR_ZIP)/swdc $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -127,7 +127,7 @@ $(BUILD_DIR_ZIP)/mercury.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mercuryhook/mercuryhook.dll \ $(DIST_DIR)/mercury/segatools.ini \ - $(DIST_DIR)/mercury/start.bat \ + $(DIST_DIR)/mercury/launch.bat \ $(BUILD_DIR_ZIP)/mercury $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -141,7 +141,7 @@ $(BUILD_DIR_ZIP)/chusan.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/chusan/DEVICE $(V)cp $(DIST_DIR)/chusan/segatools.ini \ $(DIST_DIR)/chusan/config_hook.json \ - $(DIST_DIR)/chusan/start.bat \ + $(DIST_DIR)/chusan/launch.bat \ $(BUILD_DIR_ZIP)/chusan $(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \ $(BUILD_DIR_ZIP)/chusan/chusanhook_x86.dll @@ -164,7 +164,7 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mu3hook/mu3hook.dll \ $(DIST_DIR)/mu3/segatools.ini \ - $(DIST_DIR)/mu3/start.bat \ + $(DIST_DIR)/mu3/launch.bat \ $(BUILD_DIR_ZIP)/mu3 $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -179,7 +179,7 @@ $(BUILD_DIR_ZIP)/mai2.zip: $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ $(DIST_DIR)/mai2/segatools.ini \ - $(DIST_DIR)/mai2/start.bat \ + $(DIST_DIR)/mai2/launch.bat \ $(BUILD_DIR_ZIP)/mai2 $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -195,7 +195,7 @@ $(BUILD_DIR_ZIP)/cm.zip: $(BUILD_DIR_64)/cmhook/cmhook.dll \ $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ - $(DIST_DIR)/cm/start.bat \ + $(DIST_DIR)/cm/launch.bat \ $(BUILD_DIR_ZIP)/cm $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -211,7 +211,7 @@ $(BUILD_DIR_ZIP)/tokyo.zip: $(BUILD_DIR_64)/tokyohook/tokyohook.dll \ $(DIST_DIR)/tokyo/config_hook.json \ $(DIST_DIR)/tokyo/segatools.ini \ - $(DIST_DIR)/tokyo/start.bat \ + $(DIST_DIR)/tokyo/launch.bat \ $(BUILD_DIR_ZIP)/tokyo $(V)cp pki/billing.pub \ pki/ca.crt \ @@ -224,7 +224,7 @@ $(BUILD_DIR_ZIP)/kemono.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/kemono $(V)mkdir -p $(BUILD_DIR_ZIP)/kemono/DEVICE $(V)cp $(DIST_DIR)/kemono/segatools.ini \ - $(DIST_DIR)/kemono/start.bat \ + $(DIST_DIR)/kemono/launch.bat \ $(BUILD_DIR_ZIP)/kemono $(V)cp $(BUILD_DIR_32)/kemonohook/kemonohook.dll \ $(BUILD_DIR_ZIP)/kemono/kemonohook_x86.dll diff --git a/dist/carol/start.bat b/dist/carol/launch.bat similarity index 80% rename from dist/carol/start.bat rename to dist/carol/launch.bat index 0fab950..4e75aa0 100644 --- a/dist/carol/start.bat +++ b/dist/carol/launch.bat @@ -2,10 +2,10 @@ pushd %~dp0 -taskkill /f /im aimeReaderHost.exe > nul 2>&1 - start /min inject -d -k carolhook.dll aimeReaderHost.exe -p 10 + inject -d -k carolhook.dll carol_nu.exe + taskkill /f /im aimeReaderHost.exe > nul 2>&1 echo. diff --git a/dist/chuni/start.bat b/dist/chuni/launch.bat similarity index 96% rename from dist/chuni/start.bat rename to dist/chuni/launch.bat index 0c942e9..a1c54ef 100644 --- a/dist/chuni/start.bat +++ b/dist/chuni/launch.bat @@ -3,7 +3,9 @@ pushd %~dp0 start /min inject -d -k chunihook.dll aimeReaderHost.exe -p 12 + inject -d -k chunihook.dll chuniApp.exe + taskkill /f /im aimeReaderHost.exe > nul 2>&1 echo. diff --git a/dist/chusan/start.bat b/dist/chusan/launch.bat similarity index 100% rename from dist/chusan/start.bat rename to dist/chusan/launch.bat diff --git a/dist/cm/start.bat b/dist/cm/launch.bat similarity index 100% rename from dist/cm/start.bat rename to dist/cm/launch.bat diff --git a/dist/cxb/start.bat b/dist/cxb/launch.bat similarity index 100% rename from dist/cxb/start.bat rename to dist/cxb/launch.bat diff --git a/dist/diva/start.bat b/dist/diva/launch.bat similarity index 100% rename from dist/diva/start.bat rename to dist/diva/launch.bat diff --git a/dist/fgo/start.bat b/dist/fgo/launch.bat similarity index 100% rename from dist/fgo/start.bat rename to dist/fgo/launch.bat diff --git a/dist/idac/start.bat b/dist/idac/launch.bat similarity index 100% rename from dist/idac/start.bat rename to dist/idac/launch.bat diff --git a/dist/idz/start.bat b/dist/idz/launch.bat similarity index 87% rename from dist/idz/start.bat rename to dist/idz/launch.bat index d64aa9b..4f6ea5e 100644 --- a/dist/idz/start.bat +++ b/dist/idz/launch.bat @@ -2,7 +2,7 @@ pushd %~dp0 -start /min "AM Daemon" inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json +start "AM Daemon" /min inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json rem Set dipsw1=0 and uncomment the ServerBox for in store battle? rem inject -k idzhook.dll ServerBoxD8_Nu_x64.exe diff --git a/dist/kemono/start.bat b/dist/kemono/launch.bat similarity index 100% rename from dist/kemono/start.bat rename to dist/kemono/launch.bat diff --git a/dist/mai2/start.bat b/dist/mai2/launch.bat similarity index 100% rename from dist/mai2/start.bat rename to dist/mai2/launch.bat diff --git a/dist/mercury/start.bat b/dist/mercury/launch.bat similarity index 55% rename from dist/mercury/start.bat rename to dist/mercury/launch.bat index a9a3f22..4a64365 100644 --- a/dist/mercury/start.bat +++ b/dist/mercury/launch.bat @@ -1,10 +1,8 @@ @echo off pushd %~dp0 -taskkill /f /im amdaemon.exe > nul 2>&1 - REM USA -start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json +REM start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json REM JP start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 4e24489..5e10634 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -5,7 +5,7 @@ [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains Axxx directories) +; Insert the path to the game Option directory here (unused in Mercury) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. diff --git a/dist/mu3/start.bat b/dist/mu3/launch.bat similarity index 100% rename from dist/mu3/start.bat rename to dist/mu3/launch.bat diff --git a/dist/swdc/start.bat b/dist/swdc/launch.bat similarity index 100% rename from dist/swdc/start.bat rename to dist/swdc/launch.bat diff --git a/dist/tokyo/start.bat b/dist/tokyo/launch.bat similarity index 100% rename from dist/tokyo/start.bat rename to dist/tokyo/launch.bat diff --git a/doc/chunihook.md b/doc/chunihook.md index 57e19b0..7b68a20 100644 --- a/doc/chunihook.md +++ b/doc/chunihook.md @@ -44,7 +44,7 @@ option=../../option 1. In the `[dns]` section, set `default=` to your computer's hostname or LAN IP. Do not put `127.0.0.1` here, the game specifically checks for and rejects loopback addresses. This setting controls the address of the network services server -1. Right click `start.bat` in `app/bin` and run it as Administrator. I think you need to run it as +1. Right click `launch.bat` in `app/bin` and run it as Administrator. I think you need to run it as admin at least once, but once you have done that you can run the game as a regular user 1. A sequence of several start-up screens will be displayed. You should also see a bunch of debug output in a command line window; if you're seeing hex dumps here then that's a good sign. There diff --git a/doc/config/common.md b/doc/config/common.md index a25e353..89c48c6 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -11,7 +11,7 @@ The default file path for config file is `./segatools.ini`. You can modify environment variable `SEGATOOLS_CONFIG_PATH` to another path. -For example, You can have another `start.bat` with following code in it, +For example, You can have another `launch.bat` with following code in it, Then you can copy `segatools.ini` to `another_config.ini` but with different dns host in it ```bat set SEGATOOLS_CONFIG_PATH=.\another_config.ini diff --git a/doc/idzhook.md b/doc/idzhook.md index e23c18c..1686458 100644 --- a/doc/idzhook.md +++ b/doc/idzhook.md @@ -65,7 +65,7 @@ felicaGen=0 and fill it with 20 digits, for example `01234567891234567890`. Make sure to save the file. -1. Right click `start.bat` in `package` and run it as Administrator. After the +1. Right click `launch.bat` in `package` and run it as Administrator. After the first run you may be able to run the game as a normal user. 1. Once you're at the title screen, press 2 or 3 a few times to add some credits, then _hold_ the Enter key for a few seconds to scan a card and start From 27116a7a4105a54e1b40be50906536c27a997979 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 2 Mar 2025 00:36:13 +0100 Subject: [PATCH 191/204] idac, tokyo: improve dipsw cabinet id config --- chusanhook/dllmain.c | 14 +++++++++++--- idachook/dllmain.c | 10 +++++++++- tokyohook/dllmain.c | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 6e3308f..6ba4cd4 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -26,19 +26,24 @@ #include #include -#include "amex/amex.h" #include "board/sg-reader.h" #include "board/vfd.h" + #include "chuniio/chuniio.h" #include "chusanhook/config.h" #include "chusanhook/io4.h" #include "chusanhook/slider.h" + #include "gfxhook/d3d9.h" #include "gfxhook/gfx.h" + #include "hook/process.h" + #include "hooklib/serial.h" #include "hooklib/spike.h" + #include "platform/platform.h" + #include "util/dprintf.h" #include "util/env.h" @@ -96,8 +101,11 @@ static DWORD CALLBACK chusan_pre_startup(void) { memcpy(chusan_hook_cfg.platform.system.dipsw_config, new_dipsw_config, sizeof(new_dipsw_config)); - hr = platform_hook_init(&chusan_hook_cfg.platform, "SDHD", "ACA2", - chusan_hook_mod); + hr = platform_hook_init( + &chusan_hook_cfg.platform, + "SDHD", + "ACA2", + chusan_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/idachook/dllmain.c b/idachook/dllmain.c index a7b3c86..448ea5b 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -82,13 +82,21 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } + bool *dipsw = &idac_hook_cfg.platform.system.dipsw[0]; + bool is_swdc_cvt = dipsw[1]; + + if (!dipsw[2]) { + // the next two bit are the seat number most significant bit first + dprintf("System: Seat Number: %d\n", ((dipsw[4] << 1) | dipsw[3]) + 1); + } + hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); if (FAILED(hr)) { goto fail; } - hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod); + hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, is_swdc_cvt ? 3 : 2, idac_hook_mod); if (FAILED(hr)) { goto fail; diff --git a/tokyohook/dllmain.c b/tokyohook/dllmain.c index 5f46615..9c3a262 100644 --- a/tokyohook/dllmain.c +++ b/tokyohook/dllmain.c @@ -70,6 +70,26 @@ static DWORD CALLBACK tokyo_pre_startup(void) goto fail; } + bool *dipsw = &tokyo_hook_cfg.platform.system.dipsw[0]; + unsigned int cabinet_id = 0; + + if (dipsw[0] == 1 && dipsw[1] == 0 && dipsw[2] == 0) { + cabinet_id = 1; // Server 1 + } else if (dipsw[0] == 0 && dipsw[1] == 1 && dipsw[2] == 0) { + cabinet_id = 2; // Client 2 + } else if (dipsw[0] == 0 && dipsw[1] == 0 && dipsw[2] == 1) { + cabinet_id = 3; // Client 3 + } else if (dipsw[0] == 0 && dipsw[1] == 1 && dipsw[2] == 1) { + cabinet_id = 4; // Client 4 + } else { + dprintf("Error: Invalid dip switch configuration!\n"); + } + + // Print the correct Cabinet ID if valid + if (cabinet_id > 0) { + dprintf("System: Cabinet ID %d\n", cabinet_id); + } + hr = tokyo_dll_init(&tokyo_hook_cfg.dll, tokyo_hook_mod); if (FAILED(hr)) { From 3371f3f437bb668b759cd9a0cd48d0f7413ccb35 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Sun, 2 Mar 2025 01:45:23 -0500 Subject: [PATCH 192/204] fix msvc build by removing ntstatus include from platform/system.c --- platform/system.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/system.c b/platform/system.c index 4928e05..5879032 100644 --- a/platform/system.c +++ b/platform/system.c @@ -1,11 +1,10 @@ #include "platform/system.h" +#include #include -#include #include #include #include -#include #include "platform/vfs.h" #include "util/crc.h" From 369fe286871e741cc69f01e15bd5686b2559f02e Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Sun, 2 Mar 2025 04:10:35 -0500 Subject: [PATCH 193/204] disable excess logging for carol touchscreen hook --- carolhook/touch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/carolhook/touch.c b/carolhook/touch.c index 70c2e92..cf94355 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -196,7 +196,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const flg = resp.touches[0].x1 != last_x1 || resp.touches[0].x2 != last_x2 || resp.touches[0].y1 != last_y1 || resp.touches[0].y2 != last_y2; -#if 1 +#if 0 if (flg) dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2); #endif From 70c3e2fe0fc6e16049fcc3f709f68f2bea09ee9f Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Sun, 9 Mar 2025 16:05:03 +0000 Subject: [PATCH 194/204] FGO: fix printer hook always being enabled (#60) that moment when the printer says OK but it absolutely isn't supposed to be OK lmao edit: I'm not sure why the msvc commits are also in all of these PRs, they have no effect though... Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/60 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> --- fgohook/dllmain.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index a65cbcd..fcf5132 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -82,8 +82,10 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Hook external DLL APIs */ printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod); - dll_hook_push(fgo_hook_mod, L"C330Ausb.dll"); - dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll"); + if (fgo_hook_cfg.printer.enable) { + dll_hook_push(fgo_hook_mod, L"C330Ausb.dll"); + dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll"); + } /* Initialize emulation hooks */ From 61f95c3f2e9afc55df5e0cb232250183edb6b582 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:53:31 +0000 Subject: [PATCH 195/204] GFX: add dpi-awareness switch for all games (#64) Pretty simple, adds a new config setting to the gfx category, which defaults to enabled to disable DPI scaling if a scale higher than 100% is used, causing game windows to appear stretched and blurry. Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/64 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> --- carolhook/dllmain.c | 2 -- dist/carol/segatools.ini | 2 ++ dist/chuni/segatools.ini | 2 ++ dist/chusan/segatools.ini | 2 ++ dist/cxb/segatools.ini | 2 ++ dist/diva/segatools.ini | 3 +++ dist/fgo/segatools.ini | 2 ++ dist/idz/segatools.ini | 3 +++ dist/mercury/segatools.ini | 3 +++ dist/mu3/segatools.ini | 3 +++ doc/config/common.md | 32 ++++++++++++++++++++++++++++++++ gfxhook/config.c | 1 + gfxhook/gfx.c | 8 ++++++++ gfxhook/gfx.h | 1 + 14 files changed, 64 insertions(+), 2 deletions(-) diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 762b33d..35fc7f0 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -74,8 +74,6 @@ static DWORD CALLBACK carol_pre_startup(void) HMODULE dbghelp; dprintf("--- Begin carol_pre_startup ---\n"); - if ( !SetProcessDPIAware() ) - dprintf("Failed to set process DPI awareness level!\n"); /* Pin the D3D shader compiler. This makes startup much faster. */ diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index e75f1cd..b760c6f 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -72,6 +72,8 @@ windowed=1 framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 ; ----------------------------------------------------------------------------- ; Custom IO settings diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 3e87cb0..3f32f5b 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -64,6 +64,8 @@ windowed=1 framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 ; ----------------------------------------------------------------------------- ; LED settings diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index 7ff4d0a..1fb1371 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -90,6 +90,8 @@ windowed=1 framed=0 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 ; ----------------------------------------------------------------------------- ; LED settings diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 40589de..436ef01 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -83,6 +83,8 @@ windowed=1 framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 ; ----------------------------------------------------------------------------- ; Custom IO settings diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index e8db667..744a55f 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -69,6 +69,9 @@ enable=1 windowed=1 ; Add a frame to the game window if running windowed. framed=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 + ; ----------------------------------------------------------------------------- ; Custom IO settings diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 4e846ee..6ceac0a 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -92,6 +92,8 @@ enable=1 windowed=0 ; Add a frame to the game window if running windowed. framed=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 [touch] ; WinTouch emulation setting. diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index e617de2..47778e9 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -97,6 +97,9 @@ windowed=0 framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0=primary screen) monitor=0 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 + ; ----------------------------------------------------------------------------- ; Custom IO settings diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 5e10634..3199a20 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -76,6 +76,9 @@ dipsw1=1 [gfx] ; Enables the graphics hook. enable=1 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 + ; Hooks related to the touch boards [touch] diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 43fef6e..61d8cfe 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -72,6 +72,9 @@ dipsw1=1 [gfx] ; Enables the graphics hook. enable=1 +; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used +dpiAware=1 + [unity] ; Enable Unity hook. This will allow you to run custom .NET code before the game diff --git a/doc/config/common.md b/doc/config/common.md index 89c48c6..8ef48eb 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -342,6 +342,38 @@ Nu chassis DIP switch settings: - `111`: 1920x1080 - Switch 8: Game-specific. Not used in any shipping game. +## `[gfx]` + +### `enable` + +Default: `1` + +Enables graphic hooks. + +### `windowed` + +Default: `0` + +Force the game to run windowed. + +### `framed` + +Default: `0` + +Add a frame to the game window if running windowed. + +### `monitor` + +Default: `0` + +Select the monitor to run the game on. (Fullscreen only, 0 = primary screen) + +### `dpiAware` + +Default: `1` + +Sets the game to be DPI-aware. This prevents Windows automatically scaling the game window by your desktop's scaling factor, which may cause blurry graphics. + ## `[hwmon]` Configure stub implementation of the platform hardware monitor driver. The diff --git a/gfxhook/config.c b/gfxhook/config.c index 98db059..5c49625 100644 --- a/gfxhook/config.c +++ b/gfxhook/config.c @@ -14,4 +14,5 @@ void gfx_config_load(struct gfx_config *cfg, const wchar_t *filename) cfg->windowed = GetPrivateProfileIntW(L"gfx", L"windowed", 0, filename); cfg->framed = GetPrivateProfileIntW(L"gfx", L"framed", 1, filename); cfg->monitor = GetPrivateProfileIntW(L"gfx", L"monitor", 0, filename); + cfg->dpiAware = GetPrivateProfileIntW(L"gfx", L"dpiAware", 1, filename); } diff --git a/gfxhook/gfx.c b/gfxhook/gfx.c index 0acc1ae..5d7b8cd 100644 --- a/gfxhook/gfx.c +++ b/gfxhook/gfx.c @@ -67,6 +67,14 @@ void gfx_hook_init(const struct gfx_config *cfg) return; } + if (cfg->dpiAware) { + if (SetProcessDPIAware()) { + dprintf("Gfx: Game process set to DPI aware.\n"); + } else { + dprintf("Gfx: Failed to set process DPI aware\n"); + } + } + memcpy(&gfx_config, cfg, sizeof(*cfg)); hook_table_apply(NULL, "user32.dll", gfx_hooks, _countof(gfx_hooks)); } diff --git a/gfxhook/gfx.h b/gfxhook/gfx.h index 9a7e27c..6f3c1b2 100644 --- a/gfxhook/gfx.h +++ b/gfxhook/gfx.h @@ -7,6 +7,7 @@ struct gfx_config { bool windowed; bool framed; int monitor; + bool dpiAware; }; void gfx_hook_init(const struct gfx_config *cfg); From 39711a994afff9f504a757419f09513b07e0a18f Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Sat, 5 Apr 2025 15:22:14 +0000 Subject: [PATCH 196/204] FGO: add keyboard input (#61) Probably self-explanatory :p Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/61 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> --- dist/fgo/segatools.ini | 29 ++++++++- fgohook/io4.c | 2 +- fgoio/backend.h | 10 ++++ fgoio/config.c | 40 ++++++++++++- fgoio/config.h | 22 +++++++ fgoio/fgoio.c | 123 ++++++++++++-------------------------- fgoio/fgoio.h | 2 +- fgoio/keyboard.c | 82 +++++++++++++++++++++++++ fgoio/keyboard.h | 8 +++ fgoio/meson.build | 5 ++ fgoio/xi.c | 132 +++++++++++++++++++++++++++++++++++++++++ fgoio/xi.h | 10 ++++ 12 files changed, 375 insertions(+), 90 deletions(-) create mode 100644 fgoio/backend.h create mode 100644 fgoio/keyboard.c create mode 100644 fgoio/keyboard.h create mode 100644 fgoio/xi.c create mode 100644 fgoio/xi.h diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 6ceac0a..4b7ac9f 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -158,8 +158,11 @@ coin=0x72 ; : : AIME. : : ; '·:..............................................:·' ; -; Only XInput is currently supported. +; Select the input mode. "xinput" for controller, "keyboard" for keyboard. +mode=xinput + +[xinput] ; XInput bindings ; ; Left Stick Joystick @@ -168,3 +171,27 @@ coin=0x72 ; Left Shoulder Switch Target ; A/B Attack ; X/Y Noble Phantasm + +; Configure deadzones for the left thumbsticks. +; The default value for the left stick is 7849, max value is 32767. +stickDeadzone=7849 + +[keyboard] +; Keyboard bindings: + +; Stick controls (default: WASD) +up=0x57 +left=0x41 +down=0x53 +right=0x44 + +; Attack (default: Space) +attack=0x20 +; Dash (default: LSHIFT) +dash=0xa0 +; Change Target (default: J) +target=0x4A +; Re-center camera (default: K) +camera=0x4B +; Noble Phantasm (default: L) +np=0x4C diff --git a/fgohook/io4.c b/fgohook/io4.c index b2deb5f..67dfba4 100644 --- a/fgohook/io4.c +++ b/fgohook/io4.c @@ -87,7 +87,7 @@ static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state) state->buttons[0] |= 1 << 1; } - if (gamebtn & FGO_IO_GAMEBTN_NOBLE_PHANTASHM) { + if (gamebtn & FGO_IO_GAMEBTN_NOBLE_PHANTASM) { state->buttons[0] |= 1 << 0; } diff --git a/fgoio/backend.h b/fgoio/backend.h new file mode 100644 index 0000000..578bda4 --- /dev/null +++ b/fgoio/backend.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "fgoio/fgoio.h" + +struct fgo_io_backend { + void (*get_gamebtns)(uint8_t *gamebtn); + void (*get_analogs)(int16_t *x, int16_t *y); +}; diff --git a/fgoio/config.c b/fgoio/config.c index 6270391..437b7be 100644 --- a/fgoio/config.c +++ b/fgoio/config.c @@ -1,11 +1,38 @@ #include #include -#include +#include #include #include "fgoio/config.h" +#include + + +void fgo_kb_config_load( + struct fgo_kb_config *cfg, + const wchar_t *filename) { + + cfg->vk_attack = GetPrivateProfileIntW(L"keyboard", L"attack", ' ', filename); + cfg->vk_dash = GetPrivateProfileIntW(L"keyboard", L"dash", VK_LSHIFT, filename); + cfg->vk_target = GetPrivateProfileIntW(L"keyboard", L"target", 'J', filename); + cfg->vk_camera = GetPrivateProfileIntW(L"keyboard", L"camera", 'K', filename); + cfg->vk_np = GetPrivateProfileIntW(L"keyboard", L"np", 'L', filename); + + // Standard WASD + cfg->vk_right = GetPrivateProfileIntW(L"keyboard", L"right", 'D', filename); + cfg->vk_left = GetPrivateProfileIntW(L"keyboard", L"left", 'A', filename); + cfg->vk_down = GetPrivateProfileIntW(L"keyboard", L"down", 'S', filename); + cfg->vk_up = GetPrivateProfileIntW(L"keyboard", L"up", 'W', filename); +} + +void fgo_xi_config_load( + struct fgo_xi_config *cfg, + const wchar_t *filename) { + + cfg->stick_deadzone = GetPrivateProfileIntW(L"xinput", L"stickDeadzone", XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, filename); + +} void fgo_io_config_load( struct fgo_io_config *cfg, @@ -17,4 +44,15 @@ void fgo_io_config_load( cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename); cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename); cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename); + + GetPrivateProfileStringW( + L"io4", + L"mode", + L"xinput", + cfg->mode, + _countof(cfg->mode), + filename); + + fgo_xi_config_load(&cfg->xi, filename); + fgo_kb_config_load(&cfg->kb, filename); } diff --git a/fgoio/config.h b/fgoio/config.h index 835e5e8..d824ff5 100644 --- a/fgoio/config.h +++ b/fgoio/config.h @@ -5,12 +5,34 @@ #include +struct fgo_kb_config { + uint8_t vk_np; + uint8_t vk_target; + uint8_t vk_dash; + uint8_t vk_attack; + uint8_t vk_camera; + uint8_t vk_right; + uint8_t vk_left; + uint8_t vk_down; + uint8_t vk_up; +}; + +struct fgo_xi_config { + uint16_t stick_deadzone; +}; + struct fgo_io_config { uint8_t vk_test; uint8_t vk_service; uint8_t vk_coin; + + wchar_t mode[12]; + struct fgo_kb_config kb; + struct fgo_xi_config xi; }; +void fgo_kb_config_load(struct fgo_kb_config *cfg, const wchar_t *filename); +void fgo_xi_config_load(struct fgo_xi_config *cfg, const wchar_t *filename); void fgo_io_config_load( struct fgo_io_config *cfg, const wchar_t *filename); diff --git a/fgoio/fgoio.c b/fgoio/fgoio.c index 4a362a0..4817bc0 100644 --- a/fgoio/fgoio.c +++ b/fgoio/fgoio.c @@ -2,37 +2,51 @@ #include #include -#include #include #include "fgoio/fgoio.h" + +#include + +#include "keyboard.h" +#include "xi.h" #include "fgoio/config.h" #include "util/dprintf.h" #include "util/env.h" +#include "util/str.h" static uint8_t fgo_opbtn; static uint8_t fgo_gamebtn; static int16_t fgo_stick_x; static int16_t fgo_stick_y; static struct fgo_io_config fgo_io_cfg; +static const struct fgo_io_backend* fgo_io_backend; static bool fgo_io_coin; -uint16_t fgo_io_get_api_version(void) -{ +uint16_t fgo_io_get_api_version(void) { return 0x0100; } -HRESULT fgo_io_init(void) -{ +HRESULT fgo_io_init(void) { fgo_io_config_load(&fgo_io_cfg, get_config_path()); - return S_OK; + HRESULT hr; + + if (wstr_ieq(fgo_io_cfg.mode, L"keyboard")) { + hr = fgo_kb_init(&fgo_io_cfg.kb, &fgo_io_backend); + } else if (wstr_ieq(fgo_io_cfg.mode, L"xinput")) { + hr = fgo_xi_init(&fgo_io_cfg.xi, &fgo_io_backend); + } else { + hr = E_INVALIDARG; + dprintf("FGO IO: Invalid IO mode \"%S\", use keyboard or xinput\n", + fgo_io_cfg.mode); + } + + return hr; } -HRESULT fgo_io_poll(void) -{ - XINPUT_STATE xi; - WORD xb; +HRESULT fgo_io_poll(void) { + assert(fgo_io_backend != NULL); fgo_opbtn = 0; fgo_gamebtn = 0; @@ -56,97 +70,34 @@ HRESULT fgo_io_poll(void) fgo_io_coin = false; } - memset(&xi, 0, sizeof(xi)); - XInputGetState(0, &xi); - xb = xi.Gamepad.wButtons; - - if (xi.Gamepad.bLeftTrigger > 64) { - fgo_gamebtn |= FGO_IO_GAMEBTN_SPEED_UP; - } - - if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) { - fgo_gamebtn |= FGO_IO_GAMEBTN_TARGET; - } - - if (xb & XINPUT_GAMEPAD_A || xb & XINPUT_GAMEPAD_B) { - fgo_gamebtn |= FGO_IO_GAMEBTN_ATTACK; - } - - if (xb & XINPUT_GAMEPAD_Y || xb & XINPUT_GAMEPAD_X) { - fgo_gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASHM; - } - - if (xb & XINPUT_GAMEPAD_LEFT_THUMB) { - fgo_gamebtn |= FGO_IO_GAMEBTN_CAMERA; - } - - float LX = xi.Gamepad.sThumbLX; - float LY = xi.Gamepad.sThumbLY; - - // determine how far the controller is pushed - float magnitude = sqrt(LX*LX + LY*LY); - - // determine the direction the controller is pushed - float normalizedLX = LX / magnitude; - float normalizedLY = LY / magnitude; - - float normalizedMagnitude = 0; - - // check if the controller is outside a circular dead zone - if (magnitude > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) - { - // clip the magnitude at its expected maximum value - if (magnitude > 32767) magnitude = 32767; - - // adjust magnitude relative to the end of the dead zone - magnitude -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; - - // optionally normalize the magnitude with respect to its expected range - // giving a magnitude value of 0.0 to 1.0 - normalizedMagnitude = magnitude / (32767 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - } else // if the controller is in the deadzone zero out the magnitude - { - magnitude = 0.0; - normalizedMagnitude = 0.0; - } - - fgo_stick_x = (int16_t)(normalizedLX * normalizedMagnitude * 32767); - fgo_stick_y = (int16_t)(normalizedLY * normalizedMagnitude * 32767); - return S_OK; } -void fgo_io_get_opbtns(uint8_t *opbtn) -{ +void fgo_io_get_opbtns(uint8_t* opbtn) { if (opbtn != NULL) { *opbtn = fgo_opbtn; } } -void fgo_io_get_gamebtns(uint8_t *btn) -{ - if (btn != NULL) { - *btn = fgo_gamebtn; - } +void fgo_io_get_gamebtns(uint8_t* btn) { + assert(fgo_io_backend != NULL); + assert(btn != NULL); + + fgo_io_backend->get_gamebtns(btn); } -void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y) -{ - if (stick_x != NULL) { - *stick_x = fgo_stick_x; - } +void fgo_io_get_analogs(int16_t* stick_x, int16_t* stick_y) { + assert(fgo_io_backend != NULL); + assert(stick_x != NULL); + assert(stick_y != NULL); - if (stick_y != NULL) { - *stick_y = fgo_stick_y; - } + fgo_io_backend->get_analogs(stick_x, stick_y); } -HRESULT fgo_io_led_init(void) -{ +HRESULT fgo_io_led_init(void) { return S_OK; } -void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb) -{ +void fgo_io_led_set_colors(uint8_t board, uint8_t* rgb) { return; } diff --git a/fgoio/fgoio.h b/fgoio/fgoio.h index c5b5fd8..65a11b0 100644 --- a/fgoio/fgoio.h +++ b/fgoio/fgoio.h @@ -14,7 +14,7 @@ enum { FGO_IO_GAMEBTN_SPEED_UP = 0x01, FGO_IO_GAMEBTN_TARGET = 0x02, FGO_IO_GAMEBTN_ATTACK = 0x04, - FGO_IO_GAMEBTN_NOBLE_PHANTASHM = 0x08, + FGO_IO_GAMEBTN_NOBLE_PHANTASM = 0x08, FGO_IO_GAMEBTN_CAMERA = 0x10, }; diff --git a/fgoio/keyboard.c b/fgoio/keyboard.c new file mode 100644 index 0000000..6d403dd --- /dev/null +++ b/fgoio/keyboard.c @@ -0,0 +1,82 @@ +#include + +#include +#include +#include +#include + +#include "fgoio/backend.h" +#include "fgoio/config.h" +#include "fgoio/fgoio.h" +#include "fgoio/keyboard.h" + +#include "util/dprintf.h" + +static void fgo_kb_get_gamebtns(uint8_t* gamebtn_out); +static void fgo_kb_get_analogs(int16_t* x, int16_t* y); + +static const struct fgo_io_backend fgo_kb_backend = { + .get_gamebtns = fgo_kb_get_gamebtns, + .get_analogs = fgo_kb_get_analogs +}; + +static struct fgo_kb_config config; + +HRESULT fgo_kb_init(const struct fgo_kb_config* cfg, const struct fgo_io_backend** backend) { + assert(cfg != NULL); + assert(backend != NULL); + + dprintf("Keyboard: Using keyboard input\n"); + *backend = &fgo_kb_backend; + config = *cfg; + + return S_OK; +} + +static void fgo_kb_get_gamebtns(uint8_t* gamebtn_out) { + assert(gamebtn_out != NULL); + + uint8_t gamebtn = 0; + + if (GetAsyncKeyState(config.vk_np) & 0x8000) { + gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASM; + } + + if (GetAsyncKeyState(config.vk_target) & 0x8000) { + gamebtn |= FGO_IO_GAMEBTN_TARGET; + } + + if (GetAsyncKeyState(config.vk_dash) & 0x8000) { + gamebtn |= FGO_IO_GAMEBTN_SPEED_UP; + } + + if (GetAsyncKeyState(config.vk_attack) & 0x8000) { + gamebtn |= FGO_IO_GAMEBTN_ATTACK; + } + + if (GetAsyncKeyState(config.vk_camera) & 0x8000) { + gamebtn |= FGO_IO_GAMEBTN_CAMERA; + } + + *gamebtn_out = gamebtn; +} + +static void fgo_kb_get_analogs(int16_t* x, int16_t* y) { + assert(x != NULL); + assert(y != NULL); + + if (GetAsyncKeyState(config.vk_left) & 0x8000) { + *x = SHRT_MIN + 1; + } else if (GetAsyncKeyState(config.vk_right) & 0x8000) { + *x = SHRT_MAX - 1; + } else { + *x = 0; + } + if (GetAsyncKeyState(config.vk_down) & 0x8000) { + *y = SHRT_MIN + 1; + } else if (GetAsyncKeyState(config.vk_up) & 0x8000) { + *y = SHRT_MAX - 1; + } else { + *y = 0; + } +} diff --git a/fgoio/keyboard.h b/fgoio/keyboard.h new file mode 100644 index 0000000..1b46a64 --- /dev/null +++ b/fgoio/keyboard.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#include "fgoio/backend.h" +#include "fgoio/config.h" + +HRESULT fgo_kb_init(const struct fgo_kb_config *cfg, const struct fgo_io_backend **backend); diff --git a/fgoio/meson.build b/fgoio/meson.build index eed2fd3..5847686 100644 --- a/fgoio/meson.build +++ b/fgoio/meson.build @@ -11,5 +11,10 @@ fgoio_lib = static_library( 'fgoio.h', 'config.c', 'config.h', + 'backend.h', + 'keyboard.c', + 'keyboard.h', + 'xi.c', + 'xi.h', ], ) diff --git a/fgoio/xi.c b/fgoio/xi.c new file mode 100644 index 0000000..91a78a8 --- /dev/null +++ b/fgoio/xi.c @@ -0,0 +1,132 @@ +#include +#include + +#include +#include +#include + +#include "fgoio/backend.h" +#include "fgoio/config.h" +#include "fgoio/fgoio.h" +#include "fgoio/xi.h" + +#include "util/dprintf.h" + +static void fgo_xi_get_gamebtns(uint8_t* gamebtn_out); +static void fgo_xi_get_analogs(int16_t* x, int16_t* y); +static HRESULT fgo_xi_config_apply(const struct fgo_xi_config* cfg); + +static const struct fgo_io_backend fgo_xi_backend = { + .get_gamebtns = fgo_xi_get_gamebtns, + .get_analogs = fgo_xi_get_analogs +}; + +static float fgo_xi_stick_deadzone; + +const uint16_t max_stick_value = 32767; + +HRESULT fgo_xi_init(const struct fgo_xi_config* cfg, const struct fgo_io_backend** backend) { + assert(cfg != NULL); + assert(backend != NULL); + + HRESULT hr = fgo_xi_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + + dprintf("XInput: Using XInput controller\n"); + *backend = &fgo_xi_backend; + + return S_OK; +} + +static HRESULT fgo_xi_config_apply(const struct fgo_xi_config* cfg) { + /* Deadzone check */ + if (cfg->stick_deadzone > 32767 || cfg->stick_deadzone < 0) { + dprintf("XInput: Stick deadzone is too large or negative\n"); + return E_INVALIDARG; + } + + dprintf("XInput: --- Begin configuration ---\n"); + dprintf("XInput: Left Deadzone . . . . : %i\n", cfg->stick_deadzone); + dprintf("XInput: --- End configuration ---\n"); + + fgo_xi_stick_deadzone = cfg->stick_deadzone; + + return S_OK; +} + +static void fgo_xi_get_gamebtns(uint8_t* gamebtn_out) { + assert(gamebtn_out != NULL); + + XINPUT_STATE xi; + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + uint8_t gamebtn = 0; + WORD xb = xi.Gamepad.wButtons; + + if (xi.Gamepad.bLeftTrigger > 64) { + gamebtn |= FGO_IO_GAMEBTN_SPEED_UP; + } + + if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) { + gamebtn |= FGO_IO_GAMEBTN_TARGET; + } + + if (xb & XINPUT_GAMEPAD_A || xb & XINPUT_GAMEPAD_B) { + gamebtn |= FGO_IO_GAMEBTN_ATTACK; + } + + if (xb & XINPUT_GAMEPAD_Y || xb & XINPUT_GAMEPAD_X) { + gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASM; + } + + if (xb & XINPUT_GAMEPAD_LEFT_THUMB) { + gamebtn |= FGO_IO_GAMEBTN_CAMERA; + } + + *gamebtn_out = gamebtn; +} + +static void fgo_xi_get_analogs(int16_t* x, int16_t* y) { + + assert(x != NULL); + assert(y != NULL); + + XINPUT_STATE xi; + memset(&xi, 0, sizeof(xi)); + XInputGetState(0, &xi); + + float LX = xi.Gamepad.sThumbLX; + float LY = xi.Gamepad.sThumbLY; + + // determine how far the controller is pushed + float magnitude = sqrt(LX * LX + LY * LY); + + // determine the direction the controller is pushed + float normalizedLX = LX / magnitude; + float normalizedLY = LY / magnitude; + + float normalizedMagnitude = 0; + + // check if the controller is outside a circular dead zone + if (magnitude > fgo_xi_stick_deadzone) { + // clip the magnitude at its expected maximum value + if (magnitude > 32767) magnitude = 32767; + + // adjust magnitude relative to the end of the dead zone + magnitude -= fgo_xi_stick_deadzone; + + // optionally normalize the magnitude with respect to its expected range + // giving a magnitude value of 0.0 to 1.0 + normalizedMagnitude = magnitude / (32767 - fgo_xi_stick_deadzone); + } else // if the controller is in the deadzone zero out the magnitude + { + normalizedMagnitude = 0; + } + + *x = (int16_t) (normalizedLX * normalizedMagnitude * 32767); + *y = (int16_t) (normalizedLY * normalizedMagnitude * 32767); +} diff --git a/fgoio/xi.h b/fgoio/xi.h new file mode 100644 index 0000000..ebb8859 --- /dev/null +++ b/fgoio/xi.h @@ -0,0 +1,10 @@ +#pragma once + +/* Can't call this xinput.h or it will conflict with */ + +#include + +#include "fgoio/backend.h" +#include "fgoio/config.h" + +HRESULT fgo_xi_init(const struct fgo_xi_config *cfg, const struct fgo_io_backend **backend); From 9a6c4939c278ab351914d5d5642612e6cd97f211 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Wed, 16 Apr 2025 22:09:48 -0400 Subject: [PATCH 197/204] system: fix sysfile patches not applying when compiling with msvc --- platform/system.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/system.c b/platform/system.c index 5879032..3916f58 100644 --- a/platform/system.c +++ b/platform/system.c @@ -106,13 +106,13 @@ static void system_read_sysfile(const wchar_t *sys_file) { static void system_save_sysfile(const wchar_t *sys_file) { char block[BLOCK_SIZE]; + DWORD sysfile_bytes_written = 0; uint8_t system = 0; uint8_t freeplay = 0; - // open the sysfile.dat for writing in bytes mode - FILE *f = _wfopen(sys_file, L"rb+"); + HANDLE h_sysfile = CreateFileW(sys_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, 0, 0, NULL); - if (f == NULL) { + if (h_sysfile == INVALID_HANDLE_VALUE) { return; } @@ -174,7 +174,10 @@ static void system_save_sysfile(const wchar_t *sys_file) { dprintf("\n"); */ - fwrite(system_info.data, 1, 0x6000, f); + WriteFile(h_sysfile, system_info.data, 0x6000, &sysfile_bytes_written, NULL); + CloseHandle(h_sysfile); - fclose(f); + if (sysfile_bytes_written != 0x6000) { + dprintf("System: Only 0x%04X bytes written out of 0x6000!\n", sysfile_bytes_written); + } } From b37e1105d054cbcfaffff4d0abfd501691412cdf Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Wed, 16 Apr 2025 22:10:19 -0400 Subject: [PATCH 198/204] misc: added a showcursor counter to more accuratly replicate actual function behavior --- hooklib/cursor.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hooklib/cursor.c b/hooklib/cursor.c index 87e3ca8..7caba97 100644 --- a/hooklib/cursor.c +++ b/hooklib/cursor.c @@ -14,6 +14,7 @@ static HCURSOR (*next_SetCursor)(HCURSOR hCursor); static BOOL my_SetCursorPos(int x, int y); static BOOL my_SetPhysicalCursorPos(int x, int y); static int my_ShowCursor(BOOL bShow); +static int cursor_track = -1; // If no mouse is connected, this starts as -1 static const struct hook_symbol cursor_syms[] = { { @@ -45,7 +46,7 @@ void cursor_hook_init() static BOOL my_SetCursorPos(int x, int y) { - dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y); + // dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y); return true; } @@ -58,7 +59,12 @@ static BOOL my_SetPhysicalCursorPos(int x, int y) static int my_ShowCursor(BOOL bShow) { dprintf("my_ShowCursor Hit!\n"); - return 0; + if (bShow) { + cursor_track++; + } else { + cursor_track--; + } + return cursor_track; } static HCURSOR my_SetCursor(HCURSOR hCursor) From 67eda7458bfd35021876050a7a656011913a84da Mon Sep 17 00:00:00 2001 From: Haruka Date: Thu, 17 Apr 2025 17:01:38 +0000 Subject: [PATCH 199/204] emoney: Add Thinca authentication card stuff (#35) This PR adds everything that's needed on the segatools side to add E-Money support regarding Thinca authentication cards. I've also included set-up documentation (with a network side bonus which was as far as I could figure out so far, but I'm pretty certain no more changes to segatools will be needed) Due to the nature of a custom protcol called TCAP that Thinca uses for networking (see docs), I can't fully test that everything works as I haven't yet bothered to figure that protocol out. Tested with both APMv3 and FGO. ![https://puu.sh/KeqVj/ccf4bcccbb.png](https://puu.sh/KeqVj/ccf4bcccbb.png) Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/35 Co-authored-by: Haruka Co-committed-by: Haruka --- board/config.c | 9 +++ board/sg-nfc-cmd.h | 30 +++---- board/sg-nfc.c | 68 +++++++++++++--- board/sg-nfc.h | 4 + board/sg-reader.c | 2 +- board/sg-reader.h | 2 + doc/config/common.md | 28 +++++++ doc/emoney.md | 189 +++++++++++++++++++++++++++++++++++++++++++ hooklib/dns.c | 10 ++- hooklib/dns.h | 1 + hooklib/path.c | 8 ++ meson.build | 3 + meson_options.txt | 11 ++- platform/config.c | 1 + platform/epay.c | 103 ++++++++++++++--------- platform/epay.h | 4 +- util/meson.build | 2 + util/slurp.c | 67 +++++++++++++++ util/slurp.h | 12 +++ 19 files changed, 486 insertions(+), 68 deletions(-) create mode 100644 doc/emoney.md create mode 100644 util/slurp.c create mode 100644 util/slurp.h diff --git a/board/config.c b/board/config.c index 19d47bc..96c4146 100644 --- a/board/config.c +++ b/board/config.c @@ -75,6 +75,15 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename); cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename); + cfg->proxy_flag = GetPrivateProfileIntW(L"aime", L"proxyFlag", 2, filename); + + GetPrivateProfileStringW( + L"aime", + L"authdataPath", + L"DEVICE\\authdata.bin", + cfg->authdata_path, + _countof(cfg->authdata_path), + filename); } void io4_config_load(struct io4_config *cfg, const wchar_t *filename) diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index 08923fd..e54e0a7 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -5,21 +5,21 @@ #pragma pack(push, 1) enum { - SG_NFC_CMD_GET_FW_VERSION = 0x30, - SG_NFC_CMD_GET_HW_VERSION = 0x32, - SG_NFC_CMD_RADIO_ON = 0x40, - SG_NFC_CMD_RADIO_OFF = 0x41, - SG_NFC_CMD_POLL = 0x42, - SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, - SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50, - SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51, - SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, - SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55, - SG_NFC_CMD_TO_UPDATE_MODE = 0x60, - SG_NFC_CMD_SEND_HEX_DATA = 0x61, - SG_NFC_CMD_RESET = 0x62, - SG_NFC_CMD_FELICA_ENCAP = 0x71, + SG_NFC_CMD_GET_FW_VERSION = 0x30, + SG_NFC_CMD_GET_HW_VERSION = 0x32, + SG_NFC_CMD_RADIO_ON = 0x40, + SG_NFC_CMD_RADIO_OFF = 0x41, + SG_NFC_CMD_POLL = 0x42, + SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, + SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50, + SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME = 0x51, + SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, + SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, + SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA = 0x55, + SG_NFC_CMD_TO_UPDATE_MODE = 0x60, + SG_NFC_CMD_SEND_HEX_DATA = 0x61, + SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, }; struct sg_nfc_res_get_fw_version { diff --git a/board/sg-nfc.c b/board/sg-nfc.c index eac0984..a072111 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "util/dprintf.h" #include "util/dump.h" +#include "util/slurp.h" static HRESULT sg_nfc_dispatch( void *ctx, @@ -87,6 +89,8 @@ void sg_nfc_init( uint8_t addr, const struct sg_nfc_ops *ops, unsigned int gen, + unsigned int proxy_flag, + const wchar_t* authdata_path, void *ops_ctx) { assert(nfc != NULL); @@ -96,6 +100,8 @@ void sg_nfc_init( nfc->ops_ctx = ops_ctx; nfc->addr = addr; nfc->gen = gen; + nfc->proxy_flag = proxy_flag; + nfc->authdata_path = authdata_path; } #ifdef NDEBUG @@ -189,8 +195,8 @@ static HRESULT sg_nfc_dispatch( &req->felica_encap, &res->felica_encap); - case SG_NFC_CMD_MIFARE_AUTHENTICATE_A: - case SG_NFC_CMD_MIFARE_AUTHENTICATE_B: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA: case SG_NFC_CMD_SEND_HEX_DATA: return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); @@ -382,18 +388,62 @@ static HRESULT sg_nfc_cmd_mifare_read_block( sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no); - if (req->payload.block_no > 3) { + if (req->payload.block_no > 14) { sg_nfc_dprintf(nfc, "MIFARE block number out of range\n"); return E_FAIL; + } else if (req->payload.block_no >= 5){ // emoney auth encrypted + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + char* auth; + long size = wslurp(nfc->authdata_path, &auth, false); + if (size < 0){ + sg_nfc_dprintf(nfc, "Failed to read %ls: %lx!\n", nfc->authdata_path, GetLastError()); + return E_FAIL; + } + + int offset = 0; + if (req->payload.block_no == 6){ + offset = 16; + } else if (req->payload.block_no == 8){ + offset = 32; + } else if (req->payload.block_no == 9){ + offset = 48; + } else if (req->payload.block_no == 10){ + offset = 64; + } else if (req->payload.block_no == 12){ + offset = 82; + } else if (req->payload.block_no == 13){ + offset = 98; + } else if (req->payload.block_no == 14){ + offset = 114; + } + + for (int i = 0; i < 16 && offset + i < size; i++){ + res->block[i] = auth[offset + i]; + } + + free(auth); + + } else if (req->payload.block_no == 4){ // emoney auth plain + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + res->block[0] = 0x54; // header + res->block[1] = 0x43; + res->block[2] = nfc->proxy_flag; // 2 or 3 depending on game (useProxy in env.json) + res->block[3] = 0x01; // unknown flag + + } else { // read all other blocks normally + + sg_res_init(&res->res, &req->req, sizeof(res->block)); + + memcpy( res->block, + nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes, + sizeof(res->block)); } - sg_res_init(&res->res, &req->req, sizeof(res->block)); - - memcpy( res->block, - nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes, - sizeof(res->block)); - return S_OK; } diff --git a/board/sg-nfc.h b/board/sg-nfc.h index 3c8eb49..092b3e3 100644 --- a/board/sg-nfc.h +++ b/board/sg-nfc.h @@ -23,8 +23,10 @@ struct sg_nfc { void *ops_ctx; uint8_t addr; unsigned int gen; + unsigned int proxy_flag; struct felica felica; struct mifare mifare; + const wchar_t* authdata_path; }; void sg_nfc_init( @@ -32,6 +34,8 @@ void sg_nfc_init( uint8_t addr, const struct sg_nfc_ops *ops, unsigned int gen, + unsigned int proxy_flag, + const wchar_t* authdata_path, void *ops_ctx); void sg_nfc_transact( diff --git a/board/sg-reader.c b/board/sg-reader.c index bcc9701..2dc3c3d 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -81,7 +81,7 @@ HRESULT sg_reader_hook_init( return E_INVALIDARG; } - sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL); + sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, cfg->proxy_flag, cfg->authdata_path, NULL); sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL); InitializeCriticalSection(&sg_reader_lock); diff --git a/board/sg-reader.h b/board/sg-reader.h index 1824e28..64de7e9 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -12,6 +12,8 @@ struct aime_config { unsigned int port_no; bool high_baudrate; unsigned int gen; + unsigned int proxy_flag; + wchar_t authdata_path[MAX_PATH]; }; HRESULT sg_reader_hook_init( diff --git a/doc/config/common.md b/doc/config/common.md index 8ef48eb..1485feb 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -101,6 +101,18 @@ emulates an IC card in its proximity. A variety of different IC cards can be emulated; the exact choice of card that is emulated depends on the presence or absence of the configured card ID files. +### `proxyFlag` + +Default: `2` + +The "proxy flag" of the emulated Thinca authentication card. This should be 2 if no proxy is used, and 3 if it is. Invalid values will break Thinca authentication card reading. This information can be obtained by checking for the presence of "use_proxy: true" `tfps-res-pro\env.json`. + +### `authdataPath` + +Default: `DEVICE\authdata.bin` + +Path to the binary file containing data for a Thinca authentication card (see `emoney.txt`) + ## `[vfd]` Controls emulation of the VFD GP1232A02A FUTABA assembly. @@ -636,3 +648,19 @@ Default: Empty string Configure the location of the "Option" data mount point. This mount point is optional (hence the name, probably) and contains directories which contain minor over-the-air content updates. + +## `[epay]` + +Configure Thinca Payment (E-Money) emulation and hooks. + +### `enable` + +Default: `1` + +Enables the Thinca emulation. This will allow you to enable E-Money on compatible servers. + +### `hook` + +Default: `0` + +Enables hooking of respective Thinca DLL functions to emulate the existence of E-Money. This cannot be used with a real E-Money server. \ No newline at end of file diff --git a/doc/emoney.md b/doc/emoney.md new file mode 100644 index 0000000..9ef063f --- /dev/null +++ b/doc/emoney.md @@ -0,0 +1,189 @@ +# E-Money Authentication Procedure +by Haruka Akechi + +### SETTING UP + +1) Obtain the 64 byte long authentication card encryption key and the 32 byte long static authentication card ID. amdaemon.exe holds the secrets. + +2) Get this java file, insert the ID and key, probably edit the passphrase and compile+run to generate authcard.bin: https://gist.github.com/akechi-haruka/a506184638e695a04eabe8cb53f62c36 + +3) Place authcard.bin in your DEVICE folder. + +4) Check tfps-res-pro\env.json for your game. If it contains a "use_proxy: true" statement, add "proxy_flag=3" under [aime] + +5) Replace the two URLs in tfps-res-pro\resource.xml to your servers'. This is to ensure the Host header will match the certificate's. + +6) Where amdaemon.exe is located, there should be a "ca.pem". Replace this file with either [this](https://curl.se/ca/cacert.pem) for the most common CA's (including Let's Encrypt), or whatever CA the server is using (your server will provide this). + +7) Run your game and enter the test menu, and navigate to E-Money Settings. + +8) Select "Terminal Authentication" + +9) Hold your key for scanning a card (default: RETURN) + +10) If your shop name shows up, everything was done succesfully. Otherwise, check the VFD. + +### TECHNICAL INFO + +For debugging anything e-money related, I highly recommend setting "emoney.log.level" to 4 in your game's amdaemon config.json. This should create a `\emoney_log\thincapayment.log`. + +When terminal authentication is started from the test menu, the game will check for an Aime reader of at least generation 3. If that is not fulfilled, the VFD will display "unsupported card reader" and abort. If the card reader is good, the VFD will prompt for a card to be touched, and the reader will start scanning for a MIFARE card, which from this point we call "Thinca Authentication Card". This card contains one unencrypted block (3) which contains: + +[0] = 0x54 // T + +[1] = 0x43 // C + +[2] = proxy_type + +[3] = 0x01 + +Afterwards, a number of encrypted blocks are read, namely the blocks 5,6,8,9,10,12,13 and 14. These blocks together form a 130 byte long binary blob that contains the authentication data. + +This data is encrypted as following: + +Given a fixed 0x40 byte long encryption key and a fixed 0x20 byte long static "card ID", both of which can be found in amdaemon: +XOR every byte of the encryption key with 0x1C. +Calculate a 0x20 bytes long HMAC-SHA-256 of the card ID with the XOR'ed encryption key as the key. +Calculate the needed IV by XORing the lower 0x10 bytes of the HMAC with the upper 0x10 bytes of the HMAC: + +``` +byte[] iv = new byte[16]; +for (int i = 0; i < 16; i++) { + iv[i] = (byte) (hmac[i + 16] ^ hmac[i]); +} +``` + +With this IV, and the HMAC as the key, finally encrypt the data with AES/CBC/PKCS5Padding. + +Now what is actually stored on such a card? This: + +``` ++---------------+---------------+-----------------+------------+----------+ +| Store Card ID | Merchant Code | Store Branch ID | Passphrase | NULL | ++---------------+---------------+-----------------+------------+----------+ +| 0x10 bytes | 0x14 bytes | 0xC bytes | 0x10 bytes | 0x1 byte | +| char* | char* | uint128_t | char* | NULL | ++---------------+---------------+-----------------+------------+----------+ +``` + +Only two things really matter here. The Store Branch ID must be non-zero, otherwise amdaemon will reject it, and the passphrase, which is the PFX key password for the certificate returned in the network response (see below). + +Technically with the Store Card ID you could bind different auth cards to different users, but for home usage, it really doesn't matter. + +That's the Thinca Authentication Card out of the way, so continue on to: + +### NETWORK + +First, a regular HTTP(S) connection will be made to the URL specified in tfps-res-pro\env.json, tasms.root_endpoint. + +Request Data: +`{"modelName":"ACA","serialNumber":"ACAE01A9999","merchantCode":"NOTSEGA","storeBranchNumber":11111,"storeCardId":"FAKESTORE"}` + +Note that the serialNumber here actually isn't the keychip ID, but rather the PCBID. The three other values are read from the Thinca Authentication Card. + +Response Headers: +`x-certificate-md5: ` + +Response Data: +``` +{ + "certificate": "", + "initSettings": { + "endpoints": { + "terminals": { + "uri": "https://localhost/emoney/terminals" + }, + "statuses": { + "uri": "https://localhost/emoney/statuses" + }, + "sales": { + "uri": "https://localhost/emoney/sales" + }, + "counters": { + "uri": "https://localhost/emoney/counters" + } + }, + "intervals": { + "checkSetting": 60, + "sendStatus": 60 + }, + "settigsType": "AmusementTerminalSettings", // sic + "status": "1", // a string + "terminalId": "536453645364536453645364536453", // must be exactly 30 characters + "version": "2024-01-01T01:01:01", // a timestamp + "availableElectronicMoney": [ + 1, + 2, + 3, + 5, + 6, + 8, + 9, + 91, // aimepay + 101 // "cash" ??? + ], + "cashAvailability": true, + "productCode": 1337 + } +} +``` + +Next up, we will connect to the TLAM service to get the URL for the TCAP service. Everything from this point on requires not only HTTPS, but also client certificate validation (which is the certificate returned from the previous request). Technically you don't need to validate it, but you must accept a client certificate or the client HTTPS library will not be happy. + +The client certificate itself must be signed with the same key than the server's HTTPS certificate. + +The client AND server certificate must have it's CA included in the "ca.pem" file in amdaemon's directory. You can freely replace this file with https://curl.se/ca/cacert.pem to allow Let's Encrypt and whatever else. + +At this point, "ThincaPayment::setClientCertificate(). ErrCode 203" means that the downloaded file couldn't be found, or the certificate password is wrong. + +[Warn ] TCAP communicate error 06514086 means the ca.pem has no entry for the given server CA. + +TLAM: +The TLAM url comes from tftp-res-pro\resource.xml, commonPrimaryUri. + +/initauth.jsp + +Request Data: + +Response Headers: +`Content-Type: application/x-tlam` +Response Data: +`SERV=https://localhost/emoney/tcap` + +TCAP: +Here be dragons. + +Is it this?? https://en.wikipedia.org/wiki/Transaction_Capabilities_Application_Part +Maybe thincatcapclient.dll holds the secrets? + +Request Data: +``` +02 05 01 00 ba 00 00 00 21 00 00 00 00 00 25 00 ....º... !.....%. +9f 00 01 00 00 07 47 65 6e 65 72 69 63 06 43 4c ......Ge neric.CL +49 45 4e 54 00 02 00 00 07 47 65 6e 65 72 69 63 IENT.... .Generic +06 53 54 41 54 55 53 00 03 00 00 07 47 65 6e 65 .STATUS. ....Gene +72 69 63 06 4f 50 54 49 4f 4e 00 04 00 00 06 46 ric.OPTI ON.....F +65 6c 69 43 61 03 52 2f 57 00 05 00 00 07 47 65 eliCa.R/ W.....Ge +6e 65 72 69 63 09 52 2f 57 5f 45 56 45 4e 54 00 neric.R/ W_EVENT. +06 00 00 07 47 65 6e 65 72 69 63 0a 52 2f 57 5f ....Gene ric.R/W_ +53 54 41 54 55 53 00 07 00 00 07 47 65 6e 65 72 STATUS.. ...Gener +69 63 0a 52 2f 57 5f 4f 50 54 49 4f 4e 00 08 00 ic.R/W_O PTION... +00 07 47 65 6e 65 72 69 63 06 4e 46 43 5f 52 57 ..Generi c.NFC_RW +00 00 00 26 00 03 02 05 00 00 00 00 22 00 00 ...&.... ....".. +``` + +and +``` +02 05 03 00 17 00 00 00 21 00 11 34 34 20 30 30 ........ !..44 00 +20 30 31 20 32 31 20 30 30 20 30 30 01 21 0 0 00 +``` + +Response Headers: +``` +Content-Type: application/x-tcap +Transfer-Encoding: chunked +``` +Response Data: +???? + +To be continued ... \ No newline at end of file diff --git a/hooklib/dns.c b/hooklib/dns.c index 45b463e..9e06e5b 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -217,20 +217,24 @@ static void dns_hook_init(void) dns_hook_initted = true; InitializeCriticalSection(&dns_hook_lock); + dns_hook_apply_hooks(NULL); +} + +void dns_hook_apply_hooks(HMODULE mod){ hook_table_apply( - NULL, + mod, "dnsapi.dll", dns_hook_syms_dnsapi, _countof(dns_hook_syms_dnsapi)); hook_table_apply( - NULL, + mod, "ws2_32.dll", dns_hook_syms_ws2, _countof(dns_hook_syms_ws2)); hook_table_apply( - NULL, + mod, "winhttp.dll", dns_hook_syms_winhttp, _countof(dns_hook_syms_winhttp)); diff --git a/hooklib/dns.h b/hooklib/dns.h index 9279a37..b03f7dc 100644 --- a/hooklib/dns.h +++ b/hooklib/dns.h @@ -8,3 +8,4 @@ void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, // if to_src is NULL, all lookups for from_src will fail HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src); +void dns_hook_apply_hooks(HMODULE mod); diff --git a/hooklib/path.c b/hooklib/path.c index 82f97e2..1afb8a8 100644 --- a/hooklib/path.c +++ b/hooklib/path.c @@ -11,6 +11,8 @@ #include "hooklib/path.h" +#include + /* Helpers */ static void path_hook_init(void); @@ -533,6 +535,12 @@ static BOOL path_transform_w(wchar_t **out, const wchar_t *src) goto end; } +#if LOG_VFS + if (!wcsstr(src, L"AppUser")) { + dprintf("Path: %ls -> %ls\n", src, dest); + } +#endif + break; } diff --git a/meson.build b/meson.build index aada974..9eea85d 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,9 @@ endif if get_option('log_all') or get_option('log_clock') add_project_arguments('-DLOG_CLOCK', language: 'c') endif +if get_option('log_all') or get_option('log_vfs') + add_project_arguments('-DLOG_VFS', language: 'c') +endif shlwapi_lib = cc.find_library('shlwapi') dinput8_lib = cc.find_library('dinput8') diff --git a/meson_options.txt b/meson_options.txt index de9aefc..b6989f4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -69,7 +69,12 @@ option('log_mercury_slider', description : 'Enable debug logging for the WACCA Slider' ) option('log_clock', - type : 'boolean', - value : false, - description : 'Enable debug logging for clock APIs' + type : 'boolean', + value : false, + description : 'Enable debug logging for clock APIs' +) +option('log_vfs', + type : 'boolean', + value : false, + description : 'Enable debug logging for file system redirections' ) diff --git a/platform/config.c b/platform/config.c index 2904019..c9777da 100644 --- a/platform/config.c +++ b/platform/config.c @@ -360,4 +360,5 @@ void epay_config_load(struct epay_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); + cfg->hook = GetPrivateProfileIntW(L"epay", L"hook", 0, filename); } diff --git a/platform/epay.c b/platform/epay.c index 4a231c2..6193a2d 100644 --- a/platform/epay.c +++ b/platform/epay.c @@ -7,10 +7,13 @@ #include "hook/table.h" +#include "hooklib/dns.h" #include "hooklib/reg.h" #include "platform/epay.h" +#include + #include "util/dprintf.h" static HRESULT misc_read_thinca_adapter(void *bytes, uint32_t *nbytes); @@ -119,15 +122,8 @@ static const struct hook_symbol epay_syms[] = { } }; -HRESULT epay_hook_init(const struct epay_config *cfg) { - HRESULT hr; - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - hr = reg_hook_push_key( +HRESULT epay_apply_registry_hooks(){ + HRESULT hr = reg_hook_push_key( HKEY_LOCAL_MACHINE, L"SOFTWARE\\TFPaymentService\\ThincaRwAdapter", epay_adapter_keys, @@ -162,34 +158,69 @@ HRESULT epay_hook_init(const struct epay_config *cfg) { L"SOFTWARE\\TFPaymentService\\ThincaTcapClient\\URL1", epay_tcap_url1_keys, _countof(epay_tcap_url1_keys)); - - hook_table_apply( - NULL, - "ThincaPayment.dll", - epay_syms, - _countof(epay_syms)); - - thinca_stub = (struct thinca_main *)malloc(sizeof(struct thinca_main)); - thinca_stub->impl1 = (struct thinca_impl *)malloc(sizeof(struct thinca_impl)); - thinca_stub->impl1->unk8 = thinca_unk8; - thinca_stub->impl1->initialize = thinca_initialize; - thinca_stub->impl1->dispose = thinca_dispose; - thinca_stub->impl1->setResource = thinca_set_resource; - thinca_stub->impl1->setThincaPaymentLog = thinca_set_pay_log; - thinca_stub->impl1->setThincaEventInterface = thinca_set_evt_handler; - thinca_stub->impl1->setIcasClientLog = thinca_set_client_log; - thinca_stub->impl1->setIcasClientConfig = thinca_set_client_cfg; - thinca_stub->impl1->setGoodsCode = thinca_set_goods_code; - thinca_stub->impl1->setTerminalSerial = thinca_set_serial; - thinca_stub->impl1->setClientCertificate = thinca_set_cert; - thinca_stub->impl1->checkDeal = thinca_check_deal; - thinca_stub->impl1->cancelRequest = thinca_cancel; - thinca_stub->impl1->selectButton = thinca_select; - thinca_stub->impl1->unk220 = thinca_unk; - thinca_stub->impl1->unk228 = thinca_unk; - - dprintf("Epay: Init.\n"); + return hr; +} + +HRESULT epay_hook_init(const struct epay_config *cfg) { + HRESULT hr; + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + hr = epay_apply_registry_hooks(); + if (FAILED(hr)){ + return hr; + } + + dprintf("EPay: Registry initialized\n"); + + // HACK:(?) the DLLs are loaded dynamically so we just preload it and apply DNS and VFS hooks to it + HMODULE thincahttpclient = LoadLibraryA("thincahttpclient.dll"); + if (thincahttpclient != NULL){ + dns_hook_apply_hooks(thincahttpclient); + path_hook_insert_hooks(thincahttpclient); + } + HMODULE thincapayment = LoadLibraryA("ThincaPayment.dll"); + if (thincapayment != NULL){ + path_hook_insert_hooks(thincapayment); + } + HMODULE thincatcapclient = LoadLibraryA("thincatcapclient.dll"); + if (thincatcapclient != NULL){ + path_hook_insert_hooks(thincatcapclient); + } + + if (cfg->hook) { + hook_table_apply( + NULL, + "ThincaPayment.dll", + epay_syms, + _countof(epay_syms)); + + thinca_stub = (struct thinca_main *) malloc(sizeof(struct thinca_main)); + thinca_stub->impl1 = (struct thinca_impl *) malloc(sizeof(struct thinca_impl)); + + thinca_stub->impl1->unk8 = thinca_unk8; + thinca_stub->impl1->initialize = thinca_initialize; + thinca_stub->impl1->dispose = thinca_dispose; + thinca_stub->impl1->setResource = thinca_set_resource; + thinca_stub->impl1->setThincaPaymentLog = thinca_set_pay_log; + thinca_stub->impl1->setThincaEventInterface = thinca_set_evt_handler; + thinca_stub->impl1->setIcasClientLog = thinca_set_client_log; + thinca_stub->impl1->setIcasClientConfig = thinca_set_client_cfg; + thinca_stub->impl1->setGoodsCode = thinca_set_goods_code; + thinca_stub->impl1->setTerminalSerial = thinca_set_serial; + thinca_stub->impl1->setClientCertificate = thinca_set_cert; + thinca_stub->impl1->checkDeal = thinca_check_deal; + thinca_stub->impl1->cancelRequest = thinca_cancel; + thinca_stub->impl1->selectButton = thinca_select; + thinca_stub->impl1->unk220 = thinca_unk; + thinca_stub->impl1->unk228 = thinca_unk; + + dprintf("Epay: Hooks initialized\n"); + } return hr; } diff --git a/platform/epay.h b/platform/epay.h index 6b5659b..70aa886 100644 --- a/platform/epay.h +++ b/platform/epay.h @@ -7,6 +7,7 @@ #pragma pack(push,1) struct epay_config { bool enable; + bool hook; }; /* The functions in these structs are how clients like amdaemon interface @@ -61,4 +62,5 @@ struct thinca_main { }; #pragma pack(pop) -HRESULT epay_hook_init(const struct epay_config *cfg); \ No newline at end of file +HRESULT epay_hook_init(const struct epay_config *cfg); +HRESULT epay_apply_registry_hooks(); \ No newline at end of file diff --git a/util/meson.build b/util/meson.build index 0274ad5..58782d3 100644 --- a/util/meson.build +++ b/util/meson.build @@ -21,6 +21,8 @@ util_lib = static_library( 'get_function_ordinal.h', 'lib.c', 'lib.h', + 'slurp.c', + 'slurp.h', 'str.c', 'str.h', 'env.c', diff --git a/util/slurp.c b/util/slurp.c new file mode 100644 index 0000000..1af73a4 --- /dev/null +++ b/util/slurp.c @@ -0,0 +1,67 @@ +#include +#include +#include +/* + * 'slurp' reads the file identified by 'path' into a character buffer + * pointed at by 'buf', optionally adding a terminating NUL if + * 'add_nul' is true. On success, the size of the file is returned; on + * failure, -1 is returned and ERRNO is set by the underlying system + * or library call that failed. + * + * WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by + * the caller. + */ +long wslurp(const wchar_t* path, char **buf, bool add_nul) +{ + FILE *fp; + size_t fsz; + long off_end; + int rc; + + /* Open the file */ + fp = _wfopen(path, L"rb"); + if( NULL == fp ) { + return -1L; + } + + /* Seek to the end of the file */ + rc = fseek(fp, 0L, SEEK_END); + if( 0 != rc ) { + return -1L; + } + + /* Byte offset to the end of the file (size) */ + if( 0 > (off_end = ftell(fp)) ) { + return -1L; + } + fsz = (size_t)off_end; + + /* Allocate a buffer to hold the whole file */ + *buf = malloc( fsz+(int)add_nul ); + if( NULL == *buf ) { + return -1L; + } + + /* Rewind file pointer to start of file */ + rewind(fp); + + /* Slurp file into buffer */ + if( fsz != fread(*buf, 1, fsz, fp) ) { + free(*buf); + return -1L; + } + + /* Close the file */ + if( EOF == fclose(fp) ) { + free(*buf); + return -1L; + } + + if( add_nul ) { + /* Make sure the buffer is NUL-terminated, just in case */ + buf[fsz] = '\0'; + } + + /* Return the file size */ + return (long)fsz; +} \ No newline at end of file diff --git a/util/slurp.h b/util/slurp.h new file mode 100644 index 0000000..407a2d8 --- /dev/null +++ b/util/slurp.h @@ -0,0 +1,12 @@ +#include +/* + * 'slurp' reads the file identified by 'path' into a character buffer + * pointed at by 'buf', optionally adding a terminating NUL if + * 'add_nul' is true. On success, the size of the file is returned; on + * failure, -1 is returned and ERRNO is set by the underlying system + * or library call that failed. + * + * WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by + * the caller. + */ +long wslurp(const wchar_t* path, char **buf, bool add_nul); \ No newline at end of file From 015097972a87650eb36cd162c842a30892b66cc5 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 17 Apr 2025 19:17:42 +0200 Subject: [PATCH 200/204] emoney: improce doc and add python script --- doc/emoney.md | 38 +++++++++--- emoney/authcardgen.py | 131 ++++++++++++++++++++++++++++++++++++++++ emoney/requirements.txt | 2 + 3 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 emoney/authcardgen.py create mode 100644 emoney/requirements.txt diff --git a/doc/emoney.md b/doc/emoney.md index 9ef063f..05a6192 100644 --- a/doc/emoney.md +++ b/doc/emoney.md @@ -3,17 +3,41 @@ by Haruka Akechi ### SETTING UP -1) Obtain the 64 byte long authentication card encryption key and the 32 byte long static authentication card ID. amdaemon.exe holds the secrets. +1) Obtain the 64 byte long authentication card encryption key. `amdaemon.exe` holds the secrets. -2) Get this java file, insert the ID and key, probably edit the passphrase and compile+run to generate authcard.bin: https://gist.github.com/akechi-haruka/a506184638e695a04eabe8cb53f62c36 +2) Inside the `emoney\` folder, install the python modules and launch the generator script: -3) Place authcard.bin in your DEVICE folder. +```shell +python -m pip install -r requirements.txt +python authcardgen.py --key +``` -4) Check tfps-res-pro\env.json for your game. If it contains a "use_proxy: true" statement, add "proxy_flag=3" under [aime] +``` +Usage: authcardgen.py [OPTIONS] -5) Replace the two URLs in tfps-res-pro\resource.xml to your servers'. This is to ensure the Host header will match the certificate's. +Options: + --cardid TEXT Card ID (64 hex characters) + --key TEXT Key (128 hex characters, required) [required] + --store-card-id TEXT Store Card ID (padded to 16 bytes) + --merchant-code TEXT Merchant Code (padded to 20 bytes) + --store-branch-id TEXT Store Branch ID (padded to 12 bytes) + --passphrase TEXT Passphrase, used for the pfx password (padded to 16 bytes) + --output TEXT Output filename + --help Show this message and exit. +``` -6) Where amdaemon.exe is located, there should be a "ca.pem". Replace this file with either [this](https://curl.se/ca/cacert.pem) for the most common CA's (including Let's Encrypt), or whatever CA the server is using (your server will provide this). +3) Place the generated `authcard.bin` in your `DEVICE\` folder. + +4) Check `tfps-res-pro\env.json` for your game. If it contains a `"use_proxy": true` statement, add to segatools.ini: + +```ini +[aime] +proxy_flag=3 +``` + +5) Replace the two URLs in `tfps-res-pro\resource.xml` to your servers'. This is to ensure the Host header will match the certificate's. + +6) Where amdaemon.exe is located, there should be a `ca.pem`. Replace this file with either [this](https://curl.se/ca/cacert.pem) for the most common CA's (including Let's Encrypt), or whatever CA the server is using (your server will provide this). 7) Run your game and enter the test menu, and navigate to E-Money Settings. @@ -66,7 +90,7 @@ Now what is actually stored on such a card? This: +---------------+---------------+-----------------+------------+----------+ ``` -Only two things really matter here. The Store Branch ID must be non-zero, otherwise amdaemon will reject it, and the passphrase, which is the PFX key password for the certificate returned in the network response (see below). +Only two things really matter here. The Store Branch ID must be non-zero, otherwise amdaemon will reject it, and the passphrase, which is the PFX key password (passphrase during authcard creation) for the certificate returned in the network response (see below). Technically with the Store Card ID you could bind different auth cards to different users, but for home usage, it really doesn't matter. diff --git a/emoney/authcardgen.py b/emoney/authcardgen.py new file mode 100644 index 0000000..ae821be --- /dev/null +++ b/emoney/authcardgen.py @@ -0,0 +1,131 @@ +import hmac +import hashlib +import click + +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad, unpad +from pathlib import Path + + +class CardEncryptor: + def __init__( + self, + cardid_hex, + key_hex, + store_card_id_str="FAKESTORE", + merchant_code_str="NOTSEGA", + store_branch_id_str="11111", + passphrase_str="573", + output_file="authdata.bin", + ): + self.cardid = bytes.fromhex(cardid_hex) + self.key = bytearray.fromhex(key_hex) + self.output_file = output_file + + if len(self.cardid) != 0x20: + raise ValueError("Card ID must be 32 bytes (64 hex characters)") + if len(self.key) != 0x40: + raise ValueError("Key must be 64 bytes (128 hex characters)") + + # XOR the key with 0x1C as in original Java + for i in range(len(self.key)): + self.key[i] ^= 0x1C + + self.store_card_id = self._str_to_bytes(store_card_id_str, 0x10) + self.merchant_code = self._str_to_bytes(merchant_code_str, 0x14) + self.store_branch_id = self._str_to_bytes(store_branch_id_str, 0x0C) + self.passphrase = self._str_to_bytes(passphrase_str, 0x10) + + # Construct full data payload + self.data = ( + self.store_card_id + + self.merchant_code + + self.store_branch_id + + self.passphrase + + bytes([0x00]) # +1 null terminator / padding byte + ) + + def _str_to_bytes(self, s, length): + b = bytearray(length) + b[: len(s)] = s.encode() + return bytes(b) + + def _bytes_to_str(self, b): + return b.decode() + + def _bytes_to_hex(self, b): + return b.hex().upper() + + def _calculate_hmac_sha256(self, key, data, length): + h = hmac.new(key, data, hashlib.sha256) + return h.digest()[:length] + + def _aes_cbc_encrypt(self, key, data, iv): + cipher = AES.new(key, AES.MODE_CBC, iv) + return cipher.encrypt(pad(data, AES.block_size)) + + def _aes_cbc_decrypt(self, key, data, iv): + cipher = AES.new(key, AES.MODE_CBC, iv) + return unpad(cipher.decrypt(data), AES.block_size) + + def run(self): + print("Card ID:\t\t", self._bytes_to_hex(self.cardid)) + print("Store Card ID:\t\t", self._bytes_to_str(self.store_card_id)) + print("Merchant Code:\t\t", self._bytes_to_str(self.merchant_code)) + print("Store Branch ID:\t", self._bytes_to_str(self.store_branch_id)) + print("Passphrase:\t\t", self._bytes_to_str(self.passphrase)) + + hmac_output = self._calculate_hmac_sha256(self.key, self.cardid, 0x20) + # print("HMAC:\t\t", self._bytes_to_hex(hmac_output)) + + iv = bytes([hmac_output[i + 16] ^ hmac_output[i] for i in range(16)]) + # print("IV:\t\t", self._bytes_to_hex(iv)) + + encrypted = self._aes_cbc_encrypt(hmac_output, self.data, iv) + # print("ENCRYPTED:\t", self._bytes_to_hex(encrypted)) + Path(self.output_file).write_bytes(encrypted) + + decrypted = self._aes_cbc_decrypt(hmac_output, encrypted, iv) + # print("DECRYPTED:\t", self._bytes_to_hex(decrypted)) + + +@click.command() +@click.option( + "--cardid", + default="0102030401020304010203040102030401020304010203040102030401020304", + help="Card ID (64 hex characters)", +) +@click.option( + "--key", + required=True, + help="Key (128 hex characters, required)", +) +@click.option( + "--store-card-id", default="FAKESTORE", help="Store Card ID (padded to 16 bytes)" +) +@click.option( + "--merchant-code", default="NOTSEGA", help="Merchant Code (padded to 20 bytes)" +) +@click.option( + "--store-branch-id", default="11111", help="Store Branch ID (padded to 12 bytes)" +) +@click.option("--passphrase", default="573", help="Passphrase, used for the pfx password (padded to 16 bytes)") +@click.option("--output", default="authdata.bin", help="Output filename") +def cli(cardid, key, store_card_id, merchant_code, store_branch_id, passphrase, output): + if len(key) != 128 or not all(c in "0123456789abcdefABCDEF" for c in key): + raise click.BadParameter("The key must be a 128-character hexadecimal string.") + + encryptor = CardEncryptor( + cardid, + key, + store_card_id_str=store_card_id, + merchant_code_str=merchant_code, + store_branch_id_str=store_branch_id, + passphrase_str=passphrase, + output_file=output, + ) + encryptor.run() + + +if __name__ == "__main__": + cli() diff --git a/emoney/requirements.txt b/emoney/requirements.txt new file mode 100644 index 0000000..b21ba16 --- /dev/null +++ b/emoney/requirements.txt @@ -0,0 +1,2 @@ +click +pycryptodome From ae3dd666f4be789433f5ac73ed32fefc5b1b5114 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 17 Apr 2025 19:31:37 +0200 Subject: [PATCH 201/204] refactor all common parts and games --- Makefile | 2 + Package.mk | 34 +-- {aimeio => common/aimeio}/aimeio.c | 0 {aimeio => common/aimeio}/aimeio.h | 0 {aimeio => common/aimeio}/meson.build | 0 {amex => common/amex}/amex.c | 0 {amex => common/amex}/amex.h | 0 {amex => common/amex}/config.c | 0 {amex => common/amex}/config.h | 0 {amex => common/amex}/ds.c | 0 {amex => common/amex}/ds.h | 0 {amex => common/amex}/eeprom.c | 0 {amex => common/amex}/eeprom.h | 0 {amex => common/amex}/gpio.c | 0 {amex => common/amex}/gpio.h | 0 {amex => common/amex}/guid.c | 0 {amex => common/amex}/jvs.c | 0 {amex => common/amex}/jvs.h | 0 {amex => common/amex}/meson.build | 0 {amex => common/amex}/nvram.c | 0 {amex => common/amex}/nvram.h | 0 {amex => common/amex}/sram.c | 0 {amex => common/amex}/sram.h | 0 {board => common/board}/aime-dll.c | 0 {board => common/board}/aime-dll.h | 0 {board => common/board}/config.c | 0 {board => common/board}/config.h | 0 {board => common/board}/ffb.c | 0 {board => common/board}/ffb.h | 0 {board => common/board}/guid.c | 0 {board => common/board}/guid.h | 0 {board => common/board}/io3.c | 0 {board => common/board}/io3.h | 0 {board => common/board}/io4.c | 0 {board => common/board}/io4.h | 0 {board => common/board}/led15070-cmd.h | 0 {board => common/board}/led15070-frame.c | 0 {board => common/board}/led15070-frame.h | 0 {board => common/board}/led15070.c | 0 {board => common/board}/led15070.h | 0 {board => common/board}/led15093-cmd.h | 0 {board => common/board}/led15093-frame.c | 0 {board => common/board}/led15093-frame.h | 0 {board => common/board}/led15093.c | 0 {board => common/board}/led15093.h | 0 {board => common/board}/meson.build | 3 + {board => common/board}/sg-cmd.c | 0 {board => common/board}/sg-cmd.h | 0 {board => common/board}/sg-frame.c | 0 {board => common/board}/sg-frame.h | 0 {board => common/board}/sg-led-cmd.h | 0 {board => common/board}/sg-led.c | 0 {board => common/board}/sg-led.h | 0 {board => common/board}/sg-nfc-cmd.h | 0 {board => common/board}/sg-nfc.c | 1 + {board => common/board}/sg-nfc.h | 0 {board => common/board}/sg-reader.c | 0 {board => common/board}/sg-reader.h | 0 {board => common/board}/slider-cmd.h | 0 {board => common/board}/slider-frame.c | 0 {board => common/board}/slider-frame.h | 0 {board => common/board}/vfd-cmd.h | 0 {board => common/board}/vfd-frame.c | 0 {board => common/board}/vfd-frame.h | 0 {board => common/board}/vfd.c | 0 {board => common/board}/vfd.h | 0 {gfxhook => common/gfxhook}/config.c | 0 {gfxhook => common/gfxhook}/config.h | 0 {gfxhook => common/gfxhook}/d3d11.c | 0 {gfxhook => common/gfxhook}/d3d11.h | 0 {gfxhook => common/gfxhook}/d3d9.c | 0 {gfxhook => common/gfxhook}/d3d9.h | 0 {gfxhook => common/gfxhook}/dxgi.c | 0 {gfxhook => common/gfxhook}/dxgi.h | 0 {gfxhook => common/gfxhook}/gfx.c | 0 {gfxhook => common/gfxhook}/gfx.h | 0 {gfxhook => common/gfxhook}/gl.c | 0 {gfxhook => common/gfxhook}/gl.h | 0 {gfxhook => common/gfxhook}/meson.build | 0 {gfxhook => common/gfxhook}/util.c | 0 {gfxhook => common/gfxhook}/util.h | 0 {hooklib => common/hooklib}/config.c | 0 {hooklib => common/hooklib}/config.h | 0 {hooklib => common/hooklib}/createprocess.c | 0 {hooklib => common/hooklib}/createprocess.h | 0 {hooklib => common/hooklib}/cursor.c | 0 {hooklib => common/hooklib}/cursor.h | 0 {hooklib => common/hooklib}/dll.c | 0 {hooklib => common/hooklib}/dll.h | 0 {hooklib => common/hooklib}/dns.c | 0 {hooklib => common/hooklib}/dns.h | 0 {hooklib => common/hooklib}/dvd.c | 0 {hooklib => common/hooklib}/dvd.h | 0 {hooklib => common/hooklib}/fdshark.c | 0 {hooklib => common/hooklib}/fdshark.h | 0 {hooklib => common/hooklib}/meson.build | 0 {hooklib => common/hooklib}/path.c | 0 {hooklib => common/hooklib}/path.h | 0 {hooklib => common/hooklib}/printer.c | 0 {hooklib => common/hooklib}/printer.h | 0 {hooklib => common/hooklib}/reg.c | 0 {hooklib => common/hooklib}/reg.h | 0 {hooklib => common/hooklib}/setupapi.c | 0 {hooklib => common/hooklib}/setupapi.h | 0 {hooklib => common/hooklib}/spike.c | 0 {hooklib => common/hooklib}/spike.h | 0 {hooklib => common/hooklib}/touch.c | 0 {hooklib => common/hooklib}/touch.h | 0 {iccard => common/iccard}/aime.c | 0 {iccard => common/iccard}/aime.h | 0 {iccard => common/iccard}/felica.c | 0 {iccard => common/iccard}/felica.h | 0 {iccard => common/iccard}/meson.build | 0 {iccard => common/iccard}/mifare.h | 0 {jvs => common/jvs}/jvs-bus.c | 0 {jvs => common/jvs}/jvs-bus.h | 0 {jvs => common/jvs}/jvs-cmd.h | 0 {jvs => common/jvs}/jvs-frame.c | 0 {jvs => common/jvs}/jvs-frame.h | 0 {jvs => common/jvs}/jvs-util.c | 0 {jvs => common/jvs}/jvs-util.h | 0 {jvs => common/jvs}/meson.build | 0 {platform => common/platform}/amvideo.c | 0 {platform => common/platform}/amvideo.h | 0 {platform => common/platform}/clock.c | 0 {platform => common/platform}/clock.h | 0 {platform => common/platform}/config.c | 0 {platform => common/platform}/config.h | 0 {platform => common/platform}/dns.c | 0 {platform => common/platform}/dns.h | 0 {platform => common/platform}/epay.c | 0 {platform => common/platform}/epay.h | 0 {platform => common/platform}/hwmon.c | 0 {platform => common/platform}/hwmon.h | 0 {platform => common/platform}/hwreset.c | 0 {platform => common/platform}/hwreset.h | 0 {platform => common/platform}/meson.build | 0 {platform => common/platform}/misc.c | 0 {platform => common/platform}/misc.h | 0 {platform => common/platform}/netenv.c | 0 {platform => common/platform}/netenv.h | 0 {platform => common/platform}/nusec.c | 0 {platform => common/platform}/nusec.h | 0 {platform => common/platform}/pcbid.c | 0 {platform => common/platform}/pcbid.h | 0 {platform => common/platform}/platform.c | 0 {platform => common/platform}/platform.h | 0 {platform => common/platform}/system.c | 2 +- {platform => common/platform}/system.h | 0 {platform => common/platform}/vfs.c | 0 {platform => common/platform}/vfs.h | 0 {unityhook => common/unityhook}/config.c | 0 {unityhook => common/unityhook}/config.h | 24 +-- {unityhook => common/unityhook}/doorstop.c | 0 {unityhook => common/unityhook}/doorstop.h | 8 +- {unityhook => common/unityhook}/hook.c | 0 {unityhook => common/unityhook}/hook.h | 18 +- {unityhook => common/unityhook}/meson.build | 38 ++-- {unityhook => common/unityhook}/mono.h | 198 +++++++++--------- {unityhook => common/unityhook}/util.h | 40 ++-- {util => common/util}/async.c | 0 {util => common/util}/async.h | 0 {util => common/util}/crc.c | 0 {util => common/util}/crc.h | 0 {util => common/util}/dll-bind.c | 0 {util => common/util}/dll-bind.h | 0 {util => common/util}/dprintf.c | 0 {util => common/util}/dprintf.h | 0 {util => common/util}/dump.c | 0 {util => common/util}/dump.h | 0 {util => common/util}/env.c | 0 {util => common/util}/env.h | 0 {util => common/util}/get_function_ordinal.c | 0 {util => common/util}/get_function_ordinal.h | 0 {util => common/util}/lib.c | 0 {util => common/util}/lib.h | 0 {util => common/util}/meson.build | 0 {util => common/util}/slurp.c | 0 {util => common/util}/slurp.h | 0 {util => common/util}/str.c | 0 {util => common/util}/str.h | 0 dist/fgo/launch.bat | 2 +- {carolhook => games/carolhook}/carol-dll.c | 0 {carolhook => games/carolhook}/carol-dll.h | 0 {carolhook => games/carolhook}/carolhook.def | 0 {carolhook => games/carolhook}/config.c | 0 {carolhook => games/carolhook}/config.h | 0 {carolhook => games/carolhook}/controlbd.c | 0 {carolhook => games/carolhook}/controlbd.h | 0 {carolhook => games/carolhook}/dllmain.c | 0 {carolhook => games/carolhook}/jvs.c | 0 {carolhook => games/carolhook}/jvs.h | 0 {carolhook => games/carolhook}/ledbd.c | 0 {carolhook => games/carolhook}/ledbd.h | 0 {carolhook => games/carolhook}/meson.build | 0 {carolhook => games/carolhook}/touch.c | 0 {carolhook => games/carolhook}/touch.h | 0 {carolio => games/carolio}/carolio.c | 0 {carolio => games/carolio}/carolio.h | 0 {carolio => games/carolio}/config.c | 0 {carolio => games/carolio}/config.h | 0 {carolio => games/carolio}/meson.build | 0 {chunihook => games/chunihook}/chuni-dll.c | 0 {chunihook => games/chunihook}/chuni-dll.h | 0 {chunihook => games/chunihook}/chunihook.def | 0 {chunihook => games/chunihook}/config.c | 0 {chunihook => games/chunihook}/config.h | 0 {chunihook => games/chunihook}/dllmain.c | 0 {chunihook => games/chunihook}/jvs.c | 0 {chunihook => games/chunihook}/jvs.h | 0 {chunihook => games/chunihook}/meson.build | 0 {chunihook => games/chunihook}/slider.c | 0 {chunihook => games/chunihook}/slider.h | 0 {chuniio => games/chuniio}/chu2to3.c | 0 {chuniio => games/chuniio}/chu2to3.h | 0 {chuniio => games/chuniio}/chuniio.c | 0 {chuniio => games/chuniio}/chuniio.h | 0 {chuniio => games/chuniio}/config.c | 0 {chuniio => games/chuniio}/config.h | 0 {chuniio => games/chuniio}/leddata.h | 0 {chuniio => games/chuniio}/ledoutput.c | 0 {chuniio => games/chuniio}/ledoutput.h | 0 {chuniio => games/chuniio}/meson.build | 0 {chuniio => games/chuniio}/pipeimpl.c | 0 {chuniio => games/chuniio}/pipeimpl.h | 0 {chuniio => games/chuniio}/serialimpl.c | 0 {chuniio => games/chuniio}/serialimpl.h | 0 {chusanhook => games/chusanhook}/chuni-dll.c | 0 {chusanhook => games/chusanhook}/chuni-dll.h | 0 .../chusanhook}/chusanhook.def | 0 {chusanhook => games/chusanhook}/config.c | 0 {chusanhook => games/chusanhook}/config.h | 0 {chusanhook => games/chusanhook}/dllmain.c | 0 {chusanhook => games/chusanhook}/io4.c | 0 {chusanhook => games/chusanhook}/io4.h | 0 {chusanhook => games/chusanhook}/meson.build | 0 {chusanhook => games/chusanhook}/slider.c | 0 {chusanhook => games/chusanhook}/slider.h | 0 {cmhook => games/cmhook}/cm-dll.c | 0 {cmhook => games/cmhook}/cm-dll.h | 0 {cmhook => games/cmhook}/cmhook.def | 0 {cmhook => games/cmhook}/config.c | 0 {cmhook => games/cmhook}/config.h | 0 {cmhook => games/cmhook}/dllmain.c | 0 {cmhook => games/cmhook}/io4.c | 0 {cmhook => games/cmhook}/io4.h | 0 {cmhook => games/cmhook}/meson.build | 0 {cmio => games/cmio}/cmio.c | 0 {cmio => games/cmio}/cmio.h | 0 {cmio => games/cmio}/config.c | 0 {cmio => games/cmio}/config.h | 0 {cmio => games/cmio}/meson.build | 0 {cxbhook => games/cxbhook}/config.c | 0 {cxbhook => games/cxbhook}/config.h | 0 {cxbhook => games/cxbhook}/cxb-dll.c | 0 {cxbhook => games/cxbhook}/cxb-dll.h | 0 {cxbhook => games/cxbhook}/cxbhook.def | 0 {cxbhook => games/cxbhook}/dllmain.c | 0 {cxbhook => games/cxbhook}/led.c | 0 {cxbhook => games/cxbhook}/led.h | 0 {cxbhook => games/cxbhook}/meson.build | 0 {cxbhook => games/cxbhook}/revio.c | 0 {cxbhook => games/cxbhook}/revio.h | 0 {cxbio => games/cxbio}/config.c | 0 {cxbio => games/cxbio}/config.h | 0 {cxbio => games/cxbio}/cxbio.c | 0 {cxbio => games/cxbio}/cxbio.h | 0 {cxbio => games/cxbio}/meson.build | 0 {divahook => games/divahook}/config.c | 0 {divahook => games/divahook}/config.h | 0 {divahook => games/divahook}/diva-dll.c | 0 {divahook => games/divahook}/diva-dll.h | 0 {divahook => games/divahook}/divahook.def | 0 {divahook => games/divahook}/dllmain.c | 0 {divahook => games/divahook}/jvs.c | 0 {divahook => games/divahook}/jvs.h | 0 {divahook => games/divahook}/meson.build | 0 {divahook => games/divahook}/slider.c | 0 {divahook => games/divahook}/slider.h | 0 {divaio => games/divaio}/config.c | 0 {divaio => games/divaio}/config.h | 0 {divaio => games/divaio}/divaio.c | 0 {divaio => games/divaio}/divaio.h | 0 {divaio => games/divaio}/meson.build | 0 {fgohook => games/fgohook}/config.c | 0 {fgohook => games/fgohook}/config.h | 0 {fgohook => games/fgohook}/deck.c | 0 {fgohook => games/fgohook}/deck.h | 0 {fgohook => games/fgohook}/dllmain.c | 0 {fgohook => games/fgohook}/fgo-dll.c | 0 {fgohook => games/fgohook}/fgo-dll.h | 0 {fgohook => games/fgohook}/fgohook.def | 0 {fgohook => games/fgohook}/ftdi.c | 0 {fgohook => games/fgohook}/ftdi.h | 0 {fgohook => games/fgohook}/io4.c | 0 {fgohook => games/fgohook}/io4.h | 0 {fgohook => games/fgohook}/meson.build | 0 {fgoio => games/fgoio}/backend.h | 0 {fgoio => games/fgoio}/config.c | 0 {fgoio => games/fgoio}/config.h | 0 {fgoio => games/fgoio}/fgoio.c | 0 {fgoio => games/fgoio}/fgoio.h | 0 {fgoio => games/fgoio}/keyboard.c | 0 {fgoio => games/fgoio}/keyboard.h | 0 {fgoio => games/fgoio}/meson.build | 0 {fgoio => games/fgoio}/xi.c | 0 {fgoio => games/fgoio}/xi.h | 0 {idachook => games/idachook}/config.c | 0 {idachook => games/idachook}/config.h | 0 {idachook => games/idachook}/dllmain.c | 0 {idachook => games/idachook}/ffb.c | 0 {idachook => games/idachook}/ffb.h | 0 {idachook => games/idachook}/idac-dll.c | 0 {idachook => games/idachook}/idac-dll.h | 0 {idachook => games/idachook}/idachook.def | 0 {idachook => games/idachook}/indrun.c | 0 {idachook => games/idachook}/indrun.h | 0 {idachook => games/idachook}/io4.c | 0 {idachook => games/idachook}/io4.h | 0 {idachook => games/idachook}/meson.build | 0 {idachook => games/idachook}/zinput.c | 0 {idachook => games/idachook}/zinput.h | 0 {idacio => games/idacio}/backend.h | 0 {idacio => games/idacio}/config.c | 0 {idacio => games/idacio}/config.h | 0 {idacio => games/idacio}/di-dev.c | 0 {idacio => games/idacio}/di-dev.h | 0 {idacio => games/idacio}/di.c | 0 {idacio => games/idacio}/di.h | 0 {idacio => games/idacio}/dllmain.c | 0 {idacio => games/idacio}/idacio.def | 0 {idacio => games/idacio}/idacio.h | 0 {idacio => games/idacio}/meson.build | 0 {idacio => games/idacio}/shifter.c | 0 {idacio => games/idacio}/shifter.h | 0 {idacio => games/idacio}/wnd.c | 0 {idacio => games/idacio}/wnd.h | 0 {idacio => games/idacio}/xi.c | 0 {idacio => games/idacio}/xi.h | 0 {idzhook => games/idzhook}/config.c | 0 {idzhook => games/idzhook}/config.h | 0 {idzhook => games/idzhook}/dllmain.c | 0 {idzhook => games/idzhook}/ffb.c | 0 {idzhook => games/idzhook}/ffb.h | 0 {idzhook => games/idzhook}/idz-dll.c | 0 {idzhook => games/idzhook}/idz-dll.h | 0 {idzhook => games/idzhook}/idzhook.def | 0 {idzhook => games/idzhook}/jvs.c | 0 {idzhook => games/idzhook}/jvs.h | 0 {idzhook => games/idzhook}/meson.build | 0 {idzhook => games/idzhook}/zinput.c | 0 {idzhook => games/idzhook}/zinput.h | 0 {idzio => games/idzio}/backend.h | 0 {idzio => games/idzio}/config.c | 0 {idzio => games/idzio}/config.h | 0 {idzio => games/idzio}/di-dev.c | 0 {idzio => games/idzio}/di-dev.h | 0 {idzio => games/idzio}/di.c | 0 {idzio => games/idzio}/di.h | 0 {idzio => games/idzio}/dllmain.c | 0 {idzio => games/idzio}/idzio.def | 0 {idzio => games/idzio}/idzio.h | 0 {idzio => games/idzio}/meson.build | 0 {idzio => games/idzio}/shifter.c | 0 {idzio => games/idzio}/shifter.h | 0 {idzio => games/idzio}/wnd.c | 0 {idzio => games/idzio}/wnd.h | 0 {idzio => games/idzio}/xi.c | 0 {idzio => games/idzio}/xi.h | 0 {kemonohook => games/kemonohook}/config.c | 0 {kemonohook => games/kemonohook}/config.h | 0 {kemonohook => games/kemonohook}/dllmain.c | 0 {kemonohook => games/kemonohook}/hooks.c | 0 {kemonohook => games/kemonohook}/hooks.h | 0 {kemonohook => games/kemonohook}/jvs.c | 0 {kemonohook => games/kemonohook}/jvs.h | 0 {kemonohook => games/kemonohook}/kemono-dll.c | 0 {kemonohook => games/kemonohook}/kemono-dll.h | 0 .../kemonohook}/kemonohook.def | 0 {kemonohook => games/kemonohook}/meson.build | 0 {kemonoio => games/kemonoio}/config.c | 0 {kemonoio => games/kemonoio}/config.h | 0 {kemonoio => games/kemonoio}/kemonoio.c | 0 {kemonoio => games/kemonoio}/kemonoio.h | 0 {kemonoio => games/kemonoio}/meson.build | 0 {mai2hook => games/mai2hook}/config.c | 0 {mai2hook => games/mai2hook}/config.h | 0 {mai2hook => games/mai2hook}/dllmain.c | 0 {mai2hook => games/mai2hook}/io4.c | 0 {mai2hook => games/mai2hook}/io4.h | 0 {mai2hook => games/mai2hook}/mai2-dll.c | 0 {mai2hook => games/mai2hook}/mai2-dll.h | 0 {mai2hook => games/mai2hook}/mai2hook.def | 0 {mai2hook => games/mai2hook}/meson.build | 0 {mai2hook => games/mai2hook}/touch.c | 0 {mai2hook => games/mai2hook}/touch.h | 0 {mai2io => games/mai2io}/config.c | 0 {mai2io => games/mai2io}/config.h | 0 {mai2io => games/mai2io}/mai2io.c | 0 {mai2io => games/mai2io}/mai2io.h | 0 {mai2io => games/mai2io}/meson.build | 0 {mercuryhook => games/mercuryhook}/config.c | 0 {mercuryhook => games/mercuryhook}/config.h | 0 {mercuryhook => games/mercuryhook}/dllmain.c | 0 .../mercuryhook}/elisabeth.c | 0 .../mercuryhook}/elisabeth.h | 0 {mercuryhook => games/mercuryhook}/io4.c | 0 {mercuryhook => games/mercuryhook}/io4.h | 0 .../mercuryhook}/mercury-dll.c | 0 .../mercuryhook}/mercury-dll.h | 0 .../mercuryhook}/mercuryhook.def | 0 .../mercuryhook}/meson.build | 0 {mercuryhook => games/mercuryhook}/touch.c | 0 {mercuryhook => games/mercuryhook}/touch.h | 0 {mercuryio => games/mercuryio}/config.c | 0 {mercuryio => games/mercuryio}/config.h | 0 {mercuryio => games/mercuryio}/mercuryio.c | 0 {mercuryio => games/mercuryio}/mercuryio.def | 0 {mercuryio => games/mercuryio}/mercuryio.h | 0 {mercuryio => games/mercuryio}/meson.build | 0 {mu3hook => games/mu3hook}/config.c | 0 {mu3hook => games/mu3hook}/config.h | 0 {mu3hook => games/mu3hook}/dllmain.c | 0 {mu3hook => games/mu3hook}/io4.c | 0 {mu3hook => games/mu3hook}/io4.h | 0 {mu3hook => games/mu3hook}/meson.build | 0 {mu3hook => games/mu3hook}/mu3-dll.c | 0 {mu3hook => games/mu3hook}/mu3-dll.h | 0 {mu3hook => games/mu3hook}/mu3hook.def | 0 {mu3io => games/mu3io}/config.c | 0 {mu3io => games/mu3io}/config.h | 0 {mu3io => games/mu3io}/leddata.h | 0 {mu3io => games/mu3io}/ledoutput.c | 0 {mu3io => games/mu3io}/ledoutput.h | 0 {mu3io => games/mu3io}/meson.build | 0 {mu3io => games/mu3io}/mu3io.c | 0 {mu3io => games/mu3io}/mu3io.h | 0 {mu3io => games/mu3io}/pipeimpl.c | 0 {mu3io => games/mu3io}/pipeimpl.h | 0 {mu3io => games/mu3io}/serialimpl.c | 0 {mu3io => games/mu3io}/serialimpl.h | 0 {swdchook => games/swdchook}/config.c | 0 {swdchook => games/swdchook}/config.h | 0 {swdchook => games/swdchook}/dllmain.c | 0 {swdchook => games/swdchook}/ffb.c | 0 {swdchook => games/swdchook}/ffb.h | 0 {swdchook => games/swdchook}/io4.c | 0 {swdchook => games/swdchook}/io4.h | 0 {swdchook => games/swdchook}/meson.build | 0 {swdchook => games/swdchook}/swdc-dll.c | 0 {swdchook => games/swdchook}/swdc-dll.h | 0 {swdchook => games/swdchook}/swdchook.def | 0 {swdchook => games/swdchook}/zinput.c | 0 {swdchook => games/swdchook}/zinput.h | 0 {swdcio => games/swdcio}/backend.h | 0 {swdcio => games/swdcio}/config.c | 0 {swdcio => games/swdcio}/config.h | 0 {swdcio => games/swdcio}/di-dev.c | 0 {swdcio => games/swdcio}/di-dev.h | 0 {swdcio => games/swdcio}/di.c | 0 {swdcio => games/swdcio}/di.h | 0 {swdcio => games/swdcio}/dllmain.c | 0 {swdcio => games/swdcio}/meson.build | 0 {swdcio => games/swdcio}/swdcio.def | 0 {swdcio => games/swdcio}/swdcio.h | 0 {swdcio => games/swdcio}/wnd.c | 0 {swdcio => games/swdcio}/wnd.h | 0 {swdcio => games/swdcio}/xi.c | 0 {swdcio => games/swdcio}/xi.h | 0 {tokyohook => games/tokyohook}/config.c | 0 {tokyohook => games/tokyohook}/config.h | 0 {tokyohook => games/tokyohook}/dllmain.c | 0 {tokyohook => games/tokyohook}/io4.c | 0 {tokyohook => games/tokyohook}/io4.h | 0 {tokyohook => games/tokyohook}/meson.build | 0 {tokyohook => games/tokyohook}/tokyo-dll.c | 0 {tokyohook => games/tokyohook}/tokyo-dll.h | 0 {tokyohook => games/tokyohook}/tokyohook.def | 0 {tokyohook => games/tokyohook}/zinput.c | 0 {tokyohook => games/tokyohook}/zinput.h | 0 {tokyoio => games/tokyoio}/backend.h | 0 {tokyoio => games/tokyoio}/config.c | 0 {tokyoio => games/tokyoio}/config.h | 0 {tokyoio => games/tokyoio}/dllmain.c | 0 {tokyoio => games/tokyoio}/kb.c | 0 {tokyoio => games/tokyoio}/kb.h | 0 {tokyoio => games/tokyoio}/meson.build | 0 {tokyoio => games/tokyoio}/tokyoio.h | 0 {tokyoio => games/tokyoio}/xi.c | 0 {tokyoio => games/tokyoio}/xi.h | 0 meson.build | 81 ++++--- minihook/dllmain.c | 76 ------- minihook/meson.build | 18 -- msvc-build.bat | 2 + package.ps1 | 6 + reg/chunithm.reg | 27 --- 496 files changed, 236 insertions(+), 344 deletions(-) rename {aimeio => common/aimeio}/aimeio.c (100%) rename {aimeio => common/aimeio}/aimeio.h (100%) rename {aimeio => common/aimeio}/meson.build (100%) rename {amex => common/amex}/amex.c (100%) rename {amex => common/amex}/amex.h (100%) rename {amex => common/amex}/config.c (100%) rename {amex => common/amex}/config.h (100%) rename {amex => common/amex}/ds.c (100%) rename {amex => common/amex}/ds.h (100%) rename {amex => common/amex}/eeprom.c (100%) rename {amex => common/amex}/eeprom.h (100%) rename {amex => common/amex}/gpio.c (100%) rename {amex => common/amex}/gpio.h (100%) rename {amex => common/amex}/guid.c (100%) rename {amex => common/amex}/jvs.c (100%) rename {amex => common/amex}/jvs.h (100%) rename {amex => common/amex}/meson.build (100%) rename {amex => common/amex}/nvram.c (100%) rename {amex => common/amex}/nvram.h (100%) rename {amex => common/amex}/sram.c (100%) rename {amex => common/amex}/sram.h (100%) rename {board => common/board}/aime-dll.c (100%) rename {board => common/board}/aime-dll.h (100%) rename {board => common/board}/config.c (100%) rename {board => common/board}/config.h (100%) rename {board => common/board}/ffb.c (100%) rename {board => common/board}/ffb.h (100%) rename {board => common/board}/guid.c (100%) rename {board => common/board}/guid.h (100%) rename {board => common/board}/io3.c (100%) rename {board => common/board}/io3.h (100%) rename {board => common/board}/io4.c (100%) rename {board => common/board}/io4.h (100%) rename {board => common/board}/led15070-cmd.h (100%) rename {board => common/board}/led15070-frame.c (100%) rename {board => common/board}/led15070-frame.h (100%) rename {board => common/board}/led15070.c (100%) rename {board => common/board}/led15070.h (100%) rename {board => common/board}/led15093-cmd.h (100%) rename {board => common/board}/led15093-frame.c (100%) rename {board => common/board}/led15093-frame.h (100%) rename {board => common/board}/led15093.c (100%) rename {board => common/board}/led15093.h (100%) rename {board => common/board}/meson.build (93%) rename {board => common/board}/sg-cmd.c (100%) rename {board => common/board}/sg-cmd.h (100%) rename {board => common/board}/sg-frame.c (100%) rename {board => common/board}/sg-frame.h (100%) rename {board => common/board}/sg-led-cmd.h (100%) rename {board => common/board}/sg-led.c (100%) rename {board => common/board}/sg-led.h (100%) rename {board => common/board}/sg-nfc-cmd.h (100%) rename {board => common/board}/sg-nfc.c (99%) rename {board => common/board}/sg-nfc.h (100%) rename {board => common/board}/sg-reader.c (100%) rename {board => common/board}/sg-reader.h (100%) rename {board => common/board}/slider-cmd.h (100%) rename {board => common/board}/slider-frame.c (100%) rename {board => common/board}/slider-frame.h (100%) rename {board => common/board}/vfd-cmd.h (100%) rename {board => common/board}/vfd-frame.c (100%) rename {board => common/board}/vfd-frame.h (100%) rename {board => common/board}/vfd.c (100%) rename {board => common/board}/vfd.h (100%) rename {gfxhook => common/gfxhook}/config.c (100%) rename {gfxhook => common/gfxhook}/config.h (100%) rename {gfxhook => common/gfxhook}/d3d11.c (100%) rename {gfxhook => common/gfxhook}/d3d11.h (100%) rename {gfxhook => common/gfxhook}/d3d9.c (100%) rename {gfxhook => common/gfxhook}/d3d9.h (100%) rename {gfxhook => common/gfxhook}/dxgi.c (100%) rename {gfxhook => common/gfxhook}/dxgi.h (100%) rename {gfxhook => common/gfxhook}/gfx.c (100%) rename {gfxhook => common/gfxhook}/gfx.h (100%) rename {gfxhook => common/gfxhook}/gl.c (100%) rename {gfxhook => common/gfxhook}/gl.h (100%) rename {gfxhook => common/gfxhook}/meson.build (100%) rename {gfxhook => common/gfxhook}/util.c (100%) rename {gfxhook => common/gfxhook}/util.h (100%) rename {hooklib => common/hooklib}/config.c (100%) rename {hooklib => common/hooklib}/config.h (100%) rename {hooklib => common/hooklib}/createprocess.c (100%) rename {hooklib => common/hooklib}/createprocess.h (100%) rename {hooklib => common/hooklib}/cursor.c (100%) rename {hooklib => common/hooklib}/cursor.h (100%) rename {hooklib => common/hooklib}/dll.c (100%) rename {hooklib => common/hooklib}/dll.h (100%) rename {hooklib => common/hooklib}/dns.c (100%) rename {hooklib => common/hooklib}/dns.h (100%) rename {hooklib => common/hooklib}/dvd.c (100%) rename {hooklib => common/hooklib}/dvd.h (100%) rename {hooklib => common/hooklib}/fdshark.c (100%) rename {hooklib => common/hooklib}/fdshark.h (100%) rename {hooklib => common/hooklib}/meson.build (100%) rename {hooklib => common/hooklib}/path.c (100%) rename {hooklib => common/hooklib}/path.h (100%) rename {hooklib => common/hooklib}/printer.c (100%) rename {hooklib => common/hooklib}/printer.h (100%) rename {hooklib => common/hooklib}/reg.c (100%) rename {hooklib => common/hooklib}/reg.h (100%) rename {hooklib => common/hooklib}/setupapi.c (100%) rename {hooklib => common/hooklib}/setupapi.h (100%) rename {hooklib => common/hooklib}/spike.c (100%) rename {hooklib => common/hooklib}/spike.h (100%) rename {hooklib => common/hooklib}/touch.c (100%) rename {hooklib => common/hooklib}/touch.h (100%) rename {iccard => common/iccard}/aime.c (100%) rename {iccard => common/iccard}/aime.h (100%) rename {iccard => common/iccard}/felica.c (100%) rename {iccard => common/iccard}/felica.h (100%) rename {iccard => common/iccard}/meson.build (100%) rename {iccard => common/iccard}/mifare.h (100%) rename {jvs => common/jvs}/jvs-bus.c (100%) rename {jvs => common/jvs}/jvs-bus.h (100%) rename {jvs => common/jvs}/jvs-cmd.h (100%) rename {jvs => common/jvs}/jvs-frame.c (100%) rename {jvs => common/jvs}/jvs-frame.h (100%) rename {jvs => common/jvs}/jvs-util.c (100%) rename {jvs => common/jvs}/jvs-util.h (100%) rename {jvs => common/jvs}/meson.build (100%) rename {platform => common/platform}/amvideo.c (100%) rename {platform => common/platform}/amvideo.h (100%) rename {platform => common/platform}/clock.c (100%) rename {platform => common/platform}/clock.h (100%) rename {platform => common/platform}/config.c (100%) rename {platform => common/platform}/config.h (100%) rename {platform => common/platform}/dns.c (100%) rename {platform => common/platform}/dns.h (100%) rename {platform => common/platform}/epay.c (100%) rename {platform => common/platform}/epay.h (100%) rename {platform => common/platform}/hwmon.c (100%) rename {platform => common/platform}/hwmon.h (100%) rename {platform => common/platform}/hwreset.c (100%) rename {platform => common/platform}/hwreset.h (100%) rename {platform => common/platform}/meson.build (100%) rename {platform => common/platform}/misc.c (100%) rename {platform => common/platform}/misc.h (100%) rename {platform => common/platform}/netenv.c (100%) rename {platform => common/platform}/netenv.h (100%) rename {platform => common/platform}/nusec.c (100%) rename {platform => common/platform}/nusec.h (100%) rename {platform => common/platform}/pcbid.c (100%) rename {platform => common/platform}/pcbid.h (100%) rename {platform => common/platform}/platform.c (100%) rename {platform => common/platform}/platform.h (100%) rename {platform => common/platform}/system.c (98%) rename {platform => common/platform}/system.h (100%) rename {platform => common/platform}/vfs.c (100%) rename {platform => common/platform}/vfs.h (100%) rename {unityhook => common/unityhook}/config.c (100%) rename {unityhook => common/unityhook}/config.h (94%) rename {unityhook => common/unityhook}/doorstop.c (100%) rename {unityhook => common/unityhook}/doorstop.h (83%) rename {unityhook => common/unityhook}/hook.c (100%) rename {unityhook => common/unityhook}/hook.h (96%) rename {unityhook => common/unityhook}/meson.build (95%) rename {unityhook => common/unityhook}/mono.h (97%) rename {unityhook => common/unityhook}/util.h (96%) rename {util => common/util}/async.c (100%) rename {util => common/util}/async.h (100%) rename {util => common/util}/crc.c (100%) rename {util => common/util}/crc.h (100%) rename {util => common/util}/dll-bind.c (100%) rename {util => common/util}/dll-bind.h (100%) rename {util => common/util}/dprintf.c (100%) rename {util => common/util}/dprintf.h (100%) rename {util => common/util}/dump.c (100%) rename {util => common/util}/dump.h (100%) rename {util => common/util}/env.c (100%) rename {util => common/util}/env.h (100%) rename {util => common/util}/get_function_ordinal.c (100%) rename {util => common/util}/get_function_ordinal.h (100%) rename {util => common/util}/lib.c (100%) rename {util => common/util}/lib.h (100%) rename {util => common/util}/meson.build (100%) rename {util => common/util}/slurp.c (100%) rename {util => common/util}/slurp.h (100%) rename {util => common/util}/str.c (100%) rename {util => common/util}/str.h (100%) rename {carolhook => games/carolhook}/carol-dll.c (100%) rename {carolhook => games/carolhook}/carol-dll.h (100%) rename {carolhook => games/carolhook}/carolhook.def (100%) rename {carolhook => games/carolhook}/config.c (100%) rename {carolhook => games/carolhook}/config.h (100%) rename {carolhook => games/carolhook}/controlbd.c (100%) rename {carolhook => games/carolhook}/controlbd.h (100%) rename {carolhook => games/carolhook}/dllmain.c (100%) rename {carolhook => games/carolhook}/jvs.c (100%) rename {carolhook => games/carolhook}/jvs.h (100%) rename {carolhook => games/carolhook}/ledbd.c (100%) rename {carolhook => games/carolhook}/ledbd.h (100%) rename {carolhook => games/carolhook}/meson.build (100%) rename {carolhook => games/carolhook}/touch.c (100%) rename {carolhook => games/carolhook}/touch.h (100%) rename {carolio => games/carolio}/carolio.c (100%) rename {carolio => games/carolio}/carolio.h (100%) rename {carolio => games/carolio}/config.c (100%) rename {carolio => games/carolio}/config.h (100%) rename {carolio => games/carolio}/meson.build (100%) rename {chunihook => games/chunihook}/chuni-dll.c (100%) rename {chunihook => games/chunihook}/chuni-dll.h (100%) rename {chunihook => games/chunihook}/chunihook.def (100%) rename {chunihook => games/chunihook}/config.c (100%) rename {chunihook => games/chunihook}/config.h (100%) rename {chunihook => games/chunihook}/dllmain.c (100%) rename {chunihook => games/chunihook}/jvs.c (100%) rename {chunihook => games/chunihook}/jvs.h (100%) rename {chunihook => games/chunihook}/meson.build (100%) rename {chunihook => games/chunihook}/slider.c (100%) rename {chunihook => games/chunihook}/slider.h (100%) rename {chuniio => games/chuniio}/chu2to3.c (100%) rename {chuniio => games/chuniio}/chu2to3.h (100%) rename {chuniio => games/chuniio}/chuniio.c (100%) rename {chuniio => games/chuniio}/chuniio.h (100%) rename {chuniio => games/chuniio}/config.c (100%) rename {chuniio => games/chuniio}/config.h (100%) rename {chuniio => games/chuniio}/leddata.h (100%) rename {chuniio => games/chuniio}/ledoutput.c (100%) rename {chuniio => games/chuniio}/ledoutput.h (100%) rename {chuniio => games/chuniio}/meson.build (100%) rename {chuniio => games/chuniio}/pipeimpl.c (100%) rename {chuniio => games/chuniio}/pipeimpl.h (100%) rename {chuniio => games/chuniio}/serialimpl.c (100%) rename {chuniio => games/chuniio}/serialimpl.h (100%) rename {chusanhook => games/chusanhook}/chuni-dll.c (100%) rename {chusanhook => games/chusanhook}/chuni-dll.h (100%) rename {chusanhook => games/chusanhook}/chusanhook.def (100%) rename {chusanhook => games/chusanhook}/config.c (100%) rename {chusanhook => games/chusanhook}/config.h (100%) rename {chusanhook => games/chusanhook}/dllmain.c (100%) rename {chusanhook => games/chusanhook}/io4.c (100%) rename {chusanhook => games/chusanhook}/io4.h (100%) rename {chusanhook => games/chusanhook}/meson.build (100%) rename {chusanhook => games/chusanhook}/slider.c (100%) rename {chusanhook => games/chusanhook}/slider.h (100%) rename {cmhook => games/cmhook}/cm-dll.c (100%) rename {cmhook => games/cmhook}/cm-dll.h (100%) rename {cmhook => games/cmhook}/cmhook.def (100%) rename {cmhook => games/cmhook}/config.c (100%) rename {cmhook => games/cmhook}/config.h (100%) rename {cmhook => games/cmhook}/dllmain.c (100%) rename {cmhook => games/cmhook}/io4.c (100%) rename {cmhook => games/cmhook}/io4.h (100%) rename {cmhook => games/cmhook}/meson.build (100%) rename {cmio => games/cmio}/cmio.c (100%) rename {cmio => games/cmio}/cmio.h (100%) rename {cmio => games/cmio}/config.c (100%) rename {cmio => games/cmio}/config.h (100%) rename {cmio => games/cmio}/meson.build (100%) rename {cxbhook => games/cxbhook}/config.c (100%) rename {cxbhook => games/cxbhook}/config.h (100%) rename {cxbhook => games/cxbhook}/cxb-dll.c (100%) rename {cxbhook => games/cxbhook}/cxb-dll.h (100%) rename {cxbhook => games/cxbhook}/cxbhook.def (100%) rename {cxbhook => games/cxbhook}/dllmain.c (100%) rename {cxbhook => games/cxbhook}/led.c (100%) rename {cxbhook => games/cxbhook}/led.h (100%) rename {cxbhook => games/cxbhook}/meson.build (100%) rename {cxbhook => games/cxbhook}/revio.c (100%) rename {cxbhook => games/cxbhook}/revio.h (100%) rename {cxbio => games/cxbio}/config.c (100%) rename {cxbio => games/cxbio}/config.h (100%) rename {cxbio => games/cxbio}/cxbio.c (100%) rename {cxbio => games/cxbio}/cxbio.h (100%) rename {cxbio => games/cxbio}/meson.build (100%) rename {divahook => games/divahook}/config.c (100%) rename {divahook => games/divahook}/config.h (100%) rename {divahook => games/divahook}/diva-dll.c (100%) rename {divahook => games/divahook}/diva-dll.h (100%) rename {divahook => games/divahook}/divahook.def (100%) rename {divahook => games/divahook}/dllmain.c (100%) rename {divahook => games/divahook}/jvs.c (100%) rename {divahook => games/divahook}/jvs.h (100%) rename {divahook => games/divahook}/meson.build (100%) rename {divahook => games/divahook}/slider.c (100%) rename {divahook => games/divahook}/slider.h (100%) rename {divaio => games/divaio}/config.c (100%) rename {divaio => games/divaio}/config.h (100%) rename {divaio => games/divaio}/divaio.c (100%) rename {divaio => games/divaio}/divaio.h (100%) rename {divaio => games/divaio}/meson.build (100%) rename {fgohook => games/fgohook}/config.c (100%) rename {fgohook => games/fgohook}/config.h (100%) rename {fgohook => games/fgohook}/deck.c (100%) rename {fgohook => games/fgohook}/deck.h (100%) rename {fgohook => games/fgohook}/dllmain.c (100%) rename {fgohook => games/fgohook}/fgo-dll.c (100%) rename {fgohook => games/fgohook}/fgo-dll.h (100%) rename {fgohook => games/fgohook}/fgohook.def (100%) rename {fgohook => games/fgohook}/ftdi.c (100%) rename {fgohook => games/fgohook}/ftdi.h (100%) rename {fgohook => games/fgohook}/io4.c (100%) rename {fgohook => games/fgohook}/io4.h (100%) rename {fgohook => games/fgohook}/meson.build (100%) rename {fgoio => games/fgoio}/backend.h (100%) rename {fgoio => games/fgoio}/config.c (100%) rename {fgoio => games/fgoio}/config.h (100%) rename {fgoio => games/fgoio}/fgoio.c (100%) rename {fgoio => games/fgoio}/fgoio.h (100%) rename {fgoio => games/fgoio}/keyboard.c (100%) rename {fgoio => games/fgoio}/keyboard.h (100%) rename {fgoio => games/fgoio}/meson.build (100%) rename {fgoio => games/fgoio}/xi.c (100%) rename {fgoio => games/fgoio}/xi.h (100%) rename {idachook => games/idachook}/config.c (100%) rename {idachook => games/idachook}/config.h (100%) rename {idachook => games/idachook}/dllmain.c (100%) rename {idachook => games/idachook}/ffb.c (100%) rename {idachook => games/idachook}/ffb.h (100%) rename {idachook => games/idachook}/idac-dll.c (100%) rename {idachook => games/idachook}/idac-dll.h (100%) rename {idachook => games/idachook}/idachook.def (100%) rename {idachook => games/idachook}/indrun.c (100%) rename {idachook => games/idachook}/indrun.h (100%) rename {idachook => games/idachook}/io4.c (100%) rename {idachook => games/idachook}/io4.h (100%) rename {idachook => games/idachook}/meson.build (100%) rename {idachook => games/idachook}/zinput.c (100%) rename {idachook => games/idachook}/zinput.h (100%) rename {idacio => games/idacio}/backend.h (100%) rename {idacio => games/idacio}/config.c (100%) rename {idacio => games/idacio}/config.h (100%) rename {idacio => games/idacio}/di-dev.c (100%) rename {idacio => games/idacio}/di-dev.h (100%) rename {idacio => games/idacio}/di.c (100%) rename {idacio => games/idacio}/di.h (100%) rename {idacio => games/idacio}/dllmain.c (100%) rename {idacio => games/idacio}/idacio.def (100%) rename {idacio => games/idacio}/idacio.h (100%) rename {idacio => games/idacio}/meson.build (100%) rename {idacio => games/idacio}/shifter.c (100%) rename {idacio => games/idacio}/shifter.h (100%) rename {idacio => games/idacio}/wnd.c (100%) rename {idacio => games/idacio}/wnd.h (100%) rename {idacio => games/idacio}/xi.c (100%) rename {idacio => games/idacio}/xi.h (100%) rename {idzhook => games/idzhook}/config.c (100%) rename {idzhook => games/idzhook}/config.h (100%) rename {idzhook => games/idzhook}/dllmain.c (100%) rename {idzhook => games/idzhook}/ffb.c (100%) rename {idzhook => games/idzhook}/ffb.h (100%) rename {idzhook => games/idzhook}/idz-dll.c (100%) rename {idzhook => games/idzhook}/idz-dll.h (100%) rename {idzhook => games/idzhook}/idzhook.def (100%) rename {idzhook => games/idzhook}/jvs.c (100%) rename {idzhook => games/idzhook}/jvs.h (100%) rename {idzhook => games/idzhook}/meson.build (100%) rename {idzhook => games/idzhook}/zinput.c (100%) rename {idzhook => games/idzhook}/zinput.h (100%) rename {idzio => games/idzio}/backend.h (100%) rename {idzio => games/idzio}/config.c (100%) rename {idzio => games/idzio}/config.h (100%) rename {idzio => games/idzio}/di-dev.c (100%) rename {idzio => games/idzio}/di-dev.h (100%) rename {idzio => games/idzio}/di.c (100%) rename {idzio => games/idzio}/di.h (100%) rename {idzio => games/idzio}/dllmain.c (100%) rename {idzio => games/idzio}/idzio.def (100%) rename {idzio => games/idzio}/idzio.h (100%) rename {idzio => games/idzio}/meson.build (100%) rename {idzio => games/idzio}/shifter.c (100%) rename {idzio => games/idzio}/shifter.h (100%) rename {idzio => games/idzio}/wnd.c (100%) rename {idzio => games/idzio}/wnd.h (100%) rename {idzio => games/idzio}/xi.c (100%) rename {idzio => games/idzio}/xi.h (100%) rename {kemonohook => games/kemonohook}/config.c (100%) rename {kemonohook => games/kemonohook}/config.h (100%) rename {kemonohook => games/kemonohook}/dllmain.c (100%) rename {kemonohook => games/kemonohook}/hooks.c (100%) rename {kemonohook => games/kemonohook}/hooks.h (100%) rename {kemonohook => games/kemonohook}/jvs.c (100%) rename {kemonohook => games/kemonohook}/jvs.h (100%) rename {kemonohook => games/kemonohook}/kemono-dll.c (100%) rename {kemonohook => games/kemonohook}/kemono-dll.h (100%) rename {kemonohook => games/kemonohook}/kemonohook.def (100%) rename {kemonohook => games/kemonohook}/meson.build (100%) rename {kemonoio => games/kemonoio}/config.c (100%) rename {kemonoio => games/kemonoio}/config.h (100%) rename {kemonoio => games/kemonoio}/kemonoio.c (100%) rename {kemonoio => games/kemonoio}/kemonoio.h (100%) rename {kemonoio => games/kemonoio}/meson.build (100%) rename {mai2hook => games/mai2hook}/config.c (100%) rename {mai2hook => games/mai2hook}/config.h (100%) rename {mai2hook => games/mai2hook}/dllmain.c (100%) rename {mai2hook => games/mai2hook}/io4.c (100%) rename {mai2hook => games/mai2hook}/io4.h (100%) rename {mai2hook => games/mai2hook}/mai2-dll.c (100%) rename {mai2hook => games/mai2hook}/mai2-dll.h (100%) rename {mai2hook => games/mai2hook}/mai2hook.def (100%) rename {mai2hook => games/mai2hook}/meson.build (100%) rename {mai2hook => games/mai2hook}/touch.c (100%) rename {mai2hook => games/mai2hook}/touch.h (100%) rename {mai2io => games/mai2io}/config.c (100%) rename {mai2io => games/mai2io}/config.h (100%) rename {mai2io => games/mai2io}/mai2io.c (100%) rename {mai2io => games/mai2io}/mai2io.h (100%) rename {mai2io => games/mai2io}/meson.build (100%) rename {mercuryhook => games/mercuryhook}/config.c (100%) rename {mercuryhook => games/mercuryhook}/config.h (100%) rename {mercuryhook => games/mercuryhook}/dllmain.c (100%) rename {mercuryhook => games/mercuryhook}/elisabeth.c (100%) rename {mercuryhook => games/mercuryhook}/elisabeth.h (100%) rename {mercuryhook => games/mercuryhook}/io4.c (100%) rename {mercuryhook => games/mercuryhook}/io4.h (100%) rename {mercuryhook => games/mercuryhook}/mercury-dll.c (100%) rename {mercuryhook => games/mercuryhook}/mercury-dll.h (100%) rename {mercuryhook => games/mercuryhook}/mercuryhook.def (100%) rename {mercuryhook => games/mercuryhook}/meson.build (100%) rename {mercuryhook => games/mercuryhook}/touch.c (100%) rename {mercuryhook => games/mercuryhook}/touch.h (100%) rename {mercuryio => games/mercuryio}/config.c (100%) rename {mercuryio => games/mercuryio}/config.h (100%) rename {mercuryio => games/mercuryio}/mercuryio.c (100%) rename {mercuryio => games/mercuryio}/mercuryio.def (100%) rename {mercuryio => games/mercuryio}/mercuryio.h (100%) rename {mercuryio => games/mercuryio}/meson.build (100%) rename {mu3hook => games/mu3hook}/config.c (100%) rename {mu3hook => games/mu3hook}/config.h (100%) rename {mu3hook => games/mu3hook}/dllmain.c (100%) rename {mu3hook => games/mu3hook}/io4.c (100%) rename {mu3hook => games/mu3hook}/io4.h (100%) rename {mu3hook => games/mu3hook}/meson.build (100%) rename {mu3hook => games/mu3hook}/mu3-dll.c (100%) rename {mu3hook => games/mu3hook}/mu3-dll.h (100%) rename {mu3hook => games/mu3hook}/mu3hook.def (100%) rename {mu3io => games/mu3io}/config.c (100%) rename {mu3io => games/mu3io}/config.h (100%) rename {mu3io => games/mu3io}/leddata.h (100%) rename {mu3io => games/mu3io}/ledoutput.c (100%) rename {mu3io => games/mu3io}/ledoutput.h (100%) rename {mu3io => games/mu3io}/meson.build (100%) rename {mu3io => games/mu3io}/mu3io.c (100%) rename {mu3io => games/mu3io}/mu3io.h (100%) rename {mu3io => games/mu3io}/pipeimpl.c (100%) rename {mu3io => games/mu3io}/pipeimpl.h (100%) rename {mu3io => games/mu3io}/serialimpl.c (100%) rename {mu3io => games/mu3io}/serialimpl.h (100%) rename {swdchook => games/swdchook}/config.c (100%) rename {swdchook => games/swdchook}/config.h (100%) rename {swdchook => games/swdchook}/dllmain.c (100%) rename {swdchook => games/swdchook}/ffb.c (100%) rename {swdchook => games/swdchook}/ffb.h (100%) rename {swdchook => games/swdchook}/io4.c (100%) rename {swdchook => games/swdchook}/io4.h (100%) rename {swdchook => games/swdchook}/meson.build (100%) rename {swdchook => games/swdchook}/swdc-dll.c (100%) rename {swdchook => games/swdchook}/swdc-dll.h (100%) rename {swdchook => games/swdchook}/swdchook.def (100%) rename {swdchook => games/swdchook}/zinput.c (100%) rename {swdchook => games/swdchook}/zinput.h (100%) rename {swdcio => games/swdcio}/backend.h (100%) rename {swdcio => games/swdcio}/config.c (100%) rename {swdcio => games/swdcio}/config.h (100%) rename {swdcio => games/swdcio}/di-dev.c (100%) rename {swdcio => games/swdcio}/di-dev.h (100%) rename {swdcio => games/swdcio}/di.c (100%) rename {swdcio => games/swdcio}/di.h (100%) rename {swdcio => games/swdcio}/dllmain.c (100%) rename {swdcio => games/swdcio}/meson.build (100%) rename {swdcio => games/swdcio}/swdcio.def (100%) rename {swdcio => games/swdcio}/swdcio.h (100%) rename {swdcio => games/swdcio}/wnd.c (100%) rename {swdcio => games/swdcio}/wnd.h (100%) rename {swdcio => games/swdcio}/xi.c (100%) rename {swdcio => games/swdcio}/xi.h (100%) rename {tokyohook => games/tokyohook}/config.c (100%) rename {tokyohook => games/tokyohook}/config.h (100%) rename {tokyohook => games/tokyohook}/dllmain.c (100%) rename {tokyohook => games/tokyohook}/io4.c (100%) rename {tokyohook => games/tokyohook}/io4.h (100%) rename {tokyohook => games/tokyohook}/meson.build (100%) rename {tokyohook => games/tokyohook}/tokyo-dll.c (100%) rename {tokyohook => games/tokyohook}/tokyo-dll.h (100%) rename {tokyohook => games/tokyohook}/tokyohook.def (100%) rename {tokyohook => games/tokyohook}/zinput.c (100%) rename {tokyohook => games/tokyohook}/zinput.h (100%) rename {tokyoio => games/tokyoio}/backend.h (100%) rename {tokyoio => games/tokyoio}/config.c (100%) rename {tokyoio => games/tokyoio}/config.h (100%) rename {tokyoio => games/tokyoio}/dllmain.c (100%) rename {tokyoio => games/tokyoio}/kb.c (100%) rename {tokyoio => games/tokyoio}/kb.h (100%) rename {tokyoio => games/tokyoio}/meson.build (100%) rename {tokyoio => games/tokyoio}/tokyoio.h (100%) rename {tokyoio => games/tokyoio}/xi.c (100%) rename {tokyoio => games/tokyoio}/xi.h (100%) delete mode 100644 minihook/dllmain.c delete mode 100644 minihook/meson.build delete mode 100644 reg/chunithm.reg diff --git a/Makefile b/Makefile index 28562a1..0381552 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ V ?= @ BUILD_DIR := build BUILD_DIR_32 := $(BUILD_DIR)/build32 BUILD_DIR_64 := $(BUILD_DIR)/build64 +BUILD_DIR_GAMES_32 := $(BUILD_DIR_32)/games +BUILD_DIR_GAMES_64 := $(BUILD_DIR_64)/games BUILD_DIR_ZIP := $(BUILD_DIR)/zip DOC_DIR := doc diff --git a/Package.mk b/Package.mk index 5647e9b..ae87f73 100644 --- a/Package.mk +++ b/Package.mk @@ -3,7 +3,7 @@ $(BUILD_DIR_ZIP)/chuni.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/chuni $(V)mkdir -p $(BUILD_DIR_ZIP)/chuni/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/chunihook/chunihook.dll \ + $(BUILD_DIR_GAMES_32)/chunihook/chunihook.dll \ $(DIST_DIR)/chuni/segatools.ini \ $(DIST_DIR)/chuni/launch.bat \ $(BUILD_DIR_ZIP)/chuni @@ -18,7 +18,7 @@ $(BUILD_DIR_ZIP)/cxb.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cxb $(V)mkdir -p $(BUILD_DIR_ZIP)/cxb/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/cxbhook/cxbhook.dll \ + $(BUILD_DIR_GAMES_32)/cxbhook/cxbhook.dll \ $(DIST_DIR)/cxb/segatools.ini \ $(DIST_DIR)/cxb/launch.bat \ $(BUILD_DIR_ZIP)/cxb @@ -33,7 +33,7 @@ $(BUILD_DIR_ZIP)/diva.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/diva $(V)mkdir -p $(BUILD_DIR_ZIP)/diva/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/divahook/divahook.dll \ + $(BUILD_DIR_GAMES_64)/divahook/divahook.dll \ $(DIST_DIR)/diva/segatools.ini \ $(DIST_DIR)/diva/launch.bat \ $(BUILD_DIR_ZIP)/diva @@ -48,7 +48,7 @@ $(BUILD_DIR_ZIP)/carol.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/carol $(V)mkdir -p $(BUILD_DIR_ZIP)/carol/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/carolhook/carolhook.dll \ + $(BUILD_DIR_GAMES_32)/carolhook/carolhook.dll \ $(DIST_DIR)/carol/segatools.ini \ $(DIST_DIR)/carol/launch.bat \ $(BUILD_DIR_ZIP)/carol @@ -63,7 +63,7 @@ $(BUILD_DIR_ZIP)/idz.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/idz $(V)mkdir -p $(BUILD_DIR_ZIP)/idz/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/idzhook/idzhook.dll \ + $(BUILD_DIR_GAMES_64)/idzhook/idzhook.dll \ $(DIST_DIR)/idz/segatools.ini \ $(DIST_DIR)/idz/launch.bat \ $(BUILD_DIR_ZIP)/idz @@ -78,7 +78,7 @@ $(BUILD_DIR_ZIP)/fgo.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/fgohook/fgohook.dll \ + $(BUILD_DIR_GAMES_64)/fgohook/fgohook.dll \ $(DIST_DIR)/fgo/segatools.ini \ $(DIST_DIR)/fgo/launch.bat \ $(BUILD_DIR_ZIP)/fgo @@ -93,7 +93,7 @@ $(BUILD_DIR_ZIP)/idac.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/idac $(V)mkdir -p $(BUILD_DIR_ZIP)/idac/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/idachook/idachook.dll \ + $(BUILD_DIR_GAMES_64)/idachook/idachook.dll \ $(DIST_DIR)/idac/segatools.ini \ $(DIST_DIR)/idac/config_hook.json \ $(DIST_DIR)/idac/launch.bat \ @@ -109,7 +109,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/swdchook/swdchook.dll \ + $(BUILD_DIR_GAMES_64)/swdchook/swdchook.dll \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/config_hook.json \ $(DIST_DIR)/swdc/launch.bat \ @@ -125,7 +125,7 @@ $(BUILD_DIR_ZIP)/mercury.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mercuryhook/mercuryhook.dll \ + $(BUILD_DIR_GAMES_64)/mercuryhook/mercuryhook.dll \ $(DIST_DIR)/mercury/segatools.ini \ $(DIST_DIR)/mercury/launch.bat \ $(BUILD_DIR_ZIP)/mercury @@ -143,9 +143,9 @@ $(BUILD_DIR_ZIP)/chusan.zip: $(DIST_DIR)/chusan/config_hook.json \ $(DIST_DIR)/chusan/launch.bat \ $(BUILD_DIR_ZIP)/chusan - $(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \ + $(V)cp $(BUILD_DIR_GAMES_32)/chusanhook/chusanhook.dll \ $(BUILD_DIR_ZIP)/chusan/chusanhook_x86.dll - $(V)cp $(BUILD_DIR_64)/chusanhook/chusanhook.dll \ + $(V)cp $(BUILD_DIR_GAMES_64)/chusanhook/chusanhook.dll \ $(BUILD_DIR_ZIP)/chusan/chusanhook_x64.dll $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_ZIP)/chusan/inject_x86.exe @@ -162,7 +162,7 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3 $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mu3hook/mu3hook.dll \ + $(BUILD_DIR_GAMES_64)/mu3hook/mu3hook.dll \ $(DIST_DIR)/mu3/segatools.ini \ $(DIST_DIR)/mu3/launch.bat \ $(BUILD_DIR_ZIP)/mu3 @@ -177,7 +177,7 @@ $(BUILD_DIR_ZIP)/mai2.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2 $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ + $(BUILD_DIR_GAMES_64)/mai2hook/mai2hook.dll \ $(DIST_DIR)/mai2/segatools.ini \ $(DIST_DIR)/mai2/launch.bat \ $(BUILD_DIR_ZIP)/mai2 @@ -192,7 +192,7 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cm $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/cmhook/cmhook.dll \ + $(BUILD_DIR_GAMES_64)/cmhook/cmhook.dll \ $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ $(DIST_DIR)/cm/launch.bat \ @@ -208,7 +208,7 @@ $(BUILD_DIR_ZIP)/tokyo.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/tokyohook/tokyohook.dll \ + $(BUILD_DIR_GAMES_64)/tokyohook/tokyohook.dll \ $(DIST_DIR)/tokyo/config_hook.json \ $(DIST_DIR)/tokyo/segatools.ini \ $(DIST_DIR)/tokyo/launch.bat \ @@ -226,9 +226,9 @@ $(BUILD_DIR_ZIP)/kemono.zip: $(V)cp $(DIST_DIR)/kemono/segatools.ini \ $(DIST_DIR)/kemono/launch.bat \ $(BUILD_DIR_ZIP)/kemono - $(V)cp $(BUILD_DIR_32)/kemonohook/kemonohook.dll \ + $(V)cp $(BUILD_DIR_GAMES_32)/kemonohook/kemonohook.dll \ $(BUILD_DIR_ZIP)/kemono/kemonohook_x86.dll - $(V)cp $(BUILD_DIR_64)/kemonohook/kemonohook.dll \ + $(V)cp $(BUILD_DIR_GAMES_64)/kemonohook/kemonohook.dll \ $(BUILD_DIR_ZIP)/kemono/kemonohook_x64.dll $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_ZIP)/kemono/inject_x86.exe diff --git a/aimeio/aimeio.c b/common/aimeio/aimeio.c similarity index 100% rename from aimeio/aimeio.c rename to common/aimeio/aimeio.c diff --git a/aimeio/aimeio.h b/common/aimeio/aimeio.h similarity index 100% rename from aimeio/aimeio.h rename to common/aimeio/aimeio.h diff --git a/aimeio/meson.build b/common/aimeio/meson.build similarity index 100% rename from aimeio/meson.build rename to common/aimeio/meson.build diff --git a/amex/amex.c b/common/amex/amex.c similarity index 100% rename from amex/amex.c rename to common/amex/amex.c diff --git a/amex/amex.h b/common/amex/amex.h similarity index 100% rename from amex/amex.h rename to common/amex/amex.h diff --git a/amex/config.c b/common/amex/config.c similarity index 100% rename from amex/config.c rename to common/amex/config.c diff --git a/amex/config.h b/common/amex/config.h similarity index 100% rename from amex/config.h rename to common/amex/config.h diff --git a/amex/ds.c b/common/amex/ds.c similarity index 100% rename from amex/ds.c rename to common/amex/ds.c diff --git a/amex/ds.h b/common/amex/ds.h similarity index 100% rename from amex/ds.h rename to common/amex/ds.h diff --git a/amex/eeprom.c b/common/amex/eeprom.c similarity index 100% rename from amex/eeprom.c rename to common/amex/eeprom.c diff --git a/amex/eeprom.h b/common/amex/eeprom.h similarity index 100% rename from amex/eeprom.h rename to common/amex/eeprom.h diff --git a/amex/gpio.c b/common/amex/gpio.c similarity index 100% rename from amex/gpio.c rename to common/amex/gpio.c diff --git a/amex/gpio.h b/common/amex/gpio.h similarity index 100% rename from amex/gpio.h rename to common/amex/gpio.h diff --git a/amex/guid.c b/common/amex/guid.c similarity index 100% rename from amex/guid.c rename to common/amex/guid.c diff --git a/amex/jvs.c b/common/amex/jvs.c similarity index 100% rename from amex/jvs.c rename to common/amex/jvs.c diff --git a/amex/jvs.h b/common/amex/jvs.h similarity index 100% rename from amex/jvs.h rename to common/amex/jvs.h diff --git a/amex/meson.build b/common/amex/meson.build similarity index 100% rename from amex/meson.build rename to common/amex/meson.build diff --git a/amex/nvram.c b/common/amex/nvram.c similarity index 100% rename from amex/nvram.c rename to common/amex/nvram.c diff --git a/amex/nvram.h b/common/amex/nvram.h similarity index 100% rename from amex/nvram.h rename to common/amex/nvram.h diff --git a/amex/sram.c b/common/amex/sram.c similarity index 100% rename from amex/sram.c rename to common/amex/sram.c diff --git a/amex/sram.h b/common/amex/sram.h similarity index 100% rename from amex/sram.h rename to common/amex/sram.h diff --git a/board/aime-dll.c b/common/board/aime-dll.c similarity index 100% rename from board/aime-dll.c rename to common/board/aime-dll.c diff --git a/board/aime-dll.h b/common/board/aime-dll.h similarity index 100% rename from board/aime-dll.h rename to common/board/aime-dll.h diff --git a/board/config.c b/common/board/config.c similarity index 100% rename from board/config.c rename to common/board/config.c diff --git a/board/config.h b/common/board/config.h similarity index 100% rename from board/config.h rename to common/board/config.h diff --git a/board/ffb.c b/common/board/ffb.c similarity index 100% rename from board/ffb.c rename to common/board/ffb.c diff --git a/board/ffb.h b/common/board/ffb.h similarity index 100% rename from board/ffb.h rename to common/board/ffb.h diff --git a/board/guid.c b/common/board/guid.c similarity index 100% rename from board/guid.c rename to common/board/guid.c diff --git a/board/guid.h b/common/board/guid.h similarity index 100% rename from board/guid.h rename to common/board/guid.h diff --git a/board/io3.c b/common/board/io3.c similarity index 100% rename from board/io3.c rename to common/board/io3.c diff --git a/board/io3.h b/common/board/io3.h similarity index 100% rename from board/io3.h rename to common/board/io3.h diff --git a/board/io4.c b/common/board/io4.c similarity index 100% rename from board/io4.c rename to common/board/io4.c diff --git a/board/io4.h b/common/board/io4.h similarity index 100% rename from board/io4.h rename to common/board/io4.h diff --git a/board/led15070-cmd.h b/common/board/led15070-cmd.h similarity index 100% rename from board/led15070-cmd.h rename to common/board/led15070-cmd.h diff --git a/board/led15070-frame.c b/common/board/led15070-frame.c similarity index 100% rename from board/led15070-frame.c rename to common/board/led15070-frame.c diff --git a/board/led15070-frame.h b/common/board/led15070-frame.h similarity index 100% rename from board/led15070-frame.h rename to common/board/led15070-frame.h diff --git a/board/led15070.c b/common/board/led15070.c similarity index 100% rename from board/led15070.c rename to common/board/led15070.c diff --git a/board/led15070.h b/common/board/led15070.h similarity index 100% rename from board/led15070.h rename to common/board/led15070.h diff --git a/board/led15093-cmd.h b/common/board/led15093-cmd.h similarity index 100% rename from board/led15093-cmd.h rename to common/board/led15093-cmd.h diff --git a/board/led15093-frame.c b/common/board/led15093-frame.c similarity index 100% rename from board/led15093-frame.c rename to common/board/led15093-frame.c diff --git a/board/led15093-frame.h b/common/board/led15093-frame.h similarity index 100% rename from board/led15093-frame.h rename to common/board/led15093-frame.h diff --git a/board/led15093.c b/common/board/led15093.c similarity index 100% rename from board/led15093.c rename to common/board/led15093.c diff --git a/board/led15093.h b/common/board/led15093.h similarity index 100% rename from board/led15093.h rename to common/board/led15093.h diff --git a/board/meson.build b/common/board/meson.build similarity index 93% rename from board/meson.build rename to common/board/meson.build index a9c24ea..38ec9d0 100644 --- a/board/meson.build +++ b/common/board/meson.build @@ -9,6 +9,9 @@ board_lib = static_library( iccard_lib, ], sources : [ + '3mpxsc-cmd.h', + '3mpxsc-frame.c', + '3mpxsc-frame.h', 'aime-dll.c', 'aime-dll.h', 'config.c', diff --git a/board/sg-cmd.c b/common/board/sg-cmd.c similarity index 100% rename from board/sg-cmd.c rename to common/board/sg-cmd.c diff --git a/board/sg-cmd.h b/common/board/sg-cmd.h similarity index 100% rename from board/sg-cmd.h rename to common/board/sg-cmd.h diff --git a/board/sg-frame.c b/common/board/sg-frame.c similarity index 100% rename from board/sg-frame.c rename to common/board/sg-frame.c diff --git a/board/sg-frame.h b/common/board/sg-frame.h similarity index 100% rename from board/sg-frame.h rename to common/board/sg-frame.h diff --git a/board/sg-led-cmd.h b/common/board/sg-led-cmd.h similarity index 100% rename from board/sg-led-cmd.h rename to common/board/sg-led-cmd.h diff --git a/board/sg-led.c b/common/board/sg-led.c similarity index 100% rename from board/sg-led.c rename to common/board/sg-led.c diff --git a/board/sg-led.h b/common/board/sg-led.h similarity index 100% rename from board/sg-led.h rename to common/board/sg-led.h diff --git a/board/sg-nfc-cmd.h b/common/board/sg-nfc-cmd.h similarity index 100% rename from board/sg-nfc-cmd.h rename to common/board/sg-nfc-cmd.h diff --git a/board/sg-nfc.c b/common/board/sg-nfc.c similarity index 99% rename from board/sg-nfc.c rename to common/board/sg-nfc.c index a072111..b103336 100644 --- a/board/sg-nfc.c +++ b/common/board/sg-nfc.c @@ -321,6 +321,7 @@ static HRESULT sg_nfc_poll_aime( mifare->type = 0x10; mifare->id_len = sizeof(mifare->uid); + // mifare->uid = _byteswap_ulong(0x8FBECBFF); mifare->uid = _byteswap_ulong(0x01020304); /* Initialize MIFARE IC emulator */ diff --git a/board/sg-nfc.h b/common/board/sg-nfc.h similarity index 100% rename from board/sg-nfc.h rename to common/board/sg-nfc.h diff --git a/board/sg-reader.c b/common/board/sg-reader.c similarity index 100% rename from board/sg-reader.c rename to common/board/sg-reader.c diff --git a/board/sg-reader.h b/common/board/sg-reader.h similarity index 100% rename from board/sg-reader.h rename to common/board/sg-reader.h diff --git a/board/slider-cmd.h b/common/board/slider-cmd.h similarity index 100% rename from board/slider-cmd.h rename to common/board/slider-cmd.h diff --git a/board/slider-frame.c b/common/board/slider-frame.c similarity index 100% rename from board/slider-frame.c rename to common/board/slider-frame.c diff --git a/board/slider-frame.h b/common/board/slider-frame.h similarity index 100% rename from board/slider-frame.h rename to common/board/slider-frame.h diff --git a/board/vfd-cmd.h b/common/board/vfd-cmd.h similarity index 100% rename from board/vfd-cmd.h rename to common/board/vfd-cmd.h diff --git a/board/vfd-frame.c b/common/board/vfd-frame.c similarity index 100% rename from board/vfd-frame.c rename to common/board/vfd-frame.c diff --git a/board/vfd-frame.h b/common/board/vfd-frame.h similarity index 100% rename from board/vfd-frame.h rename to common/board/vfd-frame.h diff --git a/board/vfd.c b/common/board/vfd.c similarity index 100% rename from board/vfd.c rename to common/board/vfd.c diff --git a/board/vfd.h b/common/board/vfd.h similarity index 100% rename from board/vfd.h rename to common/board/vfd.h diff --git a/gfxhook/config.c b/common/gfxhook/config.c similarity index 100% rename from gfxhook/config.c rename to common/gfxhook/config.c diff --git a/gfxhook/config.h b/common/gfxhook/config.h similarity index 100% rename from gfxhook/config.h rename to common/gfxhook/config.h diff --git a/gfxhook/d3d11.c b/common/gfxhook/d3d11.c similarity index 100% rename from gfxhook/d3d11.c rename to common/gfxhook/d3d11.c diff --git a/gfxhook/d3d11.h b/common/gfxhook/d3d11.h similarity index 100% rename from gfxhook/d3d11.h rename to common/gfxhook/d3d11.h diff --git a/gfxhook/d3d9.c b/common/gfxhook/d3d9.c similarity index 100% rename from gfxhook/d3d9.c rename to common/gfxhook/d3d9.c diff --git a/gfxhook/d3d9.h b/common/gfxhook/d3d9.h similarity index 100% rename from gfxhook/d3d9.h rename to common/gfxhook/d3d9.h diff --git a/gfxhook/dxgi.c b/common/gfxhook/dxgi.c similarity index 100% rename from gfxhook/dxgi.c rename to common/gfxhook/dxgi.c diff --git a/gfxhook/dxgi.h b/common/gfxhook/dxgi.h similarity index 100% rename from gfxhook/dxgi.h rename to common/gfxhook/dxgi.h diff --git a/gfxhook/gfx.c b/common/gfxhook/gfx.c similarity index 100% rename from gfxhook/gfx.c rename to common/gfxhook/gfx.c diff --git a/gfxhook/gfx.h b/common/gfxhook/gfx.h similarity index 100% rename from gfxhook/gfx.h rename to common/gfxhook/gfx.h diff --git a/gfxhook/gl.c b/common/gfxhook/gl.c similarity index 100% rename from gfxhook/gl.c rename to common/gfxhook/gl.c diff --git a/gfxhook/gl.h b/common/gfxhook/gl.h similarity index 100% rename from gfxhook/gl.h rename to common/gfxhook/gl.h diff --git a/gfxhook/meson.build b/common/gfxhook/meson.build similarity index 100% rename from gfxhook/meson.build rename to common/gfxhook/meson.build diff --git a/gfxhook/util.c b/common/gfxhook/util.c similarity index 100% rename from gfxhook/util.c rename to common/gfxhook/util.c diff --git a/gfxhook/util.h b/common/gfxhook/util.h similarity index 100% rename from gfxhook/util.h rename to common/gfxhook/util.h diff --git a/hooklib/config.c b/common/hooklib/config.c similarity index 100% rename from hooklib/config.c rename to common/hooklib/config.c diff --git a/hooklib/config.h b/common/hooklib/config.h similarity index 100% rename from hooklib/config.h rename to common/hooklib/config.h diff --git a/hooklib/createprocess.c b/common/hooklib/createprocess.c similarity index 100% rename from hooklib/createprocess.c rename to common/hooklib/createprocess.c diff --git a/hooklib/createprocess.h b/common/hooklib/createprocess.h similarity index 100% rename from hooklib/createprocess.h rename to common/hooklib/createprocess.h diff --git a/hooklib/cursor.c b/common/hooklib/cursor.c similarity index 100% rename from hooklib/cursor.c rename to common/hooklib/cursor.c diff --git a/hooklib/cursor.h b/common/hooklib/cursor.h similarity index 100% rename from hooklib/cursor.h rename to common/hooklib/cursor.h diff --git a/hooklib/dll.c b/common/hooklib/dll.c similarity index 100% rename from hooklib/dll.c rename to common/hooklib/dll.c diff --git a/hooklib/dll.h b/common/hooklib/dll.h similarity index 100% rename from hooklib/dll.h rename to common/hooklib/dll.h diff --git a/hooklib/dns.c b/common/hooklib/dns.c similarity index 100% rename from hooklib/dns.c rename to common/hooklib/dns.c diff --git a/hooklib/dns.h b/common/hooklib/dns.h similarity index 100% rename from hooklib/dns.h rename to common/hooklib/dns.h diff --git a/hooklib/dvd.c b/common/hooklib/dvd.c similarity index 100% rename from hooklib/dvd.c rename to common/hooklib/dvd.c diff --git a/hooklib/dvd.h b/common/hooklib/dvd.h similarity index 100% rename from hooklib/dvd.h rename to common/hooklib/dvd.h diff --git a/hooklib/fdshark.c b/common/hooklib/fdshark.c similarity index 100% rename from hooklib/fdshark.c rename to common/hooklib/fdshark.c diff --git a/hooklib/fdshark.h b/common/hooklib/fdshark.h similarity index 100% rename from hooklib/fdshark.h rename to common/hooklib/fdshark.h diff --git a/hooklib/meson.build b/common/hooklib/meson.build similarity index 100% rename from hooklib/meson.build rename to common/hooklib/meson.build diff --git a/hooklib/path.c b/common/hooklib/path.c similarity index 100% rename from hooklib/path.c rename to common/hooklib/path.c diff --git a/hooklib/path.h b/common/hooklib/path.h similarity index 100% rename from hooklib/path.h rename to common/hooklib/path.h diff --git a/hooklib/printer.c b/common/hooklib/printer.c similarity index 100% rename from hooklib/printer.c rename to common/hooklib/printer.c diff --git a/hooklib/printer.h b/common/hooklib/printer.h similarity index 100% rename from hooklib/printer.h rename to common/hooklib/printer.h diff --git a/hooklib/reg.c b/common/hooklib/reg.c similarity index 100% rename from hooklib/reg.c rename to common/hooklib/reg.c diff --git a/hooklib/reg.h b/common/hooklib/reg.h similarity index 100% rename from hooklib/reg.h rename to common/hooklib/reg.h diff --git a/hooklib/setupapi.c b/common/hooklib/setupapi.c similarity index 100% rename from hooklib/setupapi.c rename to common/hooklib/setupapi.c diff --git a/hooklib/setupapi.h b/common/hooklib/setupapi.h similarity index 100% rename from hooklib/setupapi.h rename to common/hooklib/setupapi.h diff --git a/hooklib/spike.c b/common/hooklib/spike.c similarity index 100% rename from hooklib/spike.c rename to common/hooklib/spike.c diff --git a/hooklib/spike.h b/common/hooklib/spike.h similarity index 100% rename from hooklib/spike.h rename to common/hooklib/spike.h diff --git a/hooklib/touch.c b/common/hooklib/touch.c similarity index 100% rename from hooklib/touch.c rename to common/hooklib/touch.c diff --git a/hooklib/touch.h b/common/hooklib/touch.h similarity index 100% rename from hooklib/touch.h rename to common/hooklib/touch.h diff --git a/iccard/aime.c b/common/iccard/aime.c similarity index 100% rename from iccard/aime.c rename to common/iccard/aime.c diff --git a/iccard/aime.h b/common/iccard/aime.h similarity index 100% rename from iccard/aime.h rename to common/iccard/aime.h diff --git a/iccard/felica.c b/common/iccard/felica.c similarity index 100% rename from iccard/felica.c rename to common/iccard/felica.c diff --git a/iccard/felica.h b/common/iccard/felica.h similarity index 100% rename from iccard/felica.h rename to common/iccard/felica.h diff --git a/iccard/meson.build b/common/iccard/meson.build similarity index 100% rename from iccard/meson.build rename to common/iccard/meson.build diff --git a/iccard/mifare.h b/common/iccard/mifare.h similarity index 100% rename from iccard/mifare.h rename to common/iccard/mifare.h diff --git a/jvs/jvs-bus.c b/common/jvs/jvs-bus.c similarity index 100% rename from jvs/jvs-bus.c rename to common/jvs/jvs-bus.c diff --git a/jvs/jvs-bus.h b/common/jvs/jvs-bus.h similarity index 100% rename from jvs/jvs-bus.h rename to common/jvs/jvs-bus.h diff --git a/jvs/jvs-cmd.h b/common/jvs/jvs-cmd.h similarity index 100% rename from jvs/jvs-cmd.h rename to common/jvs/jvs-cmd.h diff --git a/jvs/jvs-frame.c b/common/jvs/jvs-frame.c similarity index 100% rename from jvs/jvs-frame.c rename to common/jvs/jvs-frame.c diff --git a/jvs/jvs-frame.h b/common/jvs/jvs-frame.h similarity index 100% rename from jvs/jvs-frame.h rename to common/jvs/jvs-frame.h diff --git a/jvs/jvs-util.c b/common/jvs/jvs-util.c similarity index 100% rename from jvs/jvs-util.c rename to common/jvs/jvs-util.c diff --git a/jvs/jvs-util.h b/common/jvs/jvs-util.h similarity index 100% rename from jvs/jvs-util.h rename to common/jvs/jvs-util.h diff --git a/jvs/meson.build b/common/jvs/meson.build similarity index 100% rename from jvs/meson.build rename to common/jvs/meson.build diff --git a/platform/amvideo.c b/common/platform/amvideo.c similarity index 100% rename from platform/amvideo.c rename to common/platform/amvideo.c diff --git a/platform/amvideo.h b/common/platform/amvideo.h similarity index 100% rename from platform/amvideo.h rename to common/platform/amvideo.h diff --git a/platform/clock.c b/common/platform/clock.c similarity index 100% rename from platform/clock.c rename to common/platform/clock.c diff --git a/platform/clock.h b/common/platform/clock.h similarity index 100% rename from platform/clock.h rename to common/platform/clock.h diff --git a/platform/config.c b/common/platform/config.c similarity index 100% rename from platform/config.c rename to common/platform/config.c diff --git a/platform/config.h b/common/platform/config.h similarity index 100% rename from platform/config.h rename to common/platform/config.h diff --git a/platform/dns.c b/common/platform/dns.c similarity index 100% rename from platform/dns.c rename to common/platform/dns.c diff --git a/platform/dns.h b/common/platform/dns.h similarity index 100% rename from platform/dns.h rename to common/platform/dns.h diff --git a/platform/epay.c b/common/platform/epay.c similarity index 100% rename from platform/epay.c rename to common/platform/epay.c diff --git a/platform/epay.h b/common/platform/epay.h similarity index 100% rename from platform/epay.h rename to common/platform/epay.h diff --git a/platform/hwmon.c b/common/platform/hwmon.c similarity index 100% rename from platform/hwmon.c rename to common/platform/hwmon.c diff --git a/platform/hwmon.h b/common/platform/hwmon.h similarity index 100% rename from platform/hwmon.h rename to common/platform/hwmon.h diff --git a/platform/hwreset.c b/common/platform/hwreset.c similarity index 100% rename from platform/hwreset.c rename to common/platform/hwreset.c diff --git a/platform/hwreset.h b/common/platform/hwreset.h similarity index 100% rename from platform/hwreset.h rename to common/platform/hwreset.h diff --git a/platform/meson.build b/common/platform/meson.build similarity index 100% rename from platform/meson.build rename to common/platform/meson.build diff --git a/platform/misc.c b/common/platform/misc.c similarity index 100% rename from platform/misc.c rename to common/platform/misc.c diff --git a/platform/misc.h b/common/platform/misc.h similarity index 100% rename from platform/misc.h rename to common/platform/misc.h diff --git a/platform/netenv.c b/common/platform/netenv.c similarity index 100% rename from platform/netenv.c rename to common/platform/netenv.c diff --git a/platform/netenv.h b/common/platform/netenv.h similarity index 100% rename from platform/netenv.h rename to common/platform/netenv.h diff --git a/platform/nusec.c b/common/platform/nusec.c similarity index 100% rename from platform/nusec.c rename to common/platform/nusec.c diff --git a/platform/nusec.h b/common/platform/nusec.h similarity index 100% rename from platform/nusec.h rename to common/platform/nusec.h diff --git a/platform/pcbid.c b/common/platform/pcbid.c similarity index 100% rename from platform/pcbid.c rename to common/platform/pcbid.c diff --git a/platform/pcbid.h b/common/platform/pcbid.h similarity index 100% rename from platform/pcbid.h rename to common/platform/pcbid.h diff --git a/platform/platform.c b/common/platform/platform.c similarity index 100% rename from platform/platform.c rename to common/platform/platform.c diff --git a/platform/platform.h b/common/platform/platform.h similarity index 100% rename from platform/platform.h rename to common/platform/platform.h diff --git a/platform/system.c b/common/platform/system.c similarity index 98% rename from platform/system.c rename to common/platform/system.c index 3916f58..3baf5c1 100644 --- a/platform/system.c +++ b/common/platform/system.c @@ -178,6 +178,6 @@ static void system_save_sysfile(const wchar_t *sys_file) { CloseHandle(h_sysfile); if (sysfile_bytes_written != 0x6000) { - dprintf("System: Only 0x%04X bytes written out of 0x6000!\n", sysfile_bytes_written); + dprintf("System: Only 0x%04lX bytes written out of 0x6000!\n", sysfile_bytes_written); } } diff --git a/platform/system.h b/common/platform/system.h similarity index 100% rename from platform/system.h rename to common/platform/system.h diff --git a/platform/vfs.c b/common/platform/vfs.c similarity index 100% rename from platform/vfs.c rename to common/platform/vfs.c diff --git a/platform/vfs.h b/common/platform/vfs.h similarity index 100% rename from platform/vfs.h rename to common/platform/vfs.h diff --git a/unityhook/config.c b/common/unityhook/config.c similarity index 100% rename from unityhook/config.c rename to common/unityhook/config.c diff --git a/unityhook/config.h b/common/unityhook/config.h similarity index 94% rename from unityhook/config.h rename to common/unityhook/config.h index 6fca14a..6857c4b 100644 --- a/unityhook/config.h +++ b/common/unityhook/config.h @@ -1,12 +1,12 @@ -#pragma once - -#include - -#include - -struct unity_config { - bool enable; - wchar_t target_assembly[MAX_PATH]; -}; - -void unity_config_load(struct unity_config *cfg, const wchar_t *filename); +#pragma once + +#include + +#include + +struct unity_config { + bool enable; + wchar_t target_assembly[MAX_PATH]; +}; + +void unity_config_load(struct unity_config *cfg, const wchar_t *filename); diff --git a/unityhook/doorstop.c b/common/unityhook/doorstop.c similarity index 100% rename from unityhook/doorstop.c rename to common/unityhook/doorstop.c diff --git a/unityhook/doorstop.h b/common/unityhook/doorstop.h similarity index 83% rename from unityhook/doorstop.h rename to common/unityhook/doorstop.h index 8cc961e..2a44f33 100644 --- a/unityhook/doorstop.h +++ b/common/unityhook/doorstop.h @@ -1,5 +1,5 @@ -#pragma once - -#include "config.h" - +#pragma once + +#include "config.h" + void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module); \ No newline at end of file diff --git a/unityhook/hook.c b/common/unityhook/hook.c similarity index 100% rename from unityhook/hook.c rename to common/unityhook/hook.c diff --git a/unityhook/hook.h b/common/unityhook/hook.h similarity index 96% rename from unityhook/hook.h rename to common/unityhook/hook.h index 7be6044..a7c75e1 100644 --- a/unityhook/hook.h +++ b/common/unityhook/hook.h @@ -1,9 +1,9 @@ -#pragma once - -#include - -#include "config.h" - -typedef void (*unity_hook_callback_func)(HMODULE, const wchar_t*); - -void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback); +#pragma once + +#include + +#include "config.h" + +typedef void (*unity_hook_callback_func)(HMODULE, const wchar_t*); + +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback); diff --git a/unityhook/meson.build b/common/unityhook/meson.build similarity index 95% rename from unityhook/meson.build rename to common/unityhook/meson.build index 50d0488..f541c1e 100644 --- a/unityhook/meson.build +++ b/common/unityhook/meson.build @@ -1,19 +1,19 @@ -unityhook_lib = static_library( - 'unityhook', - include_directories: inc, - implicit_include_directories: false, - dependencies: [ - capnhook.get_variable('hook_dep'), - pathcch_lib - ], - sources: [ - 'mono.h', - 'config.c', - 'config.h', - 'doorstop.c', - 'doorstop.h', - 'hook.c', - 'hook.h', - 'util.h' - ], -) +unityhook_lib = static_library( + 'unityhook', + include_directories: inc, + implicit_include_directories: false, + dependencies: [ + capnhook.get_variable('hook_dep'), + pathcch_lib + ], + sources: [ + 'mono.h', + 'config.c', + 'config.h', + 'doorstop.c', + 'doorstop.h', + 'hook.c', + 'hook.h', + 'util.h' + ], +) diff --git a/unityhook/mono.h b/common/unityhook/mono.h similarity index 97% rename from unityhook/mono.h rename to common/unityhook/mono.h index 7056e75..39fdc01 100644 --- a/unityhook/mono.h +++ b/common/unityhook/mono.h @@ -1,100 +1,100 @@ -// SPDX-License-Identifier: CC0 -// https://github.com/NeighTools/UnityDoorstop -#pragma once - -#include - -// Here we define the pointers to some functions within mono.dll -// Note to C learners: these are not signature definitions, but rather "variable" -// definitions with the function pointer type. - -// Note: we use void* instead of the real intented structs defined in mono API -// This way we don't need to include or define any of Mono's structs, which saves space -// This, obviously, comes with a drawback of not being able to easily access the contents of the structs - -void * (*mono_thread_current)(); -void (*mono_thread_set_main)(void *); - -void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); -void *(*mono_domain_assembly_open)(void *domain, const char *name); -void *(*mono_assembly_get_image)(void *assembly); -void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); - -void *(*mono_method_desc_new)(const char *name, int include_namespace); -void* (*mono_method_desc_search_in_image)(void* desc, void* image); -void *(*mono_method_desc_search_in_class)(void *desc, void *klass); -void (*mono_method_desc_free)(void *desc); -void *(*mono_method_signature)(void *method); -UINT32 (*mono_signature_get_param_count)(void *sig); - -void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name); -void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); -void *(*mono_get_string_class)(); - -char *(*mono_assembly_getrootdir)(); - -// Additional funcs to bootstrap custom MONO -void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir); -void (*mono_config_parse)(const char* filename); -void (*mono_set_assemblies_path)(const char* path); -void *(*mono_object_to_string)(void* obj, void** exc); -char *(*mono_string_to_utf8)(void* s); - -void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly, - const char *name); - -void* (*mono_get_exception_class)(); -void* (*mono_object_get_virtual_method)(void* obj_raw, void* method); - -void* (*mono_jit_parse_options)(int argc, const char** argv); - -typedef enum { - MONO_DEBUG_FORMAT_NONE, - MONO_DEBUG_FORMAT_MONO, - /* Deprecated, the mdb debugger is not longer supported. */ - MONO_DEBUG_FORMAT_DEBUGGER -} MonoDebugFormat; - -void* (*mono_debug_init)(MonoDebugFormat format); -void* (*mono_debug_domain_create)(void* domain); - -/** -* \brief Loads Mono C API function pointers so that the above definitions can be called. -* \param mono_lib Mono.dll module. -*/ -void load_mono_functions(HMODULE mono_lib) { - // Enjoy the fact that C allows such sloppy casting - // In C++ you would have to cast to the precise function pointer type -#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name) - - // Find and assign all our functions that we are going to use - GET_MONO_PROC(mono_domain_assembly_open); - GET_MONO_PROC(mono_assembly_get_image); - GET_MONO_PROC(mono_runtime_invoke); - GET_MONO_PROC(mono_jit_init_version); - GET_MONO_PROC(mono_method_desc_new); - GET_MONO_PROC(mono_method_desc_search_in_class); - GET_MONO_PROC(mono_method_desc_search_in_image); - GET_MONO_PROC(mono_method_desc_free); - GET_MONO_PROC(mono_method_signature); - GET_MONO_PROC(mono_signature_get_param_count); - GET_MONO_PROC(mono_array_new); - GET_MONO_PROC(mono_get_string_class); - GET_MONO_PROC(mono_assembly_getrootdir); - GET_MONO_PROC(mono_thread_current); - GET_MONO_PROC(mono_thread_set_main); - GET_MONO_PROC(mono_domain_set_config); - GET_MONO_PROC(mono_set_dirs); - GET_MONO_PROC(mono_config_parse); - GET_MONO_PROC(mono_set_assemblies_path); - GET_MONO_PROC(mono_object_to_string); - GET_MONO_PROC(mono_string_to_utf8); - GET_MONO_PROC(mono_image_open_from_data_with_name); - GET_MONO_PROC(mono_get_exception_class); - GET_MONO_PROC(mono_object_get_virtual_method); - GET_MONO_PROC(mono_jit_parse_options); - GET_MONO_PROC(mono_debug_init); - GET_MONO_PROC(mono_debug_domain_create); - -#undef GET_MONO_PROC +// SPDX-License-Identifier: CC0 +// https://github.com/NeighTools/UnityDoorstop +#pragma once + +#include + +// Here we define the pointers to some functions within mono.dll +// Note to C learners: these are not signature definitions, but rather "variable" +// definitions with the function pointer type. + +// Note: we use void* instead of the real intented structs defined in mono API +// This way we don't need to include or define any of Mono's structs, which saves space +// This, obviously, comes with a drawback of not being able to easily access the contents of the structs + +void * (*mono_thread_current)(); +void (*mono_thread_set_main)(void *); + +void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); +void *(*mono_domain_assembly_open)(void *domain, const char *name); +void *(*mono_assembly_get_image)(void *assembly); +void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); + +void *(*mono_method_desc_new)(const char *name, int include_namespace); +void* (*mono_method_desc_search_in_image)(void* desc, void* image); +void *(*mono_method_desc_search_in_class)(void *desc, void *klass); +void (*mono_method_desc_free)(void *desc); +void *(*mono_method_signature)(void *method); +UINT32 (*mono_signature_get_param_count)(void *sig); + +void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name); +void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); +void *(*mono_get_string_class)(); + +char *(*mono_assembly_getrootdir)(); + +// Additional funcs to bootstrap custom MONO +void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir); +void (*mono_config_parse)(const char* filename); +void (*mono_set_assemblies_path)(const char* path); +void *(*mono_object_to_string)(void* obj, void** exc); +char *(*mono_string_to_utf8)(void* s); + +void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly, + const char *name); + +void* (*mono_get_exception_class)(); +void* (*mono_object_get_virtual_method)(void* obj_raw, void* method); + +void* (*mono_jit_parse_options)(int argc, const char** argv); + +typedef enum { + MONO_DEBUG_FORMAT_NONE, + MONO_DEBUG_FORMAT_MONO, + /* Deprecated, the mdb debugger is not longer supported. */ + MONO_DEBUG_FORMAT_DEBUGGER +} MonoDebugFormat; + +void* (*mono_debug_init)(MonoDebugFormat format); +void* (*mono_debug_domain_create)(void* domain); + +/** +* \brief Loads Mono C API function pointers so that the above definitions can be called. +* \param mono_lib Mono.dll module. +*/ +void load_mono_functions(HMODULE mono_lib) { + // Enjoy the fact that C allows such sloppy casting + // In C++ you would have to cast to the precise function pointer type +#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name) + + // Find and assign all our functions that we are going to use + GET_MONO_PROC(mono_domain_assembly_open); + GET_MONO_PROC(mono_assembly_get_image); + GET_MONO_PROC(mono_runtime_invoke); + GET_MONO_PROC(mono_jit_init_version); + GET_MONO_PROC(mono_method_desc_new); + GET_MONO_PROC(mono_method_desc_search_in_class); + GET_MONO_PROC(mono_method_desc_search_in_image); + GET_MONO_PROC(mono_method_desc_free); + GET_MONO_PROC(mono_method_signature); + GET_MONO_PROC(mono_signature_get_param_count); + GET_MONO_PROC(mono_array_new); + GET_MONO_PROC(mono_get_string_class); + GET_MONO_PROC(mono_assembly_getrootdir); + GET_MONO_PROC(mono_thread_current); + GET_MONO_PROC(mono_thread_set_main); + GET_MONO_PROC(mono_domain_set_config); + GET_MONO_PROC(mono_set_dirs); + GET_MONO_PROC(mono_config_parse); + GET_MONO_PROC(mono_set_assemblies_path); + GET_MONO_PROC(mono_object_to_string); + GET_MONO_PROC(mono_string_to_utf8); + GET_MONO_PROC(mono_image_open_from_data_with_name); + GET_MONO_PROC(mono_get_exception_class); + GET_MONO_PROC(mono_object_get_virtual_method); + GET_MONO_PROC(mono_jit_parse_options); + GET_MONO_PROC(mono_debug_init); + GET_MONO_PROC(mono_debug_domain_create); + +#undef GET_MONO_PROC } \ No newline at end of file diff --git a/unityhook/util.h b/common/unityhook/util.h similarity index 96% rename from unityhook/util.h rename to common/unityhook/util.h index 41def7b..9ad0a80 100644 --- a/unityhook/util.h +++ b/common/unityhook/util.h @@ -1,20 +1,20 @@ -#pragma once - -#include - -wchar_t *widen(const char *str) { - const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - wchar_t *result = malloc(reqsz * sizeof(wchar_t)); - - MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz); - return result; -} - -char *narrow(const wchar_t *str) { - const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); - char *result = malloc(reqsz * sizeof(char)); - - WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL); - return result; -} - +#pragma once + +#include + +wchar_t *widen(const char *str) { + const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + wchar_t *result = malloc(reqsz * sizeof(wchar_t)); + + MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz); + return result; +} + +char *narrow(const wchar_t *str) { + const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + char *result = malloc(reqsz * sizeof(char)); + + WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL); + return result; +} + diff --git a/util/async.c b/common/util/async.c similarity index 100% rename from util/async.c rename to common/util/async.c diff --git a/util/async.h b/common/util/async.h similarity index 100% rename from util/async.h rename to common/util/async.h diff --git a/util/crc.c b/common/util/crc.c similarity index 100% rename from util/crc.c rename to common/util/crc.c diff --git a/util/crc.h b/common/util/crc.h similarity index 100% rename from util/crc.h rename to common/util/crc.h diff --git a/util/dll-bind.c b/common/util/dll-bind.c similarity index 100% rename from util/dll-bind.c rename to common/util/dll-bind.c diff --git a/util/dll-bind.h b/common/util/dll-bind.h similarity index 100% rename from util/dll-bind.h rename to common/util/dll-bind.h diff --git a/util/dprintf.c b/common/util/dprintf.c similarity index 100% rename from util/dprintf.c rename to common/util/dprintf.c diff --git a/util/dprintf.h b/common/util/dprintf.h similarity index 100% rename from util/dprintf.h rename to common/util/dprintf.h diff --git a/util/dump.c b/common/util/dump.c similarity index 100% rename from util/dump.c rename to common/util/dump.c diff --git a/util/dump.h b/common/util/dump.h similarity index 100% rename from util/dump.h rename to common/util/dump.h diff --git a/util/env.c b/common/util/env.c similarity index 100% rename from util/env.c rename to common/util/env.c diff --git a/util/env.h b/common/util/env.h similarity index 100% rename from util/env.h rename to common/util/env.h diff --git a/util/get_function_ordinal.c b/common/util/get_function_ordinal.c similarity index 100% rename from util/get_function_ordinal.c rename to common/util/get_function_ordinal.c diff --git a/util/get_function_ordinal.h b/common/util/get_function_ordinal.h similarity index 100% rename from util/get_function_ordinal.h rename to common/util/get_function_ordinal.h diff --git a/util/lib.c b/common/util/lib.c similarity index 100% rename from util/lib.c rename to common/util/lib.c diff --git a/util/lib.h b/common/util/lib.h similarity index 100% rename from util/lib.h rename to common/util/lib.h diff --git a/util/meson.build b/common/util/meson.build similarity index 100% rename from util/meson.build rename to common/util/meson.build diff --git a/util/slurp.c b/common/util/slurp.c similarity index 100% rename from util/slurp.c rename to common/util/slurp.c diff --git a/util/slurp.h b/common/util/slurp.h similarity index 100% rename from util/slurp.h rename to common/util/slurp.h diff --git a/util/str.c b/common/util/str.c similarity index 100% rename from util/str.c rename to common/util/str.c diff --git a/util/str.h b/common/util/str.h similarity index 100% rename from util/str.h rename to common/util/str.h diff --git a/dist/fgo/launch.bat b/dist/fgo/launch.bat index 3be4f8a..1b76197 100644 --- a/dist/fgo/launch.bat +++ b/dist/fgo/launch.bat @@ -1,6 +1,6 @@ @echo off -cd /d %~dp0 +pushd %~dp0 inject -d -k fgohook.dll ago.exe diff --git a/carolhook/carol-dll.c b/games/carolhook/carol-dll.c similarity index 100% rename from carolhook/carol-dll.c rename to games/carolhook/carol-dll.c diff --git a/carolhook/carol-dll.h b/games/carolhook/carol-dll.h similarity index 100% rename from carolhook/carol-dll.h rename to games/carolhook/carol-dll.h diff --git a/carolhook/carolhook.def b/games/carolhook/carolhook.def similarity index 100% rename from carolhook/carolhook.def rename to games/carolhook/carolhook.def diff --git a/carolhook/config.c b/games/carolhook/config.c similarity index 100% rename from carolhook/config.c rename to games/carolhook/config.c diff --git a/carolhook/config.h b/games/carolhook/config.h similarity index 100% rename from carolhook/config.h rename to games/carolhook/config.h diff --git a/carolhook/controlbd.c b/games/carolhook/controlbd.c similarity index 100% rename from carolhook/controlbd.c rename to games/carolhook/controlbd.c diff --git a/carolhook/controlbd.h b/games/carolhook/controlbd.h similarity index 100% rename from carolhook/controlbd.h rename to games/carolhook/controlbd.h diff --git a/carolhook/dllmain.c b/games/carolhook/dllmain.c similarity index 100% rename from carolhook/dllmain.c rename to games/carolhook/dllmain.c diff --git a/carolhook/jvs.c b/games/carolhook/jvs.c similarity index 100% rename from carolhook/jvs.c rename to games/carolhook/jvs.c diff --git a/carolhook/jvs.h b/games/carolhook/jvs.h similarity index 100% rename from carolhook/jvs.h rename to games/carolhook/jvs.h diff --git a/carolhook/ledbd.c b/games/carolhook/ledbd.c similarity index 100% rename from carolhook/ledbd.c rename to games/carolhook/ledbd.c diff --git a/carolhook/ledbd.h b/games/carolhook/ledbd.h similarity index 100% rename from carolhook/ledbd.h rename to games/carolhook/ledbd.h diff --git a/carolhook/meson.build b/games/carolhook/meson.build similarity index 100% rename from carolhook/meson.build rename to games/carolhook/meson.build diff --git a/carolhook/touch.c b/games/carolhook/touch.c similarity index 100% rename from carolhook/touch.c rename to games/carolhook/touch.c diff --git a/carolhook/touch.h b/games/carolhook/touch.h similarity index 100% rename from carolhook/touch.h rename to games/carolhook/touch.h diff --git a/carolio/carolio.c b/games/carolio/carolio.c similarity index 100% rename from carolio/carolio.c rename to games/carolio/carolio.c diff --git a/carolio/carolio.h b/games/carolio/carolio.h similarity index 100% rename from carolio/carolio.h rename to games/carolio/carolio.h diff --git a/carolio/config.c b/games/carolio/config.c similarity index 100% rename from carolio/config.c rename to games/carolio/config.c diff --git a/carolio/config.h b/games/carolio/config.h similarity index 100% rename from carolio/config.h rename to games/carolio/config.h diff --git a/carolio/meson.build b/games/carolio/meson.build similarity index 100% rename from carolio/meson.build rename to games/carolio/meson.build diff --git a/chunihook/chuni-dll.c b/games/chunihook/chuni-dll.c similarity index 100% rename from chunihook/chuni-dll.c rename to games/chunihook/chuni-dll.c diff --git a/chunihook/chuni-dll.h b/games/chunihook/chuni-dll.h similarity index 100% rename from chunihook/chuni-dll.h rename to games/chunihook/chuni-dll.h diff --git a/chunihook/chunihook.def b/games/chunihook/chunihook.def similarity index 100% rename from chunihook/chunihook.def rename to games/chunihook/chunihook.def diff --git a/chunihook/config.c b/games/chunihook/config.c similarity index 100% rename from chunihook/config.c rename to games/chunihook/config.c diff --git a/chunihook/config.h b/games/chunihook/config.h similarity index 100% rename from chunihook/config.h rename to games/chunihook/config.h diff --git a/chunihook/dllmain.c b/games/chunihook/dllmain.c similarity index 100% rename from chunihook/dllmain.c rename to games/chunihook/dllmain.c diff --git a/chunihook/jvs.c b/games/chunihook/jvs.c similarity index 100% rename from chunihook/jvs.c rename to games/chunihook/jvs.c diff --git a/chunihook/jvs.h b/games/chunihook/jvs.h similarity index 100% rename from chunihook/jvs.h rename to games/chunihook/jvs.h diff --git a/chunihook/meson.build b/games/chunihook/meson.build similarity index 100% rename from chunihook/meson.build rename to games/chunihook/meson.build diff --git a/chunihook/slider.c b/games/chunihook/slider.c similarity index 100% rename from chunihook/slider.c rename to games/chunihook/slider.c diff --git a/chunihook/slider.h b/games/chunihook/slider.h similarity index 100% rename from chunihook/slider.h rename to games/chunihook/slider.h diff --git a/chuniio/chu2to3.c b/games/chuniio/chu2to3.c similarity index 100% rename from chuniio/chu2to3.c rename to games/chuniio/chu2to3.c diff --git a/chuniio/chu2to3.h b/games/chuniio/chu2to3.h similarity index 100% rename from chuniio/chu2to3.h rename to games/chuniio/chu2to3.h diff --git a/chuniio/chuniio.c b/games/chuniio/chuniio.c similarity index 100% rename from chuniio/chuniio.c rename to games/chuniio/chuniio.c diff --git a/chuniio/chuniio.h b/games/chuniio/chuniio.h similarity index 100% rename from chuniio/chuniio.h rename to games/chuniio/chuniio.h diff --git a/chuniio/config.c b/games/chuniio/config.c similarity index 100% rename from chuniio/config.c rename to games/chuniio/config.c diff --git a/chuniio/config.h b/games/chuniio/config.h similarity index 100% rename from chuniio/config.h rename to games/chuniio/config.h diff --git a/chuniio/leddata.h b/games/chuniio/leddata.h similarity index 100% rename from chuniio/leddata.h rename to games/chuniio/leddata.h diff --git a/chuniio/ledoutput.c b/games/chuniio/ledoutput.c similarity index 100% rename from chuniio/ledoutput.c rename to games/chuniio/ledoutput.c diff --git a/chuniio/ledoutput.h b/games/chuniio/ledoutput.h similarity index 100% rename from chuniio/ledoutput.h rename to games/chuniio/ledoutput.h diff --git a/chuniio/meson.build b/games/chuniio/meson.build similarity index 100% rename from chuniio/meson.build rename to games/chuniio/meson.build diff --git a/chuniio/pipeimpl.c b/games/chuniio/pipeimpl.c similarity index 100% rename from chuniio/pipeimpl.c rename to games/chuniio/pipeimpl.c diff --git a/chuniio/pipeimpl.h b/games/chuniio/pipeimpl.h similarity index 100% rename from chuniio/pipeimpl.h rename to games/chuniio/pipeimpl.h diff --git a/chuniio/serialimpl.c b/games/chuniio/serialimpl.c similarity index 100% rename from chuniio/serialimpl.c rename to games/chuniio/serialimpl.c diff --git a/chuniio/serialimpl.h b/games/chuniio/serialimpl.h similarity index 100% rename from chuniio/serialimpl.h rename to games/chuniio/serialimpl.h diff --git a/chusanhook/chuni-dll.c b/games/chusanhook/chuni-dll.c similarity index 100% rename from chusanhook/chuni-dll.c rename to games/chusanhook/chuni-dll.c diff --git a/chusanhook/chuni-dll.h b/games/chusanhook/chuni-dll.h similarity index 100% rename from chusanhook/chuni-dll.h rename to games/chusanhook/chuni-dll.h diff --git a/chusanhook/chusanhook.def b/games/chusanhook/chusanhook.def similarity index 100% rename from chusanhook/chusanhook.def rename to games/chusanhook/chusanhook.def diff --git a/chusanhook/config.c b/games/chusanhook/config.c similarity index 100% rename from chusanhook/config.c rename to games/chusanhook/config.c diff --git a/chusanhook/config.h b/games/chusanhook/config.h similarity index 100% rename from chusanhook/config.h rename to games/chusanhook/config.h diff --git a/chusanhook/dllmain.c b/games/chusanhook/dllmain.c similarity index 100% rename from chusanhook/dllmain.c rename to games/chusanhook/dllmain.c diff --git a/chusanhook/io4.c b/games/chusanhook/io4.c similarity index 100% rename from chusanhook/io4.c rename to games/chusanhook/io4.c diff --git a/chusanhook/io4.h b/games/chusanhook/io4.h similarity index 100% rename from chusanhook/io4.h rename to games/chusanhook/io4.h diff --git a/chusanhook/meson.build b/games/chusanhook/meson.build similarity index 100% rename from chusanhook/meson.build rename to games/chusanhook/meson.build diff --git a/chusanhook/slider.c b/games/chusanhook/slider.c similarity index 100% rename from chusanhook/slider.c rename to games/chusanhook/slider.c diff --git a/chusanhook/slider.h b/games/chusanhook/slider.h similarity index 100% rename from chusanhook/slider.h rename to games/chusanhook/slider.h diff --git a/cmhook/cm-dll.c b/games/cmhook/cm-dll.c similarity index 100% rename from cmhook/cm-dll.c rename to games/cmhook/cm-dll.c diff --git a/cmhook/cm-dll.h b/games/cmhook/cm-dll.h similarity index 100% rename from cmhook/cm-dll.h rename to games/cmhook/cm-dll.h diff --git a/cmhook/cmhook.def b/games/cmhook/cmhook.def similarity index 100% rename from cmhook/cmhook.def rename to games/cmhook/cmhook.def diff --git a/cmhook/config.c b/games/cmhook/config.c similarity index 100% rename from cmhook/config.c rename to games/cmhook/config.c diff --git a/cmhook/config.h b/games/cmhook/config.h similarity index 100% rename from cmhook/config.h rename to games/cmhook/config.h diff --git a/cmhook/dllmain.c b/games/cmhook/dllmain.c similarity index 100% rename from cmhook/dllmain.c rename to games/cmhook/dllmain.c diff --git a/cmhook/io4.c b/games/cmhook/io4.c similarity index 100% rename from cmhook/io4.c rename to games/cmhook/io4.c diff --git a/cmhook/io4.h b/games/cmhook/io4.h similarity index 100% rename from cmhook/io4.h rename to games/cmhook/io4.h diff --git a/cmhook/meson.build b/games/cmhook/meson.build similarity index 100% rename from cmhook/meson.build rename to games/cmhook/meson.build diff --git a/cmio/cmio.c b/games/cmio/cmio.c similarity index 100% rename from cmio/cmio.c rename to games/cmio/cmio.c diff --git a/cmio/cmio.h b/games/cmio/cmio.h similarity index 100% rename from cmio/cmio.h rename to games/cmio/cmio.h diff --git a/cmio/config.c b/games/cmio/config.c similarity index 100% rename from cmio/config.c rename to games/cmio/config.c diff --git a/cmio/config.h b/games/cmio/config.h similarity index 100% rename from cmio/config.h rename to games/cmio/config.h diff --git a/cmio/meson.build b/games/cmio/meson.build similarity index 100% rename from cmio/meson.build rename to games/cmio/meson.build diff --git a/cxbhook/config.c b/games/cxbhook/config.c similarity index 100% rename from cxbhook/config.c rename to games/cxbhook/config.c diff --git a/cxbhook/config.h b/games/cxbhook/config.h similarity index 100% rename from cxbhook/config.h rename to games/cxbhook/config.h diff --git a/cxbhook/cxb-dll.c b/games/cxbhook/cxb-dll.c similarity index 100% rename from cxbhook/cxb-dll.c rename to games/cxbhook/cxb-dll.c diff --git a/cxbhook/cxb-dll.h b/games/cxbhook/cxb-dll.h similarity index 100% rename from cxbhook/cxb-dll.h rename to games/cxbhook/cxb-dll.h diff --git a/cxbhook/cxbhook.def b/games/cxbhook/cxbhook.def similarity index 100% rename from cxbhook/cxbhook.def rename to games/cxbhook/cxbhook.def diff --git a/cxbhook/dllmain.c b/games/cxbhook/dllmain.c similarity index 100% rename from cxbhook/dllmain.c rename to games/cxbhook/dllmain.c diff --git a/cxbhook/led.c b/games/cxbhook/led.c similarity index 100% rename from cxbhook/led.c rename to games/cxbhook/led.c diff --git a/cxbhook/led.h b/games/cxbhook/led.h similarity index 100% rename from cxbhook/led.h rename to games/cxbhook/led.h diff --git a/cxbhook/meson.build b/games/cxbhook/meson.build similarity index 100% rename from cxbhook/meson.build rename to games/cxbhook/meson.build diff --git a/cxbhook/revio.c b/games/cxbhook/revio.c similarity index 100% rename from cxbhook/revio.c rename to games/cxbhook/revio.c diff --git a/cxbhook/revio.h b/games/cxbhook/revio.h similarity index 100% rename from cxbhook/revio.h rename to games/cxbhook/revio.h diff --git a/cxbio/config.c b/games/cxbio/config.c similarity index 100% rename from cxbio/config.c rename to games/cxbio/config.c diff --git a/cxbio/config.h b/games/cxbio/config.h similarity index 100% rename from cxbio/config.h rename to games/cxbio/config.h diff --git a/cxbio/cxbio.c b/games/cxbio/cxbio.c similarity index 100% rename from cxbio/cxbio.c rename to games/cxbio/cxbio.c diff --git a/cxbio/cxbio.h b/games/cxbio/cxbio.h similarity index 100% rename from cxbio/cxbio.h rename to games/cxbio/cxbio.h diff --git a/cxbio/meson.build b/games/cxbio/meson.build similarity index 100% rename from cxbio/meson.build rename to games/cxbio/meson.build diff --git a/divahook/config.c b/games/divahook/config.c similarity index 100% rename from divahook/config.c rename to games/divahook/config.c diff --git a/divahook/config.h b/games/divahook/config.h similarity index 100% rename from divahook/config.h rename to games/divahook/config.h diff --git a/divahook/diva-dll.c b/games/divahook/diva-dll.c similarity index 100% rename from divahook/diva-dll.c rename to games/divahook/diva-dll.c diff --git a/divahook/diva-dll.h b/games/divahook/diva-dll.h similarity index 100% rename from divahook/diva-dll.h rename to games/divahook/diva-dll.h diff --git a/divahook/divahook.def b/games/divahook/divahook.def similarity index 100% rename from divahook/divahook.def rename to games/divahook/divahook.def diff --git a/divahook/dllmain.c b/games/divahook/dllmain.c similarity index 100% rename from divahook/dllmain.c rename to games/divahook/dllmain.c diff --git a/divahook/jvs.c b/games/divahook/jvs.c similarity index 100% rename from divahook/jvs.c rename to games/divahook/jvs.c diff --git a/divahook/jvs.h b/games/divahook/jvs.h similarity index 100% rename from divahook/jvs.h rename to games/divahook/jvs.h diff --git a/divahook/meson.build b/games/divahook/meson.build similarity index 100% rename from divahook/meson.build rename to games/divahook/meson.build diff --git a/divahook/slider.c b/games/divahook/slider.c similarity index 100% rename from divahook/slider.c rename to games/divahook/slider.c diff --git a/divahook/slider.h b/games/divahook/slider.h similarity index 100% rename from divahook/slider.h rename to games/divahook/slider.h diff --git a/divaio/config.c b/games/divaio/config.c similarity index 100% rename from divaio/config.c rename to games/divaio/config.c diff --git a/divaio/config.h b/games/divaio/config.h similarity index 100% rename from divaio/config.h rename to games/divaio/config.h diff --git a/divaio/divaio.c b/games/divaio/divaio.c similarity index 100% rename from divaio/divaio.c rename to games/divaio/divaio.c diff --git a/divaio/divaio.h b/games/divaio/divaio.h similarity index 100% rename from divaio/divaio.h rename to games/divaio/divaio.h diff --git a/divaio/meson.build b/games/divaio/meson.build similarity index 100% rename from divaio/meson.build rename to games/divaio/meson.build diff --git a/fgohook/config.c b/games/fgohook/config.c similarity index 100% rename from fgohook/config.c rename to games/fgohook/config.c diff --git a/fgohook/config.h b/games/fgohook/config.h similarity index 100% rename from fgohook/config.h rename to games/fgohook/config.h diff --git a/fgohook/deck.c b/games/fgohook/deck.c similarity index 100% rename from fgohook/deck.c rename to games/fgohook/deck.c diff --git a/fgohook/deck.h b/games/fgohook/deck.h similarity index 100% rename from fgohook/deck.h rename to games/fgohook/deck.h diff --git a/fgohook/dllmain.c b/games/fgohook/dllmain.c similarity index 100% rename from fgohook/dllmain.c rename to games/fgohook/dllmain.c diff --git a/fgohook/fgo-dll.c b/games/fgohook/fgo-dll.c similarity index 100% rename from fgohook/fgo-dll.c rename to games/fgohook/fgo-dll.c diff --git a/fgohook/fgo-dll.h b/games/fgohook/fgo-dll.h similarity index 100% rename from fgohook/fgo-dll.h rename to games/fgohook/fgo-dll.h diff --git a/fgohook/fgohook.def b/games/fgohook/fgohook.def similarity index 100% rename from fgohook/fgohook.def rename to games/fgohook/fgohook.def diff --git a/fgohook/ftdi.c b/games/fgohook/ftdi.c similarity index 100% rename from fgohook/ftdi.c rename to games/fgohook/ftdi.c diff --git a/fgohook/ftdi.h b/games/fgohook/ftdi.h similarity index 100% rename from fgohook/ftdi.h rename to games/fgohook/ftdi.h diff --git a/fgohook/io4.c b/games/fgohook/io4.c similarity index 100% rename from fgohook/io4.c rename to games/fgohook/io4.c diff --git a/fgohook/io4.h b/games/fgohook/io4.h similarity index 100% rename from fgohook/io4.h rename to games/fgohook/io4.h diff --git a/fgohook/meson.build b/games/fgohook/meson.build similarity index 100% rename from fgohook/meson.build rename to games/fgohook/meson.build diff --git a/fgoio/backend.h b/games/fgoio/backend.h similarity index 100% rename from fgoio/backend.h rename to games/fgoio/backend.h diff --git a/fgoio/config.c b/games/fgoio/config.c similarity index 100% rename from fgoio/config.c rename to games/fgoio/config.c diff --git a/fgoio/config.h b/games/fgoio/config.h similarity index 100% rename from fgoio/config.h rename to games/fgoio/config.h diff --git a/fgoio/fgoio.c b/games/fgoio/fgoio.c similarity index 100% rename from fgoio/fgoio.c rename to games/fgoio/fgoio.c diff --git a/fgoio/fgoio.h b/games/fgoio/fgoio.h similarity index 100% rename from fgoio/fgoio.h rename to games/fgoio/fgoio.h diff --git a/fgoio/keyboard.c b/games/fgoio/keyboard.c similarity index 100% rename from fgoio/keyboard.c rename to games/fgoio/keyboard.c diff --git a/fgoio/keyboard.h b/games/fgoio/keyboard.h similarity index 100% rename from fgoio/keyboard.h rename to games/fgoio/keyboard.h diff --git a/fgoio/meson.build b/games/fgoio/meson.build similarity index 100% rename from fgoio/meson.build rename to games/fgoio/meson.build diff --git a/fgoio/xi.c b/games/fgoio/xi.c similarity index 100% rename from fgoio/xi.c rename to games/fgoio/xi.c diff --git a/fgoio/xi.h b/games/fgoio/xi.h similarity index 100% rename from fgoio/xi.h rename to games/fgoio/xi.h diff --git a/idachook/config.c b/games/idachook/config.c similarity index 100% rename from idachook/config.c rename to games/idachook/config.c diff --git a/idachook/config.h b/games/idachook/config.h similarity index 100% rename from idachook/config.h rename to games/idachook/config.h diff --git a/idachook/dllmain.c b/games/idachook/dllmain.c similarity index 100% rename from idachook/dllmain.c rename to games/idachook/dllmain.c diff --git a/idachook/ffb.c b/games/idachook/ffb.c similarity index 100% rename from idachook/ffb.c rename to games/idachook/ffb.c diff --git a/idachook/ffb.h b/games/idachook/ffb.h similarity index 100% rename from idachook/ffb.h rename to games/idachook/ffb.h diff --git a/idachook/idac-dll.c b/games/idachook/idac-dll.c similarity index 100% rename from idachook/idac-dll.c rename to games/idachook/idac-dll.c diff --git a/idachook/idac-dll.h b/games/idachook/idac-dll.h similarity index 100% rename from idachook/idac-dll.h rename to games/idachook/idac-dll.h diff --git a/idachook/idachook.def b/games/idachook/idachook.def similarity index 100% rename from idachook/idachook.def rename to games/idachook/idachook.def diff --git a/idachook/indrun.c b/games/idachook/indrun.c similarity index 100% rename from idachook/indrun.c rename to games/idachook/indrun.c diff --git a/idachook/indrun.h b/games/idachook/indrun.h similarity index 100% rename from idachook/indrun.h rename to games/idachook/indrun.h diff --git a/idachook/io4.c b/games/idachook/io4.c similarity index 100% rename from idachook/io4.c rename to games/idachook/io4.c diff --git a/idachook/io4.h b/games/idachook/io4.h similarity index 100% rename from idachook/io4.h rename to games/idachook/io4.h diff --git a/idachook/meson.build b/games/idachook/meson.build similarity index 100% rename from idachook/meson.build rename to games/idachook/meson.build diff --git a/idachook/zinput.c b/games/idachook/zinput.c similarity index 100% rename from idachook/zinput.c rename to games/idachook/zinput.c diff --git a/idachook/zinput.h b/games/idachook/zinput.h similarity index 100% rename from idachook/zinput.h rename to games/idachook/zinput.h diff --git a/idacio/backend.h b/games/idacio/backend.h similarity index 100% rename from idacio/backend.h rename to games/idacio/backend.h diff --git a/idacio/config.c b/games/idacio/config.c similarity index 100% rename from idacio/config.c rename to games/idacio/config.c diff --git a/idacio/config.h b/games/idacio/config.h similarity index 100% rename from idacio/config.h rename to games/idacio/config.h diff --git a/idacio/di-dev.c b/games/idacio/di-dev.c similarity index 100% rename from idacio/di-dev.c rename to games/idacio/di-dev.c diff --git a/idacio/di-dev.h b/games/idacio/di-dev.h similarity index 100% rename from idacio/di-dev.h rename to games/idacio/di-dev.h diff --git a/idacio/di.c b/games/idacio/di.c similarity index 100% rename from idacio/di.c rename to games/idacio/di.c diff --git a/idacio/di.h b/games/idacio/di.h similarity index 100% rename from idacio/di.h rename to games/idacio/di.h diff --git a/idacio/dllmain.c b/games/idacio/dllmain.c similarity index 100% rename from idacio/dllmain.c rename to games/idacio/dllmain.c diff --git a/idacio/idacio.def b/games/idacio/idacio.def similarity index 100% rename from idacio/idacio.def rename to games/idacio/idacio.def diff --git a/idacio/idacio.h b/games/idacio/idacio.h similarity index 100% rename from idacio/idacio.h rename to games/idacio/idacio.h diff --git a/idacio/meson.build b/games/idacio/meson.build similarity index 100% rename from idacio/meson.build rename to games/idacio/meson.build diff --git a/idacio/shifter.c b/games/idacio/shifter.c similarity index 100% rename from idacio/shifter.c rename to games/idacio/shifter.c diff --git a/idacio/shifter.h b/games/idacio/shifter.h similarity index 100% rename from idacio/shifter.h rename to games/idacio/shifter.h diff --git a/idacio/wnd.c b/games/idacio/wnd.c similarity index 100% rename from idacio/wnd.c rename to games/idacio/wnd.c diff --git a/idacio/wnd.h b/games/idacio/wnd.h similarity index 100% rename from idacio/wnd.h rename to games/idacio/wnd.h diff --git a/idacio/xi.c b/games/idacio/xi.c similarity index 100% rename from idacio/xi.c rename to games/idacio/xi.c diff --git a/idacio/xi.h b/games/idacio/xi.h similarity index 100% rename from idacio/xi.h rename to games/idacio/xi.h diff --git a/idzhook/config.c b/games/idzhook/config.c similarity index 100% rename from idzhook/config.c rename to games/idzhook/config.c diff --git a/idzhook/config.h b/games/idzhook/config.h similarity index 100% rename from idzhook/config.h rename to games/idzhook/config.h diff --git a/idzhook/dllmain.c b/games/idzhook/dllmain.c similarity index 100% rename from idzhook/dllmain.c rename to games/idzhook/dllmain.c diff --git a/idzhook/ffb.c b/games/idzhook/ffb.c similarity index 100% rename from idzhook/ffb.c rename to games/idzhook/ffb.c diff --git a/idzhook/ffb.h b/games/idzhook/ffb.h similarity index 100% rename from idzhook/ffb.h rename to games/idzhook/ffb.h diff --git a/idzhook/idz-dll.c b/games/idzhook/idz-dll.c similarity index 100% rename from idzhook/idz-dll.c rename to games/idzhook/idz-dll.c diff --git a/idzhook/idz-dll.h b/games/idzhook/idz-dll.h similarity index 100% rename from idzhook/idz-dll.h rename to games/idzhook/idz-dll.h diff --git a/idzhook/idzhook.def b/games/idzhook/idzhook.def similarity index 100% rename from idzhook/idzhook.def rename to games/idzhook/idzhook.def diff --git a/idzhook/jvs.c b/games/idzhook/jvs.c similarity index 100% rename from idzhook/jvs.c rename to games/idzhook/jvs.c diff --git a/idzhook/jvs.h b/games/idzhook/jvs.h similarity index 100% rename from idzhook/jvs.h rename to games/idzhook/jvs.h diff --git a/idzhook/meson.build b/games/idzhook/meson.build similarity index 100% rename from idzhook/meson.build rename to games/idzhook/meson.build diff --git a/idzhook/zinput.c b/games/idzhook/zinput.c similarity index 100% rename from idzhook/zinput.c rename to games/idzhook/zinput.c diff --git a/idzhook/zinput.h b/games/idzhook/zinput.h similarity index 100% rename from idzhook/zinput.h rename to games/idzhook/zinput.h diff --git a/idzio/backend.h b/games/idzio/backend.h similarity index 100% rename from idzio/backend.h rename to games/idzio/backend.h diff --git a/idzio/config.c b/games/idzio/config.c similarity index 100% rename from idzio/config.c rename to games/idzio/config.c diff --git a/idzio/config.h b/games/idzio/config.h similarity index 100% rename from idzio/config.h rename to games/idzio/config.h diff --git a/idzio/di-dev.c b/games/idzio/di-dev.c similarity index 100% rename from idzio/di-dev.c rename to games/idzio/di-dev.c diff --git a/idzio/di-dev.h b/games/idzio/di-dev.h similarity index 100% rename from idzio/di-dev.h rename to games/idzio/di-dev.h diff --git a/idzio/di.c b/games/idzio/di.c similarity index 100% rename from idzio/di.c rename to games/idzio/di.c diff --git a/idzio/di.h b/games/idzio/di.h similarity index 100% rename from idzio/di.h rename to games/idzio/di.h diff --git a/idzio/dllmain.c b/games/idzio/dllmain.c similarity index 100% rename from idzio/dllmain.c rename to games/idzio/dllmain.c diff --git a/idzio/idzio.def b/games/idzio/idzio.def similarity index 100% rename from idzio/idzio.def rename to games/idzio/idzio.def diff --git a/idzio/idzio.h b/games/idzio/idzio.h similarity index 100% rename from idzio/idzio.h rename to games/idzio/idzio.h diff --git a/idzio/meson.build b/games/idzio/meson.build similarity index 100% rename from idzio/meson.build rename to games/idzio/meson.build diff --git a/idzio/shifter.c b/games/idzio/shifter.c similarity index 100% rename from idzio/shifter.c rename to games/idzio/shifter.c diff --git a/idzio/shifter.h b/games/idzio/shifter.h similarity index 100% rename from idzio/shifter.h rename to games/idzio/shifter.h diff --git a/idzio/wnd.c b/games/idzio/wnd.c similarity index 100% rename from idzio/wnd.c rename to games/idzio/wnd.c diff --git a/idzio/wnd.h b/games/idzio/wnd.h similarity index 100% rename from idzio/wnd.h rename to games/idzio/wnd.h diff --git a/idzio/xi.c b/games/idzio/xi.c similarity index 100% rename from idzio/xi.c rename to games/idzio/xi.c diff --git a/idzio/xi.h b/games/idzio/xi.h similarity index 100% rename from idzio/xi.h rename to games/idzio/xi.h diff --git a/kemonohook/config.c b/games/kemonohook/config.c similarity index 100% rename from kemonohook/config.c rename to games/kemonohook/config.c diff --git a/kemonohook/config.h b/games/kemonohook/config.h similarity index 100% rename from kemonohook/config.h rename to games/kemonohook/config.h diff --git a/kemonohook/dllmain.c b/games/kemonohook/dllmain.c similarity index 100% rename from kemonohook/dllmain.c rename to games/kemonohook/dllmain.c diff --git a/kemonohook/hooks.c b/games/kemonohook/hooks.c similarity index 100% rename from kemonohook/hooks.c rename to games/kemonohook/hooks.c diff --git a/kemonohook/hooks.h b/games/kemonohook/hooks.h similarity index 100% rename from kemonohook/hooks.h rename to games/kemonohook/hooks.h diff --git a/kemonohook/jvs.c b/games/kemonohook/jvs.c similarity index 100% rename from kemonohook/jvs.c rename to games/kemonohook/jvs.c diff --git a/kemonohook/jvs.h b/games/kemonohook/jvs.h similarity index 100% rename from kemonohook/jvs.h rename to games/kemonohook/jvs.h diff --git a/kemonohook/kemono-dll.c b/games/kemonohook/kemono-dll.c similarity index 100% rename from kemonohook/kemono-dll.c rename to games/kemonohook/kemono-dll.c diff --git a/kemonohook/kemono-dll.h b/games/kemonohook/kemono-dll.h similarity index 100% rename from kemonohook/kemono-dll.h rename to games/kemonohook/kemono-dll.h diff --git a/kemonohook/kemonohook.def b/games/kemonohook/kemonohook.def similarity index 100% rename from kemonohook/kemonohook.def rename to games/kemonohook/kemonohook.def diff --git a/kemonohook/meson.build b/games/kemonohook/meson.build similarity index 100% rename from kemonohook/meson.build rename to games/kemonohook/meson.build diff --git a/kemonoio/config.c b/games/kemonoio/config.c similarity index 100% rename from kemonoio/config.c rename to games/kemonoio/config.c diff --git a/kemonoio/config.h b/games/kemonoio/config.h similarity index 100% rename from kemonoio/config.h rename to games/kemonoio/config.h diff --git a/kemonoio/kemonoio.c b/games/kemonoio/kemonoio.c similarity index 100% rename from kemonoio/kemonoio.c rename to games/kemonoio/kemonoio.c diff --git a/kemonoio/kemonoio.h b/games/kemonoio/kemonoio.h similarity index 100% rename from kemonoio/kemonoio.h rename to games/kemonoio/kemonoio.h diff --git a/kemonoio/meson.build b/games/kemonoio/meson.build similarity index 100% rename from kemonoio/meson.build rename to games/kemonoio/meson.build diff --git a/mai2hook/config.c b/games/mai2hook/config.c similarity index 100% rename from mai2hook/config.c rename to games/mai2hook/config.c diff --git a/mai2hook/config.h b/games/mai2hook/config.h similarity index 100% rename from mai2hook/config.h rename to games/mai2hook/config.h diff --git a/mai2hook/dllmain.c b/games/mai2hook/dllmain.c similarity index 100% rename from mai2hook/dllmain.c rename to games/mai2hook/dllmain.c diff --git a/mai2hook/io4.c b/games/mai2hook/io4.c similarity index 100% rename from mai2hook/io4.c rename to games/mai2hook/io4.c diff --git a/mai2hook/io4.h b/games/mai2hook/io4.h similarity index 100% rename from mai2hook/io4.h rename to games/mai2hook/io4.h diff --git a/mai2hook/mai2-dll.c b/games/mai2hook/mai2-dll.c similarity index 100% rename from mai2hook/mai2-dll.c rename to games/mai2hook/mai2-dll.c diff --git a/mai2hook/mai2-dll.h b/games/mai2hook/mai2-dll.h similarity index 100% rename from mai2hook/mai2-dll.h rename to games/mai2hook/mai2-dll.h diff --git a/mai2hook/mai2hook.def b/games/mai2hook/mai2hook.def similarity index 100% rename from mai2hook/mai2hook.def rename to games/mai2hook/mai2hook.def diff --git a/mai2hook/meson.build b/games/mai2hook/meson.build similarity index 100% rename from mai2hook/meson.build rename to games/mai2hook/meson.build diff --git a/mai2hook/touch.c b/games/mai2hook/touch.c similarity index 100% rename from mai2hook/touch.c rename to games/mai2hook/touch.c diff --git a/mai2hook/touch.h b/games/mai2hook/touch.h similarity index 100% rename from mai2hook/touch.h rename to games/mai2hook/touch.h diff --git a/mai2io/config.c b/games/mai2io/config.c similarity index 100% rename from mai2io/config.c rename to games/mai2io/config.c diff --git a/mai2io/config.h b/games/mai2io/config.h similarity index 100% rename from mai2io/config.h rename to games/mai2io/config.h diff --git a/mai2io/mai2io.c b/games/mai2io/mai2io.c similarity index 100% rename from mai2io/mai2io.c rename to games/mai2io/mai2io.c diff --git a/mai2io/mai2io.h b/games/mai2io/mai2io.h similarity index 100% rename from mai2io/mai2io.h rename to games/mai2io/mai2io.h diff --git a/mai2io/meson.build b/games/mai2io/meson.build similarity index 100% rename from mai2io/meson.build rename to games/mai2io/meson.build diff --git a/mercuryhook/config.c b/games/mercuryhook/config.c similarity index 100% rename from mercuryhook/config.c rename to games/mercuryhook/config.c diff --git a/mercuryhook/config.h b/games/mercuryhook/config.h similarity index 100% rename from mercuryhook/config.h rename to games/mercuryhook/config.h diff --git a/mercuryhook/dllmain.c b/games/mercuryhook/dllmain.c similarity index 100% rename from mercuryhook/dllmain.c rename to games/mercuryhook/dllmain.c diff --git a/mercuryhook/elisabeth.c b/games/mercuryhook/elisabeth.c similarity index 100% rename from mercuryhook/elisabeth.c rename to games/mercuryhook/elisabeth.c diff --git a/mercuryhook/elisabeth.h b/games/mercuryhook/elisabeth.h similarity index 100% rename from mercuryhook/elisabeth.h rename to games/mercuryhook/elisabeth.h diff --git a/mercuryhook/io4.c b/games/mercuryhook/io4.c similarity index 100% rename from mercuryhook/io4.c rename to games/mercuryhook/io4.c diff --git a/mercuryhook/io4.h b/games/mercuryhook/io4.h similarity index 100% rename from mercuryhook/io4.h rename to games/mercuryhook/io4.h diff --git a/mercuryhook/mercury-dll.c b/games/mercuryhook/mercury-dll.c similarity index 100% rename from mercuryhook/mercury-dll.c rename to games/mercuryhook/mercury-dll.c diff --git a/mercuryhook/mercury-dll.h b/games/mercuryhook/mercury-dll.h similarity index 100% rename from mercuryhook/mercury-dll.h rename to games/mercuryhook/mercury-dll.h diff --git a/mercuryhook/mercuryhook.def b/games/mercuryhook/mercuryhook.def similarity index 100% rename from mercuryhook/mercuryhook.def rename to games/mercuryhook/mercuryhook.def diff --git a/mercuryhook/meson.build b/games/mercuryhook/meson.build similarity index 100% rename from mercuryhook/meson.build rename to games/mercuryhook/meson.build diff --git a/mercuryhook/touch.c b/games/mercuryhook/touch.c similarity index 100% rename from mercuryhook/touch.c rename to games/mercuryhook/touch.c diff --git a/mercuryhook/touch.h b/games/mercuryhook/touch.h similarity index 100% rename from mercuryhook/touch.h rename to games/mercuryhook/touch.h diff --git a/mercuryio/config.c b/games/mercuryio/config.c similarity index 100% rename from mercuryio/config.c rename to games/mercuryio/config.c diff --git a/mercuryio/config.h b/games/mercuryio/config.h similarity index 100% rename from mercuryio/config.h rename to games/mercuryio/config.h diff --git a/mercuryio/mercuryio.c b/games/mercuryio/mercuryio.c similarity index 100% rename from mercuryio/mercuryio.c rename to games/mercuryio/mercuryio.c diff --git a/mercuryio/mercuryio.def b/games/mercuryio/mercuryio.def similarity index 100% rename from mercuryio/mercuryio.def rename to games/mercuryio/mercuryio.def diff --git a/mercuryio/mercuryio.h b/games/mercuryio/mercuryio.h similarity index 100% rename from mercuryio/mercuryio.h rename to games/mercuryio/mercuryio.h diff --git a/mercuryio/meson.build b/games/mercuryio/meson.build similarity index 100% rename from mercuryio/meson.build rename to games/mercuryio/meson.build diff --git a/mu3hook/config.c b/games/mu3hook/config.c similarity index 100% rename from mu3hook/config.c rename to games/mu3hook/config.c diff --git a/mu3hook/config.h b/games/mu3hook/config.h similarity index 100% rename from mu3hook/config.h rename to games/mu3hook/config.h diff --git a/mu3hook/dllmain.c b/games/mu3hook/dllmain.c similarity index 100% rename from mu3hook/dllmain.c rename to games/mu3hook/dllmain.c diff --git a/mu3hook/io4.c b/games/mu3hook/io4.c similarity index 100% rename from mu3hook/io4.c rename to games/mu3hook/io4.c diff --git a/mu3hook/io4.h b/games/mu3hook/io4.h similarity index 100% rename from mu3hook/io4.h rename to games/mu3hook/io4.h diff --git a/mu3hook/meson.build b/games/mu3hook/meson.build similarity index 100% rename from mu3hook/meson.build rename to games/mu3hook/meson.build diff --git a/mu3hook/mu3-dll.c b/games/mu3hook/mu3-dll.c similarity index 100% rename from mu3hook/mu3-dll.c rename to games/mu3hook/mu3-dll.c diff --git a/mu3hook/mu3-dll.h b/games/mu3hook/mu3-dll.h similarity index 100% rename from mu3hook/mu3-dll.h rename to games/mu3hook/mu3-dll.h diff --git a/mu3hook/mu3hook.def b/games/mu3hook/mu3hook.def similarity index 100% rename from mu3hook/mu3hook.def rename to games/mu3hook/mu3hook.def diff --git a/mu3io/config.c b/games/mu3io/config.c similarity index 100% rename from mu3io/config.c rename to games/mu3io/config.c diff --git a/mu3io/config.h b/games/mu3io/config.h similarity index 100% rename from mu3io/config.h rename to games/mu3io/config.h diff --git a/mu3io/leddata.h b/games/mu3io/leddata.h similarity index 100% rename from mu3io/leddata.h rename to games/mu3io/leddata.h diff --git a/mu3io/ledoutput.c b/games/mu3io/ledoutput.c similarity index 100% rename from mu3io/ledoutput.c rename to games/mu3io/ledoutput.c diff --git a/mu3io/ledoutput.h b/games/mu3io/ledoutput.h similarity index 100% rename from mu3io/ledoutput.h rename to games/mu3io/ledoutput.h diff --git a/mu3io/meson.build b/games/mu3io/meson.build similarity index 100% rename from mu3io/meson.build rename to games/mu3io/meson.build diff --git a/mu3io/mu3io.c b/games/mu3io/mu3io.c similarity index 100% rename from mu3io/mu3io.c rename to games/mu3io/mu3io.c diff --git a/mu3io/mu3io.h b/games/mu3io/mu3io.h similarity index 100% rename from mu3io/mu3io.h rename to games/mu3io/mu3io.h diff --git a/mu3io/pipeimpl.c b/games/mu3io/pipeimpl.c similarity index 100% rename from mu3io/pipeimpl.c rename to games/mu3io/pipeimpl.c diff --git a/mu3io/pipeimpl.h b/games/mu3io/pipeimpl.h similarity index 100% rename from mu3io/pipeimpl.h rename to games/mu3io/pipeimpl.h diff --git a/mu3io/serialimpl.c b/games/mu3io/serialimpl.c similarity index 100% rename from mu3io/serialimpl.c rename to games/mu3io/serialimpl.c diff --git a/mu3io/serialimpl.h b/games/mu3io/serialimpl.h similarity index 100% rename from mu3io/serialimpl.h rename to games/mu3io/serialimpl.h diff --git a/swdchook/config.c b/games/swdchook/config.c similarity index 100% rename from swdchook/config.c rename to games/swdchook/config.c diff --git a/swdchook/config.h b/games/swdchook/config.h similarity index 100% rename from swdchook/config.h rename to games/swdchook/config.h diff --git a/swdchook/dllmain.c b/games/swdchook/dllmain.c similarity index 100% rename from swdchook/dllmain.c rename to games/swdchook/dllmain.c diff --git a/swdchook/ffb.c b/games/swdchook/ffb.c similarity index 100% rename from swdchook/ffb.c rename to games/swdchook/ffb.c diff --git a/swdchook/ffb.h b/games/swdchook/ffb.h similarity index 100% rename from swdchook/ffb.h rename to games/swdchook/ffb.h diff --git a/swdchook/io4.c b/games/swdchook/io4.c similarity index 100% rename from swdchook/io4.c rename to games/swdchook/io4.c diff --git a/swdchook/io4.h b/games/swdchook/io4.h similarity index 100% rename from swdchook/io4.h rename to games/swdchook/io4.h diff --git a/swdchook/meson.build b/games/swdchook/meson.build similarity index 100% rename from swdchook/meson.build rename to games/swdchook/meson.build diff --git a/swdchook/swdc-dll.c b/games/swdchook/swdc-dll.c similarity index 100% rename from swdchook/swdc-dll.c rename to games/swdchook/swdc-dll.c diff --git a/swdchook/swdc-dll.h b/games/swdchook/swdc-dll.h similarity index 100% rename from swdchook/swdc-dll.h rename to games/swdchook/swdc-dll.h diff --git a/swdchook/swdchook.def b/games/swdchook/swdchook.def similarity index 100% rename from swdchook/swdchook.def rename to games/swdchook/swdchook.def diff --git a/swdchook/zinput.c b/games/swdchook/zinput.c similarity index 100% rename from swdchook/zinput.c rename to games/swdchook/zinput.c diff --git a/swdchook/zinput.h b/games/swdchook/zinput.h similarity index 100% rename from swdchook/zinput.h rename to games/swdchook/zinput.h diff --git a/swdcio/backend.h b/games/swdcio/backend.h similarity index 100% rename from swdcio/backend.h rename to games/swdcio/backend.h diff --git a/swdcio/config.c b/games/swdcio/config.c similarity index 100% rename from swdcio/config.c rename to games/swdcio/config.c diff --git a/swdcio/config.h b/games/swdcio/config.h similarity index 100% rename from swdcio/config.h rename to games/swdcio/config.h diff --git a/swdcio/di-dev.c b/games/swdcio/di-dev.c similarity index 100% rename from swdcio/di-dev.c rename to games/swdcio/di-dev.c diff --git a/swdcio/di-dev.h b/games/swdcio/di-dev.h similarity index 100% rename from swdcio/di-dev.h rename to games/swdcio/di-dev.h diff --git a/swdcio/di.c b/games/swdcio/di.c similarity index 100% rename from swdcio/di.c rename to games/swdcio/di.c diff --git a/swdcio/di.h b/games/swdcio/di.h similarity index 100% rename from swdcio/di.h rename to games/swdcio/di.h diff --git a/swdcio/dllmain.c b/games/swdcio/dllmain.c similarity index 100% rename from swdcio/dllmain.c rename to games/swdcio/dllmain.c diff --git a/swdcio/meson.build b/games/swdcio/meson.build similarity index 100% rename from swdcio/meson.build rename to games/swdcio/meson.build diff --git a/swdcio/swdcio.def b/games/swdcio/swdcio.def similarity index 100% rename from swdcio/swdcio.def rename to games/swdcio/swdcio.def diff --git a/swdcio/swdcio.h b/games/swdcio/swdcio.h similarity index 100% rename from swdcio/swdcio.h rename to games/swdcio/swdcio.h diff --git a/swdcio/wnd.c b/games/swdcio/wnd.c similarity index 100% rename from swdcio/wnd.c rename to games/swdcio/wnd.c diff --git a/swdcio/wnd.h b/games/swdcio/wnd.h similarity index 100% rename from swdcio/wnd.h rename to games/swdcio/wnd.h diff --git a/swdcio/xi.c b/games/swdcio/xi.c similarity index 100% rename from swdcio/xi.c rename to games/swdcio/xi.c diff --git a/swdcio/xi.h b/games/swdcio/xi.h similarity index 100% rename from swdcio/xi.h rename to games/swdcio/xi.h diff --git a/tokyohook/config.c b/games/tokyohook/config.c similarity index 100% rename from tokyohook/config.c rename to games/tokyohook/config.c diff --git a/tokyohook/config.h b/games/tokyohook/config.h similarity index 100% rename from tokyohook/config.h rename to games/tokyohook/config.h diff --git a/tokyohook/dllmain.c b/games/tokyohook/dllmain.c similarity index 100% rename from tokyohook/dllmain.c rename to games/tokyohook/dllmain.c diff --git a/tokyohook/io4.c b/games/tokyohook/io4.c similarity index 100% rename from tokyohook/io4.c rename to games/tokyohook/io4.c diff --git a/tokyohook/io4.h b/games/tokyohook/io4.h similarity index 100% rename from tokyohook/io4.h rename to games/tokyohook/io4.h diff --git a/tokyohook/meson.build b/games/tokyohook/meson.build similarity index 100% rename from tokyohook/meson.build rename to games/tokyohook/meson.build diff --git a/tokyohook/tokyo-dll.c b/games/tokyohook/tokyo-dll.c similarity index 100% rename from tokyohook/tokyo-dll.c rename to games/tokyohook/tokyo-dll.c diff --git a/tokyohook/tokyo-dll.h b/games/tokyohook/tokyo-dll.h similarity index 100% rename from tokyohook/tokyo-dll.h rename to games/tokyohook/tokyo-dll.h diff --git a/tokyohook/tokyohook.def b/games/tokyohook/tokyohook.def similarity index 100% rename from tokyohook/tokyohook.def rename to games/tokyohook/tokyohook.def diff --git a/tokyohook/zinput.c b/games/tokyohook/zinput.c similarity index 100% rename from tokyohook/zinput.c rename to games/tokyohook/zinput.c diff --git a/tokyohook/zinput.h b/games/tokyohook/zinput.h similarity index 100% rename from tokyohook/zinput.h rename to games/tokyohook/zinput.h diff --git a/tokyoio/backend.h b/games/tokyoio/backend.h similarity index 100% rename from tokyoio/backend.h rename to games/tokyoio/backend.h diff --git a/tokyoio/config.c b/games/tokyoio/config.c similarity index 100% rename from tokyoio/config.c rename to games/tokyoio/config.c diff --git a/tokyoio/config.h b/games/tokyoio/config.h similarity index 100% rename from tokyoio/config.h rename to games/tokyoio/config.h diff --git a/tokyoio/dllmain.c b/games/tokyoio/dllmain.c similarity index 100% rename from tokyoio/dllmain.c rename to games/tokyoio/dllmain.c diff --git a/tokyoio/kb.c b/games/tokyoio/kb.c similarity index 100% rename from tokyoio/kb.c rename to games/tokyoio/kb.c diff --git a/tokyoio/kb.h b/games/tokyoio/kb.h similarity index 100% rename from tokyoio/kb.h rename to games/tokyoio/kb.h diff --git a/tokyoio/meson.build b/games/tokyoio/meson.build similarity index 100% rename from tokyoio/meson.build rename to games/tokyoio/meson.build diff --git a/tokyoio/tokyoio.h b/games/tokyoio/tokyoio.h similarity index 100% rename from tokyoio/tokyoio.h rename to games/tokyoio/tokyoio.h diff --git a/tokyoio/xi.c b/games/tokyoio/xi.c similarity index 100% rename from tokyoio/xi.c rename to games/tokyoio/xi.c diff --git a/tokyoio/xi.h b/games/tokyoio/xi.h similarity index 100% rename from tokyoio/xi.h rename to games/tokyoio/xi.h diff --git a/meson.build b/meson.build index 9eea85d..b21d194 100644 --- a/meson.build +++ b/meson.build @@ -94,49 +94,48 @@ pathcch_lib = cc.find_library('pathcch') imagehlp_lib = cc.find_library('imagehlp') ws2_32_lib = cc.find_library('ws2_32') -inc = include_directories('.') +inc = include_directories('common', 'games') capnhook = subproject('capnhook') -subdir('amex') -subdir('iccard') -subdir('board') -subdir('hooklib') -subdir('jvs') -subdir('platform') -subdir('util') +subdir('common/amex') +subdir('common/iccard') +subdir('common/board') +subdir('common/hooklib') +subdir('common/jvs') +subdir('common/platform') +subdir('common/util') +subdir('common/aimeio') -subdir('gfxhook') -subdir('unityhook') +subdir('common/gfxhook') +subdir('common/unityhook') -subdir('aimeio') -subdir('chuniio') -subdir('divaio') -subdir('carolio') -subdir('idzio') -subdir('idacio') -subdir('swdcio') -subdir('mu3io') -subdir('mai2io') -subdir('cmio') -subdir('mercuryio') -subdir('cxbio') -subdir('tokyoio') -subdir('fgoio') -subdir('kemonoio') +subdir('games/chuniio') +subdir('games/divaio') +subdir('games/carolio') +subdir('games/idzio') +subdir('games/idacio') +subdir('games/swdcio') +subdir('games/mu3io') +subdir('games/mai2io') +subdir('games/cmio') +subdir('games/mercuryio') +subdir('games/cxbio') +subdir('games/tokyoio') +subdir('games/fgoio') +subdir('games/kemonoio') -subdir('chunihook') -subdir('divahook') -subdir('carolhook') -subdir('idzhook') -subdir('idachook') -subdir('swdchook') -subdir('minihook') -subdir('chusanhook') -subdir('mu3hook') -subdir('mai2hook') -subdir('cmhook') -subdir('mercuryhook') -subdir('cxbhook') -subdir('tokyohook') -subdir('fgohook') -subdir('kemonohook') +subdir('games/chunihook') +subdir('games/divahook') +subdir('games/carolhook') +subdir('games/idzhook') +subdir('games/idachook') +subdir('games/swdchook') +subdir('games/chusanhook') +subdir('games/mu3hook') +subdir('games/mai2hook') +subdir('games/cmhook') +subdir('games/mercuryhook') +subdir('games/cxbhook') +subdir('games/tokyohook') +subdir('games/fgohook') +subdir('games/kemonohook') diff --git a/minihook/dllmain.c b/minihook/dllmain.c deleted file mode 100644 index c72609f..0000000 --- a/minihook/dllmain.c +++ /dev/null @@ -1,76 +0,0 @@ -#include - -#include - -#include "amex/config.h" -#include "amex/ds.h" - -#include "hook/process.h" - -#include "hooklib/spike.h" - -#include "platform/clock.h" -#include "platform/config.h" -#include "platform/nusec.h" - -#include "util/dprintf.h" -#include "util/env.h" - -static process_entry_t app_startup; - -static DWORD CALLBACK app_pre_startup(void) -{ - struct clock_config clock_cfg; - struct ds_config ds_cfg; - struct nusec_config nusec_cfg; - HRESULT hr; - - dprintf("--- Begin %s ---\n", __func__); - - clock_config_load(&clock_cfg, get_config_path()); - ds_config_load(&ds_cfg, get_config_path()); - nusec_config_load(&nusec_cfg, get_config_path()); - spike_hook_init(get_config_path()); - - hr = clock_hook_init(&clock_cfg); - - if (FAILED(hr)) { - goto fail; - } - - hr = nusec_hook_init(&nusec_cfg, "SSSS", "AAV0"); - - if (FAILED(hr)) { - goto fail; - } - - hr = ds_hook_init(&ds_cfg); - - if (FAILED(hr)) { - goto fail; - } - - dprintf("--- End %s ---\n", __func__); - - return app_startup(); - -fail: - ExitProcess(EXIT_FAILURE); -} - -BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) -{ - HRESULT hr; - - if (cause != DLL_PROCESS_ATTACH) { - return TRUE; - } - - hr = process_hijack_startup(app_pre_startup, &app_startup); - - if (!SUCCEEDED(hr)) { - dprintf("Failed to hijack process startup: %x\n", (int) hr); - } - - return SUCCEEDED(hr); -} diff --git a/minihook/meson.build b/minihook/meson.build deleted file mode 100644 index 7de7f6c..0000000 --- a/minihook/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -shared_library( - 'minihook', - name_prefix : '', - include_directories: inc, - implicit_include_directories : false, - dependencies : [ - capnhook.get_variable('hook_dep'), - ], - link_with : [ - amex_lib, - hooklib_lib, - platform_lib, - util_lib, - ], - sources : [ - 'dllmain.c', - ], -) diff --git a/msvc-build.bat b/msvc-build.bat index fac3925..460b5fd 100644 --- a/msvc-build.bat +++ b/msvc-build.bat @@ -4,6 +4,8 @@ setlocal enabledelayedexpansion set BUILD_DIR=build set BUILD_DIR_32=%BUILD_DIR%\build32 set BUILD_DIR_64=%BUILD_DIR%\build64 +set BUILD_DIR_GAMES_32=%BUILD_DIR_32%\games +set BUILD_DIR_GAMES_64=%BUILD_DIR_64%\games set BUILD_DIR_ZIP=%BUILD_DIR%\zip set DIST_DIR=dist set DOC_DIR=doc diff --git a/package.ps1 b/package.ps1 index bae0e6c..d2f0316 100644 --- a/package.ps1 +++ b/package.ps1 @@ -2,6 +2,8 @@ if ($null -eq $env:BUILD_DIR) { $BUILD_DIR="build" $BUILD_DIR_32="$BUILD_DIR\build32" $BUILD_DIR_64="$BUILD_DIR\build64" + $BUILD_DIR_GAMES_32="$BUILD_DIR_32\games" + $BUILD_DIR_GAMES_64="$BUILD_DIR_64\games" $BUILD_DIR_ZIP="$BUILD_DIR\zip" $DIST_DIR="dist" $DOC_DIR="doc" @@ -9,6 +11,8 @@ if ($null -eq $env:BUILD_DIR) { $BUILD_DIR = $env:BUILD_DIR; $BUILD_DIR_32 = $env:BUILD_DIR_32; $BUILD_DIR_64 = $env:BUILD_DIR_64; + $BUILD_DIR_GAMES_32 = $env:BUILD_DIR_GAMES_32; + $BUILD_DIR_GAMES_64 = $env:BUILD_DIR_GAMES_64; $BUILD_DIR_ZIP = $env:BUILD_DIR_ZIP; $DIST_DIR = $env:DIST_DIR; $DOC_DIR = $env:DOC_DIR; @@ -26,6 +30,8 @@ cat .\Package.mk | % { Replace('$(BUILD_DIR)', $BUILD_DIR). Replace('$(BUILD_DIR_32)', $BUILD_DIR_32). Replace('$(BUILD_DIR_64)', $BUILD_DIR_64). + Replace('$(BUILD_DIR_GAMES_32)', $BUILD_DIR_GAMES_32). + Replace('$(BUILD_DIR_GAMES_64)', $BUILD_DIR_GAMES_64). Replace('$(BUILD_DIR_ZIP)', $BUILD_DIR_ZIP). Replace('$(DIST_DIR)', $DIST_DIR). Replace('$(DOC_DIR)', $DOC_DIR). diff --git a/reg/chunithm.reg b/reg/chunithm.reg deleted file mode 100644 index f7c1240..0000000 --- a/reg/chunithm.reg +++ /dev/null @@ -1,27 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA] - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty] - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\keychip] -"systemFlag"=dword:00000064 -"modelType"=dword:00000001 -"region"=dword:00000001 -"serverIpIpv4"=hex:c0,a8,8b,00 -"keychipId"=hex:41,36,39,45,2d,30,31,41,39,39,39,39,39,39,39,39 -"platformId"=hex:41,41,56 -"gameId"=hex:53,42,5a,56 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\static] -"CpuTempWarning"=dword:0000003c -"CpuTempError"=dword:00000050 -"PlatformId"=hex:41,41,56 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\wirelessNetwork] -"main_nic"=dword:00000000 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\mount] -"AMFS"="E:\\" -"APPDATA"="Y:\\" - From 66a53dd2de7951028af400a75c26f191bc9051ba Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 17 Apr 2025 19:31:37 +0200 Subject: [PATCH 202/204] refactor all common parts and games --- Makefile | 2 + Package.mk | 34 +-- {aimeio => common/aimeio}/aimeio.c | 0 {aimeio => common/aimeio}/aimeio.h | 0 {aimeio => common/aimeio}/meson.build | 0 {amex => common/amex}/amex.c | 0 {amex => common/amex}/amex.h | 0 {amex => common/amex}/config.c | 0 {amex => common/amex}/config.h | 0 {amex => common/amex}/ds.c | 0 {amex => common/amex}/ds.h | 0 {amex => common/amex}/eeprom.c | 0 {amex => common/amex}/eeprom.h | 0 {amex => common/amex}/gpio.c | 0 {amex => common/amex}/gpio.h | 0 {amex => common/amex}/guid.c | 0 {amex => common/amex}/jvs.c | 0 {amex => common/amex}/jvs.h | 0 {amex => common/amex}/meson.build | 0 {amex => common/amex}/nvram.c | 0 {amex => common/amex}/nvram.h | 0 {amex => common/amex}/sram.c | 0 {amex => common/amex}/sram.h | 0 {board => common/board}/aime-dll.c | 0 {board => common/board}/aime-dll.h | 0 {board => common/board}/config.c | 0 {board => common/board}/config.h | 0 {board => common/board}/ffb.c | 0 {board => common/board}/ffb.h | 0 {board => common/board}/guid.c | 0 {board => common/board}/guid.h | 0 {board => common/board}/io3.c | 0 {board => common/board}/io3.h | 0 {board => common/board}/io4.c | 0 {board => common/board}/io4.h | 0 {board => common/board}/led15070-cmd.h | 0 {board => common/board}/led15070-frame.c | 0 {board => common/board}/led15070-frame.h | 0 {board => common/board}/led15070.c | 0 {board => common/board}/led15070.h | 0 {board => common/board}/led15093-cmd.h | 0 {board => common/board}/led15093-frame.c | 0 {board => common/board}/led15093-frame.h | 0 {board => common/board}/led15093.c | 0 {board => common/board}/led15093.h | 0 {board => common/board}/meson.build | 0 {board => common/board}/sg-cmd.c | 0 {board => common/board}/sg-cmd.h | 0 {board => common/board}/sg-frame.c | 0 {board => common/board}/sg-frame.h | 0 {board => common/board}/sg-led-cmd.h | 0 {board => common/board}/sg-led.c | 0 {board => common/board}/sg-led.h | 0 {board => common/board}/sg-nfc-cmd.h | 0 {board => common/board}/sg-nfc.c | 1 + {board => common/board}/sg-nfc.h | 0 {board => common/board}/sg-reader.c | 0 {board => common/board}/sg-reader.h | 0 {board => common/board}/slider-cmd.h | 0 {board => common/board}/slider-frame.c | 0 {board => common/board}/slider-frame.h | 0 {board => common/board}/vfd-cmd.h | 0 {board => common/board}/vfd-frame.c | 0 {board => common/board}/vfd-frame.h | 0 {board => common/board}/vfd.c | 0 {board => common/board}/vfd.h | 0 {gfxhook => common/gfxhook}/config.c | 0 {gfxhook => common/gfxhook}/config.h | 0 {gfxhook => common/gfxhook}/d3d11.c | 0 {gfxhook => common/gfxhook}/d3d11.h | 0 {gfxhook => common/gfxhook}/d3d9.c | 0 {gfxhook => common/gfxhook}/d3d9.h | 0 {gfxhook => common/gfxhook}/dxgi.c | 0 {gfxhook => common/gfxhook}/dxgi.h | 0 {gfxhook => common/gfxhook}/gfx.c | 0 {gfxhook => common/gfxhook}/gfx.h | 0 {gfxhook => common/gfxhook}/gl.c | 0 {gfxhook => common/gfxhook}/gl.h | 0 {gfxhook => common/gfxhook}/meson.build | 0 {gfxhook => common/gfxhook}/util.c | 0 {gfxhook => common/gfxhook}/util.h | 0 {hooklib => common/hooklib}/config.c | 0 {hooklib => common/hooklib}/config.h | 0 {hooklib => common/hooklib}/createprocess.c | 0 {hooklib => common/hooklib}/createprocess.h | 0 {hooklib => common/hooklib}/cursor.c | 0 {hooklib => common/hooklib}/cursor.h | 0 {hooklib => common/hooklib}/dll.c | 0 {hooklib => common/hooklib}/dll.h | 0 {hooklib => common/hooklib}/dns.c | 0 {hooklib => common/hooklib}/dns.h | 0 {hooklib => common/hooklib}/dvd.c | 0 {hooklib => common/hooklib}/dvd.h | 0 {hooklib => common/hooklib}/fdshark.c | 0 {hooklib => common/hooklib}/fdshark.h | 0 {hooklib => common/hooklib}/meson.build | 0 {hooklib => common/hooklib}/path.c | 0 {hooklib => common/hooklib}/path.h | 0 {hooklib => common/hooklib}/printer.c | 0 {hooklib => common/hooklib}/printer.h | 0 {hooklib => common/hooklib}/reg.c | 0 {hooklib => common/hooklib}/reg.h | 0 {hooklib => common/hooklib}/setupapi.c | 0 {hooklib => common/hooklib}/setupapi.h | 0 {hooklib => common/hooklib}/spike.c | 0 {hooklib => common/hooklib}/spike.h | 0 {hooklib => common/hooklib}/touch.c | 0 {hooklib => common/hooklib}/touch.h | 0 {iccard => common/iccard}/aime.c | 0 {iccard => common/iccard}/aime.h | 0 {iccard => common/iccard}/felica.c | 0 {iccard => common/iccard}/felica.h | 0 {iccard => common/iccard}/meson.build | 0 {iccard => common/iccard}/mifare.h | 0 {jvs => common/jvs}/jvs-bus.c | 0 {jvs => common/jvs}/jvs-bus.h | 0 {jvs => common/jvs}/jvs-cmd.h | 0 {jvs => common/jvs}/jvs-frame.c | 0 {jvs => common/jvs}/jvs-frame.h | 0 {jvs => common/jvs}/jvs-util.c | 0 {jvs => common/jvs}/jvs-util.h | 0 {jvs => common/jvs}/meson.build | 0 {platform => common/platform}/amvideo.c | 0 {platform => common/platform}/amvideo.h | 0 {platform => common/platform}/clock.c | 0 {platform => common/platform}/clock.h | 0 {platform => common/platform}/config.c | 0 {platform => common/platform}/config.h | 0 {platform => common/platform}/dns.c | 0 {platform => common/platform}/dns.h | 0 {platform => common/platform}/epay.c | 0 {platform => common/platform}/epay.h | 0 {platform => common/platform}/hwmon.c | 0 {platform => common/platform}/hwmon.h | 0 {platform => common/platform}/hwreset.c | 0 {platform => common/platform}/hwreset.h | 0 {platform => common/platform}/meson.build | 0 {platform => common/platform}/misc.c | 0 {platform => common/platform}/misc.h | 0 {platform => common/platform}/netenv.c | 0 {platform => common/platform}/netenv.h | 0 {platform => common/platform}/nusec.c | 0 {platform => common/platform}/nusec.h | 0 {platform => common/platform}/pcbid.c | 0 {platform => common/platform}/pcbid.h | 0 {platform => common/platform}/platform.c | 0 {platform => common/platform}/platform.h | 0 {platform => common/platform}/system.c | 2 +- {platform => common/platform}/system.h | 0 {platform => common/platform}/vfs.c | 0 {platform => common/platform}/vfs.h | 0 {unityhook => common/unityhook}/config.c | 0 {unityhook => common/unityhook}/config.h | 24 +-- {unityhook => common/unityhook}/doorstop.c | 0 {unityhook => common/unityhook}/doorstop.h | 8 +- {unityhook => common/unityhook}/hook.c | 0 {unityhook => common/unityhook}/hook.h | 18 +- {unityhook => common/unityhook}/meson.build | 38 ++-- {unityhook => common/unityhook}/mono.h | 198 +++++++++--------- {unityhook => common/unityhook}/util.h | 40 ++-- {util => common/util}/async.c | 0 {util => common/util}/async.h | 0 {util => common/util}/crc.c | 0 {util => common/util}/crc.h | 0 {util => common/util}/dll-bind.c | 0 {util => common/util}/dll-bind.h | 0 {util => common/util}/dprintf.c | 0 {util => common/util}/dprintf.h | 0 {util => common/util}/dump.c | 0 {util => common/util}/dump.h | 0 {util => common/util}/env.c | 0 {util => common/util}/env.h | 0 {util => common/util}/get_function_ordinal.c | 0 {util => common/util}/get_function_ordinal.h | 0 {util => common/util}/lib.c | 0 {util => common/util}/lib.h | 0 {util => common/util}/meson.build | 0 {util => common/util}/slurp.c | 0 {util => common/util}/slurp.h | 0 {util => common/util}/str.c | 0 {util => common/util}/str.h | 0 dist/fgo/launch.bat | 2 +- {carolhook => games/carolhook}/carol-dll.c | 0 {carolhook => games/carolhook}/carol-dll.h | 0 {carolhook => games/carolhook}/carolhook.def | 0 {carolhook => games/carolhook}/config.c | 0 {carolhook => games/carolhook}/config.h | 0 {carolhook => games/carolhook}/controlbd.c | 0 {carolhook => games/carolhook}/controlbd.h | 0 {carolhook => games/carolhook}/dllmain.c | 0 {carolhook => games/carolhook}/jvs.c | 0 {carolhook => games/carolhook}/jvs.h | 0 {carolhook => games/carolhook}/ledbd.c | 0 {carolhook => games/carolhook}/ledbd.h | 0 {carolhook => games/carolhook}/meson.build | 0 {carolhook => games/carolhook}/touch.c | 0 {carolhook => games/carolhook}/touch.h | 0 {carolio => games/carolio}/carolio.c | 0 {carolio => games/carolio}/carolio.h | 0 {carolio => games/carolio}/config.c | 0 {carolio => games/carolio}/config.h | 0 {carolio => games/carolio}/meson.build | 0 {chunihook => games/chunihook}/chuni-dll.c | 0 {chunihook => games/chunihook}/chuni-dll.h | 0 {chunihook => games/chunihook}/chunihook.def | 0 {chunihook => games/chunihook}/config.c | 0 {chunihook => games/chunihook}/config.h | 0 {chunihook => games/chunihook}/dllmain.c | 0 {chunihook => games/chunihook}/jvs.c | 0 {chunihook => games/chunihook}/jvs.h | 0 {chunihook => games/chunihook}/meson.build | 0 {chunihook => games/chunihook}/slider.c | 0 {chunihook => games/chunihook}/slider.h | 0 {chuniio => games/chuniio}/chu2to3.c | 0 {chuniio => games/chuniio}/chu2to3.h | 0 {chuniio => games/chuniio}/chuniio.c | 0 {chuniio => games/chuniio}/chuniio.h | 0 {chuniio => games/chuniio}/config.c | 0 {chuniio => games/chuniio}/config.h | 0 {chuniio => games/chuniio}/leddata.h | 0 {chuniio => games/chuniio}/ledoutput.c | 0 {chuniio => games/chuniio}/ledoutput.h | 0 {chuniio => games/chuniio}/meson.build | 0 {chuniio => games/chuniio}/pipeimpl.c | 0 {chuniio => games/chuniio}/pipeimpl.h | 0 {chuniio => games/chuniio}/serialimpl.c | 0 {chuniio => games/chuniio}/serialimpl.h | 0 {chusanhook => games/chusanhook}/chuni-dll.c | 0 {chusanhook => games/chusanhook}/chuni-dll.h | 0 .../chusanhook}/chusanhook.def | 0 {chusanhook => games/chusanhook}/config.c | 0 {chusanhook => games/chusanhook}/config.h | 0 {chusanhook => games/chusanhook}/dllmain.c | 0 {chusanhook => games/chusanhook}/io4.c | 0 {chusanhook => games/chusanhook}/io4.h | 0 {chusanhook => games/chusanhook}/meson.build | 0 {chusanhook => games/chusanhook}/slider.c | 0 {chusanhook => games/chusanhook}/slider.h | 0 {cmhook => games/cmhook}/cm-dll.c | 0 {cmhook => games/cmhook}/cm-dll.h | 0 {cmhook => games/cmhook}/cmhook.def | 0 {cmhook => games/cmhook}/config.c | 0 {cmhook => games/cmhook}/config.h | 0 {cmhook => games/cmhook}/dllmain.c | 0 {cmhook => games/cmhook}/io4.c | 0 {cmhook => games/cmhook}/io4.h | 0 {cmhook => games/cmhook}/meson.build | 0 {cmio => games/cmio}/cmio.c | 0 {cmio => games/cmio}/cmio.h | 0 {cmio => games/cmio}/config.c | 0 {cmio => games/cmio}/config.h | 0 {cmio => games/cmio}/meson.build | 0 {cxbhook => games/cxbhook}/config.c | 0 {cxbhook => games/cxbhook}/config.h | 0 {cxbhook => games/cxbhook}/cxb-dll.c | 0 {cxbhook => games/cxbhook}/cxb-dll.h | 0 {cxbhook => games/cxbhook}/cxbhook.def | 0 {cxbhook => games/cxbhook}/dllmain.c | 0 {cxbhook => games/cxbhook}/led.c | 0 {cxbhook => games/cxbhook}/led.h | 0 {cxbhook => games/cxbhook}/meson.build | 0 {cxbhook => games/cxbhook}/revio.c | 0 {cxbhook => games/cxbhook}/revio.h | 0 {cxbio => games/cxbio}/config.c | 0 {cxbio => games/cxbio}/config.h | 0 {cxbio => games/cxbio}/cxbio.c | 0 {cxbio => games/cxbio}/cxbio.h | 0 {cxbio => games/cxbio}/meson.build | 0 {divahook => games/divahook}/config.c | 0 {divahook => games/divahook}/config.h | 0 {divahook => games/divahook}/diva-dll.c | 0 {divahook => games/divahook}/diva-dll.h | 0 {divahook => games/divahook}/divahook.def | 0 {divahook => games/divahook}/dllmain.c | 0 {divahook => games/divahook}/jvs.c | 0 {divahook => games/divahook}/jvs.h | 0 {divahook => games/divahook}/meson.build | 0 {divahook => games/divahook}/slider.c | 0 {divahook => games/divahook}/slider.h | 0 {divaio => games/divaio}/config.c | 0 {divaio => games/divaio}/config.h | 0 {divaio => games/divaio}/divaio.c | 0 {divaio => games/divaio}/divaio.h | 0 {divaio => games/divaio}/meson.build | 0 {fgohook => games/fgohook}/config.c | 0 {fgohook => games/fgohook}/config.h | 0 {fgohook => games/fgohook}/deck.c | 0 {fgohook => games/fgohook}/deck.h | 0 {fgohook => games/fgohook}/dllmain.c | 0 {fgohook => games/fgohook}/fgo-dll.c | 0 {fgohook => games/fgohook}/fgo-dll.h | 0 {fgohook => games/fgohook}/fgohook.def | 0 {fgohook => games/fgohook}/ftdi.c | 0 {fgohook => games/fgohook}/ftdi.h | 0 {fgohook => games/fgohook}/io4.c | 0 {fgohook => games/fgohook}/io4.h | 0 {fgohook => games/fgohook}/meson.build | 0 {fgoio => games/fgoio}/backend.h | 0 {fgoio => games/fgoio}/config.c | 0 {fgoio => games/fgoio}/config.h | 0 {fgoio => games/fgoio}/fgoio.c | 0 {fgoio => games/fgoio}/fgoio.h | 0 {fgoio => games/fgoio}/keyboard.c | 0 {fgoio => games/fgoio}/keyboard.h | 0 {fgoio => games/fgoio}/meson.build | 0 {fgoio => games/fgoio}/xi.c | 0 {fgoio => games/fgoio}/xi.h | 0 {idachook => games/idachook}/config.c | 0 {idachook => games/idachook}/config.h | 0 {idachook => games/idachook}/dllmain.c | 0 {idachook => games/idachook}/ffb.c | 0 {idachook => games/idachook}/ffb.h | 0 {idachook => games/idachook}/idac-dll.c | 0 {idachook => games/idachook}/idac-dll.h | 0 {idachook => games/idachook}/idachook.def | 0 {idachook => games/idachook}/indrun.c | 0 {idachook => games/idachook}/indrun.h | 0 {idachook => games/idachook}/io4.c | 0 {idachook => games/idachook}/io4.h | 0 {idachook => games/idachook}/meson.build | 0 {idachook => games/idachook}/zinput.c | 0 {idachook => games/idachook}/zinput.h | 0 {idacio => games/idacio}/backend.h | 0 {idacio => games/idacio}/config.c | 0 {idacio => games/idacio}/config.h | 0 {idacio => games/idacio}/di-dev.c | 0 {idacio => games/idacio}/di-dev.h | 0 {idacio => games/idacio}/di.c | 0 {idacio => games/idacio}/di.h | 0 {idacio => games/idacio}/dllmain.c | 0 {idacio => games/idacio}/idacio.def | 0 {idacio => games/idacio}/idacio.h | 0 {idacio => games/idacio}/meson.build | 0 {idacio => games/idacio}/shifter.c | 0 {idacio => games/idacio}/shifter.h | 0 {idacio => games/idacio}/wnd.c | 0 {idacio => games/idacio}/wnd.h | 0 {idacio => games/idacio}/xi.c | 0 {idacio => games/idacio}/xi.h | 0 {idzhook => games/idzhook}/config.c | 0 {idzhook => games/idzhook}/config.h | 0 {idzhook => games/idzhook}/dllmain.c | 0 {idzhook => games/idzhook}/ffb.c | 0 {idzhook => games/idzhook}/ffb.h | 0 {idzhook => games/idzhook}/idz-dll.c | 0 {idzhook => games/idzhook}/idz-dll.h | 0 {idzhook => games/idzhook}/idzhook.def | 0 {idzhook => games/idzhook}/jvs.c | 0 {idzhook => games/idzhook}/jvs.h | 0 {idzhook => games/idzhook}/meson.build | 0 {idzhook => games/idzhook}/zinput.c | 0 {idzhook => games/idzhook}/zinput.h | 0 {idzio => games/idzio}/backend.h | 0 {idzio => games/idzio}/config.c | 0 {idzio => games/idzio}/config.h | 0 {idzio => games/idzio}/di-dev.c | 0 {idzio => games/idzio}/di-dev.h | 0 {idzio => games/idzio}/di.c | 0 {idzio => games/idzio}/di.h | 0 {idzio => games/idzio}/dllmain.c | 0 {idzio => games/idzio}/idzio.def | 0 {idzio => games/idzio}/idzio.h | 0 {idzio => games/idzio}/meson.build | 0 {idzio => games/idzio}/shifter.c | 0 {idzio => games/idzio}/shifter.h | 0 {idzio => games/idzio}/wnd.c | 0 {idzio => games/idzio}/wnd.h | 0 {idzio => games/idzio}/xi.c | 0 {idzio => games/idzio}/xi.h | 0 {kemonohook => games/kemonohook}/config.c | 0 {kemonohook => games/kemonohook}/config.h | 0 {kemonohook => games/kemonohook}/dllmain.c | 0 {kemonohook => games/kemonohook}/hooks.c | 0 {kemonohook => games/kemonohook}/hooks.h | 0 {kemonohook => games/kemonohook}/jvs.c | 0 {kemonohook => games/kemonohook}/jvs.h | 0 {kemonohook => games/kemonohook}/kemono-dll.c | 0 {kemonohook => games/kemonohook}/kemono-dll.h | 0 .../kemonohook}/kemonohook.def | 0 {kemonohook => games/kemonohook}/meson.build | 0 {kemonoio => games/kemonoio}/config.c | 0 {kemonoio => games/kemonoio}/config.h | 0 {kemonoio => games/kemonoio}/kemonoio.c | 0 {kemonoio => games/kemonoio}/kemonoio.h | 0 {kemonoio => games/kemonoio}/meson.build | 0 {mai2hook => games/mai2hook}/config.c | 0 {mai2hook => games/mai2hook}/config.h | 0 {mai2hook => games/mai2hook}/dllmain.c | 0 {mai2hook => games/mai2hook}/io4.c | 0 {mai2hook => games/mai2hook}/io4.h | 0 {mai2hook => games/mai2hook}/mai2-dll.c | 0 {mai2hook => games/mai2hook}/mai2-dll.h | 0 {mai2hook => games/mai2hook}/mai2hook.def | 0 {mai2hook => games/mai2hook}/meson.build | 0 {mai2hook => games/mai2hook}/touch.c | 0 {mai2hook => games/mai2hook}/touch.h | 0 {mai2io => games/mai2io}/config.c | 0 {mai2io => games/mai2io}/config.h | 0 {mai2io => games/mai2io}/mai2io.c | 0 {mai2io => games/mai2io}/mai2io.h | 0 {mai2io => games/mai2io}/meson.build | 0 {mercuryhook => games/mercuryhook}/config.c | 0 {mercuryhook => games/mercuryhook}/config.h | 0 {mercuryhook => games/mercuryhook}/dllmain.c | 0 .../mercuryhook}/elisabeth.c | 0 .../mercuryhook}/elisabeth.h | 0 {mercuryhook => games/mercuryhook}/io4.c | 0 {mercuryhook => games/mercuryhook}/io4.h | 0 .../mercuryhook}/mercury-dll.c | 0 .../mercuryhook}/mercury-dll.h | 0 .../mercuryhook}/mercuryhook.def | 0 .../mercuryhook}/meson.build | 0 {mercuryhook => games/mercuryhook}/touch.c | 0 {mercuryhook => games/mercuryhook}/touch.h | 0 {mercuryio => games/mercuryio}/config.c | 0 {mercuryio => games/mercuryio}/config.h | 0 {mercuryio => games/mercuryio}/mercuryio.c | 0 {mercuryio => games/mercuryio}/mercuryio.def | 0 {mercuryio => games/mercuryio}/mercuryio.h | 0 {mercuryio => games/mercuryio}/meson.build | 0 {mu3hook => games/mu3hook}/config.c | 0 {mu3hook => games/mu3hook}/config.h | 0 {mu3hook => games/mu3hook}/dllmain.c | 0 {mu3hook => games/mu3hook}/io4.c | 0 {mu3hook => games/mu3hook}/io4.h | 0 {mu3hook => games/mu3hook}/meson.build | 0 {mu3hook => games/mu3hook}/mu3-dll.c | 0 {mu3hook => games/mu3hook}/mu3-dll.h | 0 {mu3hook => games/mu3hook}/mu3hook.def | 0 {mu3io => games/mu3io}/config.c | 0 {mu3io => games/mu3io}/config.h | 0 {mu3io => games/mu3io}/leddata.h | 0 {mu3io => games/mu3io}/ledoutput.c | 0 {mu3io => games/mu3io}/ledoutput.h | 0 {mu3io => games/mu3io}/meson.build | 0 {mu3io => games/mu3io}/mu3io.c | 0 {mu3io => games/mu3io}/mu3io.h | 0 {mu3io => games/mu3io}/pipeimpl.c | 0 {mu3io => games/mu3io}/pipeimpl.h | 0 {mu3io => games/mu3io}/serialimpl.c | 0 {mu3io => games/mu3io}/serialimpl.h | 0 {swdchook => games/swdchook}/config.c | 0 {swdchook => games/swdchook}/config.h | 0 {swdchook => games/swdchook}/dllmain.c | 0 {swdchook => games/swdchook}/ffb.c | 0 {swdchook => games/swdchook}/ffb.h | 0 {swdchook => games/swdchook}/io4.c | 0 {swdchook => games/swdchook}/io4.h | 0 {swdchook => games/swdchook}/meson.build | 0 {swdchook => games/swdchook}/swdc-dll.c | 0 {swdchook => games/swdchook}/swdc-dll.h | 0 {swdchook => games/swdchook}/swdchook.def | 0 {swdchook => games/swdchook}/zinput.c | 0 {swdchook => games/swdchook}/zinput.h | 0 {swdcio => games/swdcio}/backend.h | 0 {swdcio => games/swdcio}/config.c | 0 {swdcio => games/swdcio}/config.h | 0 {swdcio => games/swdcio}/di-dev.c | 0 {swdcio => games/swdcio}/di-dev.h | 0 {swdcio => games/swdcio}/di.c | 0 {swdcio => games/swdcio}/di.h | 0 {swdcio => games/swdcio}/dllmain.c | 0 {swdcio => games/swdcio}/meson.build | 0 {swdcio => games/swdcio}/swdcio.def | 0 {swdcio => games/swdcio}/swdcio.h | 0 {swdcio => games/swdcio}/wnd.c | 0 {swdcio => games/swdcio}/wnd.h | 0 {swdcio => games/swdcio}/xi.c | 0 {swdcio => games/swdcio}/xi.h | 0 {tokyohook => games/tokyohook}/config.c | 0 {tokyohook => games/tokyohook}/config.h | 0 {tokyohook => games/tokyohook}/dllmain.c | 0 {tokyohook => games/tokyohook}/io4.c | 0 {tokyohook => games/tokyohook}/io4.h | 0 {tokyohook => games/tokyohook}/meson.build | 0 {tokyohook => games/tokyohook}/tokyo-dll.c | 0 {tokyohook => games/tokyohook}/tokyo-dll.h | 0 {tokyohook => games/tokyohook}/tokyohook.def | 0 {tokyohook => games/tokyohook}/zinput.c | 0 {tokyohook => games/tokyohook}/zinput.h | 0 {tokyoio => games/tokyoio}/backend.h | 0 {tokyoio => games/tokyoio}/config.c | 0 {tokyoio => games/tokyoio}/config.h | 0 {tokyoio => games/tokyoio}/dllmain.c | 0 {tokyoio => games/tokyoio}/kb.c | 0 {tokyoio => games/tokyoio}/kb.h | 0 {tokyoio => games/tokyoio}/meson.build | 0 {tokyoio => games/tokyoio}/tokyoio.h | 0 {tokyoio => games/tokyoio}/xi.c | 0 {tokyoio => games/tokyoio}/xi.h | 0 meson.build | 81 ++++--- minihook/dllmain.c | 76 ------- minihook/meson.build | 18 -- msvc-build.bat | 2 + package.ps1 | 6 + reg/chunithm.reg | 27 --- 496 files changed, 233 insertions(+), 344 deletions(-) rename {aimeio => common/aimeio}/aimeio.c (100%) rename {aimeio => common/aimeio}/aimeio.h (100%) rename {aimeio => common/aimeio}/meson.build (100%) rename {amex => common/amex}/amex.c (100%) rename {amex => common/amex}/amex.h (100%) rename {amex => common/amex}/config.c (100%) rename {amex => common/amex}/config.h (100%) rename {amex => common/amex}/ds.c (100%) rename {amex => common/amex}/ds.h (100%) rename {amex => common/amex}/eeprom.c (100%) rename {amex => common/amex}/eeprom.h (100%) rename {amex => common/amex}/gpio.c (100%) rename {amex => common/amex}/gpio.h (100%) rename {amex => common/amex}/guid.c (100%) rename {amex => common/amex}/jvs.c (100%) rename {amex => common/amex}/jvs.h (100%) rename {amex => common/amex}/meson.build (100%) rename {amex => common/amex}/nvram.c (100%) rename {amex => common/amex}/nvram.h (100%) rename {amex => common/amex}/sram.c (100%) rename {amex => common/amex}/sram.h (100%) rename {board => common/board}/aime-dll.c (100%) rename {board => common/board}/aime-dll.h (100%) rename {board => common/board}/config.c (100%) rename {board => common/board}/config.h (100%) rename {board => common/board}/ffb.c (100%) rename {board => common/board}/ffb.h (100%) rename {board => common/board}/guid.c (100%) rename {board => common/board}/guid.h (100%) rename {board => common/board}/io3.c (100%) rename {board => common/board}/io3.h (100%) rename {board => common/board}/io4.c (100%) rename {board => common/board}/io4.h (100%) rename {board => common/board}/led15070-cmd.h (100%) rename {board => common/board}/led15070-frame.c (100%) rename {board => common/board}/led15070-frame.h (100%) rename {board => common/board}/led15070.c (100%) rename {board => common/board}/led15070.h (100%) rename {board => common/board}/led15093-cmd.h (100%) rename {board => common/board}/led15093-frame.c (100%) rename {board => common/board}/led15093-frame.h (100%) rename {board => common/board}/led15093.c (100%) rename {board => common/board}/led15093.h (100%) rename {board => common/board}/meson.build (100%) rename {board => common/board}/sg-cmd.c (100%) rename {board => common/board}/sg-cmd.h (100%) rename {board => common/board}/sg-frame.c (100%) rename {board => common/board}/sg-frame.h (100%) rename {board => common/board}/sg-led-cmd.h (100%) rename {board => common/board}/sg-led.c (100%) rename {board => common/board}/sg-led.h (100%) rename {board => common/board}/sg-nfc-cmd.h (100%) rename {board => common/board}/sg-nfc.c (99%) rename {board => common/board}/sg-nfc.h (100%) rename {board => common/board}/sg-reader.c (100%) rename {board => common/board}/sg-reader.h (100%) rename {board => common/board}/slider-cmd.h (100%) rename {board => common/board}/slider-frame.c (100%) rename {board => common/board}/slider-frame.h (100%) rename {board => common/board}/vfd-cmd.h (100%) rename {board => common/board}/vfd-frame.c (100%) rename {board => common/board}/vfd-frame.h (100%) rename {board => common/board}/vfd.c (100%) rename {board => common/board}/vfd.h (100%) rename {gfxhook => common/gfxhook}/config.c (100%) rename {gfxhook => common/gfxhook}/config.h (100%) rename {gfxhook => common/gfxhook}/d3d11.c (100%) rename {gfxhook => common/gfxhook}/d3d11.h (100%) rename {gfxhook => common/gfxhook}/d3d9.c (100%) rename {gfxhook => common/gfxhook}/d3d9.h (100%) rename {gfxhook => common/gfxhook}/dxgi.c (100%) rename {gfxhook => common/gfxhook}/dxgi.h (100%) rename {gfxhook => common/gfxhook}/gfx.c (100%) rename {gfxhook => common/gfxhook}/gfx.h (100%) rename {gfxhook => common/gfxhook}/gl.c (100%) rename {gfxhook => common/gfxhook}/gl.h (100%) rename {gfxhook => common/gfxhook}/meson.build (100%) rename {gfxhook => common/gfxhook}/util.c (100%) rename {gfxhook => common/gfxhook}/util.h (100%) rename {hooklib => common/hooklib}/config.c (100%) rename {hooklib => common/hooklib}/config.h (100%) rename {hooklib => common/hooklib}/createprocess.c (100%) rename {hooklib => common/hooklib}/createprocess.h (100%) rename {hooklib => common/hooklib}/cursor.c (100%) rename {hooklib => common/hooklib}/cursor.h (100%) rename {hooklib => common/hooklib}/dll.c (100%) rename {hooklib => common/hooklib}/dll.h (100%) rename {hooklib => common/hooklib}/dns.c (100%) rename {hooklib => common/hooklib}/dns.h (100%) rename {hooklib => common/hooklib}/dvd.c (100%) rename {hooklib => common/hooklib}/dvd.h (100%) rename {hooklib => common/hooklib}/fdshark.c (100%) rename {hooklib => common/hooklib}/fdshark.h (100%) rename {hooklib => common/hooklib}/meson.build (100%) rename {hooklib => common/hooklib}/path.c (100%) rename {hooklib => common/hooklib}/path.h (100%) rename {hooklib => common/hooklib}/printer.c (100%) rename {hooklib => common/hooklib}/printer.h (100%) rename {hooklib => common/hooklib}/reg.c (100%) rename {hooklib => common/hooklib}/reg.h (100%) rename {hooklib => common/hooklib}/setupapi.c (100%) rename {hooklib => common/hooklib}/setupapi.h (100%) rename {hooklib => common/hooklib}/spike.c (100%) rename {hooklib => common/hooklib}/spike.h (100%) rename {hooklib => common/hooklib}/touch.c (100%) rename {hooklib => common/hooklib}/touch.h (100%) rename {iccard => common/iccard}/aime.c (100%) rename {iccard => common/iccard}/aime.h (100%) rename {iccard => common/iccard}/felica.c (100%) rename {iccard => common/iccard}/felica.h (100%) rename {iccard => common/iccard}/meson.build (100%) rename {iccard => common/iccard}/mifare.h (100%) rename {jvs => common/jvs}/jvs-bus.c (100%) rename {jvs => common/jvs}/jvs-bus.h (100%) rename {jvs => common/jvs}/jvs-cmd.h (100%) rename {jvs => common/jvs}/jvs-frame.c (100%) rename {jvs => common/jvs}/jvs-frame.h (100%) rename {jvs => common/jvs}/jvs-util.c (100%) rename {jvs => common/jvs}/jvs-util.h (100%) rename {jvs => common/jvs}/meson.build (100%) rename {platform => common/platform}/amvideo.c (100%) rename {platform => common/platform}/amvideo.h (100%) rename {platform => common/platform}/clock.c (100%) rename {platform => common/platform}/clock.h (100%) rename {platform => common/platform}/config.c (100%) rename {platform => common/platform}/config.h (100%) rename {platform => common/platform}/dns.c (100%) rename {platform => common/platform}/dns.h (100%) rename {platform => common/platform}/epay.c (100%) rename {platform => common/platform}/epay.h (100%) rename {platform => common/platform}/hwmon.c (100%) rename {platform => common/platform}/hwmon.h (100%) rename {platform => common/platform}/hwreset.c (100%) rename {platform => common/platform}/hwreset.h (100%) rename {platform => common/platform}/meson.build (100%) rename {platform => common/platform}/misc.c (100%) rename {platform => common/platform}/misc.h (100%) rename {platform => common/platform}/netenv.c (100%) rename {platform => common/platform}/netenv.h (100%) rename {platform => common/platform}/nusec.c (100%) rename {platform => common/platform}/nusec.h (100%) rename {platform => common/platform}/pcbid.c (100%) rename {platform => common/platform}/pcbid.h (100%) rename {platform => common/platform}/platform.c (100%) rename {platform => common/platform}/platform.h (100%) rename {platform => common/platform}/system.c (98%) rename {platform => common/platform}/system.h (100%) rename {platform => common/platform}/vfs.c (100%) rename {platform => common/platform}/vfs.h (100%) rename {unityhook => common/unityhook}/config.c (100%) rename {unityhook => common/unityhook}/config.h (94%) rename {unityhook => common/unityhook}/doorstop.c (100%) rename {unityhook => common/unityhook}/doorstop.h (83%) rename {unityhook => common/unityhook}/hook.c (100%) rename {unityhook => common/unityhook}/hook.h (96%) rename {unityhook => common/unityhook}/meson.build (95%) rename {unityhook => common/unityhook}/mono.h (97%) rename {unityhook => common/unityhook}/util.h (96%) rename {util => common/util}/async.c (100%) rename {util => common/util}/async.h (100%) rename {util => common/util}/crc.c (100%) rename {util => common/util}/crc.h (100%) rename {util => common/util}/dll-bind.c (100%) rename {util => common/util}/dll-bind.h (100%) rename {util => common/util}/dprintf.c (100%) rename {util => common/util}/dprintf.h (100%) rename {util => common/util}/dump.c (100%) rename {util => common/util}/dump.h (100%) rename {util => common/util}/env.c (100%) rename {util => common/util}/env.h (100%) rename {util => common/util}/get_function_ordinal.c (100%) rename {util => common/util}/get_function_ordinal.h (100%) rename {util => common/util}/lib.c (100%) rename {util => common/util}/lib.h (100%) rename {util => common/util}/meson.build (100%) rename {util => common/util}/slurp.c (100%) rename {util => common/util}/slurp.h (100%) rename {util => common/util}/str.c (100%) rename {util => common/util}/str.h (100%) rename {carolhook => games/carolhook}/carol-dll.c (100%) rename {carolhook => games/carolhook}/carol-dll.h (100%) rename {carolhook => games/carolhook}/carolhook.def (100%) rename {carolhook => games/carolhook}/config.c (100%) rename {carolhook => games/carolhook}/config.h (100%) rename {carolhook => games/carolhook}/controlbd.c (100%) rename {carolhook => games/carolhook}/controlbd.h (100%) rename {carolhook => games/carolhook}/dllmain.c (100%) rename {carolhook => games/carolhook}/jvs.c (100%) rename {carolhook => games/carolhook}/jvs.h (100%) rename {carolhook => games/carolhook}/ledbd.c (100%) rename {carolhook => games/carolhook}/ledbd.h (100%) rename {carolhook => games/carolhook}/meson.build (100%) rename {carolhook => games/carolhook}/touch.c (100%) rename {carolhook => games/carolhook}/touch.h (100%) rename {carolio => games/carolio}/carolio.c (100%) rename {carolio => games/carolio}/carolio.h (100%) rename {carolio => games/carolio}/config.c (100%) rename {carolio => games/carolio}/config.h (100%) rename {carolio => games/carolio}/meson.build (100%) rename {chunihook => games/chunihook}/chuni-dll.c (100%) rename {chunihook => games/chunihook}/chuni-dll.h (100%) rename {chunihook => games/chunihook}/chunihook.def (100%) rename {chunihook => games/chunihook}/config.c (100%) rename {chunihook => games/chunihook}/config.h (100%) rename {chunihook => games/chunihook}/dllmain.c (100%) rename {chunihook => games/chunihook}/jvs.c (100%) rename {chunihook => games/chunihook}/jvs.h (100%) rename {chunihook => games/chunihook}/meson.build (100%) rename {chunihook => games/chunihook}/slider.c (100%) rename {chunihook => games/chunihook}/slider.h (100%) rename {chuniio => games/chuniio}/chu2to3.c (100%) rename {chuniio => games/chuniio}/chu2to3.h (100%) rename {chuniio => games/chuniio}/chuniio.c (100%) rename {chuniio => games/chuniio}/chuniio.h (100%) rename {chuniio => games/chuniio}/config.c (100%) rename {chuniio => games/chuniio}/config.h (100%) rename {chuniio => games/chuniio}/leddata.h (100%) rename {chuniio => games/chuniio}/ledoutput.c (100%) rename {chuniio => games/chuniio}/ledoutput.h (100%) rename {chuniio => games/chuniio}/meson.build (100%) rename {chuniio => games/chuniio}/pipeimpl.c (100%) rename {chuniio => games/chuniio}/pipeimpl.h (100%) rename {chuniio => games/chuniio}/serialimpl.c (100%) rename {chuniio => games/chuniio}/serialimpl.h (100%) rename {chusanhook => games/chusanhook}/chuni-dll.c (100%) rename {chusanhook => games/chusanhook}/chuni-dll.h (100%) rename {chusanhook => games/chusanhook}/chusanhook.def (100%) rename {chusanhook => games/chusanhook}/config.c (100%) rename {chusanhook => games/chusanhook}/config.h (100%) rename {chusanhook => games/chusanhook}/dllmain.c (100%) rename {chusanhook => games/chusanhook}/io4.c (100%) rename {chusanhook => games/chusanhook}/io4.h (100%) rename {chusanhook => games/chusanhook}/meson.build (100%) rename {chusanhook => games/chusanhook}/slider.c (100%) rename {chusanhook => games/chusanhook}/slider.h (100%) rename {cmhook => games/cmhook}/cm-dll.c (100%) rename {cmhook => games/cmhook}/cm-dll.h (100%) rename {cmhook => games/cmhook}/cmhook.def (100%) rename {cmhook => games/cmhook}/config.c (100%) rename {cmhook => games/cmhook}/config.h (100%) rename {cmhook => games/cmhook}/dllmain.c (100%) rename {cmhook => games/cmhook}/io4.c (100%) rename {cmhook => games/cmhook}/io4.h (100%) rename {cmhook => games/cmhook}/meson.build (100%) rename {cmio => games/cmio}/cmio.c (100%) rename {cmio => games/cmio}/cmio.h (100%) rename {cmio => games/cmio}/config.c (100%) rename {cmio => games/cmio}/config.h (100%) rename {cmio => games/cmio}/meson.build (100%) rename {cxbhook => games/cxbhook}/config.c (100%) rename {cxbhook => games/cxbhook}/config.h (100%) rename {cxbhook => games/cxbhook}/cxb-dll.c (100%) rename {cxbhook => games/cxbhook}/cxb-dll.h (100%) rename {cxbhook => games/cxbhook}/cxbhook.def (100%) rename {cxbhook => games/cxbhook}/dllmain.c (100%) rename {cxbhook => games/cxbhook}/led.c (100%) rename {cxbhook => games/cxbhook}/led.h (100%) rename {cxbhook => games/cxbhook}/meson.build (100%) rename {cxbhook => games/cxbhook}/revio.c (100%) rename {cxbhook => games/cxbhook}/revio.h (100%) rename {cxbio => games/cxbio}/config.c (100%) rename {cxbio => games/cxbio}/config.h (100%) rename {cxbio => games/cxbio}/cxbio.c (100%) rename {cxbio => games/cxbio}/cxbio.h (100%) rename {cxbio => games/cxbio}/meson.build (100%) rename {divahook => games/divahook}/config.c (100%) rename {divahook => games/divahook}/config.h (100%) rename {divahook => games/divahook}/diva-dll.c (100%) rename {divahook => games/divahook}/diva-dll.h (100%) rename {divahook => games/divahook}/divahook.def (100%) rename {divahook => games/divahook}/dllmain.c (100%) rename {divahook => games/divahook}/jvs.c (100%) rename {divahook => games/divahook}/jvs.h (100%) rename {divahook => games/divahook}/meson.build (100%) rename {divahook => games/divahook}/slider.c (100%) rename {divahook => games/divahook}/slider.h (100%) rename {divaio => games/divaio}/config.c (100%) rename {divaio => games/divaio}/config.h (100%) rename {divaio => games/divaio}/divaio.c (100%) rename {divaio => games/divaio}/divaio.h (100%) rename {divaio => games/divaio}/meson.build (100%) rename {fgohook => games/fgohook}/config.c (100%) rename {fgohook => games/fgohook}/config.h (100%) rename {fgohook => games/fgohook}/deck.c (100%) rename {fgohook => games/fgohook}/deck.h (100%) rename {fgohook => games/fgohook}/dllmain.c (100%) rename {fgohook => games/fgohook}/fgo-dll.c (100%) rename {fgohook => games/fgohook}/fgo-dll.h (100%) rename {fgohook => games/fgohook}/fgohook.def (100%) rename {fgohook => games/fgohook}/ftdi.c (100%) rename {fgohook => games/fgohook}/ftdi.h (100%) rename {fgohook => games/fgohook}/io4.c (100%) rename {fgohook => games/fgohook}/io4.h (100%) rename {fgohook => games/fgohook}/meson.build (100%) rename {fgoio => games/fgoio}/backend.h (100%) rename {fgoio => games/fgoio}/config.c (100%) rename {fgoio => games/fgoio}/config.h (100%) rename {fgoio => games/fgoio}/fgoio.c (100%) rename {fgoio => games/fgoio}/fgoio.h (100%) rename {fgoio => games/fgoio}/keyboard.c (100%) rename {fgoio => games/fgoio}/keyboard.h (100%) rename {fgoio => games/fgoio}/meson.build (100%) rename {fgoio => games/fgoio}/xi.c (100%) rename {fgoio => games/fgoio}/xi.h (100%) rename {idachook => games/idachook}/config.c (100%) rename {idachook => games/idachook}/config.h (100%) rename {idachook => games/idachook}/dllmain.c (100%) rename {idachook => games/idachook}/ffb.c (100%) rename {idachook => games/idachook}/ffb.h (100%) rename {idachook => games/idachook}/idac-dll.c (100%) rename {idachook => games/idachook}/idac-dll.h (100%) rename {idachook => games/idachook}/idachook.def (100%) rename {idachook => games/idachook}/indrun.c (100%) rename {idachook => games/idachook}/indrun.h (100%) rename {idachook => games/idachook}/io4.c (100%) rename {idachook => games/idachook}/io4.h (100%) rename {idachook => games/idachook}/meson.build (100%) rename {idachook => games/idachook}/zinput.c (100%) rename {idachook => games/idachook}/zinput.h (100%) rename {idacio => games/idacio}/backend.h (100%) rename {idacio => games/idacio}/config.c (100%) rename {idacio => games/idacio}/config.h (100%) rename {idacio => games/idacio}/di-dev.c (100%) rename {idacio => games/idacio}/di-dev.h (100%) rename {idacio => games/idacio}/di.c (100%) rename {idacio => games/idacio}/di.h (100%) rename {idacio => games/idacio}/dllmain.c (100%) rename {idacio => games/idacio}/idacio.def (100%) rename {idacio => games/idacio}/idacio.h (100%) rename {idacio => games/idacio}/meson.build (100%) rename {idacio => games/idacio}/shifter.c (100%) rename {idacio => games/idacio}/shifter.h (100%) rename {idacio => games/idacio}/wnd.c (100%) rename {idacio => games/idacio}/wnd.h (100%) rename {idacio => games/idacio}/xi.c (100%) rename {idacio => games/idacio}/xi.h (100%) rename {idzhook => games/idzhook}/config.c (100%) rename {idzhook => games/idzhook}/config.h (100%) rename {idzhook => games/idzhook}/dllmain.c (100%) rename {idzhook => games/idzhook}/ffb.c (100%) rename {idzhook => games/idzhook}/ffb.h (100%) rename {idzhook => games/idzhook}/idz-dll.c (100%) rename {idzhook => games/idzhook}/idz-dll.h (100%) rename {idzhook => games/idzhook}/idzhook.def (100%) rename {idzhook => games/idzhook}/jvs.c (100%) rename {idzhook => games/idzhook}/jvs.h (100%) rename {idzhook => games/idzhook}/meson.build (100%) rename {idzhook => games/idzhook}/zinput.c (100%) rename {idzhook => games/idzhook}/zinput.h (100%) rename {idzio => games/idzio}/backend.h (100%) rename {idzio => games/idzio}/config.c (100%) rename {idzio => games/idzio}/config.h (100%) rename {idzio => games/idzio}/di-dev.c (100%) rename {idzio => games/idzio}/di-dev.h (100%) rename {idzio => games/idzio}/di.c (100%) rename {idzio => games/idzio}/di.h (100%) rename {idzio => games/idzio}/dllmain.c (100%) rename {idzio => games/idzio}/idzio.def (100%) rename {idzio => games/idzio}/idzio.h (100%) rename {idzio => games/idzio}/meson.build (100%) rename {idzio => games/idzio}/shifter.c (100%) rename {idzio => games/idzio}/shifter.h (100%) rename {idzio => games/idzio}/wnd.c (100%) rename {idzio => games/idzio}/wnd.h (100%) rename {idzio => games/idzio}/xi.c (100%) rename {idzio => games/idzio}/xi.h (100%) rename {kemonohook => games/kemonohook}/config.c (100%) rename {kemonohook => games/kemonohook}/config.h (100%) rename {kemonohook => games/kemonohook}/dllmain.c (100%) rename {kemonohook => games/kemonohook}/hooks.c (100%) rename {kemonohook => games/kemonohook}/hooks.h (100%) rename {kemonohook => games/kemonohook}/jvs.c (100%) rename {kemonohook => games/kemonohook}/jvs.h (100%) rename {kemonohook => games/kemonohook}/kemono-dll.c (100%) rename {kemonohook => games/kemonohook}/kemono-dll.h (100%) rename {kemonohook => games/kemonohook}/kemonohook.def (100%) rename {kemonohook => games/kemonohook}/meson.build (100%) rename {kemonoio => games/kemonoio}/config.c (100%) rename {kemonoio => games/kemonoio}/config.h (100%) rename {kemonoio => games/kemonoio}/kemonoio.c (100%) rename {kemonoio => games/kemonoio}/kemonoio.h (100%) rename {kemonoio => games/kemonoio}/meson.build (100%) rename {mai2hook => games/mai2hook}/config.c (100%) rename {mai2hook => games/mai2hook}/config.h (100%) rename {mai2hook => games/mai2hook}/dllmain.c (100%) rename {mai2hook => games/mai2hook}/io4.c (100%) rename {mai2hook => games/mai2hook}/io4.h (100%) rename {mai2hook => games/mai2hook}/mai2-dll.c (100%) rename {mai2hook => games/mai2hook}/mai2-dll.h (100%) rename {mai2hook => games/mai2hook}/mai2hook.def (100%) rename {mai2hook => games/mai2hook}/meson.build (100%) rename {mai2hook => games/mai2hook}/touch.c (100%) rename {mai2hook => games/mai2hook}/touch.h (100%) rename {mai2io => games/mai2io}/config.c (100%) rename {mai2io => games/mai2io}/config.h (100%) rename {mai2io => games/mai2io}/mai2io.c (100%) rename {mai2io => games/mai2io}/mai2io.h (100%) rename {mai2io => games/mai2io}/meson.build (100%) rename {mercuryhook => games/mercuryhook}/config.c (100%) rename {mercuryhook => games/mercuryhook}/config.h (100%) rename {mercuryhook => games/mercuryhook}/dllmain.c (100%) rename {mercuryhook => games/mercuryhook}/elisabeth.c (100%) rename {mercuryhook => games/mercuryhook}/elisabeth.h (100%) rename {mercuryhook => games/mercuryhook}/io4.c (100%) rename {mercuryhook => games/mercuryhook}/io4.h (100%) rename {mercuryhook => games/mercuryhook}/mercury-dll.c (100%) rename {mercuryhook => games/mercuryhook}/mercury-dll.h (100%) rename {mercuryhook => games/mercuryhook}/mercuryhook.def (100%) rename {mercuryhook => games/mercuryhook}/meson.build (100%) rename {mercuryhook => games/mercuryhook}/touch.c (100%) rename {mercuryhook => games/mercuryhook}/touch.h (100%) rename {mercuryio => games/mercuryio}/config.c (100%) rename {mercuryio => games/mercuryio}/config.h (100%) rename {mercuryio => games/mercuryio}/mercuryio.c (100%) rename {mercuryio => games/mercuryio}/mercuryio.def (100%) rename {mercuryio => games/mercuryio}/mercuryio.h (100%) rename {mercuryio => games/mercuryio}/meson.build (100%) rename {mu3hook => games/mu3hook}/config.c (100%) rename {mu3hook => games/mu3hook}/config.h (100%) rename {mu3hook => games/mu3hook}/dllmain.c (100%) rename {mu3hook => games/mu3hook}/io4.c (100%) rename {mu3hook => games/mu3hook}/io4.h (100%) rename {mu3hook => games/mu3hook}/meson.build (100%) rename {mu3hook => games/mu3hook}/mu3-dll.c (100%) rename {mu3hook => games/mu3hook}/mu3-dll.h (100%) rename {mu3hook => games/mu3hook}/mu3hook.def (100%) rename {mu3io => games/mu3io}/config.c (100%) rename {mu3io => games/mu3io}/config.h (100%) rename {mu3io => games/mu3io}/leddata.h (100%) rename {mu3io => games/mu3io}/ledoutput.c (100%) rename {mu3io => games/mu3io}/ledoutput.h (100%) rename {mu3io => games/mu3io}/meson.build (100%) rename {mu3io => games/mu3io}/mu3io.c (100%) rename {mu3io => games/mu3io}/mu3io.h (100%) rename {mu3io => games/mu3io}/pipeimpl.c (100%) rename {mu3io => games/mu3io}/pipeimpl.h (100%) rename {mu3io => games/mu3io}/serialimpl.c (100%) rename {mu3io => games/mu3io}/serialimpl.h (100%) rename {swdchook => games/swdchook}/config.c (100%) rename {swdchook => games/swdchook}/config.h (100%) rename {swdchook => games/swdchook}/dllmain.c (100%) rename {swdchook => games/swdchook}/ffb.c (100%) rename {swdchook => games/swdchook}/ffb.h (100%) rename {swdchook => games/swdchook}/io4.c (100%) rename {swdchook => games/swdchook}/io4.h (100%) rename {swdchook => games/swdchook}/meson.build (100%) rename {swdchook => games/swdchook}/swdc-dll.c (100%) rename {swdchook => games/swdchook}/swdc-dll.h (100%) rename {swdchook => games/swdchook}/swdchook.def (100%) rename {swdchook => games/swdchook}/zinput.c (100%) rename {swdchook => games/swdchook}/zinput.h (100%) rename {swdcio => games/swdcio}/backend.h (100%) rename {swdcio => games/swdcio}/config.c (100%) rename {swdcio => games/swdcio}/config.h (100%) rename {swdcio => games/swdcio}/di-dev.c (100%) rename {swdcio => games/swdcio}/di-dev.h (100%) rename {swdcio => games/swdcio}/di.c (100%) rename {swdcio => games/swdcio}/di.h (100%) rename {swdcio => games/swdcio}/dllmain.c (100%) rename {swdcio => games/swdcio}/meson.build (100%) rename {swdcio => games/swdcio}/swdcio.def (100%) rename {swdcio => games/swdcio}/swdcio.h (100%) rename {swdcio => games/swdcio}/wnd.c (100%) rename {swdcio => games/swdcio}/wnd.h (100%) rename {swdcio => games/swdcio}/xi.c (100%) rename {swdcio => games/swdcio}/xi.h (100%) rename {tokyohook => games/tokyohook}/config.c (100%) rename {tokyohook => games/tokyohook}/config.h (100%) rename {tokyohook => games/tokyohook}/dllmain.c (100%) rename {tokyohook => games/tokyohook}/io4.c (100%) rename {tokyohook => games/tokyohook}/io4.h (100%) rename {tokyohook => games/tokyohook}/meson.build (100%) rename {tokyohook => games/tokyohook}/tokyo-dll.c (100%) rename {tokyohook => games/tokyohook}/tokyo-dll.h (100%) rename {tokyohook => games/tokyohook}/tokyohook.def (100%) rename {tokyohook => games/tokyohook}/zinput.c (100%) rename {tokyohook => games/tokyohook}/zinput.h (100%) rename {tokyoio => games/tokyoio}/backend.h (100%) rename {tokyoio => games/tokyoio}/config.c (100%) rename {tokyoio => games/tokyoio}/config.h (100%) rename {tokyoio => games/tokyoio}/dllmain.c (100%) rename {tokyoio => games/tokyoio}/kb.c (100%) rename {tokyoio => games/tokyoio}/kb.h (100%) rename {tokyoio => games/tokyoio}/meson.build (100%) rename {tokyoio => games/tokyoio}/tokyoio.h (100%) rename {tokyoio => games/tokyoio}/xi.c (100%) rename {tokyoio => games/tokyoio}/xi.h (100%) delete mode 100644 minihook/dllmain.c delete mode 100644 minihook/meson.build delete mode 100644 reg/chunithm.reg diff --git a/Makefile b/Makefile index 28562a1..0381552 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ V ?= @ BUILD_DIR := build BUILD_DIR_32 := $(BUILD_DIR)/build32 BUILD_DIR_64 := $(BUILD_DIR)/build64 +BUILD_DIR_GAMES_32 := $(BUILD_DIR_32)/games +BUILD_DIR_GAMES_64 := $(BUILD_DIR_64)/games BUILD_DIR_ZIP := $(BUILD_DIR)/zip DOC_DIR := doc diff --git a/Package.mk b/Package.mk index 5647e9b..ae87f73 100644 --- a/Package.mk +++ b/Package.mk @@ -3,7 +3,7 @@ $(BUILD_DIR_ZIP)/chuni.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/chuni $(V)mkdir -p $(BUILD_DIR_ZIP)/chuni/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/chunihook/chunihook.dll \ + $(BUILD_DIR_GAMES_32)/chunihook/chunihook.dll \ $(DIST_DIR)/chuni/segatools.ini \ $(DIST_DIR)/chuni/launch.bat \ $(BUILD_DIR_ZIP)/chuni @@ -18,7 +18,7 @@ $(BUILD_DIR_ZIP)/cxb.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cxb $(V)mkdir -p $(BUILD_DIR_ZIP)/cxb/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/cxbhook/cxbhook.dll \ + $(BUILD_DIR_GAMES_32)/cxbhook/cxbhook.dll \ $(DIST_DIR)/cxb/segatools.ini \ $(DIST_DIR)/cxb/launch.bat \ $(BUILD_DIR_ZIP)/cxb @@ -33,7 +33,7 @@ $(BUILD_DIR_ZIP)/diva.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/diva $(V)mkdir -p $(BUILD_DIR_ZIP)/diva/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/divahook/divahook.dll \ + $(BUILD_DIR_GAMES_64)/divahook/divahook.dll \ $(DIST_DIR)/diva/segatools.ini \ $(DIST_DIR)/diva/launch.bat \ $(BUILD_DIR_ZIP)/diva @@ -48,7 +48,7 @@ $(BUILD_DIR_ZIP)/carol.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/carol $(V)mkdir -p $(BUILD_DIR_ZIP)/carol/DEVICE $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_32)/carolhook/carolhook.dll \ + $(BUILD_DIR_GAMES_32)/carolhook/carolhook.dll \ $(DIST_DIR)/carol/segatools.ini \ $(DIST_DIR)/carol/launch.bat \ $(BUILD_DIR_ZIP)/carol @@ -63,7 +63,7 @@ $(BUILD_DIR_ZIP)/idz.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/idz $(V)mkdir -p $(BUILD_DIR_ZIP)/idz/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/idzhook/idzhook.dll \ + $(BUILD_DIR_GAMES_64)/idzhook/idzhook.dll \ $(DIST_DIR)/idz/segatools.ini \ $(DIST_DIR)/idz/launch.bat \ $(BUILD_DIR_ZIP)/idz @@ -78,7 +78,7 @@ $(BUILD_DIR_ZIP)/fgo.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo $(V)mkdir -p $(BUILD_DIR_ZIP)/fgo/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/fgohook/fgohook.dll \ + $(BUILD_DIR_GAMES_64)/fgohook/fgohook.dll \ $(DIST_DIR)/fgo/segatools.ini \ $(DIST_DIR)/fgo/launch.bat \ $(BUILD_DIR_ZIP)/fgo @@ -93,7 +93,7 @@ $(BUILD_DIR_ZIP)/idac.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/idac $(V)mkdir -p $(BUILD_DIR_ZIP)/idac/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/idachook/idachook.dll \ + $(BUILD_DIR_GAMES_64)/idachook/idachook.dll \ $(DIST_DIR)/idac/segatools.ini \ $(DIST_DIR)/idac/config_hook.json \ $(DIST_DIR)/idac/launch.bat \ @@ -109,7 +109,7 @@ $(BUILD_DIR_ZIP)/swdc.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc $(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/swdchook/swdchook.dll \ + $(BUILD_DIR_GAMES_64)/swdchook/swdchook.dll \ $(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/config_hook.json \ $(DIST_DIR)/swdc/launch.bat \ @@ -125,7 +125,7 @@ $(BUILD_DIR_ZIP)/mercury.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury $(V)mkdir -p $(BUILD_DIR_ZIP)/mercury/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mercuryhook/mercuryhook.dll \ + $(BUILD_DIR_GAMES_64)/mercuryhook/mercuryhook.dll \ $(DIST_DIR)/mercury/segatools.ini \ $(DIST_DIR)/mercury/launch.bat \ $(BUILD_DIR_ZIP)/mercury @@ -143,9 +143,9 @@ $(BUILD_DIR_ZIP)/chusan.zip: $(DIST_DIR)/chusan/config_hook.json \ $(DIST_DIR)/chusan/launch.bat \ $(BUILD_DIR_ZIP)/chusan - $(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \ + $(V)cp $(BUILD_DIR_GAMES_32)/chusanhook/chusanhook.dll \ $(BUILD_DIR_ZIP)/chusan/chusanhook_x86.dll - $(V)cp $(BUILD_DIR_64)/chusanhook/chusanhook.dll \ + $(V)cp $(BUILD_DIR_GAMES_64)/chusanhook/chusanhook.dll \ $(BUILD_DIR_ZIP)/chusan/chusanhook_x64.dll $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_ZIP)/chusan/inject_x86.exe @@ -162,7 +162,7 @@ $(BUILD_DIR_ZIP)/mu3.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3 $(V)mkdir -p $(BUILD_DIR_ZIP)/mu3/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mu3hook/mu3hook.dll \ + $(BUILD_DIR_GAMES_64)/mu3hook/mu3hook.dll \ $(DIST_DIR)/mu3/segatools.ini \ $(DIST_DIR)/mu3/launch.bat \ $(BUILD_DIR_ZIP)/mu3 @@ -177,7 +177,7 @@ $(BUILD_DIR_ZIP)/mai2.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2 $(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/mai2hook/mai2hook.dll \ + $(BUILD_DIR_GAMES_64)/mai2hook/mai2hook.dll \ $(DIST_DIR)/mai2/segatools.ini \ $(DIST_DIR)/mai2/launch.bat \ $(BUILD_DIR_ZIP)/mai2 @@ -192,7 +192,7 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/cm $(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/cmhook/cmhook.dll \ + $(BUILD_DIR_GAMES_64)/cmhook/cmhook.dll \ $(DIST_DIR)/cm/config_hook.json \ $(DIST_DIR)/cm/segatools.ini \ $(DIST_DIR)/cm/launch.bat \ @@ -208,7 +208,7 @@ $(BUILD_DIR_ZIP)/tokyo.zip: $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo/DEVICE $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ - $(BUILD_DIR_64)/tokyohook/tokyohook.dll \ + $(BUILD_DIR_GAMES_64)/tokyohook/tokyohook.dll \ $(DIST_DIR)/tokyo/config_hook.json \ $(DIST_DIR)/tokyo/segatools.ini \ $(DIST_DIR)/tokyo/launch.bat \ @@ -226,9 +226,9 @@ $(BUILD_DIR_ZIP)/kemono.zip: $(V)cp $(DIST_DIR)/kemono/segatools.ini \ $(DIST_DIR)/kemono/launch.bat \ $(BUILD_DIR_ZIP)/kemono - $(V)cp $(BUILD_DIR_32)/kemonohook/kemonohook.dll \ + $(V)cp $(BUILD_DIR_GAMES_32)/kemonohook/kemonohook.dll \ $(BUILD_DIR_ZIP)/kemono/kemonohook_x86.dll - $(V)cp $(BUILD_DIR_64)/kemonohook/kemonohook.dll \ + $(V)cp $(BUILD_DIR_GAMES_64)/kemonohook/kemonohook.dll \ $(BUILD_DIR_ZIP)/kemono/kemonohook_x64.dll $(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \ $(BUILD_DIR_ZIP)/kemono/inject_x86.exe diff --git a/aimeio/aimeio.c b/common/aimeio/aimeio.c similarity index 100% rename from aimeio/aimeio.c rename to common/aimeio/aimeio.c diff --git a/aimeio/aimeio.h b/common/aimeio/aimeio.h similarity index 100% rename from aimeio/aimeio.h rename to common/aimeio/aimeio.h diff --git a/aimeio/meson.build b/common/aimeio/meson.build similarity index 100% rename from aimeio/meson.build rename to common/aimeio/meson.build diff --git a/amex/amex.c b/common/amex/amex.c similarity index 100% rename from amex/amex.c rename to common/amex/amex.c diff --git a/amex/amex.h b/common/amex/amex.h similarity index 100% rename from amex/amex.h rename to common/amex/amex.h diff --git a/amex/config.c b/common/amex/config.c similarity index 100% rename from amex/config.c rename to common/amex/config.c diff --git a/amex/config.h b/common/amex/config.h similarity index 100% rename from amex/config.h rename to common/amex/config.h diff --git a/amex/ds.c b/common/amex/ds.c similarity index 100% rename from amex/ds.c rename to common/amex/ds.c diff --git a/amex/ds.h b/common/amex/ds.h similarity index 100% rename from amex/ds.h rename to common/amex/ds.h diff --git a/amex/eeprom.c b/common/amex/eeprom.c similarity index 100% rename from amex/eeprom.c rename to common/amex/eeprom.c diff --git a/amex/eeprom.h b/common/amex/eeprom.h similarity index 100% rename from amex/eeprom.h rename to common/amex/eeprom.h diff --git a/amex/gpio.c b/common/amex/gpio.c similarity index 100% rename from amex/gpio.c rename to common/amex/gpio.c diff --git a/amex/gpio.h b/common/amex/gpio.h similarity index 100% rename from amex/gpio.h rename to common/amex/gpio.h diff --git a/amex/guid.c b/common/amex/guid.c similarity index 100% rename from amex/guid.c rename to common/amex/guid.c diff --git a/amex/jvs.c b/common/amex/jvs.c similarity index 100% rename from amex/jvs.c rename to common/amex/jvs.c diff --git a/amex/jvs.h b/common/amex/jvs.h similarity index 100% rename from amex/jvs.h rename to common/amex/jvs.h diff --git a/amex/meson.build b/common/amex/meson.build similarity index 100% rename from amex/meson.build rename to common/amex/meson.build diff --git a/amex/nvram.c b/common/amex/nvram.c similarity index 100% rename from amex/nvram.c rename to common/amex/nvram.c diff --git a/amex/nvram.h b/common/amex/nvram.h similarity index 100% rename from amex/nvram.h rename to common/amex/nvram.h diff --git a/amex/sram.c b/common/amex/sram.c similarity index 100% rename from amex/sram.c rename to common/amex/sram.c diff --git a/amex/sram.h b/common/amex/sram.h similarity index 100% rename from amex/sram.h rename to common/amex/sram.h diff --git a/board/aime-dll.c b/common/board/aime-dll.c similarity index 100% rename from board/aime-dll.c rename to common/board/aime-dll.c diff --git a/board/aime-dll.h b/common/board/aime-dll.h similarity index 100% rename from board/aime-dll.h rename to common/board/aime-dll.h diff --git a/board/config.c b/common/board/config.c similarity index 100% rename from board/config.c rename to common/board/config.c diff --git a/board/config.h b/common/board/config.h similarity index 100% rename from board/config.h rename to common/board/config.h diff --git a/board/ffb.c b/common/board/ffb.c similarity index 100% rename from board/ffb.c rename to common/board/ffb.c diff --git a/board/ffb.h b/common/board/ffb.h similarity index 100% rename from board/ffb.h rename to common/board/ffb.h diff --git a/board/guid.c b/common/board/guid.c similarity index 100% rename from board/guid.c rename to common/board/guid.c diff --git a/board/guid.h b/common/board/guid.h similarity index 100% rename from board/guid.h rename to common/board/guid.h diff --git a/board/io3.c b/common/board/io3.c similarity index 100% rename from board/io3.c rename to common/board/io3.c diff --git a/board/io3.h b/common/board/io3.h similarity index 100% rename from board/io3.h rename to common/board/io3.h diff --git a/board/io4.c b/common/board/io4.c similarity index 100% rename from board/io4.c rename to common/board/io4.c diff --git a/board/io4.h b/common/board/io4.h similarity index 100% rename from board/io4.h rename to common/board/io4.h diff --git a/board/led15070-cmd.h b/common/board/led15070-cmd.h similarity index 100% rename from board/led15070-cmd.h rename to common/board/led15070-cmd.h diff --git a/board/led15070-frame.c b/common/board/led15070-frame.c similarity index 100% rename from board/led15070-frame.c rename to common/board/led15070-frame.c diff --git a/board/led15070-frame.h b/common/board/led15070-frame.h similarity index 100% rename from board/led15070-frame.h rename to common/board/led15070-frame.h diff --git a/board/led15070.c b/common/board/led15070.c similarity index 100% rename from board/led15070.c rename to common/board/led15070.c diff --git a/board/led15070.h b/common/board/led15070.h similarity index 100% rename from board/led15070.h rename to common/board/led15070.h diff --git a/board/led15093-cmd.h b/common/board/led15093-cmd.h similarity index 100% rename from board/led15093-cmd.h rename to common/board/led15093-cmd.h diff --git a/board/led15093-frame.c b/common/board/led15093-frame.c similarity index 100% rename from board/led15093-frame.c rename to common/board/led15093-frame.c diff --git a/board/led15093-frame.h b/common/board/led15093-frame.h similarity index 100% rename from board/led15093-frame.h rename to common/board/led15093-frame.h diff --git a/board/led15093.c b/common/board/led15093.c similarity index 100% rename from board/led15093.c rename to common/board/led15093.c diff --git a/board/led15093.h b/common/board/led15093.h similarity index 100% rename from board/led15093.h rename to common/board/led15093.h diff --git a/board/meson.build b/common/board/meson.build similarity index 100% rename from board/meson.build rename to common/board/meson.build diff --git a/board/sg-cmd.c b/common/board/sg-cmd.c similarity index 100% rename from board/sg-cmd.c rename to common/board/sg-cmd.c diff --git a/board/sg-cmd.h b/common/board/sg-cmd.h similarity index 100% rename from board/sg-cmd.h rename to common/board/sg-cmd.h diff --git a/board/sg-frame.c b/common/board/sg-frame.c similarity index 100% rename from board/sg-frame.c rename to common/board/sg-frame.c diff --git a/board/sg-frame.h b/common/board/sg-frame.h similarity index 100% rename from board/sg-frame.h rename to common/board/sg-frame.h diff --git a/board/sg-led-cmd.h b/common/board/sg-led-cmd.h similarity index 100% rename from board/sg-led-cmd.h rename to common/board/sg-led-cmd.h diff --git a/board/sg-led.c b/common/board/sg-led.c similarity index 100% rename from board/sg-led.c rename to common/board/sg-led.c diff --git a/board/sg-led.h b/common/board/sg-led.h similarity index 100% rename from board/sg-led.h rename to common/board/sg-led.h diff --git a/board/sg-nfc-cmd.h b/common/board/sg-nfc-cmd.h similarity index 100% rename from board/sg-nfc-cmd.h rename to common/board/sg-nfc-cmd.h diff --git a/board/sg-nfc.c b/common/board/sg-nfc.c similarity index 99% rename from board/sg-nfc.c rename to common/board/sg-nfc.c index a072111..b103336 100644 --- a/board/sg-nfc.c +++ b/common/board/sg-nfc.c @@ -321,6 +321,7 @@ static HRESULT sg_nfc_poll_aime( mifare->type = 0x10; mifare->id_len = sizeof(mifare->uid); + // mifare->uid = _byteswap_ulong(0x8FBECBFF); mifare->uid = _byteswap_ulong(0x01020304); /* Initialize MIFARE IC emulator */ diff --git a/board/sg-nfc.h b/common/board/sg-nfc.h similarity index 100% rename from board/sg-nfc.h rename to common/board/sg-nfc.h diff --git a/board/sg-reader.c b/common/board/sg-reader.c similarity index 100% rename from board/sg-reader.c rename to common/board/sg-reader.c diff --git a/board/sg-reader.h b/common/board/sg-reader.h similarity index 100% rename from board/sg-reader.h rename to common/board/sg-reader.h diff --git a/board/slider-cmd.h b/common/board/slider-cmd.h similarity index 100% rename from board/slider-cmd.h rename to common/board/slider-cmd.h diff --git a/board/slider-frame.c b/common/board/slider-frame.c similarity index 100% rename from board/slider-frame.c rename to common/board/slider-frame.c diff --git a/board/slider-frame.h b/common/board/slider-frame.h similarity index 100% rename from board/slider-frame.h rename to common/board/slider-frame.h diff --git a/board/vfd-cmd.h b/common/board/vfd-cmd.h similarity index 100% rename from board/vfd-cmd.h rename to common/board/vfd-cmd.h diff --git a/board/vfd-frame.c b/common/board/vfd-frame.c similarity index 100% rename from board/vfd-frame.c rename to common/board/vfd-frame.c diff --git a/board/vfd-frame.h b/common/board/vfd-frame.h similarity index 100% rename from board/vfd-frame.h rename to common/board/vfd-frame.h diff --git a/board/vfd.c b/common/board/vfd.c similarity index 100% rename from board/vfd.c rename to common/board/vfd.c diff --git a/board/vfd.h b/common/board/vfd.h similarity index 100% rename from board/vfd.h rename to common/board/vfd.h diff --git a/gfxhook/config.c b/common/gfxhook/config.c similarity index 100% rename from gfxhook/config.c rename to common/gfxhook/config.c diff --git a/gfxhook/config.h b/common/gfxhook/config.h similarity index 100% rename from gfxhook/config.h rename to common/gfxhook/config.h diff --git a/gfxhook/d3d11.c b/common/gfxhook/d3d11.c similarity index 100% rename from gfxhook/d3d11.c rename to common/gfxhook/d3d11.c diff --git a/gfxhook/d3d11.h b/common/gfxhook/d3d11.h similarity index 100% rename from gfxhook/d3d11.h rename to common/gfxhook/d3d11.h diff --git a/gfxhook/d3d9.c b/common/gfxhook/d3d9.c similarity index 100% rename from gfxhook/d3d9.c rename to common/gfxhook/d3d9.c diff --git a/gfxhook/d3d9.h b/common/gfxhook/d3d9.h similarity index 100% rename from gfxhook/d3d9.h rename to common/gfxhook/d3d9.h diff --git a/gfxhook/dxgi.c b/common/gfxhook/dxgi.c similarity index 100% rename from gfxhook/dxgi.c rename to common/gfxhook/dxgi.c diff --git a/gfxhook/dxgi.h b/common/gfxhook/dxgi.h similarity index 100% rename from gfxhook/dxgi.h rename to common/gfxhook/dxgi.h diff --git a/gfxhook/gfx.c b/common/gfxhook/gfx.c similarity index 100% rename from gfxhook/gfx.c rename to common/gfxhook/gfx.c diff --git a/gfxhook/gfx.h b/common/gfxhook/gfx.h similarity index 100% rename from gfxhook/gfx.h rename to common/gfxhook/gfx.h diff --git a/gfxhook/gl.c b/common/gfxhook/gl.c similarity index 100% rename from gfxhook/gl.c rename to common/gfxhook/gl.c diff --git a/gfxhook/gl.h b/common/gfxhook/gl.h similarity index 100% rename from gfxhook/gl.h rename to common/gfxhook/gl.h diff --git a/gfxhook/meson.build b/common/gfxhook/meson.build similarity index 100% rename from gfxhook/meson.build rename to common/gfxhook/meson.build diff --git a/gfxhook/util.c b/common/gfxhook/util.c similarity index 100% rename from gfxhook/util.c rename to common/gfxhook/util.c diff --git a/gfxhook/util.h b/common/gfxhook/util.h similarity index 100% rename from gfxhook/util.h rename to common/gfxhook/util.h diff --git a/hooklib/config.c b/common/hooklib/config.c similarity index 100% rename from hooklib/config.c rename to common/hooklib/config.c diff --git a/hooklib/config.h b/common/hooklib/config.h similarity index 100% rename from hooklib/config.h rename to common/hooklib/config.h diff --git a/hooklib/createprocess.c b/common/hooklib/createprocess.c similarity index 100% rename from hooklib/createprocess.c rename to common/hooklib/createprocess.c diff --git a/hooklib/createprocess.h b/common/hooklib/createprocess.h similarity index 100% rename from hooklib/createprocess.h rename to common/hooklib/createprocess.h diff --git a/hooklib/cursor.c b/common/hooklib/cursor.c similarity index 100% rename from hooklib/cursor.c rename to common/hooklib/cursor.c diff --git a/hooklib/cursor.h b/common/hooklib/cursor.h similarity index 100% rename from hooklib/cursor.h rename to common/hooklib/cursor.h diff --git a/hooklib/dll.c b/common/hooklib/dll.c similarity index 100% rename from hooklib/dll.c rename to common/hooklib/dll.c diff --git a/hooklib/dll.h b/common/hooklib/dll.h similarity index 100% rename from hooklib/dll.h rename to common/hooklib/dll.h diff --git a/hooklib/dns.c b/common/hooklib/dns.c similarity index 100% rename from hooklib/dns.c rename to common/hooklib/dns.c diff --git a/hooklib/dns.h b/common/hooklib/dns.h similarity index 100% rename from hooklib/dns.h rename to common/hooklib/dns.h diff --git a/hooklib/dvd.c b/common/hooklib/dvd.c similarity index 100% rename from hooklib/dvd.c rename to common/hooklib/dvd.c diff --git a/hooklib/dvd.h b/common/hooklib/dvd.h similarity index 100% rename from hooklib/dvd.h rename to common/hooklib/dvd.h diff --git a/hooklib/fdshark.c b/common/hooklib/fdshark.c similarity index 100% rename from hooklib/fdshark.c rename to common/hooklib/fdshark.c diff --git a/hooklib/fdshark.h b/common/hooklib/fdshark.h similarity index 100% rename from hooklib/fdshark.h rename to common/hooklib/fdshark.h diff --git a/hooklib/meson.build b/common/hooklib/meson.build similarity index 100% rename from hooklib/meson.build rename to common/hooklib/meson.build diff --git a/hooklib/path.c b/common/hooklib/path.c similarity index 100% rename from hooklib/path.c rename to common/hooklib/path.c diff --git a/hooklib/path.h b/common/hooklib/path.h similarity index 100% rename from hooklib/path.h rename to common/hooklib/path.h diff --git a/hooklib/printer.c b/common/hooklib/printer.c similarity index 100% rename from hooklib/printer.c rename to common/hooklib/printer.c diff --git a/hooklib/printer.h b/common/hooklib/printer.h similarity index 100% rename from hooklib/printer.h rename to common/hooklib/printer.h diff --git a/hooklib/reg.c b/common/hooklib/reg.c similarity index 100% rename from hooklib/reg.c rename to common/hooklib/reg.c diff --git a/hooklib/reg.h b/common/hooklib/reg.h similarity index 100% rename from hooklib/reg.h rename to common/hooklib/reg.h diff --git a/hooklib/setupapi.c b/common/hooklib/setupapi.c similarity index 100% rename from hooklib/setupapi.c rename to common/hooklib/setupapi.c diff --git a/hooklib/setupapi.h b/common/hooklib/setupapi.h similarity index 100% rename from hooklib/setupapi.h rename to common/hooklib/setupapi.h diff --git a/hooklib/spike.c b/common/hooklib/spike.c similarity index 100% rename from hooklib/spike.c rename to common/hooklib/spike.c diff --git a/hooklib/spike.h b/common/hooklib/spike.h similarity index 100% rename from hooklib/spike.h rename to common/hooklib/spike.h diff --git a/hooklib/touch.c b/common/hooklib/touch.c similarity index 100% rename from hooklib/touch.c rename to common/hooklib/touch.c diff --git a/hooklib/touch.h b/common/hooklib/touch.h similarity index 100% rename from hooklib/touch.h rename to common/hooklib/touch.h diff --git a/iccard/aime.c b/common/iccard/aime.c similarity index 100% rename from iccard/aime.c rename to common/iccard/aime.c diff --git a/iccard/aime.h b/common/iccard/aime.h similarity index 100% rename from iccard/aime.h rename to common/iccard/aime.h diff --git a/iccard/felica.c b/common/iccard/felica.c similarity index 100% rename from iccard/felica.c rename to common/iccard/felica.c diff --git a/iccard/felica.h b/common/iccard/felica.h similarity index 100% rename from iccard/felica.h rename to common/iccard/felica.h diff --git a/iccard/meson.build b/common/iccard/meson.build similarity index 100% rename from iccard/meson.build rename to common/iccard/meson.build diff --git a/iccard/mifare.h b/common/iccard/mifare.h similarity index 100% rename from iccard/mifare.h rename to common/iccard/mifare.h diff --git a/jvs/jvs-bus.c b/common/jvs/jvs-bus.c similarity index 100% rename from jvs/jvs-bus.c rename to common/jvs/jvs-bus.c diff --git a/jvs/jvs-bus.h b/common/jvs/jvs-bus.h similarity index 100% rename from jvs/jvs-bus.h rename to common/jvs/jvs-bus.h diff --git a/jvs/jvs-cmd.h b/common/jvs/jvs-cmd.h similarity index 100% rename from jvs/jvs-cmd.h rename to common/jvs/jvs-cmd.h diff --git a/jvs/jvs-frame.c b/common/jvs/jvs-frame.c similarity index 100% rename from jvs/jvs-frame.c rename to common/jvs/jvs-frame.c diff --git a/jvs/jvs-frame.h b/common/jvs/jvs-frame.h similarity index 100% rename from jvs/jvs-frame.h rename to common/jvs/jvs-frame.h diff --git a/jvs/jvs-util.c b/common/jvs/jvs-util.c similarity index 100% rename from jvs/jvs-util.c rename to common/jvs/jvs-util.c diff --git a/jvs/jvs-util.h b/common/jvs/jvs-util.h similarity index 100% rename from jvs/jvs-util.h rename to common/jvs/jvs-util.h diff --git a/jvs/meson.build b/common/jvs/meson.build similarity index 100% rename from jvs/meson.build rename to common/jvs/meson.build diff --git a/platform/amvideo.c b/common/platform/amvideo.c similarity index 100% rename from platform/amvideo.c rename to common/platform/amvideo.c diff --git a/platform/amvideo.h b/common/platform/amvideo.h similarity index 100% rename from platform/amvideo.h rename to common/platform/amvideo.h diff --git a/platform/clock.c b/common/platform/clock.c similarity index 100% rename from platform/clock.c rename to common/platform/clock.c diff --git a/platform/clock.h b/common/platform/clock.h similarity index 100% rename from platform/clock.h rename to common/platform/clock.h diff --git a/platform/config.c b/common/platform/config.c similarity index 100% rename from platform/config.c rename to common/platform/config.c diff --git a/platform/config.h b/common/platform/config.h similarity index 100% rename from platform/config.h rename to common/platform/config.h diff --git a/platform/dns.c b/common/platform/dns.c similarity index 100% rename from platform/dns.c rename to common/platform/dns.c diff --git a/platform/dns.h b/common/platform/dns.h similarity index 100% rename from platform/dns.h rename to common/platform/dns.h diff --git a/platform/epay.c b/common/platform/epay.c similarity index 100% rename from platform/epay.c rename to common/platform/epay.c diff --git a/platform/epay.h b/common/platform/epay.h similarity index 100% rename from platform/epay.h rename to common/platform/epay.h diff --git a/platform/hwmon.c b/common/platform/hwmon.c similarity index 100% rename from platform/hwmon.c rename to common/platform/hwmon.c diff --git a/platform/hwmon.h b/common/platform/hwmon.h similarity index 100% rename from platform/hwmon.h rename to common/platform/hwmon.h diff --git a/platform/hwreset.c b/common/platform/hwreset.c similarity index 100% rename from platform/hwreset.c rename to common/platform/hwreset.c diff --git a/platform/hwreset.h b/common/platform/hwreset.h similarity index 100% rename from platform/hwreset.h rename to common/platform/hwreset.h diff --git a/platform/meson.build b/common/platform/meson.build similarity index 100% rename from platform/meson.build rename to common/platform/meson.build diff --git a/platform/misc.c b/common/platform/misc.c similarity index 100% rename from platform/misc.c rename to common/platform/misc.c diff --git a/platform/misc.h b/common/platform/misc.h similarity index 100% rename from platform/misc.h rename to common/platform/misc.h diff --git a/platform/netenv.c b/common/platform/netenv.c similarity index 100% rename from platform/netenv.c rename to common/platform/netenv.c diff --git a/platform/netenv.h b/common/platform/netenv.h similarity index 100% rename from platform/netenv.h rename to common/platform/netenv.h diff --git a/platform/nusec.c b/common/platform/nusec.c similarity index 100% rename from platform/nusec.c rename to common/platform/nusec.c diff --git a/platform/nusec.h b/common/platform/nusec.h similarity index 100% rename from platform/nusec.h rename to common/platform/nusec.h diff --git a/platform/pcbid.c b/common/platform/pcbid.c similarity index 100% rename from platform/pcbid.c rename to common/platform/pcbid.c diff --git a/platform/pcbid.h b/common/platform/pcbid.h similarity index 100% rename from platform/pcbid.h rename to common/platform/pcbid.h diff --git a/platform/platform.c b/common/platform/platform.c similarity index 100% rename from platform/platform.c rename to common/platform/platform.c diff --git a/platform/platform.h b/common/platform/platform.h similarity index 100% rename from platform/platform.h rename to common/platform/platform.h diff --git a/platform/system.c b/common/platform/system.c similarity index 98% rename from platform/system.c rename to common/platform/system.c index 3916f58..3baf5c1 100644 --- a/platform/system.c +++ b/common/platform/system.c @@ -178,6 +178,6 @@ static void system_save_sysfile(const wchar_t *sys_file) { CloseHandle(h_sysfile); if (sysfile_bytes_written != 0x6000) { - dprintf("System: Only 0x%04X bytes written out of 0x6000!\n", sysfile_bytes_written); + dprintf("System: Only 0x%04lX bytes written out of 0x6000!\n", sysfile_bytes_written); } } diff --git a/platform/system.h b/common/platform/system.h similarity index 100% rename from platform/system.h rename to common/platform/system.h diff --git a/platform/vfs.c b/common/platform/vfs.c similarity index 100% rename from platform/vfs.c rename to common/platform/vfs.c diff --git a/platform/vfs.h b/common/platform/vfs.h similarity index 100% rename from platform/vfs.h rename to common/platform/vfs.h diff --git a/unityhook/config.c b/common/unityhook/config.c similarity index 100% rename from unityhook/config.c rename to common/unityhook/config.c diff --git a/unityhook/config.h b/common/unityhook/config.h similarity index 94% rename from unityhook/config.h rename to common/unityhook/config.h index 6fca14a..6857c4b 100644 --- a/unityhook/config.h +++ b/common/unityhook/config.h @@ -1,12 +1,12 @@ -#pragma once - -#include - -#include - -struct unity_config { - bool enable; - wchar_t target_assembly[MAX_PATH]; -}; - -void unity_config_load(struct unity_config *cfg, const wchar_t *filename); +#pragma once + +#include + +#include + +struct unity_config { + bool enable; + wchar_t target_assembly[MAX_PATH]; +}; + +void unity_config_load(struct unity_config *cfg, const wchar_t *filename); diff --git a/unityhook/doorstop.c b/common/unityhook/doorstop.c similarity index 100% rename from unityhook/doorstop.c rename to common/unityhook/doorstop.c diff --git a/unityhook/doorstop.h b/common/unityhook/doorstop.h similarity index 83% rename from unityhook/doorstop.h rename to common/unityhook/doorstop.h index 8cc961e..2a44f33 100644 --- a/unityhook/doorstop.h +++ b/common/unityhook/doorstop.h @@ -1,5 +1,5 @@ -#pragma once - -#include "config.h" - +#pragma once + +#include "config.h" + void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module); \ No newline at end of file diff --git a/unityhook/hook.c b/common/unityhook/hook.c similarity index 100% rename from unityhook/hook.c rename to common/unityhook/hook.c diff --git a/unityhook/hook.h b/common/unityhook/hook.h similarity index 96% rename from unityhook/hook.h rename to common/unityhook/hook.h index 7be6044..a7c75e1 100644 --- a/unityhook/hook.h +++ b/common/unityhook/hook.h @@ -1,9 +1,9 @@ -#pragma once - -#include - -#include "config.h" - -typedef void (*unity_hook_callback_func)(HMODULE, const wchar_t*); - -void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback); +#pragma once + +#include + +#include "config.h" + +typedef void (*unity_hook_callback_func)(HMODULE, const wchar_t*); + +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self, unity_hook_callback_func callback); diff --git a/unityhook/meson.build b/common/unityhook/meson.build similarity index 95% rename from unityhook/meson.build rename to common/unityhook/meson.build index 50d0488..f541c1e 100644 --- a/unityhook/meson.build +++ b/common/unityhook/meson.build @@ -1,19 +1,19 @@ -unityhook_lib = static_library( - 'unityhook', - include_directories: inc, - implicit_include_directories: false, - dependencies: [ - capnhook.get_variable('hook_dep'), - pathcch_lib - ], - sources: [ - 'mono.h', - 'config.c', - 'config.h', - 'doorstop.c', - 'doorstop.h', - 'hook.c', - 'hook.h', - 'util.h' - ], -) +unityhook_lib = static_library( + 'unityhook', + include_directories: inc, + implicit_include_directories: false, + dependencies: [ + capnhook.get_variable('hook_dep'), + pathcch_lib + ], + sources: [ + 'mono.h', + 'config.c', + 'config.h', + 'doorstop.c', + 'doorstop.h', + 'hook.c', + 'hook.h', + 'util.h' + ], +) diff --git a/unityhook/mono.h b/common/unityhook/mono.h similarity index 97% rename from unityhook/mono.h rename to common/unityhook/mono.h index 7056e75..39fdc01 100644 --- a/unityhook/mono.h +++ b/common/unityhook/mono.h @@ -1,100 +1,100 @@ -// SPDX-License-Identifier: CC0 -// https://github.com/NeighTools/UnityDoorstop -#pragma once - -#include - -// Here we define the pointers to some functions within mono.dll -// Note to C learners: these are not signature definitions, but rather "variable" -// definitions with the function pointer type. - -// Note: we use void* instead of the real intented structs defined in mono API -// This way we don't need to include or define any of Mono's structs, which saves space -// This, obviously, comes with a drawback of not being able to easily access the contents of the structs - -void * (*mono_thread_current)(); -void (*mono_thread_set_main)(void *); - -void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); -void *(*mono_domain_assembly_open)(void *domain, const char *name); -void *(*mono_assembly_get_image)(void *assembly); -void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); - -void *(*mono_method_desc_new)(const char *name, int include_namespace); -void* (*mono_method_desc_search_in_image)(void* desc, void* image); -void *(*mono_method_desc_search_in_class)(void *desc, void *klass); -void (*mono_method_desc_free)(void *desc); -void *(*mono_method_signature)(void *method); -UINT32 (*mono_signature_get_param_count)(void *sig); - -void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name); -void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); -void *(*mono_get_string_class)(); - -char *(*mono_assembly_getrootdir)(); - -// Additional funcs to bootstrap custom MONO -void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir); -void (*mono_config_parse)(const char* filename); -void (*mono_set_assemblies_path)(const char* path); -void *(*mono_object_to_string)(void* obj, void** exc); -char *(*mono_string_to_utf8)(void* s); - -void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly, - const char *name); - -void* (*mono_get_exception_class)(); -void* (*mono_object_get_virtual_method)(void* obj_raw, void* method); - -void* (*mono_jit_parse_options)(int argc, const char** argv); - -typedef enum { - MONO_DEBUG_FORMAT_NONE, - MONO_DEBUG_FORMAT_MONO, - /* Deprecated, the mdb debugger is not longer supported. */ - MONO_DEBUG_FORMAT_DEBUGGER -} MonoDebugFormat; - -void* (*mono_debug_init)(MonoDebugFormat format); -void* (*mono_debug_domain_create)(void* domain); - -/** -* \brief Loads Mono C API function pointers so that the above definitions can be called. -* \param mono_lib Mono.dll module. -*/ -void load_mono_functions(HMODULE mono_lib) { - // Enjoy the fact that C allows such sloppy casting - // In C++ you would have to cast to the precise function pointer type -#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name) - - // Find and assign all our functions that we are going to use - GET_MONO_PROC(mono_domain_assembly_open); - GET_MONO_PROC(mono_assembly_get_image); - GET_MONO_PROC(mono_runtime_invoke); - GET_MONO_PROC(mono_jit_init_version); - GET_MONO_PROC(mono_method_desc_new); - GET_MONO_PROC(mono_method_desc_search_in_class); - GET_MONO_PROC(mono_method_desc_search_in_image); - GET_MONO_PROC(mono_method_desc_free); - GET_MONO_PROC(mono_method_signature); - GET_MONO_PROC(mono_signature_get_param_count); - GET_MONO_PROC(mono_array_new); - GET_MONO_PROC(mono_get_string_class); - GET_MONO_PROC(mono_assembly_getrootdir); - GET_MONO_PROC(mono_thread_current); - GET_MONO_PROC(mono_thread_set_main); - GET_MONO_PROC(mono_domain_set_config); - GET_MONO_PROC(mono_set_dirs); - GET_MONO_PROC(mono_config_parse); - GET_MONO_PROC(mono_set_assemblies_path); - GET_MONO_PROC(mono_object_to_string); - GET_MONO_PROC(mono_string_to_utf8); - GET_MONO_PROC(mono_image_open_from_data_with_name); - GET_MONO_PROC(mono_get_exception_class); - GET_MONO_PROC(mono_object_get_virtual_method); - GET_MONO_PROC(mono_jit_parse_options); - GET_MONO_PROC(mono_debug_init); - GET_MONO_PROC(mono_debug_domain_create); - -#undef GET_MONO_PROC +// SPDX-License-Identifier: CC0 +// https://github.com/NeighTools/UnityDoorstop +#pragma once + +#include + +// Here we define the pointers to some functions within mono.dll +// Note to C learners: these are not signature definitions, but rather "variable" +// definitions with the function pointer type. + +// Note: we use void* instead of the real intented structs defined in mono API +// This way we don't need to include or define any of Mono's structs, which saves space +// This, obviously, comes with a drawback of not being able to easily access the contents of the structs + +void * (*mono_thread_current)(); +void (*mono_thread_set_main)(void *); + +void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version); +void *(*mono_domain_assembly_open)(void *domain, const char *name); +void *(*mono_assembly_get_image)(void *assembly); +void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc); + +void *(*mono_method_desc_new)(const char *name, int include_namespace); +void* (*mono_method_desc_search_in_image)(void* desc, void* image); +void *(*mono_method_desc_search_in_class)(void *desc, void *klass); +void (*mono_method_desc_free)(void *desc); +void *(*mono_method_signature)(void *method); +UINT32 (*mono_signature_get_param_count)(void *sig); + +void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name); +void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n); +void *(*mono_get_string_class)(); + +char *(*mono_assembly_getrootdir)(); + +// Additional funcs to bootstrap custom MONO +void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir); +void (*mono_config_parse)(const char* filename); +void (*mono_set_assemblies_path)(const char* path); +void *(*mono_object_to_string)(void* obj, void** exc); +char *(*mono_string_to_utf8)(void* s); + +void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly, + const char *name); + +void* (*mono_get_exception_class)(); +void* (*mono_object_get_virtual_method)(void* obj_raw, void* method); + +void* (*mono_jit_parse_options)(int argc, const char** argv); + +typedef enum { + MONO_DEBUG_FORMAT_NONE, + MONO_DEBUG_FORMAT_MONO, + /* Deprecated, the mdb debugger is not longer supported. */ + MONO_DEBUG_FORMAT_DEBUGGER +} MonoDebugFormat; + +void* (*mono_debug_init)(MonoDebugFormat format); +void* (*mono_debug_domain_create)(void* domain); + +/** +* \brief Loads Mono C API function pointers so that the above definitions can be called. +* \param mono_lib Mono.dll module. +*/ +void load_mono_functions(HMODULE mono_lib) { + // Enjoy the fact that C allows such sloppy casting + // In C++ you would have to cast to the precise function pointer type +#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name) + + // Find and assign all our functions that we are going to use + GET_MONO_PROC(mono_domain_assembly_open); + GET_MONO_PROC(mono_assembly_get_image); + GET_MONO_PROC(mono_runtime_invoke); + GET_MONO_PROC(mono_jit_init_version); + GET_MONO_PROC(mono_method_desc_new); + GET_MONO_PROC(mono_method_desc_search_in_class); + GET_MONO_PROC(mono_method_desc_search_in_image); + GET_MONO_PROC(mono_method_desc_free); + GET_MONO_PROC(mono_method_signature); + GET_MONO_PROC(mono_signature_get_param_count); + GET_MONO_PROC(mono_array_new); + GET_MONO_PROC(mono_get_string_class); + GET_MONO_PROC(mono_assembly_getrootdir); + GET_MONO_PROC(mono_thread_current); + GET_MONO_PROC(mono_thread_set_main); + GET_MONO_PROC(mono_domain_set_config); + GET_MONO_PROC(mono_set_dirs); + GET_MONO_PROC(mono_config_parse); + GET_MONO_PROC(mono_set_assemblies_path); + GET_MONO_PROC(mono_object_to_string); + GET_MONO_PROC(mono_string_to_utf8); + GET_MONO_PROC(mono_image_open_from_data_with_name); + GET_MONO_PROC(mono_get_exception_class); + GET_MONO_PROC(mono_object_get_virtual_method); + GET_MONO_PROC(mono_jit_parse_options); + GET_MONO_PROC(mono_debug_init); + GET_MONO_PROC(mono_debug_domain_create); + +#undef GET_MONO_PROC } \ No newline at end of file diff --git a/unityhook/util.h b/common/unityhook/util.h similarity index 96% rename from unityhook/util.h rename to common/unityhook/util.h index 41def7b..9ad0a80 100644 --- a/unityhook/util.h +++ b/common/unityhook/util.h @@ -1,20 +1,20 @@ -#pragma once - -#include - -wchar_t *widen(const char *str) { - const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - wchar_t *result = malloc(reqsz * sizeof(wchar_t)); - - MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz); - return result; -} - -char *narrow(const wchar_t *str) { - const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); - char *result = malloc(reqsz * sizeof(char)); - - WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL); - return result; -} - +#pragma once + +#include + +wchar_t *widen(const char *str) { + const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + wchar_t *result = malloc(reqsz * sizeof(wchar_t)); + + MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz); + return result; +} + +char *narrow(const wchar_t *str) { + const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + char *result = malloc(reqsz * sizeof(char)); + + WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL); + return result; +} + diff --git a/util/async.c b/common/util/async.c similarity index 100% rename from util/async.c rename to common/util/async.c diff --git a/util/async.h b/common/util/async.h similarity index 100% rename from util/async.h rename to common/util/async.h diff --git a/util/crc.c b/common/util/crc.c similarity index 100% rename from util/crc.c rename to common/util/crc.c diff --git a/util/crc.h b/common/util/crc.h similarity index 100% rename from util/crc.h rename to common/util/crc.h diff --git a/util/dll-bind.c b/common/util/dll-bind.c similarity index 100% rename from util/dll-bind.c rename to common/util/dll-bind.c diff --git a/util/dll-bind.h b/common/util/dll-bind.h similarity index 100% rename from util/dll-bind.h rename to common/util/dll-bind.h diff --git a/util/dprintf.c b/common/util/dprintf.c similarity index 100% rename from util/dprintf.c rename to common/util/dprintf.c diff --git a/util/dprintf.h b/common/util/dprintf.h similarity index 100% rename from util/dprintf.h rename to common/util/dprintf.h diff --git a/util/dump.c b/common/util/dump.c similarity index 100% rename from util/dump.c rename to common/util/dump.c diff --git a/util/dump.h b/common/util/dump.h similarity index 100% rename from util/dump.h rename to common/util/dump.h diff --git a/util/env.c b/common/util/env.c similarity index 100% rename from util/env.c rename to common/util/env.c diff --git a/util/env.h b/common/util/env.h similarity index 100% rename from util/env.h rename to common/util/env.h diff --git a/util/get_function_ordinal.c b/common/util/get_function_ordinal.c similarity index 100% rename from util/get_function_ordinal.c rename to common/util/get_function_ordinal.c diff --git a/util/get_function_ordinal.h b/common/util/get_function_ordinal.h similarity index 100% rename from util/get_function_ordinal.h rename to common/util/get_function_ordinal.h diff --git a/util/lib.c b/common/util/lib.c similarity index 100% rename from util/lib.c rename to common/util/lib.c diff --git a/util/lib.h b/common/util/lib.h similarity index 100% rename from util/lib.h rename to common/util/lib.h diff --git a/util/meson.build b/common/util/meson.build similarity index 100% rename from util/meson.build rename to common/util/meson.build diff --git a/util/slurp.c b/common/util/slurp.c similarity index 100% rename from util/slurp.c rename to common/util/slurp.c diff --git a/util/slurp.h b/common/util/slurp.h similarity index 100% rename from util/slurp.h rename to common/util/slurp.h diff --git a/util/str.c b/common/util/str.c similarity index 100% rename from util/str.c rename to common/util/str.c diff --git a/util/str.h b/common/util/str.h similarity index 100% rename from util/str.h rename to common/util/str.h diff --git a/dist/fgo/launch.bat b/dist/fgo/launch.bat index 3be4f8a..1b76197 100644 --- a/dist/fgo/launch.bat +++ b/dist/fgo/launch.bat @@ -1,6 +1,6 @@ @echo off -cd /d %~dp0 +pushd %~dp0 inject -d -k fgohook.dll ago.exe diff --git a/carolhook/carol-dll.c b/games/carolhook/carol-dll.c similarity index 100% rename from carolhook/carol-dll.c rename to games/carolhook/carol-dll.c diff --git a/carolhook/carol-dll.h b/games/carolhook/carol-dll.h similarity index 100% rename from carolhook/carol-dll.h rename to games/carolhook/carol-dll.h diff --git a/carolhook/carolhook.def b/games/carolhook/carolhook.def similarity index 100% rename from carolhook/carolhook.def rename to games/carolhook/carolhook.def diff --git a/carolhook/config.c b/games/carolhook/config.c similarity index 100% rename from carolhook/config.c rename to games/carolhook/config.c diff --git a/carolhook/config.h b/games/carolhook/config.h similarity index 100% rename from carolhook/config.h rename to games/carolhook/config.h diff --git a/carolhook/controlbd.c b/games/carolhook/controlbd.c similarity index 100% rename from carolhook/controlbd.c rename to games/carolhook/controlbd.c diff --git a/carolhook/controlbd.h b/games/carolhook/controlbd.h similarity index 100% rename from carolhook/controlbd.h rename to games/carolhook/controlbd.h diff --git a/carolhook/dllmain.c b/games/carolhook/dllmain.c similarity index 100% rename from carolhook/dllmain.c rename to games/carolhook/dllmain.c diff --git a/carolhook/jvs.c b/games/carolhook/jvs.c similarity index 100% rename from carolhook/jvs.c rename to games/carolhook/jvs.c diff --git a/carolhook/jvs.h b/games/carolhook/jvs.h similarity index 100% rename from carolhook/jvs.h rename to games/carolhook/jvs.h diff --git a/carolhook/ledbd.c b/games/carolhook/ledbd.c similarity index 100% rename from carolhook/ledbd.c rename to games/carolhook/ledbd.c diff --git a/carolhook/ledbd.h b/games/carolhook/ledbd.h similarity index 100% rename from carolhook/ledbd.h rename to games/carolhook/ledbd.h diff --git a/carolhook/meson.build b/games/carolhook/meson.build similarity index 100% rename from carolhook/meson.build rename to games/carolhook/meson.build diff --git a/carolhook/touch.c b/games/carolhook/touch.c similarity index 100% rename from carolhook/touch.c rename to games/carolhook/touch.c diff --git a/carolhook/touch.h b/games/carolhook/touch.h similarity index 100% rename from carolhook/touch.h rename to games/carolhook/touch.h diff --git a/carolio/carolio.c b/games/carolio/carolio.c similarity index 100% rename from carolio/carolio.c rename to games/carolio/carolio.c diff --git a/carolio/carolio.h b/games/carolio/carolio.h similarity index 100% rename from carolio/carolio.h rename to games/carolio/carolio.h diff --git a/carolio/config.c b/games/carolio/config.c similarity index 100% rename from carolio/config.c rename to games/carolio/config.c diff --git a/carolio/config.h b/games/carolio/config.h similarity index 100% rename from carolio/config.h rename to games/carolio/config.h diff --git a/carolio/meson.build b/games/carolio/meson.build similarity index 100% rename from carolio/meson.build rename to games/carolio/meson.build diff --git a/chunihook/chuni-dll.c b/games/chunihook/chuni-dll.c similarity index 100% rename from chunihook/chuni-dll.c rename to games/chunihook/chuni-dll.c diff --git a/chunihook/chuni-dll.h b/games/chunihook/chuni-dll.h similarity index 100% rename from chunihook/chuni-dll.h rename to games/chunihook/chuni-dll.h diff --git a/chunihook/chunihook.def b/games/chunihook/chunihook.def similarity index 100% rename from chunihook/chunihook.def rename to games/chunihook/chunihook.def diff --git a/chunihook/config.c b/games/chunihook/config.c similarity index 100% rename from chunihook/config.c rename to games/chunihook/config.c diff --git a/chunihook/config.h b/games/chunihook/config.h similarity index 100% rename from chunihook/config.h rename to games/chunihook/config.h diff --git a/chunihook/dllmain.c b/games/chunihook/dllmain.c similarity index 100% rename from chunihook/dllmain.c rename to games/chunihook/dllmain.c diff --git a/chunihook/jvs.c b/games/chunihook/jvs.c similarity index 100% rename from chunihook/jvs.c rename to games/chunihook/jvs.c diff --git a/chunihook/jvs.h b/games/chunihook/jvs.h similarity index 100% rename from chunihook/jvs.h rename to games/chunihook/jvs.h diff --git a/chunihook/meson.build b/games/chunihook/meson.build similarity index 100% rename from chunihook/meson.build rename to games/chunihook/meson.build diff --git a/chunihook/slider.c b/games/chunihook/slider.c similarity index 100% rename from chunihook/slider.c rename to games/chunihook/slider.c diff --git a/chunihook/slider.h b/games/chunihook/slider.h similarity index 100% rename from chunihook/slider.h rename to games/chunihook/slider.h diff --git a/chuniio/chu2to3.c b/games/chuniio/chu2to3.c similarity index 100% rename from chuniio/chu2to3.c rename to games/chuniio/chu2to3.c diff --git a/chuniio/chu2to3.h b/games/chuniio/chu2to3.h similarity index 100% rename from chuniio/chu2to3.h rename to games/chuniio/chu2to3.h diff --git a/chuniio/chuniio.c b/games/chuniio/chuniio.c similarity index 100% rename from chuniio/chuniio.c rename to games/chuniio/chuniio.c diff --git a/chuniio/chuniio.h b/games/chuniio/chuniio.h similarity index 100% rename from chuniio/chuniio.h rename to games/chuniio/chuniio.h diff --git a/chuniio/config.c b/games/chuniio/config.c similarity index 100% rename from chuniio/config.c rename to games/chuniio/config.c diff --git a/chuniio/config.h b/games/chuniio/config.h similarity index 100% rename from chuniio/config.h rename to games/chuniio/config.h diff --git a/chuniio/leddata.h b/games/chuniio/leddata.h similarity index 100% rename from chuniio/leddata.h rename to games/chuniio/leddata.h diff --git a/chuniio/ledoutput.c b/games/chuniio/ledoutput.c similarity index 100% rename from chuniio/ledoutput.c rename to games/chuniio/ledoutput.c diff --git a/chuniio/ledoutput.h b/games/chuniio/ledoutput.h similarity index 100% rename from chuniio/ledoutput.h rename to games/chuniio/ledoutput.h diff --git a/chuniio/meson.build b/games/chuniio/meson.build similarity index 100% rename from chuniio/meson.build rename to games/chuniio/meson.build diff --git a/chuniio/pipeimpl.c b/games/chuniio/pipeimpl.c similarity index 100% rename from chuniio/pipeimpl.c rename to games/chuniio/pipeimpl.c diff --git a/chuniio/pipeimpl.h b/games/chuniio/pipeimpl.h similarity index 100% rename from chuniio/pipeimpl.h rename to games/chuniio/pipeimpl.h diff --git a/chuniio/serialimpl.c b/games/chuniio/serialimpl.c similarity index 100% rename from chuniio/serialimpl.c rename to games/chuniio/serialimpl.c diff --git a/chuniio/serialimpl.h b/games/chuniio/serialimpl.h similarity index 100% rename from chuniio/serialimpl.h rename to games/chuniio/serialimpl.h diff --git a/chusanhook/chuni-dll.c b/games/chusanhook/chuni-dll.c similarity index 100% rename from chusanhook/chuni-dll.c rename to games/chusanhook/chuni-dll.c diff --git a/chusanhook/chuni-dll.h b/games/chusanhook/chuni-dll.h similarity index 100% rename from chusanhook/chuni-dll.h rename to games/chusanhook/chuni-dll.h diff --git a/chusanhook/chusanhook.def b/games/chusanhook/chusanhook.def similarity index 100% rename from chusanhook/chusanhook.def rename to games/chusanhook/chusanhook.def diff --git a/chusanhook/config.c b/games/chusanhook/config.c similarity index 100% rename from chusanhook/config.c rename to games/chusanhook/config.c diff --git a/chusanhook/config.h b/games/chusanhook/config.h similarity index 100% rename from chusanhook/config.h rename to games/chusanhook/config.h diff --git a/chusanhook/dllmain.c b/games/chusanhook/dllmain.c similarity index 100% rename from chusanhook/dllmain.c rename to games/chusanhook/dllmain.c diff --git a/chusanhook/io4.c b/games/chusanhook/io4.c similarity index 100% rename from chusanhook/io4.c rename to games/chusanhook/io4.c diff --git a/chusanhook/io4.h b/games/chusanhook/io4.h similarity index 100% rename from chusanhook/io4.h rename to games/chusanhook/io4.h diff --git a/chusanhook/meson.build b/games/chusanhook/meson.build similarity index 100% rename from chusanhook/meson.build rename to games/chusanhook/meson.build diff --git a/chusanhook/slider.c b/games/chusanhook/slider.c similarity index 100% rename from chusanhook/slider.c rename to games/chusanhook/slider.c diff --git a/chusanhook/slider.h b/games/chusanhook/slider.h similarity index 100% rename from chusanhook/slider.h rename to games/chusanhook/slider.h diff --git a/cmhook/cm-dll.c b/games/cmhook/cm-dll.c similarity index 100% rename from cmhook/cm-dll.c rename to games/cmhook/cm-dll.c diff --git a/cmhook/cm-dll.h b/games/cmhook/cm-dll.h similarity index 100% rename from cmhook/cm-dll.h rename to games/cmhook/cm-dll.h diff --git a/cmhook/cmhook.def b/games/cmhook/cmhook.def similarity index 100% rename from cmhook/cmhook.def rename to games/cmhook/cmhook.def diff --git a/cmhook/config.c b/games/cmhook/config.c similarity index 100% rename from cmhook/config.c rename to games/cmhook/config.c diff --git a/cmhook/config.h b/games/cmhook/config.h similarity index 100% rename from cmhook/config.h rename to games/cmhook/config.h diff --git a/cmhook/dllmain.c b/games/cmhook/dllmain.c similarity index 100% rename from cmhook/dllmain.c rename to games/cmhook/dllmain.c diff --git a/cmhook/io4.c b/games/cmhook/io4.c similarity index 100% rename from cmhook/io4.c rename to games/cmhook/io4.c diff --git a/cmhook/io4.h b/games/cmhook/io4.h similarity index 100% rename from cmhook/io4.h rename to games/cmhook/io4.h diff --git a/cmhook/meson.build b/games/cmhook/meson.build similarity index 100% rename from cmhook/meson.build rename to games/cmhook/meson.build diff --git a/cmio/cmio.c b/games/cmio/cmio.c similarity index 100% rename from cmio/cmio.c rename to games/cmio/cmio.c diff --git a/cmio/cmio.h b/games/cmio/cmio.h similarity index 100% rename from cmio/cmio.h rename to games/cmio/cmio.h diff --git a/cmio/config.c b/games/cmio/config.c similarity index 100% rename from cmio/config.c rename to games/cmio/config.c diff --git a/cmio/config.h b/games/cmio/config.h similarity index 100% rename from cmio/config.h rename to games/cmio/config.h diff --git a/cmio/meson.build b/games/cmio/meson.build similarity index 100% rename from cmio/meson.build rename to games/cmio/meson.build diff --git a/cxbhook/config.c b/games/cxbhook/config.c similarity index 100% rename from cxbhook/config.c rename to games/cxbhook/config.c diff --git a/cxbhook/config.h b/games/cxbhook/config.h similarity index 100% rename from cxbhook/config.h rename to games/cxbhook/config.h diff --git a/cxbhook/cxb-dll.c b/games/cxbhook/cxb-dll.c similarity index 100% rename from cxbhook/cxb-dll.c rename to games/cxbhook/cxb-dll.c diff --git a/cxbhook/cxb-dll.h b/games/cxbhook/cxb-dll.h similarity index 100% rename from cxbhook/cxb-dll.h rename to games/cxbhook/cxb-dll.h diff --git a/cxbhook/cxbhook.def b/games/cxbhook/cxbhook.def similarity index 100% rename from cxbhook/cxbhook.def rename to games/cxbhook/cxbhook.def diff --git a/cxbhook/dllmain.c b/games/cxbhook/dllmain.c similarity index 100% rename from cxbhook/dllmain.c rename to games/cxbhook/dllmain.c diff --git a/cxbhook/led.c b/games/cxbhook/led.c similarity index 100% rename from cxbhook/led.c rename to games/cxbhook/led.c diff --git a/cxbhook/led.h b/games/cxbhook/led.h similarity index 100% rename from cxbhook/led.h rename to games/cxbhook/led.h diff --git a/cxbhook/meson.build b/games/cxbhook/meson.build similarity index 100% rename from cxbhook/meson.build rename to games/cxbhook/meson.build diff --git a/cxbhook/revio.c b/games/cxbhook/revio.c similarity index 100% rename from cxbhook/revio.c rename to games/cxbhook/revio.c diff --git a/cxbhook/revio.h b/games/cxbhook/revio.h similarity index 100% rename from cxbhook/revio.h rename to games/cxbhook/revio.h diff --git a/cxbio/config.c b/games/cxbio/config.c similarity index 100% rename from cxbio/config.c rename to games/cxbio/config.c diff --git a/cxbio/config.h b/games/cxbio/config.h similarity index 100% rename from cxbio/config.h rename to games/cxbio/config.h diff --git a/cxbio/cxbio.c b/games/cxbio/cxbio.c similarity index 100% rename from cxbio/cxbio.c rename to games/cxbio/cxbio.c diff --git a/cxbio/cxbio.h b/games/cxbio/cxbio.h similarity index 100% rename from cxbio/cxbio.h rename to games/cxbio/cxbio.h diff --git a/cxbio/meson.build b/games/cxbio/meson.build similarity index 100% rename from cxbio/meson.build rename to games/cxbio/meson.build diff --git a/divahook/config.c b/games/divahook/config.c similarity index 100% rename from divahook/config.c rename to games/divahook/config.c diff --git a/divahook/config.h b/games/divahook/config.h similarity index 100% rename from divahook/config.h rename to games/divahook/config.h diff --git a/divahook/diva-dll.c b/games/divahook/diva-dll.c similarity index 100% rename from divahook/diva-dll.c rename to games/divahook/diva-dll.c diff --git a/divahook/diva-dll.h b/games/divahook/diva-dll.h similarity index 100% rename from divahook/diva-dll.h rename to games/divahook/diva-dll.h diff --git a/divahook/divahook.def b/games/divahook/divahook.def similarity index 100% rename from divahook/divahook.def rename to games/divahook/divahook.def diff --git a/divahook/dllmain.c b/games/divahook/dllmain.c similarity index 100% rename from divahook/dllmain.c rename to games/divahook/dllmain.c diff --git a/divahook/jvs.c b/games/divahook/jvs.c similarity index 100% rename from divahook/jvs.c rename to games/divahook/jvs.c diff --git a/divahook/jvs.h b/games/divahook/jvs.h similarity index 100% rename from divahook/jvs.h rename to games/divahook/jvs.h diff --git a/divahook/meson.build b/games/divahook/meson.build similarity index 100% rename from divahook/meson.build rename to games/divahook/meson.build diff --git a/divahook/slider.c b/games/divahook/slider.c similarity index 100% rename from divahook/slider.c rename to games/divahook/slider.c diff --git a/divahook/slider.h b/games/divahook/slider.h similarity index 100% rename from divahook/slider.h rename to games/divahook/slider.h diff --git a/divaio/config.c b/games/divaio/config.c similarity index 100% rename from divaio/config.c rename to games/divaio/config.c diff --git a/divaio/config.h b/games/divaio/config.h similarity index 100% rename from divaio/config.h rename to games/divaio/config.h diff --git a/divaio/divaio.c b/games/divaio/divaio.c similarity index 100% rename from divaio/divaio.c rename to games/divaio/divaio.c diff --git a/divaio/divaio.h b/games/divaio/divaio.h similarity index 100% rename from divaio/divaio.h rename to games/divaio/divaio.h diff --git a/divaio/meson.build b/games/divaio/meson.build similarity index 100% rename from divaio/meson.build rename to games/divaio/meson.build diff --git a/fgohook/config.c b/games/fgohook/config.c similarity index 100% rename from fgohook/config.c rename to games/fgohook/config.c diff --git a/fgohook/config.h b/games/fgohook/config.h similarity index 100% rename from fgohook/config.h rename to games/fgohook/config.h diff --git a/fgohook/deck.c b/games/fgohook/deck.c similarity index 100% rename from fgohook/deck.c rename to games/fgohook/deck.c diff --git a/fgohook/deck.h b/games/fgohook/deck.h similarity index 100% rename from fgohook/deck.h rename to games/fgohook/deck.h diff --git a/fgohook/dllmain.c b/games/fgohook/dllmain.c similarity index 100% rename from fgohook/dllmain.c rename to games/fgohook/dllmain.c diff --git a/fgohook/fgo-dll.c b/games/fgohook/fgo-dll.c similarity index 100% rename from fgohook/fgo-dll.c rename to games/fgohook/fgo-dll.c diff --git a/fgohook/fgo-dll.h b/games/fgohook/fgo-dll.h similarity index 100% rename from fgohook/fgo-dll.h rename to games/fgohook/fgo-dll.h diff --git a/fgohook/fgohook.def b/games/fgohook/fgohook.def similarity index 100% rename from fgohook/fgohook.def rename to games/fgohook/fgohook.def diff --git a/fgohook/ftdi.c b/games/fgohook/ftdi.c similarity index 100% rename from fgohook/ftdi.c rename to games/fgohook/ftdi.c diff --git a/fgohook/ftdi.h b/games/fgohook/ftdi.h similarity index 100% rename from fgohook/ftdi.h rename to games/fgohook/ftdi.h diff --git a/fgohook/io4.c b/games/fgohook/io4.c similarity index 100% rename from fgohook/io4.c rename to games/fgohook/io4.c diff --git a/fgohook/io4.h b/games/fgohook/io4.h similarity index 100% rename from fgohook/io4.h rename to games/fgohook/io4.h diff --git a/fgohook/meson.build b/games/fgohook/meson.build similarity index 100% rename from fgohook/meson.build rename to games/fgohook/meson.build diff --git a/fgoio/backend.h b/games/fgoio/backend.h similarity index 100% rename from fgoio/backend.h rename to games/fgoio/backend.h diff --git a/fgoio/config.c b/games/fgoio/config.c similarity index 100% rename from fgoio/config.c rename to games/fgoio/config.c diff --git a/fgoio/config.h b/games/fgoio/config.h similarity index 100% rename from fgoio/config.h rename to games/fgoio/config.h diff --git a/fgoio/fgoio.c b/games/fgoio/fgoio.c similarity index 100% rename from fgoio/fgoio.c rename to games/fgoio/fgoio.c diff --git a/fgoio/fgoio.h b/games/fgoio/fgoio.h similarity index 100% rename from fgoio/fgoio.h rename to games/fgoio/fgoio.h diff --git a/fgoio/keyboard.c b/games/fgoio/keyboard.c similarity index 100% rename from fgoio/keyboard.c rename to games/fgoio/keyboard.c diff --git a/fgoio/keyboard.h b/games/fgoio/keyboard.h similarity index 100% rename from fgoio/keyboard.h rename to games/fgoio/keyboard.h diff --git a/fgoio/meson.build b/games/fgoio/meson.build similarity index 100% rename from fgoio/meson.build rename to games/fgoio/meson.build diff --git a/fgoio/xi.c b/games/fgoio/xi.c similarity index 100% rename from fgoio/xi.c rename to games/fgoio/xi.c diff --git a/fgoio/xi.h b/games/fgoio/xi.h similarity index 100% rename from fgoio/xi.h rename to games/fgoio/xi.h diff --git a/idachook/config.c b/games/idachook/config.c similarity index 100% rename from idachook/config.c rename to games/idachook/config.c diff --git a/idachook/config.h b/games/idachook/config.h similarity index 100% rename from idachook/config.h rename to games/idachook/config.h diff --git a/idachook/dllmain.c b/games/idachook/dllmain.c similarity index 100% rename from idachook/dllmain.c rename to games/idachook/dllmain.c diff --git a/idachook/ffb.c b/games/idachook/ffb.c similarity index 100% rename from idachook/ffb.c rename to games/idachook/ffb.c diff --git a/idachook/ffb.h b/games/idachook/ffb.h similarity index 100% rename from idachook/ffb.h rename to games/idachook/ffb.h diff --git a/idachook/idac-dll.c b/games/idachook/idac-dll.c similarity index 100% rename from idachook/idac-dll.c rename to games/idachook/idac-dll.c diff --git a/idachook/idac-dll.h b/games/idachook/idac-dll.h similarity index 100% rename from idachook/idac-dll.h rename to games/idachook/idac-dll.h diff --git a/idachook/idachook.def b/games/idachook/idachook.def similarity index 100% rename from idachook/idachook.def rename to games/idachook/idachook.def diff --git a/idachook/indrun.c b/games/idachook/indrun.c similarity index 100% rename from idachook/indrun.c rename to games/idachook/indrun.c diff --git a/idachook/indrun.h b/games/idachook/indrun.h similarity index 100% rename from idachook/indrun.h rename to games/idachook/indrun.h diff --git a/idachook/io4.c b/games/idachook/io4.c similarity index 100% rename from idachook/io4.c rename to games/idachook/io4.c diff --git a/idachook/io4.h b/games/idachook/io4.h similarity index 100% rename from idachook/io4.h rename to games/idachook/io4.h diff --git a/idachook/meson.build b/games/idachook/meson.build similarity index 100% rename from idachook/meson.build rename to games/idachook/meson.build diff --git a/idachook/zinput.c b/games/idachook/zinput.c similarity index 100% rename from idachook/zinput.c rename to games/idachook/zinput.c diff --git a/idachook/zinput.h b/games/idachook/zinput.h similarity index 100% rename from idachook/zinput.h rename to games/idachook/zinput.h diff --git a/idacio/backend.h b/games/idacio/backend.h similarity index 100% rename from idacio/backend.h rename to games/idacio/backend.h diff --git a/idacio/config.c b/games/idacio/config.c similarity index 100% rename from idacio/config.c rename to games/idacio/config.c diff --git a/idacio/config.h b/games/idacio/config.h similarity index 100% rename from idacio/config.h rename to games/idacio/config.h diff --git a/idacio/di-dev.c b/games/idacio/di-dev.c similarity index 100% rename from idacio/di-dev.c rename to games/idacio/di-dev.c diff --git a/idacio/di-dev.h b/games/idacio/di-dev.h similarity index 100% rename from idacio/di-dev.h rename to games/idacio/di-dev.h diff --git a/idacio/di.c b/games/idacio/di.c similarity index 100% rename from idacio/di.c rename to games/idacio/di.c diff --git a/idacio/di.h b/games/idacio/di.h similarity index 100% rename from idacio/di.h rename to games/idacio/di.h diff --git a/idacio/dllmain.c b/games/idacio/dllmain.c similarity index 100% rename from idacio/dllmain.c rename to games/idacio/dllmain.c diff --git a/idacio/idacio.def b/games/idacio/idacio.def similarity index 100% rename from idacio/idacio.def rename to games/idacio/idacio.def diff --git a/idacio/idacio.h b/games/idacio/idacio.h similarity index 100% rename from idacio/idacio.h rename to games/idacio/idacio.h diff --git a/idacio/meson.build b/games/idacio/meson.build similarity index 100% rename from idacio/meson.build rename to games/idacio/meson.build diff --git a/idacio/shifter.c b/games/idacio/shifter.c similarity index 100% rename from idacio/shifter.c rename to games/idacio/shifter.c diff --git a/idacio/shifter.h b/games/idacio/shifter.h similarity index 100% rename from idacio/shifter.h rename to games/idacio/shifter.h diff --git a/idacio/wnd.c b/games/idacio/wnd.c similarity index 100% rename from idacio/wnd.c rename to games/idacio/wnd.c diff --git a/idacio/wnd.h b/games/idacio/wnd.h similarity index 100% rename from idacio/wnd.h rename to games/idacio/wnd.h diff --git a/idacio/xi.c b/games/idacio/xi.c similarity index 100% rename from idacio/xi.c rename to games/idacio/xi.c diff --git a/idacio/xi.h b/games/idacio/xi.h similarity index 100% rename from idacio/xi.h rename to games/idacio/xi.h diff --git a/idzhook/config.c b/games/idzhook/config.c similarity index 100% rename from idzhook/config.c rename to games/idzhook/config.c diff --git a/idzhook/config.h b/games/idzhook/config.h similarity index 100% rename from idzhook/config.h rename to games/idzhook/config.h diff --git a/idzhook/dllmain.c b/games/idzhook/dllmain.c similarity index 100% rename from idzhook/dllmain.c rename to games/idzhook/dllmain.c diff --git a/idzhook/ffb.c b/games/idzhook/ffb.c similarity index 100% rename from idzhook/ffb.c rename to games/idzhook/ffb.c diff --git a/idzhook/ffb.h b/games/idzhook/ffb.h similarity index 100% rename from idzhook/ffb.h rename to games/idzhook/ffb.h diff --git a/idzhook/idz-dll.c b/games/idzhook/idz-dll.c similarity index 100% rename from idzhook/idz-dll.c rename to games/idzhook/idz-dll.c diff --git a/idzhook/idz-dll.h b/games/idzhook/idz-dll.h similarity index 100% rename from idzhook/idz-dll.h rename to games/idzhook/idz-dll.h diff --git a/idzhook/idzhook.def b/games/idzhook/idzhook.def similarity index 100% rename from idzhook/idzhook.def rename to games/idzhook/idzhook.def diff --git a/idzhook/jvs.c b/games/idzhook/jvs.c similarity index 100% rename from idzhook/jvs.c rename to games/idzhook/jvs.c diff --git a/idzhook/jvs.h b/games/idzhook/jvs.h similarity index 100% rename from idzhook/jvs.h rename to games/idzhook/jvs.h diff --git a/idzhook/meson.build b/games/idzhook/meson.build similarity index 100% rename from idzhook/meson.build rename to games/idzhook/meson.build diff --git a/idzhook/zinput.c b/games/idzhook/zinput.c similarity index 100% rename from idzhook/zinput.c rename to games/idzhook/zinput.c diff --git a/idzhook/zinput.h b/games/idzhook/zinput.h similarity index 100% rename from idzhook/zinput.h rename to games/idzhook/zinput.h diff --git a/idzio/backend.h b/games/idzio/backend.h similarity index 100% rename from idzio/backend.h rename to games/idzio/backend.h diff --git a/idzio/config.c b/games/idzio/config.c similarity index 100% rename from idzio/config.c rename to games/idzio/config.c diff --git a/idzio/config.h b/games/idzio/config.h similarity index 100% rename from idzio/config.h rename to games/idzio/config.h diff --git a/idzio/di-dev.c b/games/idzio/di-dev.c similarity index 100% rename from idzio/di-dev.c rename to games/idzio/di-dev.c diff --git a/idzio/di-dev.h b/games/idzio/di-dev.h similarity index 100% rename from idzio/di-dev.h rename to games/idzio/di-dev.h diff --git a/idzio/di.c b/games/idzio/di.c similarity index 100% rename from idzio/di.c rename to games/idzio/di.c diff --git a/idzio/di.h b/games/idzio/di.h similarity index 100% rename from idzio/di.h rename to games/idzio/di.h diff --git a/idzio/dllmain.c b/games/idzio/dllmain.c similarity index 100% rename from idzio/dllmain.c rename to games/idzio/dllmain.c diff --git a/idzio/idzio.def b/games/idzio/idzio.def similarity index 100% rename from idzio/idzio.def rename to games/idzio/idzio.def diff --git a/idzio/idzio.h b/games/idzio/idzio.h similarity index 100% rename from idzio/idzio.h rename to games/idzio/idzio.h diff --git a/idzio/meson.build b/games/idzio/meson.build similarity index 100% rename from idzio/meson.build rename to games/idzio/meson.build diff --git a/idzio/shifter.c b/games/idzio/shifter.c similarity index 100% rename from idzio/shifter.c rename to games/idzio/shifter.c diff --git a/idzio/shifter.h b/games/idzio/shifter.h similarity index 100% rename from idzio/shifter.h rename to games/idzio/shifter.h diff --git a/idzio/wnd.c b/games/idzio/wnd.c similarity index 100% rename from idzio/wnd.c rename to games/idzio/wnd.c diff --git a/idzio/wnd.h b/games/idzio/wnd.h similarity index 100% rename from idzio/wnd.h rename to games/idzio/wnd.h diff --git a/idzio/xi.c b/games/idzio/xi.c similarity index 100% rename from idzio/xi.c rename to games/idzio/xi.c diff --git a/idzio/xi.h b/games/idzio/xi.h similarity index 100% rename from idzio/xi.h rename to games/idzio/xi.h diff --git a/kemonohook/config.c b/games/kemonohook/config.c similarity index 100% rename from kemonohook/config.c rename to games/kemonohook/config.c diff --git a/kemonohook/config.h b/games/kemonohook/config.h similarity index 100% rename from kemonohook/config.h rename to games/kemonohook/config.h diff --git a/kemonohook/dllmain.c b/games/kemonohook/dllmain.c similarity index 100% rename from kemonohook/dllmain.c rename to games/kemonohook/dllmain.c diff --git a/kemonohook/hooks.c b/games/kemonohook/hooks.c similarity index 100% rename from kemonohook/hooks.c rename to games/kemonohook/hooks.c diff --git a/kemonohook/hooks.h b/games/kemonohook/hooks.h similarity index 100% rename from kemonohook/hooks.h rename to games/kemonohook/hooks.h diff --git a/kemonohook/jvs.c b/games/kemonohook/jvs.c similarity index 100% rename from kemonohook/jvs.c rename to games/kemonohook/jvs.c diff --git a/kemonohook/jvs.h b/games/kemonohook/jvs.h similarity index 100% rename from kemonohook/jvs.h rename to games/kemonohook/jvs.h diff --git a/kemonohook/kemono-dll.c b/games/kemonohook/kemono-dll.c similarity index 100% rename from kemonohook/kemono-dll.c rename to games/kemonohook/kemono-dll.c diff --git a/kemonohook/kemono-dll.h b/games/kemonohook/kemono-dll.h similarity index 100% rename from kemonohook/kemono-dll.h rename to games/kemonohook/kemono-dll.h diff --git a/kemonohook/kemonohook.def b/games/kemonohook/kemonohook.def similarity index 100% rename from kemonohook/kemonohook.def rename to games/kemonohook/kemonohook.def diff --git a/kemonohook/meson.build b/games/kemonohook/meson.build similarity index 100% rename from kemonohook/meson.build rename to games/kemonohook/meson.build diff --git a/kemonoio/config.c b/games/kemonoio/config.c similarity index 100% rename from kemonoio/config.c rename to games/kemonoio/config.c diff --git a/kemonoio/config.h b/games/kemonoio/config.h similarity index 100% rename from kemonoio/config.h rename to games/kemonoio/config.h diff --git a/kemonoio/kemonoio.c b/games/kemonoio/kemonoio.c similarity index 100% rename from kemonoio/kemonoio.c rename to games/kemonoio/kemonoio.c diff --git a/kemonoio/kemonoio.h b/games/kemonoio/kemonoio.h similarity index 100% rename from kemonoio/kemonoio.h rename to games/kemonoio/kemonoio.h diff --git a/kemonoio/meson.build b/games/kemonoio/meson.build similarity index 100% rename from kemonoio/meson.build rename to games/kemonoio/meson.build diff --git a/mai2hook/config.c b/games/mai2hook/config.c similarity index 100% rename from mai2hook/config.c rename to games/mai2hook/config.c diff --git a/mai2hook/config.h b/games/mai2hook/config.h similarity index 100% rename from mai2hook/config.h rename to games/mai2hook/config.h diff --git a/mai2hook/dllmain.c b/games/mai2hook/dllmain.c similarity index 100% rename from mai2hook/dllmain.c rename to games/mai2hook/dllmain.c diff --git a/mai2hook/io4.c b/games/mai2hook/io4.c similarity index 100% rename from mai2hook/io4.c rename to games/mai2hook/io4.c diff --git a/mai2hook/io4.h b/games/mai2hook/io4.h similarity index 100% rename from mai2hook/io4.h rename to games/mai2hook/io4.h diff --git a/mai2hook/mai2-dll.c b/games/mai2hook/mai2-dll.c similarity index 100% rename from mai2hook/mai2-dll.c rename to games/mai2hook/mai2-dll.c diff --git a/mai2hook/mai2-dll.h b/games/mai2hook/mai2-dll.h similarity index 100% rename from mai2hook/mai2-dll.h rename to games/mai2hook/mai2-dll.h diff --git a/mai2hook/mai2hook.def b/games/mai2hook/mai2hook.def similarity index 100% rename from mai2hook/mai2hook.def rename to games/mai2hook/mai2hook.def diff --git a/mai2hook/meson.build b/games/mai2hook/meson.build similarity index 100% rename from mai2hook/meson.build rename to games/mai2hook/meson.build diff --git a/mai2hook/touch.c b/games/mai2hook/touch.c similarity index 100% rename from mai2hook/touch.c rename to games/mai2hook/touch.c diff --git a/mai2hook/touch.h b/games/mai2hook/touch.h similarity index 100% rename from mai2hook/touch.h rename to games/mai2hook/touch.h diff --git a/mai2io/config.c b/games/mai2io/config.c similarity index 100% rename from mai2io/config.c rename to games/mai2io/config.c diff --git a/mai2io/config.h b/games/mai2io/config.h similarity index 100% rename from mai2io/config.h rename to games/mai2io/config.h diff --git a/mai2io/mai2io.c b/games/mai2io/mai2io.c similarity index 100% rename from mai2io/mai2io.c rename to games/mai2io/mai2io.c diff --git a/mai2io/mai2io.h b/games/mai2io/mai2io.h similarity index 100% rename from mai2io/mai2io.h rename to games/mai2io/mai2io.h diff --git a/mai2io/meson.build b/games/mai2io/meson.build similarity index 100% rename from mai2io/meson.build rename to games/mai2io/meson.build diff --git a/mercuryhook/config.c b/games/mercuryhook/config.c similarity index 100% rename from mercuryhook/config.c rename to games/mercuryhook/config.c diff --git a/mercuryhook/config.h b/games/mercuryhook/config.h similarity index 100% rename from mercuryhook/config.h rename to games/mercuryhook/config.h diff --git a/mercuryhook/dllmain.c b/games/mercuryhook/dllmain.c similarity index 100% rename from mercuryhook/dllmain.c rename to games/mercuryhook/dllmain.c diff --git a/mercuryhook/elisabeth.c b/games/mercuryhook/elisabeth.c similarity index 100% rename from mercuryhook/elisabeth.c rename to games/mercuryhook/elisabeth.c diff --git a/mercuryhook/elisabeth.h b/games/mercuryhook/elisabeth.h similarity index 100% rename from mercuryhook/elisabeth.h rename to games/mercuryhook/elisabeth.h diff --git a/mercuryhook/io4.c b/games/mercuryhook/io4.c similarity index 100% rename from mercuryhook/io4.c rename to games/mercuryhook/io4.c diff --git a/mercuryhook/io4.h b/games/mercuryhook/io4.h similarity index 100% rename from mercuryhook/io4.h rename to games/mercuryhook/io4.h diff --git a/mercuryhook/mercury-dll.c b/games/mercuryhook/mercury-dll.c similarity index 100% rename from mercuryhook/mercury-dll.c rename to games/mercuryhook/mercury-dll.c diff --git a/mercuryhook/mercury-dll.h b/games/mercuryhook/mercury-dll.h similarity index 100% rename from mercuryhook/mercury-dll.h rename to games/mercuryhook/mercury-dll.h diff --git a/mercuryhook/mercuryhook.def b/games/mercuryhook/mercuryhook.def similarity index 100% rename from mercuryhook/mercuryhook.def rename to games/mercuryhook/mercuryhook.def diff --git a/mercuryhook/meson.build b/games/mercuryhook/meson.build similarity index 100% rename from mercuryhook/meson.build rename to games/mercuryhook/meson.build diff --git a/mercuryhook/touch.c b/games/mercuryhook/touch.c similarity index 100% rename from mercuryhook/touch.c rename to games/mercuryhook/touch.c diff --git a/mercuryhook/touch.h b/games/mercuryhook/touch.h similarity index 100% rename from mercuryhook/touch.h rename to games/mercuryhook/touch.h diff --git a/mercuryio/config.c b/games/mercuryio/config.c similarity index 100% rename from mercuryio/config.c rename to games/mercuryio/config.c diff --git a/mercuryio/config.h b/games/mercuryio/config.h similarity index 100% rename from mercuryio/config.h rename to games/mercuryio/config.h diff --git a/mercuryio/mercuryio.c b/games/mercuryio/mercuryio.c similarity index 100% rename from mercuryio/mercuryio.c rename to games/mercuryio/mercuryio.c diff --git a/mercuryio/mercuryio.def b/games/mercuryio/mercuryio.def similarity index 100% rename from mercuryio/mercuryio.def rename to games/mercuryio/mercuryio.def diff --git a/mercuryio/mercuryio.h b/games/mercuryio/mercuryio.h similarity index 100% rename from mercuryio/mercuryio.h rename to games/mercuryio/mercuryio.h diff --git a/mercuryio/meson.build b/games/mercuryio/meson.build similarity index 100% rename from mercuryio/meson.build rename to games/mercuryio/meson.build diff --git a/mu3hook/config.c b/games/mu3hook/config.c similarity index 100% rename from mu3hook/config.c rename to games/mu3hook/config.c diff --git a/mu3hook/config.h b/games/mu3hook/config.h similarity index 100% rename from mu3hook/config.h rename to games/mu3hook/config.h diff --git a/mu3hook/dllmain.c b/games/mu3hook/dllmain.c similarity index 100% rename from mu3hook/dllmain.c rename to games/mu3hook/dllmain.c diff --git a/mu3hook/io4.c b/games/mu3hook/io4.c similarity index 100% rename from mu3hook/io4.c rename to games/mu3hook/io4.c diff --git a/mu3hook/io4.h b/games/mu3hook/io4.h similarity index 100% rename from mu3hook/io4.h rename to games/mu3hook/io4.h diff --git a/mu3hook/meson.build b/games/mu3hook/meson.build similarity index 100% rename from mu3hook/meson.build rename to games/mu3hook/meson.build diff --git a/mu3hook/mu3-dll.c b/games/mu3hook/mu3-dll.c similarity index 100% rename from mu3hook/mu3-dll.c rename to games/mu3hook/mu3-dll.c diff --git a/mu3hook/mu3-dll.h b/games/mu3hook/mu3-dll.h similarity index 100% rename from mu3hook/mu3-dll.h rename to games/mu3hook/mu3-dll.h diff --git a/mu3hook/mu3hook.def b/games/mu3hook/mu3hook.def similarity index 100% rename from mu3hook/mu3hook.def rename to games/mu3hook/mu3hook.def diff --git a/mu3io/config.c b/games/mu3io/config.c similarity index 100% rename from mu3io/config.c rename to games/mu3io/config.c diff --git a/mu3io/config.h b/games/mu3io/config.h similarity index 100% rename from mu3io/config.h rename to games/mu3io/config.h diff --git a/mu3io/leddata.h b/games/mu3io/leddata.h similarity index 100% rename from mu3io/leddata.h rename to games/mu3io/leddata.h diff --git a/mu3io/ledoutput.c b/games/mu3io/ledoutput.c similarity index 100% rename from mu3io/ledoutput.c rename to games/mu3io/ledoutput.c diff --git a/mu3io/ledoutput.h b/games/mu3io/ledoutput.h similarity index 100% rename from mu3io/ledoutput.h rename to games/mu3io/ledoutput.h diff --git a/mu3io/meson.build b/games/mu3io/meson.build similarity index 100% rename from mu3io/meson.build rename to games/mu3io/meson.build diff --git a/mu3io/mu3io.c b/games/mu3io/mu3io.c similarity index 100% rename from mu3io/mu3io.c rename to games/mu3io/mu3io.c diff --git a/mu3io/mu3io.h b/games/mu3io/mu3io.h similarity index 100% rename from mu3io/mu3io.h rename to games/mu3io/mu3io.h diff --git a/mu3io/pipeimpl.c b/games/mu3io/pipeimpl.c similarity index 100% rename from mu3io/pipeimpl.c rename to games/mu3io/pipeimpl.c diff --git a/mu3io/pipeimpl.h b/games/mu3io/pipeimpl.h similarity index 100% rename from mu3io/pipeimpl.h rename to games/mu3io/pipeimpl.h diff --git a/mu3io/serialimpl.c b/games/mu3io/serialimpl.c similarity index 100% rename from mu3io/serialimpl.c rename to games/mu3io/serialimpl.c diff --git a/mu3io/serialimpl.h b/games/mu3io/serialimpl.h similarity index 100% rename from mu3io/serialimpl.h rename to games/mu3io/serialimpl.h diff --git a/swdchook/config.c b/games/swdchook/config.c similarity index 100% rename from swdchook/config.c rename to games/swdchook/config.c diff --git a/swdchook/config.h b/games/swdchook/config.h similarity index 100% rename from swdchook/config.h rename to games/swdchook/config.h diff --git a/swdchook/dllmain.c b/games/swdchook/dllmain.c similarity index 100% rename from swdchook/dllmain.c rename to games/swdchook/dllmain.c diff --git a/swdchook/ffb.c b/games/swdchook/ffb.c similarity index 100% rename from swdchook/ffb.c rename to games/swdchook/ffb.c diff --git a/swdchook/ffb.h b/games/swdchook/ffb.h similarity index 100% rename from swdchook/ffb.h rename to games/swdchook/ffb.h diff --git a/swdchook/io4.c b/games/swdchook/io4.c similarity index 100% rename from swdchook/io4.c rename to games/swdchook/io4.c diff --git a/swdchook/io4.h b/games/swdchook/io4.h similarity index 100% rename from swdchook/io4.h rename to games/swdchook/io4.h diff --git a/swdchook/meson.build b/games/swdchook/meson.build similarity index 100% rename from swdchook/meson.build rename to games/swdchook/meson.build diff --git a/swdchook/swdc-dll.c b/games/swdchook/swdc-dll.c similarity index 100% rename from swdchook/swdc-dll.c rename to games/swdchook/swdc-dll.c diff --git a/swdchook/swdc-dll.h b/games/swdchook/swdc-dll.h similarity index 100% rename from swdchook/swdc-dll.h rename to games/swdchook/swdc-dll.h diff --git a/swdchook/swdchook.def b/games/swdchook/swdchook.def similarity index 100% rename from swdchook/swdchook.def rename to games/swdchook/swdchook.def diff --git a/swdchook/zinput.c b/games/swdchook/zinput.c similarity index 100% rename from swdchook/zinput.c rename to games/swdchook/zinput.c diff --git a/swdchook/zinput.h b/games/swdchook/zinput.h similarity index 100% rename from swdchook/zinput.h rename to games/swdchook/zinput.h diff --git a/swdcio/backend.h b/games/swdcio/backend.h similarity index 100% rename from swdcio/backend.h rename to games/swdcio/backend.h diff --git a/swdcio/config.c b/games/swdcio/config.c similarity index 100% rename from swdcio/config.c rename to games/swdcio/config.c diff --git a/swdcio/config.h b/games/swdcio/config.h similarity index 100% rename from swdcio/config.h rename to games/swdcio/config.h diff --git a/swdcio/di-dev.c b/games/swdcio/di-dev.c similarity index 100% rename from swdcio/di-dev.c rename to games/swdcio/di-dev.c diff --git a/swdcio/di-dev.h b/games/swdcio/di-dev.h similarity index 100% rename from swdcio/di-dev.h rename to games/swdcio/di-dev.h diff --git a/swdcio/di.c b/games/swdcio/di.c similarity index 100% rename from swdcio/di.c rename to games/swdcio/di.c diff --git a/swdcio/di.h b/games/swdcio/di.h similarity index 100% rename from swdcio/di.h rename to games/swdcio/di.h diff --git a/swdcio/dllmain.c b/games/swdcio/dllmain.c similarity index 100% rename from swdcio/dllmain.c rename to games/swdcio/dllmain.c diff --git a/swdcio/meson.build b/games/swdcio/meson.build similarity index 100% rename from swdcio/meson.build rename to games/swdcio/meson.build diff --git a/swdcio/swdcio.def b/games/swdcio/swdcio.def similarity index 100% rename from swdcio/swdcio.def rename to games/swdcio/swdcio.def diff --git a/swdcio/swdcio.h b/games/swdcio/swdcio.h similarity index 100% rename from swdcio/swdcio.h rename to games/swdcio/swdcio.h diff --git a/swdcio/wnd.c b/games/swdcio/wnd.c similarity index 100% rename from swdcio/wnd.c rename to games/swdcio/wnd.c diff --git a/swdcio/wnd.h b/games/swdcio/wnd.h similarity index 100% rename from swdcio/wnd.h rename to games/swdcio/wnd.h diff --git a/swdcio/xi.c b/games/swdcio/xi.c similarity index 100% rename from swdcio/xi.c rename to games/swdcio/xi.c diff --git a/swdcio/xi.h b/games/swdcio/xi.h similarity index 100% rename from swdcio/xi.h rename to games/swdcio/xi.h diff --git a/tokyohook/config.c b/games/tokyohook/config.c similarity index 100% rename from tokyohook/config.c rename to games/tokyohook/config.c diff --git a/tokyohook/config.h b/games/tokyohook/config.h similarity index 100% rename from tokyohook/config.h rename to games/tokyohook/config.h diff --git a/tokyohook/dllmain.c b/games/tokyohook/dllmain.c similarity index 100% rename from tokyohook/dllmain.c rename to games/tokyohook/dllmain.c diff --git a/tokyohook/io4.c b/games/tokyohook/io4.c similarity index 100% rename from tokyohook/io4.c rename to games/tokyohook/io4.c diff --git a/tokyohook/io4.h b/games/tokyohook/io4.h similarity index 100% rename from tokyohook/io4.h rename to games/tokyohook/io4.h diff --git a/tokyohook/meson.build b/games/tokyohook/meson.build similarity index 100% rename from tokyohook/meson.build rename to games/tokyohook/meson.build diff --git a/tokyohook/tokyo-dll.c b/games/tokyohook/tokyo-dll.c similarity index 100% rename from tokyohook/tokyo-dll.c rename to games/tokyohook/tokyo-dll.c diff --git a/tokyohook/tokyo-dll.h b/games/tokyohook/tokyo-dll.h similarity index 100% rename from tokyohook/tokyo-dll.h rename to games/tokyohook/tokyo-dll.h diff --git a/tokyohook/tokyohook.def b/games/tokyohook/tokyohook.def similarity index 100% rename from tokyohook/tokyohook.def rename to games/tokyohook/tokyohook.def diff --git a/tokyohook/zinput.c b/games/tokyohook/zinput.c similarity index 100% rename from tokyohook/zinput.c rename to games/tokyohook/zinput.c diff --git a/tokyohook/zinput.h b/games/tokyohook/zinput.h similarity index 100% rename from tokyohook/zinput.h rename to games/tokyohook/zinput.h diff --git a/tokyoio/backend.h b/games/tokyoio/backend.h similarity index 100% rename from tokyoio/backend.h rename to games/tokyoio/backend.h diff --git a/tokyoio/config.c b/games/tokyoio/config.c similarity index 100% rename from tokyoio/config.c rename to games/tokyoio/config.c diff --git a/tokyoio/config.h b/games/tokyoio/config.h similarity index 100% rename from tokyoio/config.h rename to games/tokyoio/config.h diff --git a/tokyoio/dllmain.c b/games/tokyoio/dllmain.c similarity index 100% rename from tokyoio/dllmain.c rename to games/tokyoio/dllmain.c diff --git a/tokyoio/kb.c b/games/tokyoio/kb.c similarity index 100% rename from tokyoio/kb.c rename to games/tokyoio/kb.c diff --git a/tokyoio/kb.h b/games/tokyoio/kb.h similarity index 100% rename from tokyoio/kb.h rename to games/tokyoio/kb.h diff --git a/tokyoio/meson.build b/games/tokyoio/meson.build similarity index 100% rename from tokyoio/meson.build rename to games/tokyoio/meson.build diff --git a/tokyoio/tokyoio.h b/games/tokyoio/tokyoio.h similarity index 100% rename from tokyoio/tokyoio.h rename to games/tokyoio/tokyoio.h diff --git a/tokyoio/xi.c b/games/tokyoio/xi.c similarity index 100% rename from tokyoio/xi.c rename to games/tokyoio/xi.c diff --git a/tokyoio/xi.h b/games/tokyoio/xi.h similarity index 100% rename from tokyoio/xi.h rename to games/tokyoio/xi.h diff --git a/meson.build b/meson.build index 9eea85d..b21d194 100644 --- a/meson.build +++ b/meson.build @@ -94,49 +94,48 @@ pathcch_lib = cc.find_library('pathcch') imagehlp_lib = cc.find_library('imagehlp') ws2_32_lib = cc.find_library('ws2_32') -inc = include_directories('.') +inc = include_directories('common', 'games') capnhook = subproject('capnhook') -subdir('amex') -subdir('iccard') -subdir('board') -subdir('hooklib') -subdir('jvs') -subdir('platform') -subdir('util') +subdir('common/amex') +subdir('common/iccard') +subdir('common/board') +subdir('common/hooklib') +subdir('common/jvs') +subdir('common/platform') +subdir('common/util') +subdir('common/aimeio') -subdir('gfxhook') -subdir('unityhook') +subdir('common/gfxhook') +subdir('common/unityhook') -subdir('aimeio') -subdir('chuniio') -subdir('divaio') -subdir('carolio') -subdir('idzio') -subdir('idacio') -subdir('swdcio') -subdir('mu3io') -subdir('mai2io') -subdir('cmio') -subdir('mercuryio') -subdir('cxbio') -subdir('tokyoio') -subdir('fgoio') -subdir('kemonoio') +subdir('games/chuniio') +subdir('games/divaio') +subdir('games/carolio') +subdir('games/idzio') +subdir('games/idacio') +subdir('games/swdcio') +subdir('games/mu3io') +subdir('games/mai2io') +subdir('games/cmio') +subdir('games/mercuryio') +subdir('games/cxbio') +subdir('games/tokyoio') +subdir('games/fgoio') +subdir('games/kemonoio') -subdir('chunihook') -subdir('divahook') -subdir('carolhook') -subdir('idzhook') -subdir('idachook') -subdir('swdchook') -subdir('minihook') -subdir('chusanhook') -subdir('mu3hook') -subdir('mai2hook') -subdir('cmhook') -subdir('mercuryhook') -subdir('cxbhook') -subdir('tokyohook') -subdir('fgohook') -subdir('kemonohook') +subdir('games/chunihook') +subdir('games/divahook') +subdir('games/carolhook') +subdir('games/idzhook') +subdir('games/idachook') +subdir('games/swdchook') +subdir('games/chusanhook') +subdir('games/mu3hook') +subdir('games/mai2hook') +subdir('games/cmhook') +subdir('games/mercuryhook') +subdir('games/cxbhook') +subdir('games/tokyohook') +subdir('games/fgohook') +subdir('games/kemonohook') diff --git a/minihook/dllmain.c b/minihook/dllmain.c deleted file mode 100644 index c72609f..0000000 --- a/minihook/dllmain.c +++ /dev/null @@ -1,76 +0,0 @@ -#include - -#include - -#include "amex/config.h" -#include "amex/ds.h" - -#include "hook/process.h" - -#include "hooklib/spike.h" - -#include "platform/clock.h" -#include "platform/config.h" -#include "platform/nusec.h" - -#include "util/dprintf.h" -#include "util/env.h" - -static process_entry_t app_startup; - -static DWORD CALLBACK app_pre_startup(void) -{ - struct clock_config clock_cfg; - struct ds_config ds_cfg; - struct nusec_config nusec_cfg; - HRESULT hr; - - dprintf("--- Begin %s ---\n", __func__); - - clock_config_load(&clock_cfg, get_config_path()); - ds_config_load(&ds_cfg, get_config_path()); - nusec_config_load(&nusec_cfg, get_config_path()); - spike_hook_init(get_config_path()); - - hr = clock_hook_init(&clock_cfg); - - if (FAILED(hr)) { - goto fail; - } - - hr = nusec_hook_init(&nusec_cfg, "SSSS", "AAV0"); - - if (FAILED(hr)) { - goto fail; - } - - hr = ds_hook_init(&ds_cfg); - - if (FAILED(hr)) { - goto fail; - } - - dprintf("--- End %s ---\n", __func__); - - return app_startup(); - -fail: - ExitProcess(EXIT_FAILURE); -} - -BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) -{ - HRESULT hr; - - if (cause != DLL_PROCESS_ATTACH) { - return TRUE; - } - - hr = process_hijack_startup(app_pre_startup, &app_startup); - - if (!SUCCEEDED(hr)) { - dprintf("Failed to hijack process startup: %x\n", (int) hr); - } - - return SUCCEEDED(hr); -} diff --git a/minihook/meson.build b/minihook/meson.build deleted file mode 100644 index 7de7f6c..0000000 --- a/minihook/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -shared_library( - 'minihook', - name_prefix : '', - include_directories: inc, - implicit_include_directories : false, - dependencies : [ - capnhook.get_variable('hook_dep'), - ], - link_with : [ - amex_lib, - hooklib_lib, - platform_lib, - util_lib, - ], - sources : [ - 'dllmain.c', - ], -) diff --git a/msvc-build.bat b/msvc-build.bat index fac3925..460b5fd 100644 --- a/msvc-build.bat +++ b/msvc-build.bat @@ -4,6 +4,8 @@ setlocal enabledelayedexpansion set BUILD_DIR=build set BUILD_DIR_32=%BUILD_DIR%\build32 set BUILD_DIR_64=%BUILD_DIR%\build64 +set BUILD_DIR_GAMES_32=%BUILD_DIR_32%\games +set BUILD_DIR_GAMES_64=%BUILD_DIR_64%\games set BUILD_DIR_ZIP=%BUILD_DIR%\zip set DIST_DIR=dist set DOC_DIR=doc diff --git a/package.ps1 b/package.ps1 index bae0e6c..d2f0316 100644 --- a/package.ps1 +++ b/package.ps1 @@ -2,6 +2,8 @@ if ($null -eq $env:BUILD_DIR) { $BUILD_DIR="build" $BUILD_DIR_32="$BUILD_DIR\build32" $BUILD_DIR_64="$BUILD_DIR\build64" + $BUILD_DIR_GAMES_32="$BUILD_DIR_32\games" + $BUILD_DIR_GAMES_64="$BUILD_DIR_64\games" $BUILD_DIR_ZIP="$BUILD_DIR\zip" $DIST_DIR="dist" $DOC_DIR="doc" @@ -9,6 +11,8 @@ if ($null -eq $env:BUILD_DIR) { $BUILD_DIR = $env:BUILD_DIR; $BUILD_DIR_32 = $env:BUILD_DIR_32; $BUILD_DIR_64 = $env:BUILD_DIR_64; + $BUILD_DIR_GAMES_32 = $env:BUILD_DIR_GAMES_32; + $BUILD_DIR_GAMES_64 = $env:BUILD_DIR_GAMES_64; $BUILD_DIR_ZIP = $env:BUILD_DIR_ZIP; $DIST_DIR = $env:DIST_DIR; $DOC_DIR = $env:DOC_DIR; @@ -26,6 +30,8 @@ cat .\Package.mk | % { Replace('$(BUILD_DIR)', $BUILD_DIR). Replace('$(BUILD_DIR_32)', $BUILD_DIR_32). Replace('$(BUILD_DIR_64)', $BUILD_DIR_64). + Replace('$(BUILD_DIR_GAMES_32)', $BUILD_DIR_GAMES_32). + Replace('$(BUILD_DIR_GAMES_64)', $BUILD_DIR_GAMES_64). Replace('$(BUILD_DIR_ZIP)', $BUILD_DIR_ZIP). Replace('$(DIST_DIR)', $DIST_DIR). Replace('$(DOC_DIR)', $DOC_DIR). diff --git a/reg/chunithm.reg b/reg/chunithm.reg deleted file mode 100644 index f7c1240..0000000 --- a/reg/chunithm.reg +++ /dev/null @@ -1,27 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA] - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty] - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\keychip] -"systemFlag"=dword:00000064 -"modelType"=dword:00000001 -"region"=dword:00000001 -"serverIpIpv4"=hex:c0,a8,8b,00 -"keychipId"=hex:41,36,39,45,2d,30,31,41,39,39,39,39,39,39,39,39 -"platformId"=hex:41,41,56 -"gameId"=hex:53,42,5a,56 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\static] -"CpuTempWarning"=dword:0000003c -"CpuTempError"=dword:00000050 -"PlatformId"=hex:41,41,56 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\wirelessNetwork] -"main_nic"=dword:00000000 - -[HKEY_LOCAL_MACHINE\SYSTEM\SEGA\SystemProperty\mount] -"AMFS"="E:\\" -"APPDATA"="Y:\\" - From 24e8bc87a302dd679658b4cb3b2bb1ff8f826474 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Thu, 17 Apr 2025 14:06:55 -0400 Subject: [PATCH 203/204] remove reference to nonexistant files --- common/board/meson.build | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/board/meson.build b/common/board/meson.build index 38ec9d0..a9c24ea 100644 --- a/common/board/meson.build +++ b/common/board/meson.build @@ -9,9 +9,6 @@ board_lib = static_library( iccard_lib, ], sources : [ - '3mpxsc-cmd.h', - '3mpxsc-frame.c', - '3mpxsc-frame.h', 'aime-dll.c', 'aime-dll.h', 'config.c', From dbfc62b5d44ab96c579e4cb0baff2efb2cfe771f Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Thu, 19 Jun 2025 18:17:20 +0200 Subject: [PATCH 204/204] platform: fix dipsw settings not applying --- common/platform/platform.c | 4 ++-- common/platform/system.c | 13 ++----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/common/platform/platform.c b/common/platform/platform.c index a769c97..c882760 100644 --- a/common/platform/platform.c +++ b/common/platform/platform.c @@ -82,13 +82,13 @@ HRESULT platform_hook_init( return hr; } - hr = system_init(&cfg->system, &cfg->vfs); + hr = epay_hook_init(&cfg->epay); if (FAILED(hr)) { return hr; } - hr = epay_hook_init(&cfg->epay); + hr = system_init(&cfg->system, &cfg->vfs); if (FAILED(hr)) { return hr; diff --git a/common/platform/system.c b/common/platform/system.c index 3baf5c1..c9dd1fd 100644 --- a/common/platform/system.c +++ b/common/platform/system.c @@ -110,7 +110,8 @@ static void system_save_sysfile(const wchar_t *sys_file) { uint8_t system = 0; uint8_t freeplay = 0; - HANDLE h_sysfile = CreateFileW(sys_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, 0, 0, NULL); + // open the sysfile.dat for writing + HANDLE h_sysfile = CreateFileW(sys_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h_sysfile == INVALID_HANDLE_VALUE) { return; @@ -164,16 +165,6 @@ static void system_save_sysfile(const wchar_t *sys_file) { memcpy(system_info.data + 0x2800, block, BLOCK_SIZE); memcpy(system_info.data + 0x5800, block, BLOCK_SIZE); - // print the dip_switch_block in hex - /* - dprintf("System Block: "); - for (size_t i = 0; i < BLOCK_SIZE; i++) - { - dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]); - } - dprintf("\n"); - */ - WriteFile(h_sysfile, system_info.data, 0x6000, &sysfile_bytes_written, NULL); CloseHandle(h_sysfile);