idz: add ffb and led emulation

This commit is contained in:
2024-09-30 23:10:16 +02:00
parent 2251585ef0
commit 259b763a13
26 changed files with 886 additions and 152 deletions

View File

@ -18,6 +18,42 @@
#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 idz_dll_config_load(
struct idz_dll_config *cfg,
const wchar_t *filename)
@ -47,6 +83,8 @@ void idz_hook_config_load(
dvd_config_load(&cfg->dvd, filename);
gfx_config_load(&cfg->gfx, filename);
idz_dll_config_load(&cfg->dll, filename);
ffb_config_load(&cfg->ffb, filename);
led15070_config_load(&cfg->led15070, filename);
zinput_config_load(&cfg->zinput, filename);
}

View File

@ -5,7 +5,8 @@
#include "amex/amex.h"
#include "board/sg-reader.h"
#include "board/config.h"
#include "board/led15070.h"
#include "gfxhook/gfx.h"
@ -23,6 +24,8 @@ struct idz_hook_config {
struct dvd_config dvd;
struct gfx_config gfx;
struct idz_dll_config dll;
struct ffb_config ffb;
struct led15070_config led15070;
struct zinput_config zinput;
};

View File

@ -33,6 +33,7 @@
#include "idzhook/config.h"
#include "idzhook/idz-dll.h"
#include "idzhook/jvs.h"
#include "idzhook/ffb.h"
#include "idzhook/zinput.h"
#include "platform/platform.h"
@ -102,6 +103,12 @@ static DWORD CALLBACK idz_pre_startup(void)
goto fail;
}
hr = idz_jvs_hook_init();
if (FAILED(hr)) {
goto fail;
}
hr = amex_hook_init(&idz_hook_cfg.amex, idz_jvs_init);
if (FAILED(hr)) {
@ -114,6 +121,19 @@ static DWORD CALLBACK idz_pre_startup(void)
goto fail;
}
hr = idz_ffb_hook_init(&idz_hook_cfg.ffb, 1);
if (FAILED(hr)) {
goto fail;
}
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);
if (FAILED(hr)) {
goto fail;
}
/* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini");

59
idzhook/ffb.c Normal file
View File

@ -0,0 +1,59 @@
#include <windows.h>
#include <xinput.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "board/ffb.h"
#include "idzhook/idz-dll.h"
#include "util/dprintf.h"
static void idz_ffb_toggle(bool active);
static void idz_ffb_constant_force(uint8_t direction, uint8_t force);
static void idz_ffb_rumble(uint8_t force, uint8_t period);
static void idz_ffb_damper(uint8_t force);
static const struct ffb_ops idz_ffb_ops = {
.toggle = idz_ffb_toggle,
.constant_force = idz_ffb_constant_force,
.rumble = idz_ffb_rumble,
.damper = idz_ffb_damper
};
HRESULT idz_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no)
{
HRESULT hr;
assert(idz_dll.jvs_init != NULL);
hr = ffb_hook_init(cfg, &idz_ffb_ops, port_no);
if (FAILED(hr)) {
return hr;
}
return idz_dll.ffb_init();
}
static void idz_ffb_toggle(bool active)
{
idz_dll.ffb_toggle(active);
}
static void idz_ffb_constant_force(uint8_t direction, uint8_t force)
{
idz_dll.ffb_constant_force(direction, force);
}
static void idz_ffb_rumble(uint8_t force, uint8_t period)
{
idz_dll.ffb_rumble(force, period);
}
static void idz_ffb_damper(uint8_t force)
{
idz_dll.ffb_damper(force);
}

7
idzhook/ffb.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include "board/ffb.h"
HRESULT idz_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no);

View File

@ -24,6 +24,33 @@ const struct dll_bind_sym idz_dll_syms[] = {
}, {
.sym = "idz_io_jvs_read_coin_counter",
.off = offsetof(struct idz_dll, jvs_read_coin_counter),
}, {
.sym = "idz_io_led_init",
.off = offsetof(struct idz_dll, led_init),
}, {
.sym = "idz_io_led_set_fet_output",
.off = offsetof(struct idz_dll, led_set_fet_output),
}, {
.sym = "idz_io_led_gs_update",
.off = offsetof(struct idz_dll, led_gs_update),
}, {
.sym = "idz_io_led_set_leds",
.off = offsetof(struct idz_dll, led_set_leds),
}, {
.sym = "idz_io_ffb_init",
.off = offsetof(struct idz_dll, ffb_init),
}, {
.sym = "idz_io_ffb_toggle",
.off = offsetof(struct idz_dll, ffb_toggle),
}, {
.sym = "idz_io_ffb_constant_force",
.off = offsetof(struct idz_dll, ffb_constant_force),
}, {
.sym = "idz_io_ffb_rumble",
.off = offsetof(struct idz_dll, ffb_rumble),
}, {
.sym = "idz_io_ffb_damper",
.off = offsetof(struct idz_dll, ffb_damper),
}
};

View File

@ -11,6 +11,15 @@ struct idz_dll {
void (*jvs_read_buttons)(uint8_t *opbtn, uint8_t *gamebtn);
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);
HRESULT (*ffb_init)(void);
void (*ffb_toggle)(bool active);
void (*ffb_constant_force)(uint8_t direction, uint8_t force);
void (*ffb_rumble)(uint8_t period, uint8_t force);
void (*ffb_damper)(uint8_t force);
};
struct idz_dll_config {

View File

@ -22,3 +22,12 @@ EXPORTS
idz_io_jvs_read_buttons
idz_io_jvs_read_coin_counter
idz_io_jvs_read_shifter
idz_io_led_init
idz_io_led_set_fet_output
idz_io_led_gs_update
idz_io_led_set_leds
idz_io_ffb_init
idz_io_ffb_toggle
idz_io_ffb_constant_force
idz_io_ffb_rumble
idz_io_ffb_damper

View File

@ -24,11 +24,13 @@ static void idz_jvs_read_coin_counter(
void *ctx,
uint8_t slot_no,
uint16_t *out);
static void idz_jvs_write_gpio(void *ctx, uint32_t state);
static const struct io3_ops idz_jvs_io3_ops = {
.read_switches = idz_jvs_read_switches,
.read_analogs = idz_jvs_read_analogs,
.read_coin_counter = idz_jvs_read_coin_counter,
.write_gpio = idz_jvs_write_gpio
};
static const uint16_t idz_jvs_gear_signals[] = {
@ -50,21 +52,20 @@ static const uint16_t idz_jvs_gear_signals[] = {
static struct io3 idz_jvs_io3;
HRESULT idz_jvs_hook_init(void)
{
HRESULT hr;
assert(idz_dll.jvs_init != NULL);
return idz_dll.jvs_init();
}
HRESULT idz_jvs_init(struct jvs_node **out)
{
HRESULT hr;
assert(out != NULL);
assert(idz_dll.jvs_init != NULL);
dprintf("JVS I/O: Starting Initial D Zero backend DLL\n");
hr = idz_dll.jvs_init();
if (FAILED(hr)) {
dprintf("JVS I/O: Backend error, I/O disconnected; %x\n", (int) hr);
return hr;
}
io3_init(&idz_jvs_io3, NULL, &idz_jvs_io3_ops, NULL);
*out = io3_to_jvs_node(&idz_jvs_io3);
@ -175,3 +176,21 @@ static void idz_jvs_read_coin_counter(
idz_dll.jvs_read_coin_counter(out);
}
static void idz_jvs_write_gpio(void *ctx, uint32_t state)
{
assert(idz_dll.led_set_leds != NULL);
// 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] = {
state & IDZ_IO_LED_START ? 0xFF : 0x00,
state & IDZ_IO_LED_VIEW_CHANGE ? 0xFF : 0x00,
state & IDZ_IO_LED_UP ? 0xFF : 0x00,
state & IDZ_IO_LED_DOWN ? 0xFF : 0x00,
state & IDZ_IO_LED_RIGHT ? 0xFF : 0x00,
state & IDZ_IO_LED_LEFT ? 0xFF : 0x00,
};
idz_dll.led_set_leds(rgb_out);
}

View File

@ -4,4 +4,6 @@
#include "jvs/jvs-bus.h"
HRESULT idz_jvs_hook_init(void);
HRESULT idz_jvs_init(struct jvs_node **root);

View File

@ -32,5 +32,7 @@ shared_library(
'jvs.h',
'zinput.c',
'zinput.h',
'ffb.c',
'ffb.h',
],
)