forked from TeamTofuShop/segatools
swdc: add ffb and led emulation
This commit is contained in:
@ -13,6 +13,43 @@
|
||||
#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", 0xdead, 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 swdc_dll_config_load(
|
||||
struct swdc_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
@ -43,6 +80,7 @@ void swdc_hook_config_load(
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
vfd_config_load(&cfg->vfd, filename);
|
||||
led15070_config_load(&cfg->led15070, filename);
|
||||
}
|
||||
|
||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "board/led15070.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
@ -17,7 +18,9 @@ struct swdc_hook_config {
|
||||
struct aime_config aime;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct ffb_config ffb;
|
||||
struct vfd_config vfd;
|
||||
struct led15070_config led15070;
|
||||
struct swdc_dll_config dll;
|
||||
struct zinput_config zinput;
|
||||
};
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "swdchook/config.h"
|
||||
#include "swdchook/swdc-dll.h"
|
||||
#include "swdchook/io4.h"
|
||||
#include "swdchook/ffb.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
@ -91,6 +92,19 @@ static DWORD CALLBACK swdc_pre_startup(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = swdc_ffb_hook_init(&swdc_hook_cfg.ffb, 1);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Hook external DLL APIs */
|
||||
|
||||
zinput_hook_init(&swdc_hook_cfg.zinput);
|
||||
|
59
swdchook/ffb.c
Normal file
59
swdchook/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 "swdchook/swdc-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void swdc_ffb_toggle(bool active);
|
||||
static void swdc_ffb_constant_force(uint8_t direction, uint8_t force);
|
||||
static void swdc_ffb_rumble(uint8_t force, uint8_t period);
|
||||
static void swdc_ffb_damper(uint8_t force);
|
||||
|
||||
static const struct ffb_ops swdc_ffb_ops = {
|
||||
.toggle = swdc_ffb_toggle,
|
||||
.constant_force = swdc_ffb_constant_force,
|
||||
.rumble = swdc_ffb_rumble,
|
||||
.damper = swdc_ffb_damper
|
||||
};
|
||||
|
||||
HRESULT swdc_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(swdc_dll.init != NULL);
|
||||
|
||||
hr = ffb_hook_init(cfg, &swdc_ffb_ops, port_no);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return swdc_dll.ffb_init();
|
||||
}
|
||||
|
||||
static void swdc_ffb_toggle(bool active)
|
||||
{
|
||||
swdc_dll.ffb_toggle(active);
|
||||
}
|
||||
|
||||
static void swdc_ffb_constant_force(uint8_t direction, uint8_t force)
|
||||
{
|
||||
swdc_dll.ffb_constant_force(direction, force);
|
||||
}
|
||||
|
||||
static void swdc_ffb_rumble(uint8_t force, uint8_t period)
|
||||
{
|
||||
swdc_dll.ffb_rumble(force, period);
|
||||
}
|
||||
|
||||
static void swdc_ffb_damper(uint8_t force)
|
||||
{
|
||||
swdc_dll.ffb_damper(force);
|
||||
}
|
7
swdchook/ffb.h
Normal file
7
swdchook/ffb.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/ffb.h"
|
||||
|
||||
HRESULT swdc_ffb_hook_init(const struct ffb_config *cfg, unsigned int port_no);
|
@ -15,10 +15,12 @@ static HRESULT init_mmf(void);
|
||||
static void swdc_set_gamebtns(uint16_t value);
|
||||
|
||||
static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state);
|
||||
static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len);
|
||||
static uint16_t coins;
|
||||
|
||||
static const struct io4_ops swdc_io4_ops = {
|
||||
.poll = swdc_io4_poll,
|
||||
.poll = swdc_io4_poll,
|
||||
.write_gpio = swdc_io4_write_gpio
|
||||
};
|
||||
|
||||
HRESULT swdc_io4_hook_init(const struct io4_config *cfg) {
|
||||
@ -172,3 +174,34 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) {
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT swdc_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 SWDC, 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 & SWDC_IO_LED_START ? 0xFF : 0x00,
|
||||
lights_data & SWDC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00,
|
||||
lights_data & SWDC_IO_LED_UP ? 0xFF : 0x00,
|
||||
lights_data & SWDC_IO_LED_DOWN ? 0xFF : 0x00,
|
||||
lights_data & SWDC_IO_LED_RIGHT ? 0xFF : 0x00,
|
||||
lights_data & SWDC_IO_LED_LEFT ? 0xFF : 0x00,
|
||||
};
|
||||
|
||||
swdc_dll.led_set_leds(rgb_out);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -28,5 +28,7 @@ shared_library(
|
||||
'io4.h',
|
||||
'zinput.c',
|
||||
'zinput.h',
|
||||
'ffb.c',
|
||||
'ffb.h'
|
||||
],
|
||||
)
|
||||
|
@ -21,6 +21,33 @@ const struct dll_bind_sym swdc_dll_syms[] = {
|
||||
}, {
|
||||
.sym = "swdc_io_get_analogs",
|
||||
.off = offsetof(struct swdc_dll, get_analogs),
|
||||
}, {
|
||||
.sym = "swdc_io_led_init",
|
||||
.off = offsetof(struct swdc_dll, led_init),
|
||||
}, {
|
||||
.sym = "swdc_io_led_set_fet_output",
|
||||
.off = offsetof(struct swdc_dll, led_set_fet_output),
|
||||
}, {
|
||||
.sym = "swdc_io_led_gs_update",
|
||||
.off = offsetof(struct swdc_dll, led_gs_update),
|
||||
}, {
|
||||
.sym = "swdc_io_led_set_leds",
|
||||
.off = offsetof(struct swdc_dll, led_set_leds),
|
||||
}, {
|
||||
.sym = "swdc_io_ffb_init",
|
||||
.off = offsetof(struct swdc_dll, ffb_init),
|
||||
}, {
|
||||
.sym = "swdc_io_ffb_toggle",
|
||||
.off = offsetof(struct swdc_dll, ffb_toggle),
|
||||
}, {
|
||||
.sym = "swdc_io_ffb_constant_force",
|
||||
.off = offsetof(struct swdc_dll, ffb_constant_force),
|
||||
}, {
|
||||
.sym = "swdc_io_ffb_rumble",
|
||||
.off = offsetof(struct swdc_dll, ffb_rumble),
|
||||
}, {
|
||||
.sym = "swdc_io_ffb_damper",
|
||||
.off = offsetof(struct swdc_dll, ffb_damper),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,15 @@ struct swdc_dll {
|
||||
void (*get_opbtns)(uint8_t *opbtn);
|
||||
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);
|
||||
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 swdc_dll_config {
|
||||
|
@ -16,3 +16,12 @@ EXPORTS
|
||||
swdc_io_get_opbtns
|
||||
swdc_io_get_gamebtns
|
||||
swdc_io_get_analogs
|
||||
swdc_io_led_init
|
||||
swdc_io_led_set_fet_output
|
||||
swdc_io_led_gs_update
|
||||
swdc_io_led_set_leds
|
||||
swdc_io_ffb_init
|
||||
swdc_io_ffb_toggle
|
||||
swdc_io_ffb_constant_force
|
||||
swdc_io_ffb_rumble
|
||||
swdc_io_ffb_damper
|
||||
|
Reference in New Issue
Block a user