#include "bi2x.h" #include "misc/eamuse.h" #include "rawinput/rawinput.h" #include "util/utils.h" #include "iidx.h" #include "io.h" using namespace acioemu; games::iidx::BI2XSerialHandle::BI2XDevice::BI2XDevice() { this->node_count = 1; } bool games::iidx::BI2XSerialHandle::BI2XDevice::parse_msg( MessageData *msg_in, circular_buffer *response_buffer ) { #ifdef ACIOEMU_LOG log_info("iidx", "BI2X ADDR: {}, CMD: 0x{:04x}", msg_in->addr, msg_in->cmd.code); #endif // check command switch (msg_in->cmd.code) { case ACIO_CMD_GET_VERSION: { // send version data auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE); this->set_version(msg, 0x03, 0, 4, 2, 0, "BI2X"); write_msg(msg, response_buffer); delete msg; break; } case 0x0153: if (DISABLE_ESPEC_IO) { return false; } [[fallthrough]]; // to 0x0152 case 0x0152: { // STATUS // check input data length if (msg_in->cmd.data_size == 0x30) { // LED TICKER IIDX_LED_TICKER_LOCK.lock(); if (!IIDXIO_LED_TICKER_READONLY) memcpy(IIDXIO_LED_TICKER, &msg_in->cmd.raw[0x17], 9); IIDX_LED_TICKER_LOCK.unlock(); // NEON LIGHT bool neon_light = msg_in->cmd.raw[0x24] != 0; write_top_neon(neon_light ? (uint8_t) 0xFF : (uint8_t) 0); // SPOT LIGHT uint8_t spot_light_bits = 0; for (size_t i = 0; i < 8; i++) { auto index = i > 3 ? i + 1 : i; if (msg_in->cmd.raw[0x20 + index] != 0) spot_light_bits |= 1 << i; } write_top_lamp(spot_light_bits); // SWLED (DECK) uint16_t lamp_bits = 0; for (size_t i = 0; i < 14; i++) { if (msg_in->cmd.raw[0x07 + i] != 0) lamp_bits |= 1 << i; } write_lamp(lamp_bits); // SWLED (PANEL) uint8_t led_bits = 0; for (size_t i = 0; i < 4; i++) { if (msg_in->cmd.raw[0x03 + i] != 0) led_bits |= 1 << i; } write_led(led_bits); // flush device output RI_MGR->devices_flush_output(); } // sleep - otherwise the IO thread will go too hard on the CPU Sleep(1); // generate message auto msg = this->create_msg(msg_in, 0x2E); // get buttons auto &buttons = get_buttons(); // player 1 buttons if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_1))) ARRAY_SETB(msg->cmd.raw, 151); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_2))) ARRAY_SETB(msg->cmd.raw, 167); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_3))) ARRAY_SETB(msg->cmd.raw, 183); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_4))) ARRAY_SETB(msg->cmd.raw, 199); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_5))) ARRAY_SETB(msg->cmd.raw, 215); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_6))) ARRAY_SETB(msg->cmd.raw, 231); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_7))) ARRAY_SETB(msg->cmd.raw, 247); // player 2 buttons if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_1))) ARRAY_SETB(msg->cmd.raw, 263); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_2))) ARRAY_SETB(msg->cmd.raw, 279); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_3))) ARRAY_SETB(msg->cmd.raw, 295); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_4))) ARRAY_SETB(msg->cmd.raw, 311); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_5))) ARRAY_SETB(msg->cmd.raw, 327); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_6))) ARRAY_SETB(msg->cmd.raw, 343); if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_7))) ARRAY_SETB(msg->cmd.raw, 359); // player 1 start if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_Start))) ARRAY_SETB(msg->cmd.raw, 79); // player 2 start if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_Start))) ARRAY_SETB(msg->cmd.raw, 78); // VEFX if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::VEFX))) ARRAY_SETB(msg->cmd.raw, 77); // EFFECT if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Effect))) ARRAY_SETB(msg->cmd.raw, 76); // service if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service))) ARRAY_SETB(msg->cmd.raw, 10); // test if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test))) ARRAY_SETB(msg->cmd.raw, 11); // turntables msg->cmd.raw[16] = get_tt(0, true); msg->cmd.raw[17] = get_tt(1, true); // slider msg->cmd.raw[0] |= get_slider(0) << 4; msg->cmd.raw[2] |= get_slider(1) << 4; msg->cmd.raw[4] |= get_slider(2) << 4; msg->cmd.raw[6] |= get_slider(3) << 4; msg->cmd.raw[7] |= get_slider(4) << 4; // coin this->coin_counter += eamuse_coin_consume_stock(); msg->cmd.raw[8] |= this->coin_counter; /* * TODO * bit 9 appears to be the coin mech */ // write message write_msg(msg, response_buffer); delete msg; break; } case ACIO_CMD_CLEAR: case ACIO_CMD_STARTUP: case 0x0120: // WD COMMAND case 0xFF: // BROADCAST { // send status 0 auto msg = this->create_msg_status(msg_in, 0); write_msg(msg, response_buffer); delete msg; break; } default: return false; } // mark as handled return true; } bool games::iidx::BI2XSerialHandle::open(LPCWSTR lpFileName) { if (wcscmp(lpFileName, L"COM3") != 0) { return false; } log_info("iidx", "Opened COM3 (BIO2)"); // ACIO device //acio_emu.add_device(new FMSerialDevice()); return true; } int games::iidx::BI2XSerialHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) { //auto buffer = reinterpret_cast(lpBuffer); // read from emu /* DWORD bytes_read = 0; while (bytes_read < nNumberOfBytesToRead) { auto cur_byte = acio_emu.read(); if (cur_byte.has_value()) { buffer[bytes_read++] = cur_byte.value(); } else { break; } } */ // return amount of bytes read //return (int) bytes_read; return (int) nNumberOfBytesToRead; } int games::iidx::BI2XSerialHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) { auto buffer = reinterpret_cast(lpBuffer); log_info("iidx", "BIO2 Data: {}", bin2hex(buffer, nNumberOfBytesToWrite)); // write to emu /* for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) { acio_emu.write(buffer[i]); } */ // return all data written return (int) nNumberOfBytesToWrite; } int games::iidx::BI2XSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize) { return -1; } bool games::iidx::BI2XSerialHandle::close() { log_info("iidx", "Closed COM3 (BIO2)"); return true; }