254 lines
8.1 KiB
C++
254 lines
8.1 KiB
C++
|
#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<uint8_t> *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<uint8_t *>(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<const uint8_t *>(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;
|
||
|
}
|