From e0cfc8c948723430c21a6e29a634668d60108538 Mon Sep 17 00:00:00 2001 From: icex2 Date: Thu, 13 Aug 2020 13:14:54 +0200 Subject: [PATCH 1/8] Bump to version 5.32 and update changelog --- CHANGELOG.md | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea79c9..ed5dc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Release history +## 5.32 +* Various bugfixes + ## 5.31 * DDR: Fix p3io and extio lights not working / being swapped when using geninput * DDR: Add HDXS light support diff --git a/README.md b/README.md index a1db020..563628e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Bemanitools 5 [![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master) -Version: 5.31
+Version: 5.32
[Release history](CHANGELOG.md) A collection of tools to run [various Bemani arcade games](#list-of-supported-games). From bbb5157460903d51c98120576091197f391ece0b Mon Sep 17 00:00:00 2001 From: icex2 Date: Thu, 13 Aug 2020 13:15:41 +0200 Subject: [PATCH 2/8] Version bump 5.33 --- CHANGELOG.md | 2 ++ README.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed5dc44..feb978b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # Release history +## 5.33 + ## 5.32 * Various bugfixes diff --git a/README.md b/README.md index 563628e..d69b3f3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Bemanitools 5 [![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master) -Version: 5.32
+Version: 5.33
[Release history](CHANGELOG.md) A collection of tools to run [various Bemani arcade games](#list-of-supported-games). From bfbb7103efeea82217f31f6bfbda1120c6b70ede Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Sun, 2 Aug 2020 23:02:13 -0700 Subject: [PATCH 3/8] bio2emu: refactor BIO2 emulation --- Module.mk | 1 + src/main/acio/kfca.h | 2 + .../{iidxhook8/bi2a.h => bio2/bi2a-iidx.h} | 21 +---- src/main/bio2/bi2a-sdvx.h | 75 ++++++++++++++++++ src/main/bio2/bio2.h | 15 ++++ src/main/bio2emu-iidx/Module.mk | 7 ++ src/main/{iidxhook8 => bio2emu-iidx}/bi2a.c | 5 +- src/main/bio2emu-iidx/bi2a.h | 12 +++ src/main/bio2emu/setupapi.c | 4 +- src/main/iidxhook8/Module.mk | 2 +- src/main/iidxhook8/dllmain.c | 2 +- src/main/sdvxhook2/bi2a.h | 76 +------------------ 12 files changed, 122 insertions(+), 100 deletions(-) rename src/main/{iidxhook8/bi2a.h => bio2/bi2a-iidx.h} (83%) create mode 100644 src/main/bio2/bi2a-sdvx.h create mode 100644 src/main/bio2/bio2.h create mode 100644 src/main/bio2emu-iidx/Module.mk rename src/main/{iidxhook8 => bio2emu-iidx}/bi2a.c (99%) create mode 100644 src/main/bio2emu-iidx/bi2a.h diff --git a/Module.mk b/Module.mk index a623237..d0d975f 100644 --- a/Module.mk +++ b/Module.mk @@ -79,6 +79,7 @@ include src/main/acioemu/Module.mk include src/main/aciotest/Module.mk include src/main/asio/Module.mk include src/main/bio2emu/Module.mk +include src/main/bio2emu-iidx/Module.mk include src/main/bsthook/Module.mk include src/main/bstio/Module.mk include src/main/camhook/Module.mk diff --git a/src/main/acio/kfca.h b/src/main/acio/kfca.h index d8b31c3..13fbe4b 100644 --- a/src/main/acio/kfca.h +++ b/src/main/acio/kfca.h @@ -1,6 +1,8 @@ #ifndef AC_IO_KFCA_H #define AC_IO_KFCA_H +#include + #define AC_IO_CMD_KFCA_POLL 0x0113 #define AC_IO_CMD_KFCA_WATCHDOG 0x0120 #define AC_IO_CMD_KFCA_AMP_CONTROL 0x0128 diff --git a/src/main/iidxhook8/bi2a.h b/src/main/bio2/bi2a-iidx.h similarity index 83% rename from src/main/iidxhook8/bi2a.h rename to src/main/bio2/bi2a-iidx.h index 46a4d82..b219682 100644 --- a/src/main/iidxhook8/bi2a.h +++ b/src/main/bio2/bi2a-iidx.h @@ -1,18 +1,7 @@ -#ifndef IIDXHOOK_BI2A_H -#define IIDXHOOK_BI2A_H +#ifndef BIO2_BI2A_IIDX +#define BIO2_BI2A_IIDX -#include -#include -#include - -#include "bio2emu/emu.h" - -enum bio2_iidx_cmd { - // Custom Stuff - BIO2_BI2A_CMD_UNK_0100 = 0x0100, - BIO2_BI2A_CMD_UNK_0120 = 0x0120, - BIO2_BI2A_CMD_POLL = 0x0152, -}; +#include "bio2/bio2.h" #pragma pack(push, 1) struct bi2a_iidx_slider { @@ -114,8 +103,4 @@ _Static_assert( "bi2a_iidx_state_out is the wrong size"); #pragma pack(pop) -void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter); -void bio2_emu_bi2a_dispatch_request( - struct bio2emu_port *bio2port, const struct ac_io_message *req); - #endif diff --git a/src/main/bio2/bi2a-sdvx.h b/src/main/bio2/bi2a-sdvx.h new file mode 100644 index 0000000..d75d909 --- /dev/null +++ b/src/main/bio2/bi2a-sdvx.h @@ -0,0 +1,75 @@ +#ifndef BIO2_BI2A_SDVX +#define BIO2_BI2A_SDVX + +#include "bio2/bio2.h" + +#pragma pack(push, 1) +struct bi2a_sdvx_analog { + uint16_t unk1 : 1; + uint16_t a_coin : 1; + uint16_t a_service : 1; + uint16_t a_test : 1; + uint16_t unk2 : 2; + uint16_t a_val : 10; +}; + +struct bi2a_sdvx_buttons1 { + uint8_t b_fxl : 1; + uint8_t b_d : 1; + uint8_t b_c : 1; + uint8_t b_b : 1; + uint8_t b_a : 1; + uint8_t b_start : 1; + uint8_t b_recorder : 1; + uint8_t b_headphone : 1; +}; + +struct bi2a_sdvx_buttons2 { + uint8_t unk : 5; + uint8_t b_ex2 : 1; + uint8_t b_ex1 : 1; + uint8_t b_fxr : 1; +}; + +struct bio2_bi2a_state { + union { + uint16_t raw[8]; + struct { + struct bi2a_sdvx_analog analogs[4]; + uint8_t unk_1; // coin mech? + struct bi2a_sdvx_buttons1 buttons_1; + struct bi2a_sdvx_buttons2 buttons_2; + uint8_t unk_2[5]; + }; + }; +}; + +struct bio2_bi2a_state_out { + uint8_t unk1[2]; + uint8_t c_block; + uint8_t woof_r; + uint8_t woof_g; + uint8_t unk2; + uint8_t woof_b; + uint8_t controller[3]; + uint8_t unk3; + uint8_t gpio[7]; // START, ABCD, FXL, FXR + uint8_t unk4[3]; + uint8_t generator[3]; + uint8_t unk5[3]; + uint8_t gpio2[3]; // pop, titleL, titleR + uint8_t unk6; + uint8_t wingUpper[3]; + uint8_t wingLower[3]; + uint8_t unk7[3]; +}; + +_Static_assert( + sizeof(struct bio2_bi2a_state) == 16, + "bio2_bi2a_state_in is the wrong size"); +_Static_assert( + sizeof(struct bio2_bi2a_state_out) == 40, + "bio2_bi2a_state_out is the wrong size"); +#pragma pack(pop) + +#endif diff --git a/src/main/bio2/bio2.h b/src/main/bio2/bio2.h new file mode 100644 index 0000000..c30067f --- /dev/null +++ b/src/main/bio2/bio2.h @@ -0,0 +1,15 @@ +#ifndef BIO2_BIO2 +#define BIO2_BIO2 + +#include +#include +#include + +enum bio2_bi2a_cmd { + // Custom Stuff + BIO2_BI2A_CMD_UNK_0100 = 0x0100, + BIO2_BI2A_CMD_UNK_0120 = 0x0120, + BIO2_BI2A_CMD_POLL = 0x0152, // For IIDX +}; + +#endif \ No newline at end of file diff --git a/src/main/bio2emu-iidx/Module.mk b/src/main/bio2emu-iidx/Module.mk new file mode 100644 index 0000000..aa9e7d1 --- /dev/null +++ b/src/main/bio2emu-iidx/Module.mk @@ -0,0 +1,7 @@ +libs += bio2emu-iidx + +libs_bio2emu-iidx := \ + bio2emu \ + +src_bio2emu-iidx := \ + bi2a.c \ diff --git a/src/main/iidxhook8/bi2a.c b/src/main/bio2emu-iidx/bi2a.c similarity index 99% rename from src/main/iidxhook8/bi2a.c rename to src/main/bio2emu-iidx/bi2a.c index d419e2e..c590f29 100644 --- a/src/main/iidxhook8/bi2a.c +++ b/src/main/bio2emu-iidx/bi2a.c @@ -1,7 +1,6 @@ -#define LOG_MODULE "bio2emu-bi2a" +#define LOG_MODULE "bio2emu-iidx" -#include "iidxhook8/bi2a.h" -#include "bio2emu/emu.h" +#include "bio2emu-iidx/bi2a.h" #include /* for _BitScanForward */ diff --git a/src/main/bio2emu-iidx/bi2a.h b/src/main/bio2emu-iidx/bi2a.h new file mode 100644 index 0000000..c8e3d55 --- /dev/null +++ b/src/main/bio2emu-iidx/bi2a.h @@ -0,0 +1,12 @@ +#ifndef BIO2EMU_IIDX_BI2A_H +#define BIO2EMU_IIDX_BI2A_H + +#include "bio2/bi2a-iidx.h" + +#include "bio2emu/emu.h" + +void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter); +void bio2_emu_bi2a_dispatch_request( + struct bio2emu_port *bio2port, const struct ac_io_message *req); + +#endif diff --git a/src/main/bio2emu/setupapi.c b/src/main/bio2emu/setupapi.c index ac33ec8..5dbfffc 100644 --- a/src/main/bio2emu/setupapi.c +++ b/src/main/bio2emu/setupapi.c @@ -350,8 +350,8 @@ static CONFIGRET my_CM_Get_Device_IDA( log_info("%s: Injecting custom parent ID for BIO2", __FUNCTION__); strcpy(Buffer, devpath); - Buffer[devpathsize - 1] = - '\0' + (dnDevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK); + Buffer[devpathsize - 2] = + '0' + (dnDevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK); log_info("%s: %s", __FUNCTION__, Buffer); return CR_SUCCESS; } diff --git a/src/main/iidxhook8/Module.mk b/src/main/iidxhook8/Module.mk index 9d2f8a3..f51688c 100644 --- a/src/main/iidxhook8/Module.mk +++ b/src/main/iidxhook8/Module.mk @@ -15,6 +15,7 @@ libs_iidxhook8 := \ iidxhook-util \ acioemu \ bio2emu \ + bio2emu-iidx \ camhook \ iidxio \ hook \ @@ -24,6 +25,5 @@ libs_iidxhook8 := \ eamio \ src_iidxhook8 := \ - bi2a.c \ config-io.c \ dllmain.c \ diff --git a/src/main/iidxhook8/dllmain.c b/src/main/iidxhook8/dllmain.c index 862609c..a17abaa 100644 --- a/src/main/iidxhook8/dllmain.c +++ b/src/main/iidxhook8/dllmain.c @@ -24,7 +24,7 @@ #include "iidxhook-util/log-server.h" #include "bio2emu/emu.h" -#include "iidxhook8/bi2a.h" +#include "bio2emu-iidx/bi2a.h" #include "camhook/cam.h" #include "camhook/config-cam.h" diff --git a/src/main/sdvxhook2/bi2a.h b/src/main/sdvxhook2/bi2a.h index d65b655..f0444e7 100644 --- a/src/main/sdvxhook2/bi2a.h +++ b/src/main/sdvxhook2/bi2a.h @@ -6,82 +6,8 @@ #include #include "bio2emu/emu.h" +#include "bio2/bi2a-sdvx.h" -enum bio2_bi2a_cmd { - // Custom Stuff - BIO2_BI2A_CMD_UNK_0100 = 0x0100, - BIO2_BI2A_CMD_UNK_0120 = 0x0120, - BIO2_BI2A_CMD_POLL = 0x0152, -}; - -#pragma pack(push, 1) -struct bi2a_sdvx_analog { - uint16_t unk1 : 1; - uint16_t a_coin : 1; - uint16_t a_service : 1; - uint16_t a_test : 1; - uint16_t unk2 : 2; - uint16_t a_val : 10; -}; - -struct bi2a_sdvx_buttons1 { - uint8_t b_fxl : 1; - uint8_t b_d : 1; - uint8_t b_c : 1; - uint8_t b_b : 1; - uint8_t b_a : 1; - uint8_t b_start : 1; - uint8_t b_recorder : 1; - uint8_t b_headphone : 1; -}; - -struct bi2a_sdvx_buttons2 { - uint8_t unk : 5; - uint8_t b_ex2 : 1; - uint8_t b_ex1 : 1; - uint8_t b_fxr : 1; -}; - -struct bio2_bi2a_state { - union { - uint16_t raw[8]; - struct { - struct bi2a_sdvx_analog analogs[4]; - uint8_t unk_1; // coin mech? - struct bi2a_sdvx_buttons1 buttons_1; - struct bi2a_sdvx_buttons2 buttons_2; - uint8_t unk_2[5]; - }; - }; -}; - -struct bio2_bi2a_state_out { - uint8_t unk1[2]; - uint8_t c_block; - uint8_t woof_r; - uint8_t woof_g; - uint8_t unk2; - uint8_t woof_b; - uint8_t controller[3]; - uint8_t unk3; - uint8_t gpio[7]; // START, ABCD, FXL, FXR - uint8_t unk4[3]; - uint8_t generator[3]; - uint8_t unk5[3]; - uint8_t gpio2[3]; // pop, titleL, titleR - uint8_t unk6; - uint8_t wingUpper[3]; - uint8_t wingLower[3]; - uint8_t unk7[3]; -}; - -_Static_assert( - sizeof(struct bio2_bi2a_state) == 16, - "bio2_bi2a_state_in is the wrong size"); -_Static_assert( - sizeof(struct bio2_bi2a_state_out) == 40, - "bio2_bi2a_state_out is the wrong size"); -#pragma pack(pop) void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter, bool force_headphones); void bio2_emu_bi2a_dispatch_request( From f028bdeb20d3dfff907c5e9563691df65353b82a Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Sun, 2 Aug 2020 23:03:04 -0700 Subject: [PATCH 4/8] iidxhook-util: allow setting specified ICCA emulation version --- src/main/iidxhook-util/acio.c | 16 ++++++++++++++++ src/main/iidxhook-util/acio.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/iidxhook-util/acio.c b/src/main/iidxhook-util/acio.c index df34606..7b5b442 100644 --- a/src/main/iidxhook-util/acio.c +++ b/src/main/iidxhook-util/acio.c @@ -30,6 +30,16 @@ static struct ac_io_emu iidxhook_util_acio_emu; static struct ac_io_emu_icca iidxhook_util_acio_emu_icca[2]; +static bool iidxhook_util_icca_override_version; +static enum ac_io_emu_icca_version iidxhook_util_icca_override_version_value; + + +void iidxhook_util_acio_override_version(enum ac_io_emu_icca_version version) +{ + iidxhook_util_icca_override_version = true; + iidxhook_util_icca_override_version_value = version; +} + void iidxhook_util_acio_init(bool legacy_mode) { uint8_t i; @@ -43,6 +53,12 @@ void iidxhook_util_acio_init(bool legacy_mode) for (i = 0; i < lengthof(iidxhook_util_acio_emu_icca); i++) { ac_io_emu_icca_init( &iidxhook_util_acio_emu_icca[i], &iidxhook_util_acio_emu, i); + if (iidxhook_util_icca_override_version) { + ac_io_emu_icca_set_version( + &iidxhook_util_acio_emu_icca[i], + iidxhook_util_icca_override_version_value + ); + } } rs232_hook_add_fd(iidxhook_util_acio_emu.fd); diff --git a/src/main/iidxhook-util/acio.h b/src/main/iidxhook-util/acio.h index bfcd900..1a7d204 100644 --- a/src/main/iidxhook-util/acio.h +++ b/src/main/iidxhook-util/acio.h @@ -5,6 +5,7 @@ #include +#include "acioemu/icca.h" #include "hook/iohook.h" /** @@ -19,6 +20,12 @@ */ void iidxhook_util_acio_init(bool legacy_mode); + +/** + * Use the specified ICCA emulation version + */ +void iidxhook_util_acio_override_version(enum ac_io_emu_icca_version version); + /** * Cleanup the ACIO emulation layer. */ From caba39843f48c56edf50360b8dee768ffec0dcd4 Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Sun, 2 Aug 2020 23:12:34 -0700 Subject: [PATCH 5/8] bio2: bio2_bi2a_state -> bi2a_sdvx_state --- src/main/bio2/bi2a-sdvx.h | 12 ++++++------ src/main/sdvxhook2/bi2a.c | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/bio2/bi2a-sdvx.h b/src/main/bio2/bi2a-sdvx.h index d75d909..502f36b 100644 --- a/src/main/bio2/bi2a-sdvx.h +++ b/src/main/bio2/bi2a-sdvx.h @@ -31,7 +31,7 @@ struct bi2a_sdvx_buttons2 { uint8_t b_fxr : 1; }; -struct bio2_bi2a_state { +struct bi2a_sdvx_state_in { union { uint16_t raw[8]; struct { @@ -44,7 +44,7 @@ struct bio2_bi2a_state { }; }; -struct bio2_bi2a_state_out { +struct bi2a_sdvx_state_out { uint8_t unk1[2]; uint8_t c_block; uint8_t woof_r; @@ -65,11 +65,11 @@ struct bio2_bi2a_state_out { }; _Static_assert( - sizeof(struct bio2_bi2a_state) == 16, - "bio2_bi2a_state_in is the wrong size"); + sizeof(struct bi2a_sdvx_state_in) == 16, + "bi2a_sdvx_state_in is the wrong size"); _Static_assert( - sizeof(struct bio2_bi2a_state_out) == 40, - "bio2_bi2a_state_out is the wrong size"); + sizeof(struct bi2a_sdvx_state_out) == 40, + "bi2a_sdvx_state_out is the wrong size"); #pragma pack(pop) #endif diff --git a/src/main/sdvxhook2/bi2a.c b/src/main/sdvxhook2/bi2a.c index 4e5a1d9..cab5916 100644 --- a/src/main/sdvxhook2/bi2a.c +++ b/src/main/sdvxhook2/bi2a.c @@ -179,16 +179,16 @@ static void bio2_emu_bi2a_send_state(struct ac_io_emu *emu, const struct ac_io_message *req) { struct ac_io_message resp; - struct bio2_bi2a_state *pin; - struct bio2_bi2a_state_out *pout; + struct bi2a_sdvx_state_in *pin; + struct bi2a_sdvx_state_out *pout; resp.addr = req->addr | AC_IO_RESPONSE_FLAG; resp.cmd.code = req->cmd.code; resp.cmd.seq_no = req->cmd.seq_no; resp.cmd.nbytes = sizeof(*pin); - pout = (struct bio2_bi2a_state_out *) &req->cmd.raw; - pin = (struct bio2_bi2a_state *) &resp.cmd.raw; + pout = (struct bi2a_sdvx_state_out *) &req->cmd.raw; + pin = (struct bi2a_sdvx_state_in *) &resp.cmd.raw; memset(pin, 0, sizeof(*pin)); uint32_t gpio = 0; From 4c0f60fc93752d63b12be0774e61e899ab0f2088 Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Fri, 14 Aug 2020 04:38:38 -0700 Subject: [PATCH 6/8] sdvx: Allow setting digital amp level from sdvxio For SDVX 1-4: passes amp values through as-is For SDVX5: ignores the amp volume control (as the game uses windows volume controls, which will work without any hooks) --- src/main/aciodrv/kfca.c | 19 +++++++++++-------- src/main/aciodrv/kfca.h | 18 ++++++++++++++++++ src/main/bemanitools/sdvxio.h | 4 ++++ src/main/sdvxhook/kfca.c | 12 +++++++++--- src/main/sdvxhook2/bi2a.c | 8 ++++++-- src/main/sdvxio-kfca/sdvxio-kfca.def | 1 + src/main/sdvxio-kfca/sdvxio.c | 27 ++++++++++++++++++++++++--- src/main/sdvxio/sdvxio.c | 5 +++++ src/main/sdvxio/sdvxio.def | 1 + 9 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/main/aciodrv/kfca.c b/src/main/aciodrv/kfca.c index 0149d11..000656f 100644 --- a/src/main/aciodrv/kfca.c +++ b/src/main/aciodrv/kfca.c @@ -37,7 +37,12 @@ static bool aciodrv_kfca_watchdog_start(uint8_t node_id) */ } -static bool aciodrv_kfca_amp(uint8_t node_id) +bool aciodrv_kfca_amp( + uint8_t node_id, + uint8_t primary, + uint8_t headphone, + uint8_t unused, + uint8_t subwoofer) { struct ac_io_message msg; @@ -45,12 +50,10 @@ static bool aciodrv_kfca_amp(uint8_t node_id) msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL); msg.cmd.nbytes = 4; - // yes this sets the amp to 100% volume - // TODO: expose this to sdvxio instead at some point - msg.cmd.raw[0] = 0; - msg.cmd.raw[1] = 0; - msg.cmd.raw[2] = 0; - msg.cmd.raw[3] = 0; + msg.cmd.raw[0] = primary; + msg.cmd.raw[1] = headphone; + msg.cmd.raw[2] = unused; + msg.cmd.raw[3] = subwoofer; if (!aciodrv_send_and_recv( &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) { @@ -69,7 +72,7 @@ bool aciodrv_kfca_init(uint8_t node_id) return false; } - if (!aciodrv_kfca_amp(node_id)) { + if (!aciodrv_kfca_amp(node_id, 0, 0, 0, 0)) { return false; } diff --git a/src/main/aciodrv/kfca.h b/src/main/aciodrv/kfca.h index 7722f42..9f146bd 100644 --- a/src/main/aciodrv/kfca.h +++ b/src/main/aciodrv/kfca.h @@ -30,4 +30,22 @@ bool aciodrv_kfca_poll( const struct ac_io_kfca_poll_out *pout, struct ac_io_kfca_poll_in *pin); +/** + * Set the KFCA digital amp level + * + * @param node_id Id of the node to query (0 based). + * @param primary primary volume (96-0) + * @param headphone headphone volume (96-0) + * @param unused unknown volume (96-0) (unused) + * @param subwoofer subwoofer volume (96-0) + * @return True on success, false on error. + * @note Note 96 (or 100?) is lowest volume level, 0 is highest + */ +bool aciodrv_kfca_amp( + uint8_t node_id, + uint8_t primary, + uint8_t headphone, + uint8_t unused, + uint8_t subwoofer); + #endif diff --git a/src/main/bemanitools/sdvxio.h b/src/main/bemanitools/sdvxio.h index 5778e0d..c3dfa83 100644 --- a/src/main/bemanitools/sdvxio.h +++ b/src/main/bemanitools/sdvxio.h @@ -98,4 +98,8 @@ uint16_t sdvx_io_get_input_gpio(uint8_t gpio_bank); uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no); +/* Sets the volume of the digital amps if possible */ + +bool sdvx_io_set_amp_volume(uint8_t primary, uint8_t headphone, uint8_t subwoofer); + #endif diff --git a/src/main/sdvxhook/kfca.c b/src/main/sdvxhook/kfca.c index f4d8894..69780ce 100644 --- a/src/main/sdvxhook/kfca.c +++ b/src/main/sdvxhook/kfca.c @@ -15,7 +15,7 @@ static void kfca_send_version(const struct ac_io_message *req); static void kfca_report_status(const struct ac_io_message *req, uint8_t status); -static void kfca_report_0128(const struct ac_io_message *req); +static void kfca_amp_control(const struct ac_io_message *req); static void kfca_poll(const struct ac_io_message *req); static void kfca_poll_thunk(void *ctx_ptr, struct ac_io_message *resp); @@ -60,7 +60,7 @@ void kfca_dispatch_request(const struct ac_io_message *req) case AC_IO_CMD_KFCA_AMP_CONTROL: log_misc("AC_IO_CMD_KFCA_AMP_CONTROL(%d)", req->addr); - kfca_report_0128(req); + kfca_amp_control(req); break; @@ -110,7 +110,7 @@ static void kfca_report_status(const struct ac_io_message *req, uint8_t status) ac_io_emu_response_push(kfca_ac_io_emu, &resp, 0); } -static void kfca_report_0128(const struct ac_io_message *req) +static void kfca_amp_control(const struct ac_io_message *req) { struct ac_io_message resp; @@ -120,6 +120,12 @@ static void kfca_report_0128(const struct ac_io_message *req) resp.cmd.nbytes = req->cmd.nbytes; memcpy(resp.cmd.raw, req->cmd.raw, req->cmd.nbytes); + // bytes 0-4: main, headphone, unused, subwoofer + + if (!sdvx_io_set_amp_volume(req->cmd.raw[0], req->cmd.raw[1], req->cmd.raw[3])) { + log_warning("Unable to set amp volume?"); + } + ac_io_emu_response_push(kfca_ac_io_emu, &resp, 0); } diff --git a/src/main/sdvxhook2/bi2a.c b/src/main/sdvxhook2/bi2a.c index cab5916..2aca18d 100644 --- a/src/main/sdvxhook2/bi2a.c +++ b/src/main/sdvxhook2/bi2a.c @@ -104,8 +104,12 @@ kfca_amp_control(struct ac_io_emu *emu, const struct ac_io_message *req) resp.cmd.nbytes = req->cmd.nbytes; memcpy(resp.cmd.raw, req->cmd.raw, req->cmd.nbytes); - // log_misc("sz %d: %d, %d, %d, %d", req->cmd.nbytes, req->cmd.raw[0], - // req->cmd.raw[1], req->cmd.raw[2], req->cmd.raw[3]); + // so SDVX5 sets the amps to 0 aka ALL MAX and uses Windows instead + // let's leave it to the individual sdvxio to set on init instead + // this way if any sdvxio's want to use Windows APIs for SDVX1-4 comapt. + // they can do so without doubly affecting the volume + + // sdvx_io_set_amp_volume(0, 0, 0, 0); ac_io_emu_response_push(emu, &resp, 0); } diff --git a/src/main/sdvxio-kfca/sdvxio-kfca.def b/src/main/sdvxio-kfca/sdvxio-kfca.def index e4783a2..8d6e632 100644 --- a/src/main/sdvxio-kfca/sdvxio-kfca.def +++ b/src/main/sdvxio-kfca/sdvxio-kfca.def @@ -11,3 +11,4 @@ EXPORTS sdvx_io_set_loggers sdvx_io_set_pwm_light sdvx_io_write_output + sdvx_io_set_amp_volume diff --git a/src/main/sdvxio-kfca/sdvxio.c b/src/main/sdvxio-kfca/sdvxio.c index 8f1d6f3..7c7533e 100644 --- a/src/main/sdvxio-kfca/sdvxio.c +++ b/src/main/sdvxio-kfca/sdvxio.c @@ -31,6 +31,7 @@ static uint16_t sdvx_io_analog[2]; static bool running; static bool processing_io; +static int16_t kfca_node_id; struct ac_io_kfca_poll_out pout_staging; struct ac_io_kfca_poll_out pout_ready; @@ -86,7 +87,7 @@ bool sdvx_io_init( uint8_t node_count = aciodrv_device_get_node_count(); log_info("Enumerated %d nodes", node_count); - int16_t kfca_node_id = -1; + kfca_node_id = -1; for (uint8_t i = 0; i < node_count; i++) { char product[4]; @@ -109,7 +110,11 @@ bool sdvx_io_init( if (kfca_node_id != -1) { log_warning("Using KFCA on node: %d", kfca_node_id); - aciodrv_kfca_init(kfca_node_id); + + if (!aciodrv_kfca_init(kfca_node_id)) { + log_warning("Unable to start KFCA on node: %d", kfca_node_id); + return false; + } running = true; log_warning("sdvxio-kfca now running"); @@ -155,7 +160,7 @@ bool sdvx_io_read_input(void) } processing_io = true; - if (!aciodrv_kfca_poll(0, &pout_ready, &pin)) { + if (!aciodrv_kfca_poll(kfca_node_id, &pout_ready, &pin)) { return false; } @@ -199,3 +204,19 @@ uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no) } return sdvx_io_analog[spinner_no]; } + +bool sdvx_io_set_amp_volume( + uint8_t primary, + uint8_t headphone, + uint8_t subwoofer) +{ + if (!running) { + return false; + } + + if (!aciodrv_kfca_amp(kfca_node_id, primary, 96, headphone, subwoofer)) { + return false; + } + + return true; +} diff --git a/src/main/sdvxio/sdvxio.c b/src/main/sdvxio/sdvxio.c index 7aae8fe..3bf59a6 100644 --- a/src/main/sdvxio/sdvxio.c +++ b/src/main/sdvxio/sdvxio.c @@ -88,3 +88,8 @@ uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no) { return mapper_read_analog(spinner_no) * 4; } + +bool sdvx_io_set_amp_volume(uint8_t primary, uint8_t headphone, uint8_t subwoofer) +{ + return true; +} diff --git a/src/main/sdvxio/sdvxio.def b/src/main/sdvxio/sdvxio.def index e4783a2..8d6e632 100644 --- a/src/main/sdvxio/sdvxio.def +++ b/src/main/sdvxio/sdvxio.def @@ -11,3 +11,4 @@ EXPORTS sdvx_io_set_loggers sdvx_io_set_pwm_light sdvx_io_write_output + sdvx_io_set_amp_volume From ff1b9ff9a20543457400a5b677a21396b6265f7d Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Fri, 14 Aug 2020 06:25:27 -0700 Subject: [PATCH 7/8] sdvxio-bio2: Add sdvxio BIO2 along with bio2drv and aciotest updates --- Module.mk | 4 + src/main/aciotest/Module.mk | 2 + src/main/aciotest/bi2a-sdvx.c | 58 +++++ src/main/aciotest/bi2a-sdvx.h | 10 + src/main/aciotest/main.c | 15 +- src/main/bio2drv/Module.mk | 9 + src/main/bio2drv/bi2a-sdvx.c | 138 ++++++++++++ src/main/bio2drv/bi2a-sdvx.h | 51 +++++ src/main/bio2drv/config-bio2.c | 75 +++++++ src/main/bio2drv/config-bio2.h | 19 ++ src/main/bio2drv/detect.c | 163 ++++++++++++++ src/main/bio2drv/detect.h | 23 ++ src/main/sdvxio-bio2/Module.mk | 14 ++ src/main/sdvxio-bio2/sdvxio-bio2.def | 15 ++ src/main/sdvxio-bio2/sdvxio.c | 324 +++++++++++++++++++++++++++ 15 files changed, 919 insertions(+), 1 deletion(-) create mode 100644 src/main/aciotest/bi2a-sdvx.c create mode 100644 src/main/aciotest/bi2a-sdvx.h create mode 100644 src/main/bio2drv/Module.mk create mode 100644 src/main/bio2drv/bi2a-sdvx.c create mode 100644 src/main/bio2drv/bi2a-sdvx.h create mode 100644 src/main/bio2drv/config-bio2.c create mode 100644 src/main/bio2drv/config-bio2.h create mode 100644 src/main/bio2drv/detect.c create mode 100644 src/main/bio2drv/detect.h create mode 100644 src/main/sdvxio-bio2/Module.mk create mode 100644 src/main/sdvxio-bio2/sdvxio-bio2.def create mode 100644 src/main/sdvxio-bio2/sdvxio.c diff --git a/Module.mk b/Module.mk index d0d975f..31713e2 100644 --- a/Module.mk +++ b/Module.mk @@ -78,6 +78,7 @@ include src/main/aciodrv/Module.mk include src/main/acioemu/Module.mk include src/main/aciotest/Module.mk include src/main/asio/Module.mk +include src/main/bio2drv/Module.mk include src/main/bio2emu/Module.mk include src/main/bio2emu-iidx/Module.mk include src/main/bsthook/Module.mk @@ -142,6 +143,7 @@ include src/main/sdvxhook2/Module.mk include src/main/sdvxhook2-cn/Module.mk include src/main/sdvxio/Module.mk include src/main/sdvxio-kfca/Module.mk +include src/main/sdvxio-bio2/Module.mk include src/main/security/Module.mk include src/main/unicorntail/Module.mk include src/main/util/Module.mk @@ -416,6 +418,7 @@ $(zipdir)/sdvx-01-to-04.zip: \ build/bin/indep-32/geninput.dll \ build/bin/indep-32/sdvxio.dll \ build/bin/indep-32/sdvxio-kfca.dll \ + build/bin/indep-32/sdvxio-bio2.dll \ dist/sdvx/config.bat \ dist/sdvx/gamestart.bat \ | $(zipdir)/ @@ -430,6 +433,7 @@ $(zipdir)/sdvx-05.zip: \ build/bin/indep-64/geninput.dll \ build/bin/indep-64/sdvxio.dll \ build/bin/indep-64/sdvxio-kfca.dll \ + build/bin/indep-64/sdvxio-bio2.dll \ dist/sdvx5/config.bat \ dist/sdvx5/gamestart.bat \ dist/sdvx5/sdvxhook2.conf \ diff --git a/src/main/aciotest/Module.mk b/src/main/aciotest/Module.mk index 4af9fae..339db10 100644 --- a/src/main/aciotest/Module.mk +++ b/src/main/aciotest/Module.mk @@ -1,10 +1,12 @@ exes += aciotest libs_aciotest := \ + bio2drv \ aciodrv \ util \ src_aciotest := \ icca.c \ kfca.c \ + bi2a-sdvx.c \ main.c \ diff --git a/src/main/aciotest/bi2a-sdvx.c b/src/main/aciotest/bi2a-sdvx.c new file mode 100644 index 0000000..8c7b9f2 --- /dev/null +++ b/src/main/aciotest/bi2a-sdvx.c @@ -0,0 +1,58 @@ +#include "aciotest/bi2a-sdvx.h" + +#include "acio/acio.h" + +#include +#include +#include + +#include "bio2drv/bi2a-sdvx.h" + +bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx) +{ + *ctx = malloc(sizeof(uint32_t)); + *((uint32_t *) *ctx) = 0; + + return bio2drv_bi2a_sdvx_init(node_id); +} + +bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx) +{ + struct bi2a_sdvx_state_in pin; + struct bi2a_sdvx_state_out pout; + + memset(&pout, 0, sizeof(pout)); + + if (!bio2drv_bi2a_sdvx_poll(node_id, &pout, &pin)) { + return false; + } + + + pin.raw[0] = ac_io_u16(pin.raw[0]); + pin.raw[1] = ac_io_u16(pin.raw[1]); + + printf( + ">>> BI2A (SDVX) %d:\n" + "BTN A B C D: %d %d %d %d\n" + "FX-L R: %d %d\n" + "VOL L: %d\n" + "VOL R: %d\n" + "START COIN TEST SERV REC HP: %d %d %d %d %d %d\n", + node_id, + pin.buttons_1.b_a, + pin.buttons_1.b_b, + pin.buttons_1.b_c, + pin.buttons_1.b_d, + pin.buttons_1.b_fxl, + pin.buttons_2.b_fxr, + pin.analogs[0].a_val, + pin.analogs[1].a_val, + pin.buttons_1.b_start, + pin.analogs[0].a_coin, + pin.analogs[0].a_test, + pin.analogs[0].a_service, + pin.buttons_1.b_recorder, + pin.buttons_1.b_headphone); + + return true; +} diff --git a/src/main/aciotest/bi2a-sdvx.h b/src/main/aciotest/bi2a-sdvx.h new file mode 100644 index 0000000..59d4a2d --- /dev/null +++ b/src/main/aciotest/bi2a-sdvx.h @@ -0,0 +1,10 @@ +#ifndef ACIOTEST_BI2A_SDVX_H +#define ACIOTEST_BI2A_SDVX_H + +#include +#include + +bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx); +bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx); + +#endif diff --git a/src/main/aciotest/main.c b/src/main/aciotest/main.c index 38396cf..53da2ce 100644 --- a/src/main/aciotest/main.c +++ b/src/main/aciotest/main.c @@ -9,10 +9,12 @@ #include "aciotest/handler.h" #include "aciotest/icca.h" #include "aciotest/kfca.h" +#include "aciotest/bi2a-sdvx.h" #include "util/log.h" static uint8_t aciotest_cnt = 0; +static uint8_t bi2a_mode = 0; /** * Enumerate supported ACIO nodes based on their product id. @@ -35,6 +37,17 @@ static bool aciotest_assign_handler( return true; } + if (!memcmp(product, "BI2A", 4)) { + if (bi2a_mode == 0) { + handler->init = aciotest_bi2a_sdvx_handler_init; + handler->update = aciotest_bi2a_sdvx_handler_update; + + return true; + } else { + printf("Unknown BI2A device specified"); + } + } + return false; } @@ -125,7 +138,7 @@ int main(int argc, char **argv) } /* avoid cpu banging */ - Sleep(20); + Sleep(30); } return 0; diff --git a/src/main/bio2drv/Module.mk b/src/main/bio2drv/Module.mk new file mode 100644 index 0000000..3d8b063 --- /dev/null +++ b/src/main/bio2drv/Module.mk @@ -0,0 +1,9 @@ +libs += bio2drv + +libs_bio2drv := \ + aciodrv + +src_bio2drv := \ + detect.c \ + config-bio2.c \ + bi2a-sdvx.c \ diff --git a/src/main/bio2drv/bi2a-sdvx.c b/src/main/bio2drv/bi2a-sdvx.c new file mode 100644 index 0000000..87d2ff2 --- /dev/null +++ b/src/main/bio2drv/bi2a-sdvx.c @@ -0,0 +1,138 @@ +#define LOG_MODULE "bio2drv-bi2a_sdvx" + +#include "bio2drv/bi2a-sdvx.h" + +#include +#include + +#include "aciodrv/device.h" + +#include "util/log.h" + +// this is probably InitIO +static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id) +{ + struct ac_io_message msg; + + msg.addr = node_id + 1; + msg.cmd.code = ac_io_u16(AC_IO_CMD_CLEAR); + msg.cmd.nbytes = 1; + msg.cmd.count = 0x3B; + + if (!aciodrv_send_and_recv( + &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) { + log_warning("Init node failed"); + return 0; + } + + log_warning("Init of node %d, status: %d", node_id, msg.cmd.status); + + return 1; +} + +static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id) +{ + // exit early and don't actually call watchdog + // the watchdog call actually returns different sized packets depending on + // the state this results in an issue during packet processing (see: #68) + return true; + + /* + struct ac_io_message msg; + + msg.addr = node_id + 1; + msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG); + msg.cmd.nbytes = 2; + msg.cmd.nbytes = 2; + + // uint16_t: 6000 + msg.cmd.raw[0] = 23; + msg.cmd.raw[1] = 112; + + if (!aciodrv_send_and_recv( + &msg, offsetof(struct ac_io_message, cmd.raw) + 2 + )) { + log_warning("Starting watchdog failed"); return false; + } + + log_warning("Started watchdog of node %d, status: %d", + node_id, msg.cmd.status); + + return true; + */ +} + +bool bio2drv_bi2a_sdvx_amp( + uint8_t node_id, + uint8_t unused_1, + uint8_t unused_2, + uint8_t left, + uint8_t right) +{ + struct ac_io_message msg; + + msg.addr = node_id + 1; + msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL); + msg.cmd.nbytes = 4; + + // the BIO2 DOES NOT MATCH THE KFCA for what these mean + // 0 and 1 are ignored, 2 and 3 seem to map to left/right for ALL 3 AMPS + // in the future, maybe use windows APIs and write the volume levels there + msg.cmd.raw[0] = unused_1; + msg.cmd.raw[1] = unused_2; + msg.cmd.raw[2] = left; + msg.cmd.raw[3] = right; + + if (!aciodrv_send_and_recv( + &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) { + log_warning("Setting AMP failed"); + return false; + } + + log_warning("Started AMP node %d", node_id); + + return true; +} + +bool bio2drv_bi2a_sdvx_init(uint8_t node_id) +{ + if (!bio2drv_bi2a_sdvx_init_io(node_id)) { + return false; + } + + if (!bio2drv_bi2a_sdvx_watchdog_start(node_id)) { + return false; + } + + if (!bio2drv_bi2a_sdvx_amp(node_id, 0, 0, 0, 0)) { + return false; + } + + return true; +} + +bool bio2drv_bi2a_sdvx_poll( + uint8_t node_id, + const struct bi2a_sdvx_state_out *pout, + struct bi2a_sdvx_state_in *pin) +{ + struct ac_io_message msg; + + msg.addr = node_id + 1; + msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL); + msg.cmd.nbytes = sizeof(*pout); + /* buffer size of data we expect */ + *(struct bi2a_sdvx_state_out *) msg.cmd.raw = *pout; + + if (!aciodrv_send_and_recv( + &msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) { + log_warning("Polling of node %d failed", node_id + 1); + return false; + } + + if (pin != NULL) { + memcpy(pin, &msg.cmd.raw, sizeof(*pin)); + } + + return true; +} diff --git a/src/main/bio2drv/bi2a-sdvx.h b/src/main/bio2drv/bi2a-sdvx.h new file mode 100644 index 0000000..a68aa78 --- /dev/null +++ b/src/main/bio2drv/bi2a-sdvx.h @@ -0,0 +1,51 @@ +#ifndef BIO2DRV_BI2A_H +#define BIO2DRV_BI2A_H + +#include "bio2/bi2a-sdvx.h" + +/** + * Initialize a BI2A node. + * + * @param node_id Id of the node to initialize (0 based). + * @return True if successful, false on error. + * @note This module is supposed to be used in combination with the common + * device driver foundation. + * @see driver.h + */ +bool bio2drv_bi2a_sdvx_init(uint8_t node_id); + +/** + * Poll the board + * + * @param node_id Id of the node to query (0 based). + * @param state Pointer to a state struct to return the current state to + * (optional, NULL for none). + * @return True on success, false on error. + * @note This module is supposed to be used in combination with the common + * device driver foundation. + * @see driver.h + */ +bool bio2drv_bi2a_sdvx_poll( + uint8_t node_id, + const struct bi2a_sdvx_state_out *pout, + struct bi2a_sdvx_state_in *pin); + +/** + * Set the BIO2 BI2A SDVX digital amp level + * + * @param node_id Id of the node to query (0 based). + * @param primary primary volume (96-0) + * @param headphone headphone volume (96-0) + * @param unused unknown volume (96-0) (unused) + * @param subwoofer subwoofer volume (96-0) + * @return True on success, false on error. + * @note Note 96 is lowest volume level, 0 is highest + */ +bool bio2drv_bi2a_sdvx_amp( + uint8_t node_id, + uint8_t unused_1, + uint8_t unused_2, + uint8_t left, + uint8_t right); + +#endif diff --git a/src/main/bio2drv/config-bio2.c b/src/main/bio2drv/config-bio2.c new file mode 100644 index 0000000..2a68cc1 --- /dev/null +++ b/src/main/bio2drv/config-bio2.c @@ -0,0 +1,75 @@ +#include "cconfig/cconfig-util.h" + +#include "bio2drv/config-bio2.h" + +#include "util/log.h" + +#define BIO2DRV_CONFIG_BIO2_AUTO_KEY "bio2.autodetect" +#define BIO2DRV_CONFIG_BIO2_PORT_KEY "bio2.port" +#define BIO2DRV_CONFIG_BIO2_BAUD_KEY "bio2.baud" + +#define BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE true +#define BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE "COM4" +#define BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE 115200 + +void bio2drv_config_bio2_init(struct cconfig *config) +{ + cconfig_util_set_bool( + config, + BIO2DRV_CONFIG_BIO2_AUTO_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE, + "Autodetect BIO2 port (default: on)"); + + cconfig_util_set_str( + config, + BIO2DRV_CONFIG_BIO2_PORT_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE, + "BIO2 serial port"); + + cconfig_util_set_int( + config, + BIO2DRV_CONFIG_BIO2_BAUD_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE, + "BIO2 bus baudrate (real devices expect 115200)"); +} + +void bio2drv_config_bio2_get( + struct bio2drv_config_bio2 *config_bio2, struct cconfig *config) +{ + if (!cconfig_util_get_bool( + config, + BIO2DRV_CONFIG_BIO2_AUTO_KEY, + &config_bio2->autodetect, + BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + BIO2DRV_CONFIG_BIO2_AUTO_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE); + } + + if (!cconfig_util_get_str( + config, + BIO2DRV_CONFIG_BIO2_PORT_KEY, + config_bio2->port, + sizeof(config_bio2->port) - 1, + BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%s'", + BIO2DRV_CONFIG_BIO2_PORT_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE); + } + + if (!cconfig_util_get_int( + config, + BIO2DRV_CONFIG_BIO2_BAUD_KEY, + &config_bio2->baud, + BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + BIO2DRV_CONFIG_BIO2_BAUD_KEY, + BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE); + } +} diff --git a/src/main/bio2drv/config-bio2.h b/src/main/bio2drv/config-bio2.h new file mode 100644 index 0000000..a626e86 --- /dev/null +++ b/src/main/bio2drv/config-bio2.h @@ -0,0 +1,19 @@ +#ifndef BIO2DRV_CONFIG_BIO2_H +#define BIO2DRV_CONFIG_BIO2_H + +#include + +#include "cconfig/cconfig.h" + +struct bio2drv_config_bio2 { + bool autodetect; + char port[64]; + int32_t baud; +}; + +void bio2drv_config_bio2_init(struct cconfig *config); + +void bio2drv_config_bio2_get( + struct bio2drv_config_bio2 *config_bio2, struct cconfig *config); + +#endif diff --git a/src/main/bio2drv/detect.c b/src/main/bio2drv/detect.c new file mode 100644 index 0000000..be9ad04 --- /dev/null +++ b/src/main/bio2drv/detect.c @@ -0,0 +1,163 @@ +#define LOG_MODULE "bio2drv-detect" + +#include +#include + +#include +#include + +#include "bio2drv/detect.h" + +#include +#include + +#include "util/log.h" + +DEFINE_GUID( + GUID_COM_BUS_ENUMERATOR, + 0x4D36E978, + 0xE325, + 0x11CE, + 0xBF, + 0xC1, + 0x08, + 0x00, + 0x2B, + 0xE1, + 0x03, + 0x18); + +static char work_buffer[0x400]; + +static bool check_property( + HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData, DWORD property) +{ + if (SetupDiGetDeviceRegistryPropertyA( + DeviceInfoSet, + PDeviceInfoData, + property, + NULL, + (BYTE *) work_buffer, + sizeof(work_buffer), + NULL)) { + if (strstr(work_buffer, "BIO2(VIDEO)")) { + log_info("Found matching device: %s", work_buffer); + return true; + } + } + + log_info("Device with property: %s does not match", work_buffer); + return false; +} + +static bool check_id( + HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData) +{ + if (CM_Get_Device_IDA(PDeviceInfoData->DevInst, work_buffer, sizeof(work_buffer), 0)) { + return false; + } + + if (strstr(work_buffer, "VID_1CCF&PID_804C")) { + log_info("Found matching device: %s", work_buffer); + return true; + } + + if (strstr(work_buffer, "VID_1CCF&PID_8040")) { + log_info("Found matching device: %s", work_buffer); + return true; + } + + log_info("Device with ID: %s does not match", work_buffer); + return false; +} + +static bool get_device_by_filter( + bool id_filter, DWORD property, size_t devnum, char *path, size_t length) +{ + HDEVINFO DeviceInfoSet = SetupDiGetClassDevsA( + &GUID_COM_BUS_ENUMERATOR, NULL, NULL, DIGCF_PRESENT); + + if (DeviceInfoSet == INVALID_HANDLE_VALUE) { + return false; + } + + SP_DEVINFO_DATA DeviceInfoData; + ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA)); + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + DWORD idx = 0; + size_t num_found = 0; + + while (SetupDiEnumDeviceInfo(DeviceInfoSet, idx, &DeviceInfoData)) { + HKEY DeviceRegKey = SetupDiOpenDevRegKey( + DeviceInfoSet, + &DeviceInfoData, + DICS_FLAG_GLOBAL, + 0, + DIREG_DEV, + KEY_QUERY_VALUE); + + if (DeviceRegKey) { + bool found = false; + log_info("Found a serial device at index: %d", idx); + + if (!id_filter) { + if (check_property(DeviceInfoSet, &DeviceInfoData, property)) { + found = true; + } + } else { + if (check_id(DeviceInfoSet, &DeviceInfoData)) { + found = true; + } + } + + if (found) { + if (num_found == devnum) { + DWORD path_length = length; + RegQueryValueExA( + DeviceRegKey, + "PortName", + 0, + NULL, + (BYTE *) path, + &path_length); + log_info("Using port: %s", path); + + return true; + } + num_found++; + } + } + ++idx; + } + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + + log_warning("No matching device found"); + return false; +} + +void bio2drv_set_loggers( + log_formatter_t misc, + log_formatter_t info, + log_formatter_t warning, + log_formatter_t fatal) +{ + log_to_external(misc, info, warning, fatal); +} + +bool bio2drv_detect( + enum bio2drv_detect_mode mode, size_t index, char *path, size_t length) +{ + if (mode == DETECT_DEVICEDESC) { + return get_device_by_filter( + false, SPDRP_DEVICEDESC, index, path, length); + } else if (mode == DETECT_FRIENDLYNAME) { + return get_device_by_filter( + false, SPDRP_FRIENDLYNAME, index, path, length); + } else if (mode == DETECT_DEVICEID) { + return get_device_by_filter(true, -1, index, path, length); + } + + log_warning("Unknown autodetect mode: %d", mode); + return false; +} diff --git a/src/main/bio2drv/detect.h b/src/main/bio2drv/detect.h new file mode 100644 index 0000000..21ab725 --- /dev/null +++ b/src/main/bio2drv/detect.h @@ -0,0 +1,23 @@ +#ifndef BIO2DRV_DETECT_H +#define BIO2DRV_DETECT_H + +#include + +#include "bemanitools/glue.h" + +enum bio2drv_detect_mode { + DETECT_DEVICEDESC = 0x1, // look for serial devices containing BIO2(VIDEO) + DETECT_FRIENDLYNAME = 0x2, // look for serial devices containing BIO2(VIDEO) + DETECT_DEVICEID = 0x3, // look for serial devices by vid/pid +}; + +void bio2drv_set_loggers( + log_formatter_t misc, + log_formatter_t info, + log_formatter_t warning, + log_formatter_t fatal); + +bool bio2drv_detect( + enum bio2drv_detect_mode mode, size_t devnum, char *path, size_t length); + +#endif diff --git a/src/main/sdvxio-bio2/Module.mk b/src/main/sdvxio-bio2/Module.mk new file mode 100644 index 0000000..bf16a3b --- /dev/null +++ b/src/main/sdvxio-bio2/Module.mk @@ -0,0 +1,14 @@ +dlls += sdvxio-bio2 + +ldflags_sdvxio-bio2 := \ + -lsetupapi \ + +libs_sdvxio-bio2 := \ + aciodrv \ + bio2drv \ + cconfig \ + util \ + +src_sdvxio-bio2 := \ + sdvxio.c \ + diff --git a/src/main/sdvxio-bio2/sdvxio-bio2.def b/src/main/sdvxio-bio2/sdvxio-bio2.def new file mode 100644 index 0000000..7b14921 --- /dev/null +++ b/src/main/sdvxio-bio2/sdvxio-bio2.def @@ -0,0 +1,15 @@ +LIBRARY sdvxio-bio2 + +EXPORTS + sdvx_io_fini + sdvx_io_get_input_gpio + sdvx_io_get_input_gpio_sys + sdvx_io_get_spinner_pos + sdvx_io_init + sdvx_io_read_input + sdvx_io_set_gpio_lights + sdvx_io_set_loggers + sdvx_io_set_pwm_light + sdvx_io_write_output + sdvx_io_set_amp_volume + _bio2_sdvx_io_poll diff --git a/src/main/sdvxio-bio2/sdvxio.c b/src/main/sdvxio-bio2/sdvxio.c new file mode 100644 index 0000000..315f500 --- /dev/null +++ b/src/main/sdvxio-bio2/sdvxio.c @@ -0,0 +1,324 @@ +#include +#include +#include +#include + +#include "bemanitools/glue.h" +#include "bemanitools/sdvxio.h" + +#include "cconfig/cconfig-main.h" + +#include "aciodrv/device.h" +#include "bio2drv/bi2a-sdvx.h" +#include "bio2drv/config-bio2.h" +#include "bio2drv/detect.h" + +#define LOG_MODULE "sdvxio-bio2" + +#define log_misc(...) sdvx_io_log_misc(LOG_MODULE, __VA_ARGS__) +#define log_info(...) sdvx_io_log_info(LOG_MODULE, __VA_ARGS__) +#define log_warning(...) sdvx_io_log_warning(LOG_MODULE, __VA_ARGS__) +#define log_fatal(...) sdvx_io_log_fatal(LOG_MODULE, __VA_ARGS__) + +static log_formatter_t sdvx_io_log_misc; +static log_formatter_t sdvx_io_log_info; +static log_formatter_t sdvx_io_log_warning; +static log_formatter_t sdvx_io_log_fatal; + +static uint16_t sdvx_io_gpio[2]; +static uint8_t sdvx_io_gpio_sys; +static uint16_t sdvx_io_analog[2]; + +static char autodetect_buffer[512]; + +static bool running; +static bool processing_io; +static int16_t bio2_node_id; + +uint8_t wing_staging[12]; +struct bi2a_sdvx_state_out pout_staging; +struct bi2a_sdvx_state_out pout_ready; + +void sdvx_io_set_loggers( + log_formatter_t misc, + log_formatter_t info, + log_formatter_t warning, + log_formatter_t fatal) +{ + sdvx_io_log_misc = misc; + sdvx_io_log_info = info; + sdvx_io_log_warning = warning; + sdvx_io_log_fatal = fatal; + + bio2drv_set_loggers(misc, info, warning, fatal); +} + +bool sdvx_io_init( + thread_create_t thread_create, + thread_join_t thread_join, + thread_destroy_t thread_destroy) +{ + + struct cconfig *config; + struct bio2drv_config_bio2 config_bio2; + + config = cconfig_init(); + + bio2drv_config_bio2_init(config); + + if (!cconfig_main_config_init( + config, + "--bio2-config", + "sdvxio-bio2.conf", + "--help", + "-h", + "sdvxio-bio2", + CCONFIG_CMD_USAGE_OUT_STDOUT)) { + cconfig_finit(config); + exit(EXIT_FAILURE); + } + + bio2drv_config_bio2_get(&config_bio2, config); + + cconfig_finit(config); + + const char *selected_port = config_bio2.port; + + if (config_bio2.autodetect) { + log_info("Attempting autodetect"); + + if (bio2drv_detect( + DETECT_DEVICEID, + 0, + autodetect_buffer, + sizeof(autodetect_buffer))) { + selected_port = autodetect_buffer; + } else { + log_info("Autodetect failed, falling back to using specified port"); + } + } + + if (!aciodrv_device_open(selected_port, config_bio2.baud)) { + log_info("Opening BIO2 device on [%s] failed", selected_port); + return 0; + } + + log_info("Opening BIO2 device on [%s] successful", selected_port); + + uint8_t node_count = aciodrv_device_get_node_count(); + log_info("Enumerated %d nodes", node_count); + + bio2_node_id = -1; + + for (uint8_t i = 0; i < node_count; i++) { + char product[4]; + aciodrv_device_get_node_product_ident(i, product); + log_info( + "> %d: %c%c%c%c\n", + i, + product[0], + product[1], + product[2], + product[3]); + + if (!memcmp(product, "BI2A", 4)) { + if (bio2_node_id != -1) { + log_warning("Multiple BI2A found! Using highest node id."); + } + bio2_node_id = i; + } + } + + if (bio2_node_id != -1) { + log_warning("Using BI2A on node: %d", bio2_node_id); + + if (!bio2drv_bi2a_sdvx_init(bio2_node_id)) { + log_warning("Unable to start BI2A on node: %d", bio2_node_id); + return false; + } + + running = true; + log_warning("sdvxio-bio2 now running"); + } else { + log_warning("No KFCA device found"); + } + + return running; +} + +void sdvx_io_fini(void) +{ + running = false; + while (processing_io) { + } +} + +static uint8_t assign_light(uint32_t gpio_lights, uint32_t shift) +{ + uint32_t shifted = (1 << shift); + + if ((gpio_lights & shifted) == shifted) { + return 255; + } + + return 0; +} + +void sdvx_io_set_gpio_lights(uint32_t gpio_lights) +{ + pout_staging.gpio[0] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_START); + pout_staging.gpio[1] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_A); + pout_staging.gpio[2] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_B); + pout_staging.gpio[3] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_C); + pout_staging.gpio[4] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_D); + pout_staging.gpio[5] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_FX_L); + pout_staging.gpio[6] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_FX_R); +} + +void sdvx_io_set_pwm_light(uint8_t light_no, uint8_t intensity) +{ + if (light_no < 12) { + wing_staging[light_no] = intensity; + } else { + switch (light_no) { + case 12: + pout_staging.woof_r = intensity; + break; + case 13: + pout_staging.woof_g = intensity; + break; + case 14: + pout_staging.woof_b = intensity; + break; + case 15: + pout_staging.controller[0] = intensity; + break; + case 16: + pout_staging.controller[1] = intensity; + break; + case 17: + pout_staging.controller[2] = intensity; + break; + default: + break; + } + } +} + +bool sdvx_io_write_output(void) +{ + memcpy(&pout_ready, &pout_staging, sizeof(struct bi2a_sdvx_state_out)); + pout_ready.wingUpper[0] = wing_staging[0] / 2 + wing_staging[3] / 2; + pout_ready.wingUpper[1] = wing_staging[1] / 2 + wing_staging[4] / 2; + pout_ready.wingUpper[2] = wing_staging[2] / 2 + wing_staging[5] / 2; + + pout_ready.wingLower[0] = wing_staging[6] / 2 + wing_staging[9] / 2; + pout_ready.wingLower[1] = wing_staging[7] / 2 + wing_staging[10] / 2; + pout_ready.wingLower[2] = wing_staging[8] / 2 + wing_staging[11] / 2; + + return true; +} + +static uint8_t shift_pin(uint16_t value, uint8_t pin) +{ + if (value) { + return (1 << pin); + } + + return 0; +} + +bool _bio2_sdvx_io_poll( + const struct bi2a_sdvx_state_out *pout, struct bi2a_sdvx_state_in *pin) +{ + if (!running) { + return false; + } + + processing_io = true; + + if (!bio2drv_bi2a_sdvx_poll(bio2_node_id, pout, pin)) { + processing_io = false; + return false; + } + + processing_io = false; + return true; +} + +bool sdvx_io_read_input(void) +{ + struct bi2a_sdvx_state_in pin; + + if (!_bio2_sdvx_io_poll(&pout_ready, &pin)) { + return false; + } + + pin.raw[0] = ac_io_u16(pin.raw[0]); + pin.raw[1] = ac_io_u16(pin.raw[1]); + + sdvx_io_analog[0] = pin.analogs[0].a_val; + sdvx_io_analog[1] = pin.analogs[1].a_val; + + sdvx_io_gpio_sys = 0; + sdvx_io_gpio_sys |= + shift_pin(pin.analogs[0].a_coin, SDVX_IO_IN_GPIO_SYS_COIN); + sdvx_io_gpio_sys |= + shift_pin(pin.analogs[0].a_test, SDVX_IO_IN_GPIO_SYS_TEST); + sdvx_io_gpio_sys |= + shift_pin(pin.analogs[0].a_service, SDVX_IO_IN_GPIO_SYS_SERVICE); + + sdvx_io_gpio[0] = 0; + sdvx_io_gpio[1] = 0; + + sdvx_io_gpio[0] |= + shift_pin(pin.buttons_1.b_start, SDVX_IO_IN_GPIO_0_START); + sdvx_io_gpio[0] |= + shift_pin(pin.buttons_1.b_headphone, SDVX_IO_IN_GPIO_0_HEADPHONE); + sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_a, SDVX_IO_IN_GPIO_0_A); + sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_b, SDVX_IO_IN_GPIO_0_B); + sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_c, SDVX_IO_IN_GPIO_0_C); + sdvx_io_gpio[1] |= shift_pin(pin.buttons_1.b_d, SDVX_IO_IN_GPIO_1_D); + sdvx_io_gpio[1] |= shift_pin(pin.buttons_1.b_fxl, SDVX_IO_IN_GPIO_1_FX_L); + sdvx_io_gpio[1] |= shift_pin(pin.buttons_2.b_fxr, SDVX_IO_IN_GPIO_1_FX_R); + + return true; +} + +uint8_t sdvx_io_get_input_gpio_sys(void) +{ + return sdvx_io_gpio_sys; +} + +uint16_t sdvx_io_get_input_gpio(uint8_t gpio_bank) +{ + if (gpio_bank > 1) { + return 0; + } + + return sdvx_io_gpio[gpio_bank]; +} + +uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no) +{ + if (spinner_no >= 2) { + return 0; + } + return sdvx_io_analog[spinner_no]; +} + +bool sdvx_io_set_amp_volume( + uint8_t primary, uint8_t headphone, uint8_t subwoofer) +{ + if (!running) { + return false; + } + + // yes, the BIO2 doesn't allow control of the amps individually + // so let's just set it so that people's ear's don't blow out + if (!bio2drv_bi2a_sdvx_amp(bio2_node_id, 0, 0, primary, primary)) { + return false; + } + + return true; +} From 89989ae49c9750f46e7d655437c9ed82ef966405 Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Fri, 14 Aug 2020 19:05:44 -0700 Subject: [PATCH 8/8] doc: add documentation for sdvxio-bio2 --- doc/sdvxhook/sdvxio-bio2.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 doc/sdvxhook/sdvxio-bio2.md diff --git a/doc/sdvxhook/sdvxio-bio2.md b/doc/sdvxhook/sdvxio-bio2.md new file mode 100644 index 0000000..24547c4 --- /dev/null +++ b/doc/sdvxhook/sdvxio-bio2.md @@ -0,0 +1,18 @@ +This library talks to a BIO2 BI2A node and implements the sdvxio API of BT5. +Thus, it allows you to use a BIO2 SDVX device board with *any* version of SDVX that is supported by BT5. + +# Setup +* Make sure that your BIO2 is flashed with a SDVX firmware (if you can boot SDVX5 with it, it's already the right firmware) + * The firmware persists between boots, so as long as it's flashed to the correct firmware, you no longer need to do this step +* Rename sdvxio-kfca.dll to sdvxio.dll. +* Ensure that your gamestart.bat actually injects the appropriate sdvxhook dll +for example: +``` +launcher -K sdvxhook.dll soundvoltex.dll ...* +``` +or that the application otherwise uses sdvxio.dll + +* sdvxio-bio2 implements BIO2 device autodetection + * if this fails please make a bug report, and set the port manually in the config +* You can change the port and baudrate by editing the sdvxio-bio2.conf that should be created by default +* Please connect any additional acio devices to their own port (ex: SDVX5 expects an ICCA by itself on COM2)