forked from TeamTofuShop/segatools
idz: add ffb and led emulation
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
59
idzhook/ffb.c
Normal 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
7
idzhook/ffb.h
Normal 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);
|
@ -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),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -4,4 +4,6 @@
|
||||
|
||||
#include "jvs/jvs-bus.h"
|
||||
|
||||
HRESULT idz_jvs_hook_init(void);
|
||||
|
||||
HRESULT idz_jvs_init(struct jvs_node **root);
|
||||
|
@ -32,5 +32,7 @@ shared_library(
|
||||
'jvs.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'ffb.c',
|
||||
'ffb.h',
|
||||
],
|
||||
)
|
||||
|
Reference in New Issue
Block a user