Compare commits

..

No commits in common. "develop" and "develop" have entirely different histories.

120 changed files with 1069 additions and 6368 deletions

3
.gitignore vendored
View File

@ -18,6 +18,3 @@ build/
# External dependencies
subprojects/capnhook
# For enabling debug logging on local builds
MesonLocalOptions.mk

View File

@ -11,11 +11,6 @@ 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
# -----------------------------------------------------------------------------
@ -24,9 +19,9 @@ include Package.mk
.PHONY: build # Build the project
build:
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-32.txt $(BUILD_DIR_32)
$(V)meson --cross cross-mingw-32.txt $(BUILD_DIR_32)
$(V)ninja -C $(BUILD_DIR_32)
$(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-64.txt $(BUILD_DIR_64)
$(V)meson --cross cross-mingw-64.txt $(BUILD_DIR_64)
$(V)ninja -C $(BUILD_DIR_64)
.PHONY: dist # Build and create a zip distribution package

View File

@ -203,22 +203,6 @@ $(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 \
@ -241,7 +225,6 @@ $(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 \

View File

@ -1,33 +1,31 @@
# Segatools
Version: `2024-08-20`
Version: `2024-03-13`
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
* maimai DX
* starting from maimai DX
* Mario & Sonic
* Mario & Sonic at the Tokyo 2020 Olympics Arcade
* O.N.G.E.K.I.
* starting from O.N.G.E.K.I.
* 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
* WACCA
* starting from WACCA

View File

@ -185,14 +185,14 @@ static HRESULT jvs_ioctl_sense(struct irp *irp)
static HRESULT jvs_ioctl_transact(struct irp *irp)
{
#if defined(LOG_JVS)
#if 0
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 defined(LOG_JVS)
#if 0
dprintf("JVS Port: Inbound frame:\n");
dump_iobuf(&irp->read);
dprintf("\n");

View File

@ -90,6 +90,4 @@ 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->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename);
}

View File

@ -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 defined(LOG_IO3)
#if 0
dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n",
req.num_players,
req.bytes_per_player);

View File

@ -1,81 +0,0 @@
#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;
};

View File

@ -1,194 +0,0 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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;
}

View File

@ -1,26 +0,0 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#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);

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
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);

View File

@ -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 defined(LOG_LED15093)
#if 0
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 defined(LOG_LED15093)
#if 0
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;
// }

View File

@ -25,11 +25,6 @@ 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',
@ -47,8 +42,5 @@ board_lib = static_library(
'slider-frame.h',
'vfd.c',
'vfd.h',
'vfd-cmd.h',
'vfd-frame.c',
'vfd-frame.h',
],
)

View File

@ -5,21 +5,19 @@
#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_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,
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,
};
struct sg_nfc_res_get_fw_version {
@ -34,7 +32,7 @@ struct sg_nfc_res_get_hw_version {
struct sg_nfc_req_mifare_set_key {
struct sg_req_header req;
uint8_t key[6];
uint8_t key_a[6];
};
struct sg_nfc_req_mifare_50 {

View File

@ -60,11 +60,6 @@ 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,
@ -190,15 +185,12 @@ 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_TO_UPDATE_MODE:
case SG_NFC_CMD_SEND_HEX_DATA: // TODO: implement?
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default:
@ -428,7 +420,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
f_res.nbytes = sizeof(res->payload);
f_res.pos = 1;
#if defined(LOG_NFC)
#if 0
dprintf("FELICA OUTBOUND:\n");
dump_const_iobuf(&f_req);
#endif
@ -442,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 defined(LOG_NFC)
#if 0
dprintf("FELICA INBOUND:\n");
dump_iobuf(&f_res);
#endif
@ -450,22 +442,6 @@ 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,

View File

@ -115,14 +115,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
{
HRESULT hr;
#if defined(LOG_NFC)
#if 0
if (irp->op == IRP_OP_WRITE) {
dprintf("WRITE:\n");
dump_const_iobuf(&irp->write);
}
#endif
#if defined(LOG_NFC)
#if 0
if (irp->op == IRP_OP_READ) {
dprintf("READ:\n");
dump_iobuf(&sg_reader_uart.readable);

View File

@ -1,123 +0,0 @@
#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];
};

View File

@ -1,88 +0,0 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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;
}

View File

@ -1,20 +0,0 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#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);

View File

@ -2,16 +2,17 @@
directly by amdaemon, and it has something to do with displaying the status
of electronic payments.
Part number in schematics is "VFD GP1232A02A FUTABA". */
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. */
#include <windows.h>
#include <assert.h>
#include <stdint.h>
#include "board/config.h"
#include "board/vfd.h"
#include "board/vfd-cmd.h"
#include "hook/iohook.h"
@ -20,101 +21,33 @@
#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[4096];
static uint8_t vfd_readable[4096];
static uint8_t vfd_written[512];
static uint8_t vfd_readable[512];
UINT codepage;
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, int default_port)
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
{
if (!cfg->enable){
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
utf_enabled = cfg->utf_conversion;
int port = cfg->port;
if (port == 0){
port = default_port;
}
dprintf("VFD: enabling (port=%d)\n", port);
uart_init(&vfd_uart, port);
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);
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;
@ -125,274 +58,67 @@ 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;
}
#if SUPER_VERBOSE
dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written);
#endif
struct const_iobuf reader;
iobuf_flip(&reader, &vfd_uart.written);
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;
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 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;
else if (cmd == 0x50) {
i++;
}
continue;
}
if (!SUCCEEDED(hr)){
return hr;
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;
}
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;
}

View File

@ -4,10 +4,7 @@
struct vfd_config {
bool enable;
int port;
bool utf_conversion;
};
HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port);
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no);

View File

@ -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 defined(LOG_CAROL_CONTROL_BD)
#if 0
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 defined(LOG_CAROL_CONTROL_BD)
#if 0
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;

View File

@ -1,31 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>

View File

@ -94,7 +94,7 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp)
}
for (;;) {
#if defined(LOG_CAROL_LED_BD)
#if 0
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;
}
}

View File

@ -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 defined(LOG_CAROL_TOUCH)
#if 0
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 defined(LOG_CAROL_TOUCH)
#if 0
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
dump_iobuf(&touch_uart.readable);
#endif

View File

@ -1,15 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>

View File

@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
}
for (;;) {
#if defined(LOG_CHUNI_SLIDER)
#if 0
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 defined(LOG_CHUNI_SLIDER)
#if 0
dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf);
#endif

View File

@ -139,10 +139,9 @@ 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, 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.
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.
Minimum API version: 0x0100 */

View File

@ -63,8 +63,6 @@ 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(

View File

@ -18,8 +18,6 @@ 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;

View File

@ -127,11 +127,7 @@ void led_output_update(uint8_t board, const byte* rgb)
if (config->controller_led_output_serial)
{
if (config->controller_led_output_openithm){
led_serial_update_openithm(rgb);
} else {
led_serial_update(escaped_data);
}
led_serial_update(escaped_data);
}
}
}

View File

@ -4,7 +4,6 @@ chuniio_lib = static_library(
include_directories : inc,
implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [
'chu2to3.c',
'chu2to3.h',

View File

@ -97,27 +97,3 @@ 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);
}
}

View File

@ -13,4 +13,3 @@
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);

View File

@ -1,27 +1,3 @@
/*
"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 <windows.h>
#include <stddef.h>
@ -123,7 +99,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
goto fail;
}
bool *dipsw = &chusan_hook_cfg.platform.system.dipsw[0];
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0];
bool is_cvt = dipsw[2];
for (int i = 0; i < 3; i++) {

View File

@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
}
for (;;) {
#if defined(LOG_CHUSAN_SLIDER)
#if 0
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 defined(LOG_CHUSAN_SLIDER)
#if 0
dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf);
#endif

View File

@ -15,59 +15,3 @@ 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

View File

@ -39,7 +39,6 @@ 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);
}

View File

@ -6,7 +6,6 @@
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "cmhook/cm-dll.h"
@ -22,7 +21,6 @@ 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;
};

View File

@ -1,16 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>
@ -56,10 +43,6 @@ 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, 0, cm_hook_mod);
/* Initialize emulation hooks */
hr = platform_hook_init(
@ -72,12 +55,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 = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod);
if (FAILED(hr)) {
@ -90,6 +67,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 = cm_io4_hook_init(&cm_hook_cfg.io4);
if (FAILED(hr)) {

View File

@ -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);
void cm_io_get_opbtns(uint8_t *opbtn);

View File

@ -82,12 +82,10 @@ 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 (set to 115200 if using OpeNITHM)
; Baud rate for serial data
;serialBaud=921600
; Data output a sequence of bytes, with JVS-like framing.

View File

@ -25,7 +25,7 @@ aimePath=DEVICE\aime.txt
;highBaud=1
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -43,7 +43,6 @@ 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`).
@ -59,8 +58,8 @@ addrSuffix=11
; that subnet must start with 192.168.
subnet=192.168.139.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
@ -108,12 +107,10 @@ 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 (set to 115200 if using OpeNITHM)
; Baud rate for serial data
;serialBaud=921600
; Data output a sequence of bytes, with JVS-like framing.
@ -204,3 +201,7 @@ ir=0x20
; ... etc ...
;cell31=0x53
;cell32=0x53
; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol.
; eg. COM5
;ledport=

16
dist/cm/segatools.ini vendored
View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -50,10 +50,10 @@ 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.165.0
subnet=192.168.100.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; LAN Install: If multiple machines are present on the same LAN then set
@ -73,14 +73,6 @@ 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
; -----------------------------------------------------------------------------

View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -72,8 +72,8 @@ addrSuffix=11
; that subnet must start with 192.168.
subnet=192.168.167.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to

View File

@ -54,8 +54,8 @@ subnet=192.168.158.0
; 1: JPN: Japan, 4: EXP: Export (for Asian markets)
region=4
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
@ -75,25 +75,6 @@ dipsw3=0
dipsw4=0
dipsw5=0
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
[led15070]
; 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
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------

View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -56,8 +56,8 @@ addrSuffix=11
; that subnet must start with 192.168.
subnet=192.168.172.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to

View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -56,8 +56,8 @@ addrSuffix=11
; that subnet must start with 192.168.
subnet=192.168.174.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to

View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -52,8 +52,8 @@ enable=1
; that subnet must start with 192.168.
subnet=192.168.162.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
@ -190,7 +190,7 @@ leftSide=0x01 ; Mouse Left
rightSide=0x02 ; Mouse Right
right1=0x4A ; J
right2=0x4B ; K
right1=0x4B ; K
right3=0x4C ; L
leftMenu=0x55 ; U

View File

@ -23,7 +23,7 @@ enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation. Disable to use a real VFD
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
@ -56,8 +56,8 @@ addrSuffix=11
; in order to find the MAIN cabinet.
subnet=192.168.160.0
[system]
; Enable ALLS system settings.
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to

View File

@ -1,9 +0,0 @@
{
"network" :
{
"property" :
{
"dhcp" : true
}
}
}

View File

@ -1,199 +0,0 @@
; -----------------------------------------------------------------------------
; 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

57
dist/tokyo/start.bat vendored
View File

@ -1,57 +0,0 @@
@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

View File

@ -1,14 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>

View File

@ -99,7 +99,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
}
for (;;) {
#if defined(LOG_DIVA_SLIDER)
#if 0
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 defined(LOG_DIVA_SLIDER)
#if 0
dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf);
#endif

View File

@ -92,21 +92,9 @@ Controls emulation of the VFD GP1232A02A FUTABA assembly.
Default: `1`
Enable VFD emulation. Disable to use a real VFD
Enable VFD emulation (currently just stubbed). 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
@ -364,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: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
pattern: `A6xE-01Ayyyyyyyy`.
### `gameId`

View File

@ -1,20 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>

View File

@ -52,12 +52,16 @@ 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: this contains bit mask definitions for button
states returned in *gamebtn. All buttons are active-high.
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 *gamebtn);
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.

View File

@ -224,19 +224,9 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice(
gfx_util_frame_window(hwnd);
}
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);
}
dprintf("Gfx: Using adapter %d\n", gfx_config.monitor);
return IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev);
return IDirect3D9_CreateDevice(real, gfx_config.monitor, type, hwnd, flags, pp, pdev);
}
static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice(

File diff suppressed because it is too large Load Diff

View File

@ -14,4 +14,3 @@ 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);

View File

@ -13,43 +13,6 @@
#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)
@ -66,16 +29,6 @@ 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)
@ -89,8 +42,6 @@ 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);
indrun_config_load(&cfg->indrun, filename);
}
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)

View File

@ -4,13 +4,11 @@
#include <stddef.h>
#include "board/config.h"
#include "board/led15070.h"
#include "hooklib/dvd.h"
#include "idachook/idac-dll.h"
#include "idachook/zinput.h"
#include "idachook/indrun.h"
#include "platform/platform.h"
@ -21,8 +19,6 @@ struct idac_hook_config {
struct io4_config io4;
struct idac_dll_config dll;
struct zinput_config zinput;
struct led15070_config led15070;
struct indrun_config indrun;
};
void idac_dll_config_load(
@ -33,10 +29,4 @@ 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 indrun_config_load(
struct indrun_config *cfg,
const wchar_t *filename);
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename);

View File

@ -1,16 +1,3 @@
/*
"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 <windows.h>
#include <shlwapi.h>
@ -66,13 +53,13 @@ static DWORD CALLBACK idac_pre_startup(void)
goto fail;
}
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
if (FAILED(hr)) {
goto fail;
@ -84,20 +71,6 @@ static DWORD CALLBACK idac_pre_startup(void)
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 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");

View File

@ -24,18 +24,6 @@ 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),
}
};

View File

@ -11,10 +11,6 @@ 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 {

View File

@ -17,7 +17,3 @@ 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

View File

@ -1,260 +0,0 @@
#include <assert.h>
#include <stdbool.h>
#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;
}

View File

@ -1,9 +0,0 @@
#pragma once
#include <windows.h>
struct indrun_config {
bool enable;
};
void indrun_hook_init(struct indrun_config *cfg);

View File

@ -11,12 +11,10 @@
#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[] = {
@ -130,34 +128,3 @@ 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;
}

View File

@ -28,7 +28,5 @@ shared_library(
'io4.h',
'zinput.c',
'zinput.h',
'indrun.c',
'indrun.h',
],
)

View File

@ -19,7 +19,7 @@ static bool idac_io_coin;
uint16_t idac_io_get_api_version(void)
{
return 0x0101;
return 0x0100;
}
HRESULT idac_io_init(void)
@ -118,44 +118,3 @@ 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;
}

View File

@ -6,7 +6,3 @@ 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

View File

@ -19,17 +19,6 @@ 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.
@ -103,60 +92,4 @@ void idac_io_get_analogs(struct idac_io_analog_state *out);
Minimum API version: 0x0100 */
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);
void idac_io_get_shifter(uint8_t *gear);

View File

@ -1,14 +1,3 @@
/*
"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 <windows.h>
#include <shlwapi.h>

View File

@ -46,7 +46,7 @@ void jvs_crack_request(
return;
}
#if defined(LOG_JVS)
#if 0
dprintf("Decoded request:\n");
dump_iobuf(&decode);
#endif
@ -96,7 +96,7 @@ void jvs_crack_request(
resp_bytes[2] = 0x01; /* Status: Success */
}
#if defined(LOG_JVS)
#if 0
dprintf("Encoding response:\n");
dump_iobuf(&encode);
#endif

View File

@ -1,22 +1,3 @@
/*
"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 <windows.h>
#include "board/io4.h"
@ -24,8 +5,6 @@
#include "board/vfd.h"
#include "hook/process.h"
#include "hook/table.h"
#include "hook/iohook.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"

View File

@ -1,16 +1,3 @@
/*
"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 <windows.h>
#include "board/io4.h"

View File

@ -130,7 +130,7 @@ static HRESULT touch0_handle_irp_locked(struct irp *irp)
}
for (;;) {
#if defined(LOG_MERCURY_SLIDER)
#if 0
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 defined(LOG_MERCURY_SLIDER)
#if 0
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 defined(LOG_MERCURY_SLIDER)
#if 0
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 defined(LOG_MERCURY_SLIDER)
#if 0
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 defined(LOG_MERCURY_SLIDER)
#if 0
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));

View File

@ -39,43 +39,6 @@ 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')
@ -108,7 +71,6 @@ subdir('mai2io')
subdir('cmio')
subdir('mercuryio')
subdir('cxbio')
subdir('tokyoio')
subdir('fgoio')
subdir('chunihook')
@ -124,5 +86,4 @@ subdir('mai2hook')
subdir('cmhook')
subdir('mercuryhook')
subdir('cxbhook')
subdir('tokyohook')
subdir('fgohook')

View File

@ -1,65 +0,0 @@
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'
)

View File

@ -1,15 +1,3 @@
/*
"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 <windows.h>
#include <stdlib.h>

View File

@ -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 process as a sub one.
to use the amdaemon process as the main one and the mu3 call as a sub one.
Minimum API version: 0x0101 */

View File

@ -4,7 +4,6 @@
#include <stdint.h>
#include "hook/table.h"
#include "hook/procaddr.h"
#include "platform/clock.h"
@ -20,9 +19,7 @@ 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[] = {
{
@ -161,7 +158,7 @@ static BOOL WINAPI my_GetSystemTime(SYSTEMTIME *out)
return ok;
}
#if defined(LOG_CLOCK)
#if 0
static int last_second;
if (out->wSecond != last_second) {
@ -228,41 +225,35 @@ 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;
clock_hook_insert_hooks(NULL);
return S_OK;
}
void clock_hook_insert_hooks(HMODULE target) {
if (clock_timezone || clock_time_warp || !clock_writeable) {
if (cfg->timezone || cfg->timewarp || !cfg->writeable) {
/* All the clock hooks require the core GSTAFT hook to be installed */
/* Note the ! up there btw. */
hook_table_apply(
target,
NULL,
"kernel32.dll",
clock_base_hook_syms,
_countof(clock_base_hook_syms));
}
if (clock_timezone) {
if (cfg->timezone) {
hook_table_apply(
target,
NULL,
"kernel32.dll",
clock_read_hook_syms,
_countof(clock_read_hook_syms));
}
if (!clock_writeable) {
if (!cfg->writeable) {
/* Install hook if this config parameter is FALSE! */
hook_table_apply(
target,
NULL,
"kernel32.dll",
clock_write_hook_syms,
_countof(clock_write_hook_syms));
}
return S_OK;
}

View File

@ -11,4 +11,3 @@ struct clock_config {
};
HRESULT clock_hook_init(const struct clock_config *cfg);
void clock_hook_insert_hooks(HMODULE target);

View File

@ -22,7 +22,7 @@
#include "platform/pcbid.h"
#include "platform/platform.h"
#include "platform/vfs.h"
#include "platform/system.h"
#include "platform/dipsw.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);
system_config_load(&cfg->system, filename);
dipsw_config_load(&cfg->dipsw, 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 system_config_load(struct system_config *cfg, const wchar_t *filename)
void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename)
{
wchar_t name[7];
size_t i;
@ -337,14 +337,14 @@ void system_config_load(struct system_config *cfg, const wchar_t *filename)
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"system", L"enable", 0, filename);
cfg->freeplay = GetPrivateProfileIntW(L"system", L"freeplay", 0, filename);
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");
for (i = 0 ; i < 8 ; i++) {
name[5] = L'1' + i;
cfg->dipsw[i] = GetPrivateProfileIntW(L"system", name, 0, filename);
cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename);
}
}

View File

@ -18,7 +18,7 @@
#include "platform/pcbid.h"
#include "platform/platform.h"
#include "platform/vfs.h"
#include "platform/system.h"
#include "platform/dipsw.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 system_config_load(struct system_config *cfg, const wchar_t *filename);
void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename);

View File

@ -4,7 +4,7 @@
#include <assert.h>
#include <string.h>
#include "platform/system.h"
#include "platform/dipsw.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];
} DipSwBlock;
} DipSwitchBlock;
typedef struct
{
CreditBlock credit_block;
DipSwBlock dip_switch_block;
DipSwitchBlock dip_switch_block;
char *data;
} SystemInfo;
@ -43,13 +43,13 @@ typedef struct
static SystemInfo system_info;
static struct system_config system_config;
static struct dipsw_config dipsw_config;
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);
static void dipsw_read_sysfile(const wchar_t *sys_file);
static void dipsw_save_sysfile(const wchar_t *sys_file);
HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg)
HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg)
{
HRESULT hr;
wchar_t sys_file_path[MAX_PATH];
@ -62,28 +62,28 @@ HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vf
return S_FALSE;
}
memcpy(&system_config, cfg, sizeof(*cfg));
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);
system_read_sysfile(sys_file_path);
dipsw_read_sysfile(sys_file_path);
// now write the system_config.system to the dip_switch_block
system_save_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 system_read_sysfile(const wchar_t *sys_file)
static void dipsw_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");
dprintf("DipSw: First run detected, DipSw settings can only be applied AFTER the first run\n");
return;
}
@ -93,7 +93,7 @@ static void system_read_sysfile(const wchar_t *sys_file)
if (file_size != 0x6000)
{
dprintf("System: Invalid sysfile.dat file size\n");
dprintf("DipSw: Invalid sysfile.dat file size\n");
fclose(f);
return;
@ -108,10 +108,10 @@ static void system_read_sysfile(const wchar_t *sys_file)
memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE);
}
static void system_save_sysfile(const wchar_t *sys_file)
static void dipsw_save_sysfile(const wchar_t *sys_file)
{
char block[BLOCK_SIZE];
uint8_t system = 0;
uint8_t dipsw = 0;
uint8_t freeplay = 0;
// open the sysfile.dat for writing in bytes mode
@ -122,28 +122,28 @@ static void system_save_sysfile(const wchar_t *sys_file)
return;
}
// write the system_config.system to the dip_switch_block
// write the dipsw_config.dipsw to the dip_switch_block
for (int i = 0; i < 8; i++)
{
if (system_config.dipsw[i])
if (dipsw_config.dipsw[i])
{
// print which system is enabled
dprintf("System: DipSw%d=1 set\n", i + 1);
system |= (1 << i);
// print which dipsw is enabled
dprintf("DipSw: DipSw%d=1 set\n", i + 1);
dipsw |= (1 << i);
}
}
if (system_config.freeplay)
if (dipsw_config.freeplay)
{
// print that freeplay is enabled
dprintf("System: Freeplay enabled\n");
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 = system;
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
@ -167,7 +167,7 @@ static void system_save_sysfile(const wchar_t *sys_file)
// print the dip_switch_block in hex
/*
dprintf("System Block: ");
dprintf("DipSw Block: ");
for (size_t i = 0; i < BLOCK_SIZE; i++)
{
dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]);

View File

@ -7,10 +7,10 @@
#include "platform/vfs.h"
struct system_config {
struct dipsw_config {
bool enable;
bool freeplay;
bool dipsw[8];
};
HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg);
HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg);

View File

@ -109,23 +109,17 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
return hr;
}
// WAHLAP PowerOn
// CHN
// PowerOn
hr = dns_hook_push(L"at.sys-all.cn", cfg->startup);
if (FAILED(hr)) {
return hr;
}
// WAHLAP WeChat AimeDB Server
// 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;
}

View File

@ -34,7 +34,7 @@ platform_lib = static_library(
'platform.h',
'vfs.c',
'vfs.h',
'system.c',
'system.h',
'dipsw.c',
'dipsw.h',
],
)

View File

@ -13,7 +13,7 @@
#include "platform/pcbid.h"
#include "platform/platform.h"
#include "platform/vfs.h"
#include "platform/system.h"
#include "platform/dipsw.h"
HRESULT platform_hook_init(
const struct platform_config *cfg,
@ -76,13 +76,13 @@ HRESULT platform_hook_init(
return hr;
}
hr = vfs_hook_init(&cfg->vfs, game_id);
hr = vfs_hook_init(&cfg->vfs);
if (FAILED(hr)) {
return hr;
}
hr = system_init(&cfg->system, &cfg->vfs);
hr = dipsw_init(&cfg->dipsw, &cfg->vfs);
if (FAILED(hr)) {
return hr;

View File

@ -13,7 +13,7 @@
#include "platform/nusec.h"
#include "platform/pcbid.h"
#include "platform/vfs.h"
#include "platform/system.h"
#include "platform/dipsw.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 system_config system;
struct dipsw_config dipsw;
};
HRESULT platform_hook_init(

View File

@ -9,9 +9,6 @@
#include "hooklib/path.h"
#include "hooklib/reg.h"
#include "hook/procaddr.h"
#include "hook/table.h"
#include "platform/vfs.h"
#include "util/dprintf.h"
@ -34,26 +31,6 @@ 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;
@ -78,7 +55,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, const char* game_id)
HRESULT vfs_hook_init(const struct vfs_config *config)
{
wchar_t temp[MAX_PATH];
size_t nthome_len;
@ -91,8 +68,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
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");
@ -200,13 +175,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
return hr;
}
proc_addr_table_push(
NULL,
"amdaemon_api.dll",
amdaemon_syms,
_countof(amdaemon_syms)
);
return S_OK;
}
@ -319,6 +287,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;
@ -509,21 +479,3 @@ 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;
}

View File

@ -12,4 +12,4 @@ struct vfs_config {
wchar_t option[MAX_PATH];
};
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id);
HRESULT vfs_hook_init(const struct vfs_config *config);

456
segatools.md Normal file
View File

@ -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: `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.

View File

@ -1,18 +1,3 @@
/*
"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 <windows.h>
#include <shlwapi.h>

View File

@ -1,110 +0,0 @@
#include <assert.h>
#include <stddef.h>
#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);
}

View File

@ -1,30 +0,0 @@
#pragma once
#include <stddef.h>
#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);

Some files were not shown because too many files have changed in this diff Show More