From 53f8cb3bf3bc9b964205d027021f71672fda7766 Mon Sep 17 00:00:00 2001 From: icex2 Date: Wed, 16 Dec 2020 22:50:05 +0100 Subject: [PATCH] iidxio-bio2: Add iidxio implementation using bio2 iidx driver Use the original bio2 hardware with anything that supports BT5's iidxio interface, e.g. old IIDX versions of BT5. --- Module.mk | 3 + doc/api.md | 1 + src/main/iidxio-bio2/Module.mk | 13 + src/main/iidxio-bio2/iidxio-bio2.def | 18 ++ src/main/iidxio-bio2/iidxio.c | 344 +++++++++++++++++++++++++++ 5 files changed, 379 insertions(+) create mode 100644 src/main/iidxio-bio2/Module.mk create mode 100644 src/main/iidxio-bio2/iidxio-bio2.def create mode 100644 src/main/iidxio-bio2/iidxio.c diff --git a/Module.mk b/Module.mk index 522e433..71cf703 100644 --- a/Module.mk +++ b/Module.mk @@ -126,6 +126,7 @@ include src/main/iidxhook6/Module.mk include src/main/iidxhook7/Module.mk include src/main/iidxhook8/Module.mk include src/main/iidxhook9/Module.mk +include src/main/iidxio-bio2/Module.mk include src/main/iidxio-ezusb/Module.mk include src/main/iidxio-ezusb2/Module.mk include src/main/iidxio/Module.mk @@ -374,6 +375,7 @@ $(zipdir)/iidx-27.zip: \ $(zipdir)/iidx-hwio-x86.zip: \ build/bin/indep-32/eamio-icca.dll \ + build/bin/indep-32/iidxio-bio2.dll \ build/bin/indep-32/iidxio-ezusb.dll \ build/bin/indep-32/iidxio-ezusb2.dll \ | $(zipdir)/ @@ -382,6 +384,7 @@ $(zipdir)/iidx-hwio-x86.zip: \ $(zipdir)/iidx-hwio-x64.zip: \ build/bin/indep-64/eamio-icca.dll \ + build/bin/indep-64/iidxio-bio2.dll \ build/bin/indep-64/iidxio-ezusb.dll \ build/bin/indep-64/iidxio-ezusb2.dll \ | $(zipdir)/ diff --git a/doc/api.md b/doc/api.md index 974e533..a999a89 100644 --- a/doc/api.md +++ b/doc/api.md @@ -22,6 +22,7 @@ The following implementations are already shipped with BT5. * ddrio-smx.dll: StepManiaX platforms * Beatmania IIDX * iidxio.dll (default): Keyboard, joystick and mouse input + * iidxio-bio2.dll: BIO2 driver * iidxio-ezusb.dll: Ezusb (C02 IO) driver * iidxio-ezusb2.dll: Ezusb FX2 (IO2) driver * jubeat diff --git a/src/main/iidxio-bio2/Module.mk b/src/main/iidxio-bio2/Module.mk new file mode 100644 index 0000000..09632c2 --- /dev/null +++ b/src/main/iidxio-bio2/Module.mk @@ -0,0 +1,13 @@ +dlls += iidxio-bio2 + +ldflags_iidxio-bio2 := \ + -lsetupapi \ + +libs_iidxio-bio2 := \ + aciodrv \ + bio2drv \ + cconfig \ + util \ + +src_iidxio-bio2 := \ + iidxio.c \ diff --git a/src/main/iidxio-bio2/iidxio-bio2.def b/src/main/iidxio-bio2/iidxio-bio2.def new file mode 100644 index 0000000..403900d --- /dev/null +++ b/src/main/iidxio-bio2/iidxio-bio2.def @@ -0,0 +1,18 @@ +LIBRARY iidxio + +EXPORTS + iidx_io_ep1_send + iidx_io_ep1_set_deck_lights + iidx_io_ep1_set_panel_lights + iidx_io_ep1_set_top_lamps + iidx_io_ep1_set_top_neons + iidx_io_ep2_get_keys + iidx_io_ep2_get_panel + iidx_io_ep2_get_sys + iidx_io_ep2_get_slider + iidx_io_ep2_get_turntable + iidx_io_ep2_recv + iidx_io_ep3_write_16seg + iidx_io_fini + iidx_io_init + iidx_io_set_loggers diff --git a/src/main/iidxio-bio2/iidxio.c b/src/main/iidxio-bio2/iidxio.c new file mode 100644 index 0000000..a0ed1cb --- /dev/null +++ b/src/main/iidxio-bio2/iidxio.c @@ -0,0 +1,344 @@ +#include + +#define LOG_MODULE "iidxio-bio2" + +#include +#include +#include +#include +#include + +#include "bemanitools/glue.h" +#include "bemanitools/iidxio.h" + +#include "cconfig/cconfig-main.h" + +#include "aciodrv/device.h" +#include "bio2drv/bi2a-iidx.h" +#include "bio2drv/config-bio2.h" +#include "bio2drv/detect.h" + +#define log_misc(...) iidx_io_log_misc(LOG_MODULE, __VA_ARGS__) +#define log_info(...) iidx_io_log_info(LOG_MODULE, __VA_ARGS__) +#define log_warning(...) iidx_io_log_warning(LOG_MODULE, __VA_ARGS__) +#define log_fatal(...) iidx_io_log_fatal(LOG_MODULE, __VA_ARGS__) + +static log_formatter_t iidx_io_log_misc; +static log_formatter_t iidx_io_log_info; +static log_formatter_t iidx_io_log_warning; +static log_formatter_t iidx_io_log_fatal; + +static char autodetect_buffer[512]; + +static atomic_bool running; +static atomic_bool processing_io; +static int16_t bio2_node_id; + +static struct bi2a_iidx_state_in pin_cur; +static struct bi2a_iidx_state_out pout_staging; +static struct bi2a_iidx_state_out pout_ready; + +static bool _bio2_iidx_io_poll( + const struct bi2a_iidx_state_out *pout, struct bi2a_iidx_state_in *pin) +{ + if (!running) { + return false; + } + + processing_io = true; + + if (!bio2drv_bi2a_iidx_poll(bio2_node_id, pout, pin)) { + processing_io = false; + return false; + } + + processing_io = false; + return true; +} + +void iidx_io_set_loggers( + log_formatter_t misc, + log_formatter_t info, + log_formatter_t warning, + log_formatter_t fatal) +{ + iidx_io_log_misc = misc; + iidx_io_log_info = info; + iidx_io_log_warning = warning; + iidx_io_log_fatal = fatal; + + bio2drv_set_loggers(misc, info, warning, fatal); +} + +bool iidx_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", + "iidxio-bio2.conf", + "--help", + "-h", + "iidxio-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_iidx_init(bio2_node_id)) { + log_warning("Unable to start BI2A on node: %d", bio2_node_id); + return false; + } + + running = true; + log_warning("iidxio-bio2 now running"); + } else { + log_warning("No bio2 device found"); + } + + return running; +} + +void iidx_io_fini(void) +{ + running = false; + + while (processing_io) { + // avoid banging + Sleep(1); + } +} + +void iidx_io_ep1_set_deck_lights(uint16_t deck_lights) +{ + for (uint8_t i = 0; i < sizeof(pout_staging.DECKSW); i++) { + pout_staging.DECKSW[i].l_state = (deck_lights & (1 << i)) > 0; + } +} + +void iidx_io_ep1_set_panel_lights(uint8_t panel_lights) +{ + pout_staging.PANEL[BI2A_IIDX_PANEL_BUTTON_START_P1].l_state = + (panel_lights & (1 << IIDX_IO_PANEL_P1_START)) > 0; + pout_staging.PANEL[BI2A_IIDX_PANEL_BUTTON_START_P2].l_state = + (panel_lights & (1 << IIDX_IO_PANEL_P2_START)) > 0; + pout_staging.PANEL[BI2A_IIDX_PANEL_BUTTON_VEFX].l_state = + (panel_lights & (1 << IIDX_IO_PANEL_VEFX)) > 0; + pout_staging.PANEL[BI2A_IIDX_PANEL_BUTTON_EFFECT].l_state = + (panel_lights & (1 << IIDX_IO_PANEL_EFFECT)) > 0; +} + +void iidx_io_ep1_set_top_lamps(uint8_t top_lamps) +{ + pout_staging.SPOTLIGHT1[BI2A_IIDX_SPOTLIGHT_RIGHT_RED].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_RIGHT_RED)) > 0; + pout_staging.SPOTLIGHT1[BI2A_IIDX_SPOTLIGHT_RIGHT_YELLOW].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_RIGHT_YELLOW)) > 0; + pout_staging.SPOTLIGHT1[BI2A_IIDX_SPOTLIGHT_RIGHT_GREEN].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_RIGHT_GREEN)) > 0; + pout_staging.SPOTLIGHT1[BI2A_IIDX_SPOTLIGHT_RIGHT_BLUE].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_RIGHT_BLUE)) > 0; + + pout_staging.SPOTLIGHT2[BI2A_IIDX_SPOTLIGHT_LEFT_RED].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_LEFT_RED)) > 0; + pout_staging.SPOTLIGHT2[BI2A_IIDX_SPOTLIGHT_LEFT_YELLOW].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_LEFT_YELLOW)) > 0; + pout_staging.SPOTLIGHT2[BI2A_IIDX_SPOTLIGHT_LEFT_GREEN].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_LEFT_GREEN)) > 0; + pout_staging.SPOTLIGHT2[BI2A_IIDX_SPOTLIGHT_LEFT_BLUE].l_state = + (top_lamps & (1 << IIDX_IO_TOP_LAMP_LEFT_BLUE)) > 0; +} + +void iidx_io_ep1_set_top_neons(bool top_neons) +{ + pout_staging.NEONLAMP.l_state = top_neons; +} + +bool iidx_io_ep1_send(void) +{ + memcpy(&pout_ready, &pout_staging, sizeof(struct bi2a_iidx_state_out)); + + return true; +} + +bool iidx_io_ep2_recv(void) +{ + if (!_bio2_iidx_io_poll(&pout_ready, &pin_cur)) { + return false; + } + + return true; +} + +uint8_t iidx_io_ep2_get_turntable(uint8_t player_no) +{ + switch (player_no) { + case 0: + return pin_cur.TURNTABLE1; + case 1: + return pin_cur.TURNTABLE2; + default: + return 0; + } +} + +uint8_t iidx_io_ep2_get_slider(uint8_t slider_no) +{ + switch (slider_no) { + case 0: + return pin_cur.SLIDER1.s_val & 0xF; + case 1: + return pin_cur.SLIDER2.s_val & 0xF; + case 2: + return pin_cur.SLIDER3.s_val & 0xF; + case 3: + return pin_cur.SLIDER4.s_val & 0xF; + case 4: + return pin_cur.SLIDER5.s_val & 0xF; + default: + return 0; + } +} + +uint8_t iidx_io_ep2_get_sys(void) +{ + uint8_t state; + + state = 0; + + if (pin_cur.SYSTEM.v_test) { + state |= (1 << IIDX_IO_SYS_TEST); + } + + if (pin_cur.SYSTEM.v_service) { + state |= (1 << IIDX_IO_SYS_SERVICE); + } + + if (pin_cur.SYSTEM.v_coin) { + state |= (1 << IIDX_IO_SYS_COIN); + } + + return state; +} + +uint8_t iidx_io_ep2_get_panel(void) +{ + uint8_t state; + + state = 0; + + if (pin_cur.PANEL.y_start1) { + state |= (1 << IIDX_IO_PANEL_P1_START); + } + + if (pin_cur.PANEL.y_start2) { + state |= (1 << IIDX_IO_PANEL_P2_START); + } + + if (pin_cur.PANEL.y_vefx) { + state |= (1 << IIDX_IO_PANEL_VEFX); + } + + if (pin_cur.PANEL.y_effect) { + state |= (1 << IIDX_IO_PANEL_EFFECT); + } + + return state; +} + +uint16_t iidx_io_ep2_get_keys(void) +{ + uint16_t state; + + state = 0; + + state |= ((pin_cur.P1SW1.b_val > 0) << IIDX_IO_KEY_P1_1); + state |= ((pin_cur.P1SW2.b_val > 0) << IIDX_IO_KEY_P1_2); + state |= ((pin_cur.P1SW3.b_val > 0) << IIDX_IO_KEY_P1_3); + state |= ((pin_cur.P1SW4.b_val > 0) << IIDX_IO_KEY_P1_4); + state |= ((pin_cur.P1SW5.b_val > 0) << IIDX_IO_KEY_P1_5); + state |= ((pin_cur.P1SW6.b_val > 0) << IIDX_IO_KEY_P1_6); + state |= ((pin_cur.P1SW7.b_val > 0) << IIDX_IO_KEY_P1_7); + + state |= ((pin_cur.P2SW1.b_val > 0) << IIDX_IO_KEY_P2_1); + state |= ((pin_cur.P2SW2.b_val > 0) << IIDX_IO_KEY_P2_2); + state |= ((pin_cur.P2SW3.b_val > 0) << IIDX_IO_KEY_P2_3); + state |= ((pin_cur.P2SW4.b_val > 0) << IIDX_IO_KEY_P2_4); + state |= ((pin_cur.P2SW5.b_val > 0) << IIDX_IO_KEY_P2_5); + state |= ((pin_cur.P2SW6.b_val > 0) << IIDX_IO_KEY_P2_6); + state |= ((pin_cur.P2SW7.b_val > 0) << IIDX_IO_KEY_P2_7); + + return state; +} + +bool iidx_io_ep3_write_16seg(const char *text) +{ + memcpy(pout_staging.SEG16, text, sizeof(pout_staging.SEG16)); + + return true; +}