Merge branch 'feature/mai2-touch-led' into develop

pull/60/head
Dniel97 2025-03-02 00:04:00 +01:00
commit b8af67377c
No known key found for this signature in database
GPG Key ID: DE105D481972329C
54 changed files with 1056 additions and 247 deletions

View File

@ -103,19 +103,30 @@ HRESULT led15070_hook_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)
unsigned int port_no[2])
{
unsigned int num_boards = 0;
assert(cfg != NULL);
assert(_led_init != NULL);
if (!cfg->enable) {
return S_FALSE;
}
if (cfg->port_no != 0) {
first_port = cfg->port_no;
for (int i = 0; i < led15070_nboards; i++)
{
if (cfg->port_no[i] != 0) {
port_no[i] = cfg->port_no[i];
}
if (port_no[i] != 0) {
num_boards++;
}
}
assert(num_boards != 0);
led_init = _led_init;
led_set_fet_output = _led_set_fet_output;
led_dc_update = _led_dc_update;
@ -131,10 +142,7 @@ HRESULT led15070_hook_init(
InitializeCriticalSection(&v->lock);
// TODO: IMPROVE!
first_port = i == 1 ? first_port + 2 : first_port;
uart_init(&v->boarduart, first_port);
uart_init(&v->boarduart, port_no[i]);
v->boarduart.baud.BaudRate = 115200;
v->boarduart.written.bytes = v->written_bytes;
v->boarduart.written.nbytes = sizeof(v->written_bytes);
@ -238,7 +246,7 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp)
}
for (;;) {
#if 0
#if defined(LOG_LED15070)
dprintf("TX Buffer:\n");
dump_iobuf(&boarduart->written);
#endif
@ -257,7 +265,7 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp)
return hr;
}
#if 0
#if defined(LOG_LED15070)
dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf);
#endif
@ -385,7 +393,9 @@ static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req)
static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set input (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -408,9 +418,10 @@ static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *
static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req)
{
uint8_t idx = req->payload[0];
#if defined(LOG_LED15070)
dprintf("LED 15070: Set LED - Normal 12bit (board %u, index %u)\n",
board, idx);
#endif
// TODO: Data for this command. Seen with Carol
@ -435,9 +446,10 @@ static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_re
static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req)
{
uint8_t idx = req->payload[0];
// dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n",
// board, idx);
#if defined(LOG_LED15070)
dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n",
board, idx);
#endif
led15070_per_board_vars[board].gs[idx][0] = req->payload[1]; // R
led15070_per_board_vars[board].gs[idx][1] = req->payload[2]; // G
@ -468,8 +480,10 @@ static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led1507
uint8_t idx_skip = req->payload[2];
// TODO: useful?
// dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n",
// board, idx_start, idx_end, idx_skip);
#if defined(LOG_LED15070)
dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n",
board, idx_start, idx_end, idx_skip);
#endif
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
idx_start += idx_skip;
@ -508,9 +522,10 @@ static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070
uint8_t idx_start = req->payload[0];
uint8_t idx_end = req->payload[1];
uint8_t idx_skip = req->payload[2];
// dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n",
// board, idx_start, idx_end, idx_skip);
#if defined(LOG_LED15070)
dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n",
board, idx_start, idx_end, idx_skip);
#endif
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
idx_start += idx_skip;
@ -545,7 +560,9 @@ static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070
static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set palette - 7 Normal LED (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -567,7 +584,9 @@ static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led
static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set palette - 6 Flash LED (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -589,7 +608,9 @@ static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led1
static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set 15DC out (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -611,7 +632,9 @@ static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_an
static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set 15GS out (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -633,7 +656,9 @@ static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_an
static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set PSC max (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -655,14 +680,16 @@ static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any
static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Set FET output (board %u)\n", board);
#endif
led15070_per_board_vars[board].fet[0] = req->payload[0]; // R or FET0 intensity
led15070_per_board_vars[board].fet[1] = req->payload[1]; // G or FET1 intensity
led15070_per_board_vars[board].fet[2] = req->payload[2]; // B or FET2 intensity
if (led_set_fet_output)
led_set_fet_output((const uint8_t*)led15070_per_board_vars[board].fet);
led_set_fet_output(board, (const uint8_t*)led15070_per_board_vars[board].fet);
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -685,8 +712,9 @@ static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_
static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req)
{
uint8_t idx = req->payload[0];
#if defined(LOG_LED15070)
dprintf("LED 15070: Set GS palette (board %u, index %u)\n", board, idx);
#endif
led15070_per_board_vars[board].gs_palette[idx][0] = req->payload[1]; // R
led15070_per_board_vars[board].gs_palette[idx][1] = req->payload[2]; // G
@ -712,10 +740,12 @@ static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_
static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req)
{
// dprintf("LED 15070: DC update (board %u)\n", board);
#if defined(LOG_LED15070)
dprintf("LED 15070: DC update (board %u)\n", board);
#endif
if (led_dc_update)
led_dc_update((const uint8_t*)led15070_per_board_vars[board].dc);
led_dc_update(board, (const uint8_t*)led15070_per_board_vars[board].dc);
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -737,10 +767,12 @@ static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *
static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req)
{
// dprintf("LED 15070: GS update (board %u)\n", board);
#if defined(LOG_LED15070)
dprintf("LED 15070: GS update (board %u)\n", board);
#endif
if (led_gs_update)
led_gs_update((const uint8_t*)led15070_per_board_vars[board].gs);
led_gs_update(board, (const uint8_t*)led15070_per_board_vars[board].gs);
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -762,7 +794,9 @@ static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *
static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Rotate (board %u)\n", board);
#endif
if (!led15070_per_board_vars[board].enable_response)
return S_OK;
@ -787,9 +821,10 @@ static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any
uint8_t idx_start = req->payload[0];
uint8_t idx_end = req->payload[1];
uint8_t idx_skip = req->payload[2];
// dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n",
// board, idx_start, idx_end, idx_skip);
#if defined(LOG_LED15070)
dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n",
board, idx_start, idx_end, idx_skip);
#endif
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
idx_start += idx_skip;
@ -829,9 +864,10 @@ static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_an
uint8_t addr = req->payload[0];
uint8_t data = req->payload[1];
#if defined(LOG_LED15070)
dprintf("LED 15070: EEPROM write (board %u, address %02x, data %02x)\n",
board, addr, data);
#endif
if (addr > 0x07) {
dprintf("LED 15070: Error -- Invalid EEPROM write address %02x\n",
@ -919,8 +955,9 @@ static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any
uint8_t addr = req->payload[0];
uint8_t data = 0;
#if defined(LOG_LED15070)
dprintf("LED 15070: EEPROM read (board %u, address %02x)\n", board, addr);
#endif
if (addr > 0x07) {
dprintf("LED 15070: Error -- Invalid EEPROM read address %02x\n",
@ -1002,7 +1039,9 @@ static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any
static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Acknowledge commands ON (board %u)\n", board);
#endif
led15070_per_board_vars[board].enable_response = true;
@ -1023,7 +1062,9 @@ static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req
static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Acknowledge commands OFF (board %u)\n", board);
#endif
led15070_per_board_vars[board].enable_response = false;
@ -1044,7 +1085,9 @@ static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *re
static HRESULT led15070_req_board_info(int board)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Get board info (board %u)\n", board);
#endif
struct led15070_resp_board_info resp;
@ -1067,7 +1110,9 @@ static HRESULT led15070_req_board_info(int board)
static HRESULT led15070_req_board_status(int board)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Get board status (board %u)\n", board);
#endif
struct led15070_resp_any resp;
@ -1091,7 +1136,9 @@ static HRESULT led15070_req_board_status(int board)
static HRESULT led15070_req_fw_sum(int board)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Get firmware checksum (board %u)\n", board);
#endif
struct led15070_resp_any resp;
@ -1113,7 +1160,9 @@ static HRESULT led15070_req_fw_sum(int board)
static HRESULT led15070_req_protocol_ver(int board)
{
#if defined(LOG_LED15070)
dprintf("LED 15070: Get protocol version (board %u)\n", board);
#endif
struct led15070_resp_any resp;
@ -1187,7 +1236,7 @@ static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle)
HRESULT hr;
BOOL ok;
#if 0
#if defined(LOG_LED15070)
dprintf("LED 15070: Opening EEPROM file '%S' handle (board %u)\n", path, board);
#endif
@ -1233,7 +1282,7 @@ static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle)
HRESULT hr;
BOOL ok;
#if 0
#if defined(LOG_LED15070)
dprintf("LED 15070: Closing EEPROM file '%S' handle (board %u)\n", path, board);
#endif

View File

@ -7,7 +7,7 @@
struct led15070_config {
bool enable;
unsigned int port_no;
unsigned int port_no[2];
char board_number[8];
uint8_t fw_ver;
uint16_t fw_sum;
@ -15,9 +15,9 @@ struct led15070_config {
};
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);
typedef void (*io_led_set_fet_output_t)(uint8_t board, const uint8_t *rgb);
typedef void (*io_led_dc_update_t)(uint8_t board, const uint8_t *rgb);
typedef void (*io_led_gs_update_t)(uint8_t board, const uint8_t *rgb);
HRESULT led15070_hook_init(
const struct led15070_config *cfg,
@ -25,5 +25,4 @@ HRESULT led15070_hook_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);
unsigned int port_no[2]);

View File

@ -107,9 +107,13 @@ 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,
io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr)
HRESULT led15093_hook_init(
const struct led15093_config *cfg,
io_led_init_t _led_init,
io_led_set_leds_t _set_leds,
unsigned int port_no[2])
{
unsigned int num_boards = 0;
assert(cfg != NULL);
assert(_led_init != NULL);
@ -119,14 +123,24 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led
return S_FALSE;
}
if (cfg->port_no != 0) {
first_port = cfg->port_no;
for (int i = 0; i < led15093_nboards; i++)
{
if (cfg->port_no[i] != 0) {
port_no[i] = cfg->port_no[i];
}
if (port_no[i] != 0) {
num_boards++;
}
}
assert(num_boards != 0);
led15093_board_adr = num_boards;
led15093_host_adr = num_boards == 2 ? 1 : 2;
led_init = _led_init;
set_leds = _set_leds;
led15093_board_adr = board_adr;
led15093_host_adr = host_adr;
memcpy(led15093_board_num, cfg->board_number, sizeof(led15093_board_num));
memcpy(led15093_chip_num, cfg->chip_number, sizeof(led15093_chip_num));
@ -140,7 +154,7 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led
InitializeCriticalSection(&vb->lock);
uart_init(&vb->boarduart, first_port + i);
uart_init(&vb->boarduart, port_no[i]);
if (cfg->high_baudrate) {
vb->boarduart.baud.BaudRate = 460800;
} else {
@ -209,7 +223,6 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
_led15093_per_board_vars *v = &led15093_per_board_vars[board];
struct uart *boarduart = &led15093_per_board_vars[board].boarduart;
/*
if (irp->op == IRP_OP_OPEN) {
// Unfortunately the LED board UART gets opened and closed repeatedly
@ -236,30 +249,6 @@ 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: "
"%d\n",
res);
return E_FAIL;
}
*/
if (FAILED(hr)) {
dprintf("LED 15093: Backend error, LED board disconnected: "
"%x\n",
(int) hr);
return hr;
}
}
hr = uart_handle_irp(boarduart, irp);
@ -688,16 +677,6 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set
return E_INVALIDARG;
}
/*
if (board == 0) {
dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0x96], req->data[0x97], req->data[0x98]);
}
else if (board == 1)
{
dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0xb4], req->data[0xb5], req->data[0xb6]);
}
*/
// Return the current LED data, remove const qualifier
set_leds(board, (uint8_t *) req->data);

View File

@ -8,7 +8,7 @@
struct led15093_config {
bool enable;
bool high_baudrate;
unsigned int port_no;
unsigned int port_no[2];
char board_number[8];
char chip_number[5];
char boot_chip_number[5];
@ -20,5 +20,5 @@ typedef HRESULT (*io_led_init_t)(void);
typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb);
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);
io_led_set_leds_t _set_leds, unsigned int port_no[2]);

View File

@ -56,7 +56,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0;
cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 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", 0xadf7, filename);

View File

@ -114,8 +114,9 @@ static DWORD CALLBACK chuni_pre_startup(void)
{
dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n");
} else {
unsigned int led_port_no[2] = {10, 11};
hr = led15093_hook_init(&chuni_hook_cfg.led15093,
chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1);
chuni_dll.led_init, chuni_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
goto fail;

View File

@ -174,6 +174,20 @@ HRESULT chuni_io_led_init(void)
}
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb)
{
{
#if 0
if (board == 0) {
dprintf("CHUNI LED: Left Air 1: red: %d, green: %d, blue: %d\n", rgb[0x96], rgb[0x97], rgb[0x98]);
dprintf("CHUNI LED: Left Air 2: red: %d, green: %d, blue: %d\n", rgb[0x99], rgb[0x9A], rgb[0x9B]);
dprintf("CHUNI LED: Left Air 3: red: %d, green: %d, blue: %d\n", rgb[0x9C], rgb[0x9D], rgb[0x9E]);
}
else if (board == 1)
{
dprintf("CHUNI LED: Right Air 1: red: %d, green: %d, blue: %d\n", rgb[0xB4], rgb[0xB5], rgb[0xB6]);
dprintf("CHUNI LED: Right Air 2: red: %d, green: %d, blue: %d\n", rgb[0xB7], rgb[0xB8], rgb[0xB9]);
dprintf("CHUNI LED: Right Air 3: red: %d, green: %d, blue: %d\n", rgb[0xBA], rgb[0xBB], rgb[0xBC]);
}
#endif
led_output_update(board, rgb);
}

View File

@ -96,7 +96,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0;
cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 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", 0xadf7, filename);

View File

@ -22,32 +22,23 @@
COM4: 837-15396 "Gen 3" Aime Reader
*/
#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include <windows.h>
#include "amex/amex.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
#include "chuniio/chuniio.h"
#include "chusanhook/config.h"
#include "chusanhook/io4.h"
#include "chusanhook/slider.h"
#include "chuniio/chuniio.h"
#include "hook/process.h"
#include "gfxhook/d3d9.h"
#include "gfxhook/gfx.h"
#include "hook/process.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"
#include "platform/platform.h"
#include "util/dprintf.h"
#include "util/env.h"
@ -55,8 +46,7 @@ static HMODULE chusan_hook_mod;
static process_entry_t chusan_startup;
static struct chusan_hook_config chusan_hook_cfg;
static DWORD CALLBACK chusan_pre_startup(void)
{
static DWORD CALLBACK chusan_pre_startup(void) {
HMODULE d3dc;
HMODULE dbghelp;
HRESULT hr;
@ -88,7 +78,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
chusan_hook_config_load(&chusan_hook_cfg, get_config_path());
/* Hook Win32 APIs */
dvd_hook_init(&chusan_hook_cfg.dvd, chusan_hook_mod);
gfx_hook_init(&chusan_hook_cfg.gfx);
gfx_d3d9_hook_init(&chusan_hook_cfg.gfx, chusan_hook_mod);
@ -154,19 +144,31 @@ static DWORD CALLBACK chusan_pre_startup(void)
}
}
if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL )
{
dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n");
unsigned int led_port_no[2];
if (is_cvt) {
led_port_no[0] = 2;
led_port_no[1] = 3;
} else {
hr = led15093_hook_init(&chusan_hook_cfg.led15093,
chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1);
led_port_no[0] = 20;
led_port_no[1] = 21;
}
if (chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL) {
dprintf(
"IO DLL doesn't support led_init/led_set_leds, cannot start "
"LED15093 hook\n");
} else {
hr = led15093_hook_init(&chusan_hook_cfg.led15093, chuni_dll.led_init,
chuni_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
goto fail;
}
}
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod);
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2 : 3,
chusan_hook_mod);
if (FAILED(hr)) {
goto fail;
@ -186,8 +188,7 @@ fail:
ExitProcess(EXIT_FAILURE);
}
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
{
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) {
HRESULT hr;
if (cause != DLL_PROCESS_ATTACH) {
@ -199,7 +200,7 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
hr = process_hijack_startup(chusan_pre_startup, &chusan_startup);
if (!SUCCEEDED(hr)) {
dprintf("Failed to hijack process startup: %x\n", (int) hr);
dprintf("Failed to hijack process startup: %x\n", (int)hr);
}
return SUCCEEDED(hr);

View File

@ -69,6 +69,15 @@ freeplay=0
; this to 1 on exactly one machine and set this to 0 on all others.
dipsw1=1
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
[led15070]
; Enable emulation of the 837-15070-04 controlled lights, which handle the
; cabinet and button LEDs.
enable=1
; -----------------------------------------------------------------------------
; Misc. hook settings
; -----------------------------------------------------------------------------
@ -126,11 +135,22 @@ coin=0x72
; Uncomment and complete the following sequence of settings to configure a
; custom keybinding.
[button]
;1p_btn1=0x53
;1p_btn2=0x53
;1p_btn3=0x53
enable=1
;p1Btn1=0x53
;p1Btn2=0x53
;p1Btn3=0x53
; ... etc ...
;2p_btn1=0x53
;2p_btn2=0x53
;2p_btn3=0x53
;p2Btn1=0x53
;p2Btn2=0x53
;p2Btn3=0x53
; ... etc ...
[touch]
p1Enable=1
;p1DebugInput=0
p2Enable=1
;p2DebugInput=0
;p1TouchA1=0x53
;p1TouchA2=0x53
; ... etc ...
;p1TouchE8=0x53

View File

@ -48,7 +48,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
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->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);

View File

@ -133,8 +133,9 @@ static DWORD CALLBACK fgo_pre_startup(void)
goto fail;
}
unsigned int led_port_no[2] = {17, 0};
hr = led15093_hook_init(&fgo_hook_cfg.led15093,
fgo_dll.led_init, fgo_dll.led_set_leds, 17, 1, 1, 2);
fgo_dll.led_init, fgo_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
goto fail;

View File

@ -308,7 +308,7 @@ static void reg_hook_init(void)
reg_hook_initted = true;
InitializeCriticalSection(&reg_hook_lock);
dprintf("Reg hook init\n");
dprintf("Reg: hook init.\n");
reg_hook_insert_hooks(NULL);

View File

@ -23,7 +23,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
wchar_t tmpstr[16];
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 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);

View File

@ -94,8 +94,9 @@ static DWORD CALLBACK idac_pre_startup(void)
goto fail;
}
unsigned int led_port_no[2] = {2, 0};
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);
idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, led_port_no);
if (FAILED(hr)) {
goto fail;

View File

@ -12,9 +12,9 @@ struct idac_dll {
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);
void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb);
void (*led_gs_update)(uint8_t board, const uint8_t *rgb);
void (*led_set_leds)(uint8_t board, const uint8_t *rgb);
HRESULT (*ffb_init)(void);
void (*ffb_toggle)(bool active);
void (*ffb_constant_force)(uint8_t direction, uint8_t force);

View File

@ -159,7 +159,7 @@ static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len)
lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00,
};
idac_dll.led_set_leds(rgb_out);
idac_dll.led_set_leds(0, rgb_out);
return S_OK;
}

View File

@ -127,7 +127,7 @@ HRESULT idac_io_led_init(void)
return S_OK;
}
void idac_io_led_set_fet_output(const uint8_t *rgb)
void idac_io_led_set_fet_output(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]);
@ -137,7 +137,7 @@ void idac_io_led_set_fet_output(const uint8_t *rgb)
return;
}
void idac_io_led_gs_update(const uint8_t *rgb)
void idac_io_led_gs_update(uint8_t board, const uint8_t *rgb)
{
#if 0
for (int i = 0; i < 9; i++) {
@ -149,7 +149,7 @@ void idac_io_led_gs_update(const uint8_t *rgb)
return;
}
void idac_io_led_set_leds(const uint8_t *rgb)
void idac_io_led_set_leds(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("IDAC LED: START: %02X\n", rgb[0]);

View File

@ -127,7 +127,7 @@ HRESULT idac_io_led_init(void);
Minimum API version: 0x0101 */
void idac_io_led_set_fet_output(const uint8_t *rgb);
void idac_io_led_set_fet_output(uint8_t board, const uint8_t *rgb);
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
@ -144,7 +144,7 @@ void idac_io_led_set_fet_output(const uint8_t *rgb);
Minimum API version: 0x0101 */
void idac_io_led_gs_update(const uint8_t *rgb);
void idac_io_led_gs_update(uint8_t board, const uint8_t *rgb);
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
@ -160,7 +160,7 @@ void idac_io_led_gs_update(const uint8_t *rgb);
Minimum API version: 0x0101 */
void idac_io_led_set_leds(const uint8_t *rgb);
void idac_io_led_set_leds(uint8_t board, const uint8_t *rgb);
/* Initialize FFB emulation. This function will be called before any
other idac_io_ffb_*() function calls.

View File

@ -27,7 +27,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
wchar_t tmpstr[16];
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 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);

View File

@ -128,8 +128,9 @@ static DWORD CALLBACK idz_pre_startup(void)
goto fail;
}
unsigned int led_port_no[2] = {11, 0};
hr = led15070_hook_init(&idz_hook_cfg.led15070, idz_dll.led_init,
idz_dll.led_set_fet_output, NULL, idz_dll.led_gs_update, 11, 1);
idz_dll.led_set_fet_output, NULL, idz_dll.led_gs_update, led_port_no);
if (FAILED(hr)) {
goto fail;

View File

@ -12,9 +12,9 @@ struct idz_dll {
void (*jvs_read_shifter)(uint8_t *gear);
void (*jvs_read_coin_counter)(uint16_t *total);
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);
void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb);
void (*led_gs_update)(uint8_t board, const uint8_t *rgb);
void (*led_set_leds)(uint8_t board, const uint8_t *rgb);
HRESULT (*ffb_init)(void);
void (*ffb_toggle)(bool active);
void (*ffb_constant_force)(uint8_t direction, uint8_t force);

View File

@ -192,5 +192,5 @@ static void idz_jvs_write_gpio(void *ctx, uint32_t state)
state & IDZ_IO_LED_LEFT ? 0xFF : 0x00,
};
idz_dll.led_set_leds(rgb_out);
idz_dll.led_set_leds(0, rgb_out);
}

View File

@ -130,7 +130,7 @@ HRESULT idz_io_led_init(void)
return S_OK;
}
void idz_io_led_set_fet_output(const uint8_t *rgb)
void idz_io_led_set_fet_output(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("IDZ LED: LEFT SEAT LED: %02X\n", rgb[0]);
@ -140,7 +140,7 @@ void idz_io_led_set_fet_output(const uint8_t *rgb)
return;
}
void idz_io_led_gs_update(const uint8_t *rgb)
void idz_io_led_gs_update(uint8_t board, const uint8_t *rgb)
{
#if 0
for (int i = 0; i < 9; i++) {
@ -152,7 +152,7 @@ void idz_io_led_gs_update(const uint8_t *rgb)
return;
}
void idz_io_led_set_leds(const uint8_t *rgb)
void idz_io_led_set_leds(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("IDZ LED: START: %02X\n", rgb[0]);

View File

@ -138,7 +138,7 @@ HRESULT idz_io_led_init(void);
Minimum API version: 0x0101 */
void idz_io_led_set_fet_output(const uint8_t *rgb);
void idz_io_led_set_fet_output(uint8_t board, const uint8_t *rgb);
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
@ -155,7 +155,7 @@ void idz_io_led_set_fet_output(const uint8_t *rgb);
Minimum API version: 0x0101 */
void idz_io_led_gs_update(const uint8_t *rgb);
void idz_io_led_gs_update(uint8_t board, const uint8_t *rgb);
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
@ -171,7 +171,7 @@ void idz_io_led_gs_update(const uint8_t *rgb);
Minimum API version: 0x0101 */
void idz_io_led_set_leds(const uint8_t *rgb);
void idz_io_led_set_leds(uint8_t board, const uint8_t *rgb);
/* Initialize FFB emulation. This function will be called before any
other idz_io_ffb_*() function calls.

View File

@ -65,7 +65,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
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->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 1, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);

View File

@ -1,28 +1,21 @@
#include <windows.h>
#include <stdlib.h>
#include <windows.h>
#include "board/io4.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
#include "hook/iohook.h"
#include "hook/process.h"
#include "hook/table.h"
#include "hook/iohook.h"
#include "hooklib/printer.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"
#include "kemonohook/config.h"
#include "kemonohook/hooks.h"
#include "kemonohook/jvs.h"
#include "kemonohook/kemono-dll.h"
#include "platform/platform.h"
#include "unityhook/hook.h"
#include "util/dprintf.h"
#include "util/env.h"
@ -47,29 +40,38 @@ static DWORD CALLBACK kemono_pre_startup(void) {
// 2.02 does not call printer update functions
uint16_t ret;
fwdlusb_updateFirmware_main(1, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223100-014E-C300-MAINAPP.BIN", &ret);
if (ret != 0){
fwdlusb_updateFirmware_main(
1,
"UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223100-014E-C300-"
"MAINAPP.BIN",
&ret);
if (ret != 0) {
goto fail;
}
fwdlusb_updateFirmware_dsp(2, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223200-0101-C300-DSPAPP.BIN", &ret);
if (ret != 0){
fwdlusb_updateFirmware_dsp(
2,
"UnityApp\\Parade_Data\\StreamingAssets\\Printer\\E0223200-0101-C300-"
"DSPAPP.BIN",
&ret);
if (ret != 0) {
goto fail;
}
fwdlusb_updateFirmware_param(3, "UnityApp\\Parade_Data\\StreamingAssets\\Printer\\D0460700-0101-C300-PARAM.BIN", &ret);
if (ret != 0){
fwdlusb_updateFirmware_param(
3,
"UnityApp\\Parade_Data\\StreamingAssets\\Printer\\D0460700-0101-C300-"
"PARAM.BIN",
&ret);
if (ret != 0) {
goto fail;
}
printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod);
printer_set_dimensions(720, 1028); // printer doesn't call setimageformat
printer_set_dimensions(720, 1028); // printer doesn't call setimageformat
/* Initialize emulation hooks */
hr = platform_hook_init(
&kemono_hook_cfg.platform,
"SDFL",
"AAW1",
kemono_hook_mod);
hr = platform_hook_init(&kemono_hook_cfg.platform, "SDFL", "AAW1",
kemono_hook_mod);
if (FAILED(hr)) {
goto fail;
@ -93,7 +95,9 @@ static DWORD CALLBACK kemono_pre_startup(void) {
goto fail;
}
hr = led15093_hook_init(&kemono_hook_cfg.led15093, kemono_dll.led_init, kemono_dll.led_set_leds, 10, 1, 1, 2);
unsigned int led_port_no[2] = {10, 0};
hr = led15093_hook_init(&kemono_hook_cfg.led15093, kemono_dll.led_init,
kemono_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
goto fail;
@ -106,7 +110,8 @@ static DWORD CALLBACK kemono_pre_startup(void) {
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
hooked earlier in the `kemonohook` initialization. */
unity_hook_init(&kemono_hook_cfg.unity, kemono_hook_mod, kemono_extra_hooks_load);
unity_hook_init(&kemono_hook_cfg.unity, kemono_hook_mod,
kemono_extra_hooks_load);
/* Initialize debug helpers */
@ -118,7 +123,7 @@ static DWORD CALLBACK kemono_pre_startup(void) {
return kemono_startup();
fail:
fail:
ExitProcess(EXIT_FAILURE);
}
@ -134,7 +139,7 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) {
hr = process_hijack_startup(kemono_pre_startup, &kemono_startup);
if (!SUCCEEDED(hr)) {
dprintf("Failed to hijack process startup: %x\n", (int) hr);
dprintf("Failed to hijack process startup: %x\n", (int)hr);
}
return SUCCEEDED(hr);

View File

@ -12,24 +12,71 @@
#include "platform/config.h"
void mai2_dll_config_load(
struct mai2_dll_config *cfg,
const wchar_t *filename)
struct mai2_dll_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
L"mai2io",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
L"mai2io",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
void touch_config_load(
struct touch_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable_1p = GetPrivateProfileIntW(L"touch", L"p1Enable", 1, filename);
cfg->enable_2p = GetPrivateProfileIntW(L"touch", L"p2Enable", 1, filename);
}
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[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x00, filename);
GetPrivateProfileStringW(
L"led15070",
L"boardNumber",
L"15070-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"led15070",
L"eepromPath",
L"DEVICE",
cfg->eeprom_path,
_countof(cfg->eeprom_path),
filename);
}
void mai2_hook_config_load(
struct mai2_hook_config *cfg,
const wchar_t *filename)
struct mai2_hook_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
@ -40,5 +87,7 @@ void mai2_hook_config_load(
io4_config_load(&cfg->io4, filename);
vfd_config_load(&cfg->vfd, filename);
mai2_dll_config_load(&cfg->dll, filename);
touch_config_load(&cfg->touch, filename);
led15070_config_load(&cfg->led15070, filename);
unity_config_load(&cfg->unity, filename);
}

View File

@ -10,6 +10,10 @@
#include "platform/config.h"
#include "mai2hook/touch.h"
#include "board/led15070.h"
#include "unityhook/config.h"
struct mai2_hook_config {
@ -19,13 +23,23 @@ struct mai2_hook_config {
struct io4_config io4;
struct vfd_config vfd;
struct mai2_dll_config dll;
struct touch_config touch;
struct led15070_config led15070;
struct unity_config unity;
};
void mai2_dll_config_load(
struct mai2_dll_config *cfg,
const wchar_t *filename);
struct mai2_dll_config *cfg,
const wchar_t *filename);
void touch_config_load(
struct touch_config *cfg,
const wchar_t *filename);
void led15070_config_load(
struct led15070_config *cfg,
const wchar_t *filename);
void mai2_hook_config_load(
struct mai2_hook_config *cfg,
const wchar_t *filename);
struct mai2_hook_config *cfg,
const wchar_t *filename);

View File

@ -67,16 +67,45 @@ static DWORD CALLBACK mai2_pre_startup(void)
/* Initialize emulation hooks */
hr = platform_hook_init(
&mai2_hook_cfg.platform,
"SDEZ",
"ACA1",
mai2_hook_mod);
&mai2_hook_cfg.platform,
"SDEZ",
"ACA1",
mai2_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, 1, mai2_hook_mod);
/* Initialize DLLs */
hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod);
if (FAILED(hr)) {
goto fail;
}
// Touch Panel uses COM3 and COM4
hr = touch_hook_init(&mai2_hook_cfg.touch);
if (FAILED(hr)) {
goto fail;
}
// LED board uses COM21 and COM23
unsigned int led_port_no[2] = {21, 23};
hr = led15070_hook_init(&mai2_hook_cfg.led15070,
mai2_dll.led_init,
mai2_dll.led_set_fet_output,
mai2_dll.led_dc_update,
mai2_dll.led_gs_update,
led_port_no);
if (FAILED(hr)) {
goto fail;
}
hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, 3, mai2_hook_mod);
if (FAILED(hr)) {
goto fail;
@ -88,12 +117,6 @@ static DWORD CALLBACK mai2_pre_startup(void)
goto fail;
}
hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = mai2_io4_hook_init(&mai2_hook_cfg.io4);
if (FAILED(hr)) {

View File

@ -21,7 +21,28 @@ const struct dll_bind_sym mai2_dll_syms[] = {
}, {
.sym = "mai2_io_get_gamebtns",
.off = offsetof(struct mai2_dll, get_gamebtns),
}
}, {
.sym = "mai2_io_touch_init",
.off = offsetof(struct mai2_dll, touch_init),
}, {
.sym = "mai2_io_touch_set_sens",
.off = offsetof(struct mai2_dll, touch_set_sens),
}, {
.sym = "mai2_io_touch_update",
.off = offsetof(struct mai2_dll, touch_update),
}, {
.sym = "mai2_io_led_init",
.off = offsetof(struct mai2_dll, led_init),
}, {
.sym = "mai2_io_led_set_fet_output",
.off = offsetof(struct mai2_dll, led_set_fet_output),
}, {
.sym = "mai2_io_led_dc_update",
.off = offsetof(struct mai2_dll, led_dc_update),
}, {
.sym = "mai2_io_led_gs_update",
.off = offsetof(struct mai2_dll, led_gs_update),
},
};
struct mai2_dll mai2_dll;
@ -67,7 +88,7 @@ HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self)
if (get_api_version != NULL) {
mai2_dll.api_version = get_api_version();
} else {
mai2_dll.api_version = 0x0100;
mai2_dll.api_version = 0x0101;
dprintf("Custom IO DLL does not expose mai2_io_get_api_version, "
"assuming API version 1.0.\n"
"Please ask the developer to update their DLL.\n");

View File

@ -10,6 +10,13 @@ struct mai2_dll {
HRESULT (*poll)(void);
void (*get_opbtns)(uint8_t *opbtn);
void (*get_gamebtns)(uint16_t *player1, uint16_t *player2);
HRESULT (*touch_init)(mai2_io_touch_callback_t callback);
void (*touch_set_sens)(uint8_t *bytes);
void (*touch_update)(bool player1, bool player2);
HRESULT (*led_init)(void);
void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb);
void (*led_dc_update)(uint8_t board, const uint8_t *rgb);
void (*led_gs_update)(uint8_t board, const uint8_t *rgb);
};
struct mai2_dll_config {

View File

@ -15,4 +15,11 @@ EXPORTS
mai2_io_get_gamebtns
mai2_io_get_opbtns
mai2_io_init
mai2_io_poll
mai2_io_poll
mai2_io_touch_init
mai2_io_touch_set_sens
mai2_io_touch_update
mai2_io_led_init
mai2_io_led_set_fet_output
mai2_io_led_dc_update
mai2_io_led_gs_update

View File

@ -23,6 +23,8 @@ shared_library(
'dllmain.c',
'io4.c',
'io4.h',
'touch.c',
'touch.h',
'mai2-dll.c',
'mai2-dll.h',
],

259
mai2hook/touch.c 100644
View File

@ -0,0 +1,259 @@
#include <assert.h>
#include <stdlib.h>
#include "hooklib/fdshark.h"
#include "hooklib/reg.h"
#include "mai2hook/mai2-dll.h"
#include "mai2hook/touch.h"
#include "util/dprintf.h"
#include "util/dump.h"
static HRESULT read_reg_touch_1p(void *bytes, uint32_t *nbytes)
{
return reg_hook_read_wstr(bytes, nbytes, L"COM3");
}
static HRESULT read_reg_touch_2p(void *bytes, uint32_t *nbytes)
{
return reg_hook_read_wstr(bytes, nbytes, L"COM4");
}
static const struct reg_hook_val touch_reg_key[] = {
{
.name = L"\\Device\\RealTouchBoard0",
.read = read_reg_touch_1p,
.type = REG_SZ,
},
{
.name = L"\\Device\\RealTouchBoard1",
.read = read_reg_touch_2p,
.type = REG_SZ,
},
};
const char *sensor_map[34] = {
"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", // 0x41 - 0x48
"B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", // 0x49 - 0x50
"C1", "C2", // 0x51 - 0x52
"D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", // 0x53 - 0x5A
"E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8" // 0x5B - 0x62
};
const char *sensor_to_str(uint8_t sensor)
{
if (sensor < 0x41 || sensor > 0x62)
{
return "Invalid";
}
return sensor_map[sensor - 0x41];
}
static CRITICAL_SECTION touch_1p_lock;
static struct uart touch_1p_uart;
static uint8_t touch_1p_written_bytes[64];
static uint8_t touch_1p_readable_bytes[64];
static bool touch_1p_status = false;
static CRITICAL_SECTION touch_2p_lock;
static struct uart touch_2p_uart;
static uint8_t touch_2p_written_bytes[64];
static uint8_t touch_2p_readable_bytes[64];
static bool touch_2p_status = false;
HRESULT touch_hook_init(const struct touch_config *cfg)
{
assert(cfg != NULL);
if (!cfg->enable_1p && !cfg->enable_2p)
{
return S_FALSE;
}
HRESULT hr = reg_hook_push_key(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", touch_reg_key, _countof(touch_reg_key));
if (FAILED(hr))
{
return hr;
}
if (cfg->enable_1p)
{
dprintf("Mai2 touch 1P: Init.\n");
InitializeCriticalSection(&touch_1p_lock);
uart_init(&touch_1p_uart, 3);
touch_1p_uart.written.bytes = touch_1p_written_bytes;
touch_1p_uart.written.nbytes = sizeof(touch_1p_written_bytes);
touch_1p_uart.readable.bytes = touch_1p_readable_bytes;
touch_1p_uart.readable.nbytes = sizeof(touch_1p_readable_bytes);
}
if (cfg->enable_2p)
{
dprintf("Mai2 touch 2P: Init.\n");
InitializeCriticalSection(&touch_2p_lock);
uart_init(&touch_2p_uart, 4);
touch_2p_uart.written.bytes = touch_2p_written_bytes;
touch_2p_uart.written.nbytes = sizeof(touch_2p_written_bytes);
touch_2p_uart.readable.bytes = touch_2p_readable_bytes;
touch_2p_uart.readable.nbytes = sizeof(touch_2p_readable_bytes);
}
return iohook_push_handler(touch_handle_irp);
}
static HRESULT touch_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (uart_match_irp(&touch_1p_uart, irp))
{
EnterCriticalSection(&touch_1p_lock);
hr = touch_handle_irp_locked(irp, &touch_1p_uart);
LeaveCriticalSection(&touch_1p_lock);
}
else if (uart_match_irp(&touch_2p_uart, irp))
{
EnterCriticalSection(&touch_2p_lock);
hr = touch_handle_irp_locked(irp, &touch_2p_uart);
LeaveCriticalSection(&touch_2p_lock);
}
else
{
return iohook_invoke_next(irp);
}
return hr;
}
static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart)
{
HRESULT hr;
if (irp->op == IRP_OP_OPEN)
{
dprintf("Mai2 touch port %d: Starting backend\n", uart->port_no);
hr = mai2_dll.touch_init(touch_auto_scan);
if (FAILED(hr))
{
dprintf("Mai2 touch port %d: Backend error: %x\n", uart->port_no, (int)hr);
return hr;
}
}
hr = uart_handle_irp(uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE)
{
return hr;
}
#if defined(LOG_MAI2_TOUCH)
dprintf("Mai2 touch port %d WRITE:\n", uart->port_no);
dump_iobuf(&uart->written);
#endif
uint8_t port_no = uart->port_no;
uint8_t *src = uart->written.bytes;
uint8_t *dest = uart->readable.bytes;
switch (src[3])
{
case commandRSET:
dprintf("Mai2 touch port %d: Reset\n", port_no);
break;
case commandHALT: // Enter Conditioning mode and stop sending touch data.
dprintf("Mai2 touch port %d: Halt\n", port_no);
assert(mai2_dll.touch_update != NULL);
if (port_no == 3)
{
EnterCriticalSection(&touch_1p_lock);
touch_1p_status = false;
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
LeaveCriticalSection(&touch_1p_lock);
}
else
{
EnterCriticalSection(&touch_2p_lock);
touch_2p_status = false;
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
LeaveCriticalSection(&touch_2p_lock);
}
break;
case commandSTAT: // Exit Conditioning mode and resume sending touch data.
dprintf("Mai2 touch port %d: Stat\n", port_no);
assert(mai2_dll.touch_update != NULL);
if (port_no == 3)
{
EnterCriticalSection(&touch_1p_lock);
touch_1p_status = true;
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
LeaveCriticalSection(&touch_1p_lock);
}
else
{
EnterCriticalSection(&touch_2p_lock);
touch_2p_status = true;
mai2_dll.touch_update(touch_1p_status, touch_2p_status);
LeaveCriticalSection(&touch_2p_lock);
}
break;
case commandRatio:
#if defined(LOG_MAI2_TOUCH)
dprintf("Mai2 touch side %c: set sensor %s ratio to %d\n", src[1], sensor_to_str(src[2]), src[4]);
#endif
dest[0] = res_start;
dest[1] = src[1]; // L,R
dest[2] = src[2]; // sensor
dest[3] = commandRatio;
dest[4] = src[4]; // Ratio
dest[5] = res_end;
uart->readable.pos = 6;
// The Ratio is fixed at 0x72 and does not need to be sent to mai2io for processing.
break;
case commandSens:
#if defined(LOG_MAI2_TOUCH)
dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", src[1], sensor_to_str(src[2]), src[4]);
#endif
dest[0] = res_start;
dest[1] = src[1]; // L,R
dest[2] = src[2]; // sensor
dest[3] = commandSens;
dest[4] = src[4]; // Sensitivity
dest[5] = res_end;
uart->readable.pos = 6;
mai2_dll.touch_set_sens(dest);
break;
default:
dprintf("Mai2 touch port %d: Unknow %02x\n", port_no, src[3]);
break;
}
#if defined(LOG_MAI2_TOUCH)
dprintf("Mai2 touch port %d READ:\n", uart->port_no);
dump_iobuf(&uart->readable);
#endif
uart->written.pos = 0;
return hr;
}
static void touch_auto_scan(const uint8_t player, const uint8_t state[7])
{
struct uart *touch_uart = player == 1 ? &touch_1p_uart : &touch_2p_uart;
touch_uart->readable.bytes[0] = res_start;
memcpy(&touch_uart->readable.bytes[1], state, 7);
touch_uart->readable.bytes[8] = res_end;
touch_uart->readable.pos = 9;
}

38
mai2hook/touch.h 100644
View File

@ -0,0 +1,38 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include "hooklib/uart.h"
struct touch_config
{
bool enable_1p;
bool enable_2p;
};
enum
{
commandRSET = 0x45, // E
commandHALT = 0x4C, // L
commandSTAT = 0x41, // A
commandRatio = 0x72, // r
commandSens = 0x6B, // k
req_start = 0x7b, // {
req_end = 0x7d, // }
res_start = 0x28, // (
res_end = 0x29, // )
};
extern const char *sensor_map[34];
const char *sensor_to_str(uint8_t sensor);
HRESULT touch_hook_init(const struct touch_config *cfg);
static HRESULT touch_handle_irp(struct irp *irp);
static HRESULT touch_handle_irp_locked(struct irp *irp, struct uart *uart);
/* Called in mai2io to send touch data.
Similar to chuni slider_res_auto_scan, but the host does not require periodic updates.
Touch data is sent only when there is a change. */
static void touch_auto_scan(const uint8_t player, const uint8_t state[7]);

View File

@ -6,6 +6,7 @@
#include <stdlib.h>
#include "mai2io/config.h"
#include "mai2hook/touch.h"
/*
Maimai DX Default key binding
@ -15,9 +16,24 @@ Maimai DX Default key binding
static const int mai2_io_1p_default[] = {'W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q', '3'};
static const int mai2_io_2p_default[] = {0x68, 0x69, 0x66, 0x63, 0x62, 0x61, 0x64, 0x67, 0x54};
static const int mai2_io_1p_touch_default[] = {
'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R',
'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R',
'G', 'G',
'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R',
'T', 'Y', 'H', 'N', 'B', 'V', 'F', 'R',
};
static const int mai2_io_2p_touch_default[] = {
'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U',
'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U',
'K', 'K',
'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U',
'I', 'O', 'L', VK_OEM_PERIOD, VK_OEM_COMMA, 'M', 'J', 'U',
};
void mai2_io_config_load(
struct mai2_io_config *cfg,
const wchar_t *filename)
struct mai2_io_config *cfg,
const wchar_t *filename)
{
wchar_t key[16];
int i;
@ -28,22 +44,41 @@ void mai2_io_config_load(
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename);
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename);
cfg->vk_btn_enable = GetPrivateProfileIntW(L"button", L"enable", 1, filename);
for (i = 0 ; i < 9 ; i++) {
swprintf_s(key, _countof(key), L"1p_btn%i", i + 1);
for (i = 0; i < 9; i++)
{
swprintf_s(key, _countof(key), L"p1Btn%i", i + 1);
cfg->vk_1p_btn[i] = GetPrivateProfileIntW(
L"button",
key,
mai2_io_1p_default[i],
filename);
L"button",
key,
mai2_io_1p_default[i],
filename);
swprintf_s(key, _countof(key), L"p2Btn%i", i + 1);
cfg->vk_2p_btn[i] = GetPrivateProfileIntW(
L"button",
key,
mai2_io_2p_default[i],
filename);
}
for (i = 0 ; i < 9 ; i++) {
swprintf_s(key, _countof(key), L"2p_btn%i", i + 1);
cfg->vk_2p_btn[i] = GetPrivateProfileIntW(
L"button",
key,
mai2_io_2p_default[i],
filename);
cfg->debug_input_1p = GetPrivateProfileIntW(L"touch", L"p1DebugInput", 0, filename);
cfg->debug_input_2p = GetPrivateProfileIntW(L"touch", L"p2DebugInput", 0, filename);
for (i = 0; i < 34; i++)
{
swprintf_s(key, _countof(key), L"p1Touch%S", sensor_map[i]);
cfg->vk_1p_touch[i] = GetPrivateProfileIntW(
L"touch",
key,
mai2_io_1p_touch_default[i],
filename);
swprintf_s(key, _countof(key), L"p2Touch%S", sensor_map[i]);
cfg->vk_2p_touch[i] = GetPrivateProfileIntW(
L"touch",
key,
mai2_io_2p_touch_default[i],
filename);
}
}

View File

@ -9,8 +9,13 @@ struct mai2_io_config {
uint8_t vk_test;
uint8_t vk_service;
uint8_t vk_coin;
bool vk_btn_enable;
uint8_t vk_1p_btn[9];
uint8_t vk_2p_btn[9];
bool debug_input_1p;
bool debug_input_2p;
uint8_t vk_1p_touch[34];
uint8_t vk_2p_touch[34];
};
void mai2_io_config_load(

View File

@ -1,10 +1,11 @@
#include <windows.h>
#include "mai2io/mai2io.h"
#include <limits.h>
#include <stdint.h>
#include <process.h>
#include "mai2io/mai2io.h"
#include "mai2hook/touch.h"
#include "mai2io/config.h"
#include "util/dprintf.h"
#include "util/env.h"
static uint8_t mai2_opbtn;
@ -12,21 +13,21 @@ static uint16_t mai2_player1_btn;
static uint16_t mai2_player2_btn;
static struct mai2_io_config mai2_io_cfg;
static bool mai2_io_coin;
mai2_io_touch_callback_t _callback;
static HANDLE mai2_io_touch_1p_thread;
static bool mai2_io_touch_1p_stop_flag;
static HANDLE mai2_io_touch_2p_thread;
static bool mai2_io_touch_2p_stop_flag;
uint16_t mai2_io_get_api_version(void)
{
return 0x0100;
}
uint16_t mai2_io_get_api_version(void) { return 0x0101; }
HRESULT mai2_io_init(void)
{
HRESULT mai2_io_init(void) {
mai2_io_config_load(&mai2_io_cfg, get_config_path());
return S_OK;
}
HRESULT mai2_io_poll(void)
{
HRESULT mai2_io_poll(void) {
mai2_opbtn = 0;
mai2_player1_btn = 0;
mai2_player2_btn = 0;
@ -47,8 +48,13 @@ HRESULT mai2_io_poll(void)
} else {
mai2_io_coin = false;
}
// If sinmai has enabled DebugInput, there is no need to input buttons
// through hook amdaemon.
if (!mai2_io_cfg.vk_btn_enable) {
return S_OK;
}
//Player 1
// Player 1
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[0])) {
mai2_player1_btn |= MAI2_IO_GAMEBTN_1;
}
@ -85,7 +91,7 @@ HRESULT mai2_io_poll(void)
mai2_player1_btn |= MAI2_IO_GAMEBTN_SELECT;
}
//Player 2
// Player 2
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[0])) {
mai2_player2_btn |= MAI2_IO_GAMEBTN_1;
}
@ -125,20 +131,137 @@ HRESULT mai2_io_poll(void)
return S_OK;
}
void mai2_io_get_opbtns(uint8_t *opbtn)
{
void mai2_io_get_opbtns(uint8_t *opbtn) {
if (opbtn != NULL) {
*opbtn = mai2_opbtn;
}
}
void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2)
{
void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2) {
if (player1 != NULL) {
*player1 = mai2_player1_btn;
}
if (player2 != NULL ){
if (player2 != NULL) {
*player2 = mai2_player2_btn;
}
}
HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback) {
_callback = callback;
return S_OK;
}
void mai2_io_touch_set_sens(uint8_t *bytes) {
#if 0
dprintf("Mai2 touch side %c: set sensor %s sensitivity to %d\n", bytes[1], sensor_to_str(bytes[2]), bytes[4]);
#endif
return;
}
void mai2_io_touch_update(bool player1, bool player2) {
if (mai2_io_cfg.debug_input_1p) {
if (player1 && mai2_io_touch_1p_thread == NULL) {
mai2_io_touch_1p_thread = (HANDLE)_beginthreadex(
NULL, 0, mai2_io_touch_1p_thread_proc, _callback, 0, NULL);
} else if (!player1 && mai2_io_touch_1p_thread != NULL) {
mai2_io_touch_1p_stop_flag = true;
WaitForSingleObject(mai2_io_touch_1p_thread, INFINITE);
CloseHandle(mai2_io_touch_1p_thread);
mai2_io_touch_1p_thread = NULL;
mai2_io_touch_1p_stop_flag = false;
}
}
if (mai2_io_cfg.debug_input_2p) {
if (player2 && mai2_io_touch_2p_thread == NULL) {
mai2_io_touch_2p_thread = (HANDLE)_beginthreadex(
NULL, 0, mai2_io_touch_2p_thread_proc, _callback, 0, NULL);
} else if (!player2 && mai2_io_touch_2p_thread != NULL) {
mai2_io_touch_2p_stop_flag = true;
WaitForSingleObject(mai2_io_touch_2p_thread, INFINITE);
CloseHandle(mai2_io_touch_2p_thread);
mai2_io_touch_2p_thread = NULL;
mai2_io_touch_2p_stop_flag = false;
}
}
}
static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx) {
mai2_io_touch_callback_t callback = ctx;
while (!mai2_io_touch_1p_stop_flag) {
uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0};
for (int i = 0; i < 34; i++) {
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_touch[i])) {
int byteIndex = i / 5;
int bitIndex = i % 5;
state[byteIndex] |= (1 << bitIndex);
}
}
callback(1, state);
Sleep(1);
}
return 0;
}
static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx) {
mai2_io_touch_callback_t callback = ctx;
while (!mai2_io_touch_2p_stop_flag) {
uint8_t state[7] = {0, 0, 0, 0, 0, 0, 0};
for (int i = 0; i < 34; i++) {
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_touch[i])) {
int byteIndex = i / 5;
int bitIndex = i % 5;
state[byteIndex] |= (1 << bitIndex);
}
}
callback(2, state);
Sleep(1);
}
return 0;
}
HRESULT mai2_io_led_init(void) { return S_OK; }
void mai2_io_led_set_fet_output(uint8_t board, const uint8_t *rgb) {
#if 0
uint8_t player = board + 1;
dprintf("MAI2 LED %dP: BodyLed brightness: %d%%\n", player,
(rgb[0] * 100) / 255);
dprintf("MAI2 LED %dP: ExtLed brightness: %d%%\n", player,
(rgb[1] * 100) / 255);
dprintf("MAI2 LED %dP: SideLed brightness: %d%%\n", player,
(rgb[2] * 100) / 255);
#endif
return;
}
void mai2_io_led_dc_update(uint8_t board, const uint8_t *rgb) {
#if 0
uint8_t player = board + 1;
for (int i = 0; i < 10; i++) {
dprintf("Mai2 LED %dP: LED %d: %02X %02X %02X Speed: %02X\n", player
i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]);
}
#endif
return;
}
void mai2_io_led_gs_update(uint8_t board, const uint8_t *rgb) {
#if 0
uint8_t player = board + 1;
for (int i = 0; i < 8; i++) {
dprintf("Mai2 LED %dP: LED %d: %02X %02X %02X Speed: %02X\n", player, i,
rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]);
}
#endif
return;
}

View File

@ -3,6 +3,7 @@
#include <windows.h>
#include <stdint.h>
#include <stdbool.h>
enum {
MAI2_IO_OPBTN_TEST = 0x01,
@ -66,3 +67,126 @@ void mai2_io_get_opbtns(uint8_t *opbtn);
Minimum API version: 0x0100 */
void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2);
/* Callback function used by mai2_io_touch_1p/2p_thread_proc.
The 'player'(1 or 2) parameter indicates which player the touch data is for.
The 'state' represents a complete response packet.
The format of the state array is as follows:
uint8_t state[7] = {
bytes[0] - bit(0 , 0 , 0 , A5, A4, A3, A2, A1)
bytes[1] - bit(0 , 0 , 0 , B2, B1, A8, A7, A6)
bytes[2] - bit(0 , 0 , 0 , B7, B6, B5, B4, B3)
bytes[3] - bit(0 , 0 , 0 , D2, D1, C2, C1, B8)
bytes[4] - bit(0 , 0 , 0 , D7, D6, D5, D4, D3)
bytes[5] - bit(0 , 0 , 0 , E4, E3, E2, E1, D8)
bytes[6] - bit(0 , 0 , 0 , 0 , E8, E7, E6, E5)
}
The 7 bytes are the touch data, with each byte storing the touch state in the lower 5 bits.
A value of 1 indicates that the corresponding touch area is pressed.
The touch areas are ordered from A1 to E8, and the binary values are stored from low to high. */
typedef void (*mai2_io_touch_callback_t)(const uint8_t player, const uint8_t state[7]);
/**
* @brief Initializes the touch input callback function
*
* This function accepts a callback function as a parameter and stores it in the global variable `_callback`
* for later handling of touch input events.
*
* @param callback The touch input callback function that takes two parameters: player number and the touch state array.
* @return HRESULT Returns the result of the operation, S_OK on success.
*/
HRESULT mai2_io_touch_init(mai2_io_touch_callback_t callback);
/* Send sensitivity setting data to the touch device.
Format:
bytes[0] - Header
bytes[1] - Target device, ASCII characters 'L' or 'R'
bytes[2] - Target touch point
bytes[3] - commandRatio identifier
bytes[4] - Ratio value to be set, within a fixed range
bytes[5] - Footer
Example function, not actually used. The sensitivity range can be determined
based on the Ratio set within the game. */
void mai2_io_touch_set_sens(uint8_t *bytes);
/**
* @brief Updates the touch input acceptance state
*
* This function determines whether the game is ready to accept touch input based on the states of player 1 and player 2.
* If the game is ready, it creates or stops the corresponding threads to handle touch data for each player.
* Whether or not threads are created for each player is controlled by `mai2_io_cfg.debug_input_1p` and `mai2_io_cfg.debug_input_2p` configuration.
*
* @param player1 If `true`, indicates the game is ready to accept touch data from player 1, `false` means the game is not ready.
* @param player2 If `true`, indicates the game is ready to accept touch data from player 2, `false` means the game is not ready.
*/
void mai2_io_touch_update(bool player1, bool player2);
/**
* @brief Player touch input handling thread
*
* This function runs in a separate thread, continuously monitoring player touch status and passing the state data
* to the main thread via a callback function. Each time a touch input is detected, it updates the `state` array and calls the callback.
* The thread stops when `mai2_io_touch_1p/2p_stop_flag` is `true`.
*
* @param ctx The callback function context, of type `mai2_io_touch_callback_t`, used to handle the touch input events.
* @return The thread's return value, typically `0`.
*/
static unsigned int __stdcall mai2_io_touch_1p_thread_proc(void *ctx);
static unsigned int __stdcall mai2_io_touch_2p_thread_proc(void *ctx);
/* Initialize LED emulation. This function will be called before any
other mai2_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 mai2_io_led_init(void);
/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes.
maimai DX uses two boards. Board 0 is for the player 1 side (left) and board 1
is for the player 2 side (right).
Set the brightness of the white light on the machine's outer shell.
The program will continuously send changed values to request the blinking effect.
[0]: BodyLed
[1]: ExtLed
[2]: SideLed
The LED is truned on when the byte is 255 and turned off when the byte is 0.
Minimum API version: 0x0101 */
void mai2_io_led_set_fet_output(uint8_t board, const uint8_t *rgb);
/* The effect of this command is unknown, it is triggered after LED_15070_CMD_EEPROM_READ. */
void mai2_io_led_dc_update(uint8_t board, const uint8_t *rgb);
/* Update the RGB LEDs. rgb is a pointer to an array up to 8 * 4 = 32 bytes.
maimai DX uses two boards. Board 0 is for the player 1 side (left) and board 1
is for the player 2 side (right).
The LEDs are laid out as follows:
[0-7]: 8 button 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 mai2_io_led_gs_update(uint8_t board, const uint8_t *rgb);

View File

@ -3,6 +3,9 @@ mai2io_lib = static_library(
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
dependencies : [
capnhook.get_variable('hook_dep'),
],
sources : [
'mai2io.c',
'mai2io.h',

View File

@ -46,6 +46,9 @@ 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_led15070')
add_project_arguments('-DLOG_LED15070', language: 'c')
endif
if get_option('log_all') or get_option('log_led15093')
add_project_arguments('-DLOG_LED15093', language: 'c')
endif
@ -61,6 +64,9 @@ 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_mai2_touch')
add_project_arguments('-DLOG_MAI2_TOUCH', language: 'c')
endif
if get_option('log_all') or get_option('log_chuni_slider')
add_project_arguments('-DLOG_CHUNI_SLIDER', language: 'c')
endif

View File

@ -13,6 +13,11 @@ option('log_io3',
value : false,
description : 'Enable debug logging for JVS'
)
option('log_led15070',
type : 'boolean',
value : false,
description : 'Enable debug logging for the 15070 LED board emulation'
)
option('log_led15093',
type : 'boolean',
value : false,
@ -38,6 +43,11 @@ option('log_carol_touch',
value : false,
description : 'Enable debug logging for the Carlo Touchscreen'
)
option('log_mai2_touch',
type : 'boolean',
value : false,
description : 'Enable debug logging for the mai2 TouchPanel'
)
option('log_chuni_slider',
type : 'boolean',
value : false,

View File

@ -41,7 +41,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
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->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 0, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);

View File

@ -81,8 +81,9 @@ static DWORD CALLBACK mu3_pre_startup(void)
goto fail;
}
unsigned int led_port_no[2] = {3, 0};
hr = led15093_hook_init(&mu3_hook_cfg.led15093,
mu3_dll.led_init, mu3_dll.led_set_leds, 3, 1, 1, 2);
mu3_dll.led_init, mu3_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
return hr;

View File

@ -189,7 +189,7 @@ HRESULT epay_hook_init(const struct epay_config *cfg) {
thinca_stub->impl1->unk220 = thinca_unk;
thinca_stub->impl1->unk228 = thinca_unk;
dprintf("Epay: Init\n");
dprintf("Epay: Init.\n");
return hr;
}

View File

@ -23,7 +23,8 @@ void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
wchar_t tmpstr[16];
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
cfg->port_no[0] = GetPrivateProfileIntW(L"led15070", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15070", L"portNo2", 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", 0xdead, filename);

View File

@ -100,8 +100,9 @@ static DWORD CALLBACK swdc_pre_startup(void)
}
/* Not working, different board -04 instead of -02? */
unsigned int led_port_no[2] = {2, 0};
hr = led15070_hook_init(&swdc_hook_cfg.led15070, swdc_dll.led_init,
swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, 2, 1);
swdc_dll.led_set_fet_output, NULL, swdc_dll.led_gs_update, led_port_no);
if (FAILED(hr)) {
goto fail;

View File

@ -203,7 +203,7 @@ static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len)
lights_data & SWDC_IO_LED_LEFT ? 0xFF : 0x00,
};
swdc_dll.led_set_leds(rgb_out);
swdc_dll.led_set_leds(0, rgb_out);
return S_OK;
}

View File

@ -11,9 +11,9 @@ struct swdc_dll {
void (*get_gamebtns)(uint16_t *gamebtn);
void (*get_analogs)(struct swdc_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);
void (*led_set_fet_output)(uint8_t board, const uint8_t *rgb);
void (*led_gs_update)(uint8_t board, const uint8_t *rgb);
void (*led_set_leds)(uint8_t board, const uint8_t *rgb);
HRESULT (*ffb_init)(void);
void (*ffb_toggle)(bool active);
void (*ffb_constant_force)(uint8_t direction, uint8_t force);

View File

@ -119,7 +119,7 @@ HRESULT swdc_io_led_init(void)
return S_OK;
}
void swdc_io_led_set_fet_output(const uint8_t *rgb)
void swdc_io_led_set_fet_output(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("SWDC LED: LEFT SEAT LED: %02X\n", rgb[0]);
@ -129,7 +129,7 @@ void swdc_io_led_set_fet_output(const uint8_t *rgb)
return;
}
void swdc_io_led_gs_update(const uint8_t *rgb)
void swdc_io_led_gs_update(uint8_t board, const uint8_t *rgb)
{
#if 0
for (int i = 0; i < 9; i++) {
@ -141,7 +141,7 @@ void swdc_io_led_gs_update(const uint8_t *rgb)
return;
}
void swdc_io_led_set_leds(const uint8_t *rgb)
void swdc_io_led_set_leds(uint8_t board, const uint8_t *rgb)
{
#if 0
dprintf("SWDC LED: START: %02X\n", rgb[0]);

View File

@ -123,7 +123,7 @@ HRESULT swdc_io_led_init(void);
Minimum API version: 0x0101 */
void swdc_io_led_set_fet_output(const uint8_t *rgb);
void swdc_io_led_set_fet_output(uint8_t board, const uint8_t *rgb);
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
@ -140,7 +140,7 @@ void swdc_io_led_set_fet_output(const uint8_t *rgb);
Minimum API version: 0x0101 */
void swdc_io_led_gs_update(const uint8_t *rgb);
void swdc_io_led_gs_update(uint8_t board, const uint8_t *rgb);
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
@ -156,7 +156,7 @@ void swdc_io_led_gs_update(const uint8_t *rgb);
Minimum API version: 0x0101 */
void swdc_io_led_set_leds(const uint8_t *rgb);
void swdc_io_led_set_leds(uint8_t board, const uint8_t *rgb);
/* Initialize FFB emulation. This function will be called before any
other swdc_io_ffb_*() function calls.

View File

@ -40,7 +40,8 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
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->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename);
cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo2", 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);

View File

@ -66,8 +66,9 @@ static DWORD CALLBACK tokyo_pre_startup(void)
goto fail;
}
unsigned int led_port_no[2] = {1, 0};
hr = led15093_hook_init(&tokyo_hook_cfg.led15093,
tokyo_dll.led_init, tokyo_dll.led_set_leds, 1, 1, 1, 2);
tokyo_dll.led_init, tokyo_dll.led_set_leds, led_port_no);
if (FAILED(hr)) {
return hr;