forked from Dniel97/segatools
Merge pull request 'Include chu2to3 engine' (#1) from CrazyRedMachine/segatools:chuniio into chuniio
Reviewed-on: Dniel97/segatools#1
This commit is contained in:
commit
16bbd87c73
@ -97,11 +97,16 @@ static DWORD CALLBACK chuni_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&chuni_hook_cfg.led15093,
|
if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL )
|
||||||
chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1);
|
{
|
||||||
|
dprintf("IO DLL doesn't support led_init/led_set_leds, cannot start LED15093 hook\n");
|
||||||
|
} else {
|
||||||
|
hr = led15093_hook_init(&chuni_hook_cfg.led15093,
|
||||||
|
chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod);
|
hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod);
|
||||||
|
357
chuniio/chu2to3.c
Normal file
357
chuniio/chu2to3.c
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "chuniio/chu2to3.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
// Check windows
|
||||||
|
#if _WIN32 || _WIN64
|
||||||
|
#if _WIN64
|
||||||
|
#define ENV64BIT
|
||||||
|
#else
|
||||||
|
#define ENV32BIT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check GCC
|
||||||
|
#if __GNUC__
|
||||||
|
#if __x86_64__ || __ppc64__
|
||||||
|
#define ENV64BIT
|
||||||
|
#else
|
||||||
|
#define ENV32BIT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* chuniio.dll dynamic loading */
|
||||||
|
HMODULE hinstLib;
|
||||||
|
typedef uint16_t (*chuni_io_get_api_version_t)(void);
|
||||||
|
typedef HRESULT (*chuni_io_jvs_init_t)(void);
|
||||||
|
typedef void (*chuni_io_jvs_poll_t)(uint8_t*, uint8_t*);
|
||||||
|
typedef void (*chuni_io_jvs_read_coin_counter_t)(uint16_t *);
|
||||||
|
typedef HRESULT (*chuni_io_slider_init_t)(void);
|
||||||
|
typedef void (*chuni_io_slider_set_leds_t)(const uint8_t *);
|
||||||
|
typedef void (*chuni_io_slider_start_t)(chuni_io_slider_callback_t);
|
||||||
|
typedef void (*chuni_io_slider_stop_t)(void);
|
||||||
|
typedef HRESULT (*chuni_io_led_init_t)(void);
|
||||||
|
typedef void (*chuni_io_led_set_colors_t)(uint8_t, uint8_t *);
|
||||||
|
|
||||||
|
chuni_io_get_api_version_t _chuni_io_get_api_version;
|
||||||
|
chuni_io_jvs_init_t _chuni_io_jvs_init;
|
||||||
|
chuni_io_jvs_poll_t _chuni_io_jvs_poll;
|
||||||
|
chuni_io_jvs_read_coin_counter_t _chuni_io_jvs_read_coin_counter;
|
||||||
|
chuni_io_slider_init_t _chuni_io_slider_init;
|
||||||
|
chuni_io_slider_set_leds_t _chuni_io_slider_set_leds;
|
||||||
|
chuni_io_slider_start_t _chuni_io_slider_start;
|
||||||
|
chuni_io_slider_stop_t _chuni_io_slider_stop;
|
||||||
|
chuni_io_led_init_t _chuni_io_led_init;
|
||||||
|
chuni_io_led_set_colors_t _chuni_io_led_set_colors;
|
||||||
|
|
||||||
|
/* SHMEM Handling */
|
||||||
|
#define BUF_SIZE 1024
|
||||||
|
#define SHMEM_WRITE(buf, size) CopyMemory((PVOID)g_pBuf, buf, size)
|
||||||
|
#define SHMEM_READ(buf, size) CopyMemory(buf,(PVOID)g_pBuf, size)
|
||||||
|
TCHAR g_shmem_name[]=TEXT("Local\\Chu2to3Shmem");
|
||||||
|
HANDLE g_hMapFile;
|
||||||
|
LPVOID g_pBuf;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct shared_data_s {
|
||||||
|
uint16_t coin_counter;
|
||||||
|
uint8_t opbtn;
|
||||||
|
uint8_t beams;
|
||||||
|
uint16_t version;
|
||||||
|
} shared_data_t;
|
||||||
|
|
||||||
|
shared_data_t g_shared_data;
|
||||||
|
|
||||||
|
bool shmem_create()
|
||||||
|
{
|
||||||
|
g_hMapFile = CreateFileMapping(
|
||||||
|
INVALID_HANDLE_VALUE, // use paging file
|
||||||
|
NULL, // default security
|
||||||
|
PAGE_READWRITE, // read/write access
|
||||||
|
0, // maximum object size (high-order DWORD)
|
||||||
|
BUF_SIZE, // maximum object size (low-order DWORD)
|
||||||
|
g_shmem_name); // name of mapping object
|
||||||
|
|
||||||
|
if (g_hMapFile == NULL)
|
||||||
|
{
|
||||||
|
dprintf("shmem_create : Could not create file mapping object (%d).\n",
|
||||||
|
GetLastError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
g_pBuf = MapViewOfFile(g_hMapFile, // handle to map object
|
||||||
|
FILE_MAP_ALL_ACCESS, // read/write permission
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
BUF_SIZE);
|
||||||
|
|
||||||
|
if (g_pBuf == NULL)
|
||||||
|
{
|
||||||
|
dprintf("shmem_create : Could not map view of file (%d).\n",
|
||||||
|
GetLastError());
|
||||||
|
|
||||||
|
CloseHandle(g_hMapFile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shmem_load()
|
||||||
|
{
|
||||||
|
g_hMapFile = OpenFileMapping(
|
||||||
|
FILE_MAP_ALL_ACCESS, // read/write access
|
||||||
|
FALSE, // do not inherit the name
|
||||||
|
g_shmem_name); // name of mapping object
|
||||||
|
|
||||||
|
if (g_hMapFile == NULL)
|
||||||
|
{
|
||||||
|
dprintf("shmem_load : Could not open file mapping object (%d).\n", GetLastError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pBuf = MapViewOfFile(g_hMapFile, // handle to map object
|
||||||
|
FILE_MAP_ALL_ACCESS, // read/write permission
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
BUF_SIZE);
|
||||||
|
|
||||||
|
if (g_pBuf == NULL)
|
||||||
|
{
|
||||||
|
dprintf("shmem_load : Could not map view of file (%d).\n", GetLastError());
|
||||||
|
CloseHandle(g_hMapFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("shmem_load : shmem loaded succesfully.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shmem_free()
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(g_pBuf);
|
||||||
|
CloseHandle(g_hMapFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* jvs polling thread (to forward info to x64 dll) */
|
||||||
|
static HANDLE jvs_poll_thread;
|
||||||
|
static bool jvs_poll_stop_flag;
|
||||||
|
|
||||||
|
static unsigned int __stdcall jvs_poll_thread_proc(void *ctx)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
_chuni_io_jvs_read_coin_counter(&g_shared_data.coin_counter);
|
||||||
|
g_shared_data.opbtn = 0;
|
||||||
|
_chuni_io_jvs_poll(&g_shared_data.opbtn, &g_shared_data.beams);
|
||||||
|
SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t chu2to3_load_dll(wchar_t *dllname)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x64 must just open the shmem and do nothing else */
|
||||||
|
int errcount = 0;
|
||||||
|
while (!shmem_load())
|
||||||
|
{
|
||||||
|
if (errcount >= 10)
|
||||||
|
return -1;
|
||||||
|
Sleep(5000);
|
||||||
|
errcount++;
|
||||||
|
}
|
||||||
|
Sleep(1000);
|
||||||
|
return S_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* this is the first function called so let's setup the chuniio forwarding */
|
||||||
|
hinstLib = LoadLibraryW(dllname);
|
||||||
|
if (hinstLib == NULL) {
|
||||||
|
dprintf("ERROR: unable to load %S (error %d)\n",dllname, GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_chuni_io_get_api_version = (chuni_io_get_api_version_t)GetProcAddress(hinstLib, "chuni_io_get_api_version");
|
||||||
|
_chuni_io_jvs_init = (chuni_io_jvs_init_t)GetProcAddress(hinstLib, "chuni_io_jvs_init");
|
||||||
|
_chuni_io_jvs_poll = (chuni_io_jvs_poll_t)GetProcAddress(hinstLib, "chuni_io_jvs_poll");
|
||||||
|
_chuni_io_jvs_read_coin_counter = (chuni_io_jvs_read_coin_counter_t)GetProcAddress(hinstLib, "chuni_io_jvs_read_coin_counter");
|
||||||
|
_chuni_io_slider_init = (chuni_io_slider_init_t)GetProcAddress(hinstLib, "chuni_io_slider_init");
|
||||||
|
_chuni_io_slider_set_leds = (chuni_io_slider_set_leds_t)GetProcAddress(hinstLib, "chuni_io_slider_set_leds");
|
||||||
|
_chuni_io_slider_start = (chuni_io_slider_start_t)GetProcAddress(hinstLib, "chuni_io_slider_start");
|
||||||
|
_chuni_io_slider_stop = (chuni_io_slider_stop_t)GetProcAddress(hinstLib, "chuni_io_slider_stop");
|
||||||
|
_chuni_io_led_init = (chuni_io_led_init_t)GetProcAddress(hinstLib, "chuni_io_led_init");
|
||||||
|
_chuni_io_led_set_colors = (chuni_io_led_set_colors_t)GetProcAddress(hinstLib, "chuni_io_led_set_colors");
|
||||||
|
|
||||||
|
/* x86 has to create the shmem */
|
||||||
|
if (!shmem_create())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chuniio exports */
|
||||||
|
uint16_t chu2to3_io_get_api_version(void)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* This might be called too soon so let's make sure x86 has time to write to the shmem */
|
||||||
|
SHMEM_READ(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
int errcount = 0;
|
||||||
|
while (g_shared_data.version == 0)
|
||||||
|
{
|
||||||
|
if (errcount >= 3)
|
||||||
|
{
|
||||||
|
dprintf("CHU2TO3 X64: Couldn't retrieve api version from shmem, assuming 0x0100\n");
|
||||||
|
return 0x0100;
|
||||||
|
}
|
||||||
|
Sleep(5000);
|
||||||
|
errcount++;
|
||||||
|
SHMEM_READ(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
}
|
||||||
|
dprintf("CHU2TO3 X64: api version is %04X\n", g_shared_data.version);
|
||||||
|
return g_shared_data.version;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( _chuni_io_get_api_version == NULL )
|
||||||
|
{
|
||||||
|
g_shared_data.version = 0x0100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_shared_data.version = _chuni_io_get_api_version();
|
||||||
|
}
|
||||||
|
dprintf("CHU2TO3: api version is %04X\n", g_shared_data.version);
|
||||||
|
|
||||||
|
SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
|
||||||
|
return g_shared_data.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT chu2to3_io_jvs_init(void)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return S_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_chuni_io_jvs_init();
|
||||||
|
|
||||||
|
/* start jvs poll thread now that jvs_init is done */
|
||||||
|
if (jvs_poll_thread != NULL) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jvs_poll_thread = (HANDLE) _beginthreadex(NULL,
|
||||||
|
0,
|
||||||
|
jvs_poll_thread_proc,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_jvs_read_coin_counter(uint16_t *out)
|
||||||
|
{
|
||||||
|
#if defined(ENV32BIT)
|
||||||
|
/* x86 can perform the call and update shmem (although this call never happens) */
|
||||||
|
_chuni_io_jvs_read_coin_counter(&g_shared_data.coin_counter);
|
||||||
|
SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* x64 must read value from shmem and update arg */
|
||||||
|
SHMEM_READ(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
if (out == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*out = g_shared_data.coin_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
|
||||||
|
{
|
||||||
|
#if defined(ENV32BIT)
|
||||||
|
/* x86 can perform the call and update shmem (although this call never happens) */
|
||||||
|
_chuni_io_jvs_poll(&g_shared_data.opbtn, &g_shared_data.beams);
|
||||||
|
SHMEM_WRITE(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* x64 must read value from shmem and update args */
|
||||||
|
SHMEM_READ(&g_shared_data, sizeof(shared_data_t));
|
||||||
|
*opbtn = g_shared_data.opbtn;
|
||||||
|
*beams = g_shared_data.beams;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT chu2to3_io_slider_init(void)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return S_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return _chuni_io_slider_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_slider_start(chuni_io_slider_callback_t callback)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_chuni_io_slider_start(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_slider_stop(void)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_chuni_io_slider_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_slider_set_leds(const uint8_t *rgb)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_chuni_io_slider_set_leds(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT chu2to3_io_led_init(void)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return S_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_chuni_io_led_init != NULL)
|
||||||
|
return _chuni_io_led_init();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chu2to3_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||||
|
{
|
||||||
|
#if defined(ENV64BIT)
|
||||||
|
/* x86 only */
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_chuni_io_led_set_colors != NULL)
|
||||||
|
{
|
||||||
|
_chuni_io_led_set_colors(board, rgb);
|
||||||
|
}
|
||||||
|
}
|
26
chuniio/chu2to3.h
Normal file
26
chuniio/chu2to3.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
CHU2TO3 CUSTOM IO API
|
||||||
|
|
||||||
|
This dll just mirrors chuniio dll binds but with a dynamic library loading and
|
||||||
|
a SHMEM system to let a single 32bit dll talk with x86 and x64 processes at once
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint16_t chu2to3_io_get_api_version(void);
|
||||||
|
HRESULT chu2to3_io_jvs_init(void);
|
||||||
|
void chu2to3_io_jvs_poll(uint8_t *opbtn, uint8_t *beams);
|
||||||
|
void chu2to3_io_jvs_read_coin_counter(uint16_t *total);
|
||||||
|
HRESULT chu2to3_io_slider_init(void);
|
||||||
|
typedef void (*chuni_io_slider_callback_t)(const uint8_t *state);
|
||||||
|
void chu2to3_io_slider_start(chuni_io_slider_callback_t callback);
|
||||||
|
void chu2to3_io_slider_stop(void);
|
||||||
|
void chu2to3_io_slider_set_leds(const uint8_t *rgb);
|
||||||
|
HRESULT chu2to3_io_led_init(void);
|
||||||
|
void chu2to3_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||||
|
uint16_t chu2to3_load_dll(wchar_t *dllname);
|
@ -8,6 +8,7 @@
|
|||||||
- 0x0100: Initial API version (assumed if chuni_io_get_api_version is not
|
- 0x0100: Initial API version (assumed if chuni_io_get_api_version is not
|
||||||
exported)
|
exported)
|
||||||
- 0x0101: Fix IR beam mappings
|
- 0x0101: Fix IR beam mappings
|
||||||
|
- 0x0102: Add air tower led and billboard support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -151,15 +152,24 @@ void chuni_io_slider_set_leds(const uint8_t *rgb);
|
|||||||
|
|
||||||
All subsequent calls may originate from arbitrary threads and some may
|
All subsequent calls may originate from arbitrary threads and some may
|
||||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||||
your responsibility. */
|
your responsibility.
|
||||||
|
|
||||||
|
Minimum API version: 0x0102 */
|
||||||
|
|
||||||
HRESULT chuni_io_led_init(void);
|
HRESULT chuni_io_led_init(void);
|
||||||
|
|
||||||
/* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198
|
/* Update the RGB LEDs. rgb is a pointer to an array of up to 63 * 3 = 189 bytes.
|
||||||
bytes. The majority of these are for the marquee display, but the final
|
|
||||||
LEDs are for the side partitions.
|
Chunithm uses two chains/boards with WS2811 protocol (each logical led corresponds to 3 physical leds).
|
||||||
|
board 0 is on the left side and board 1 on the right side of the cab
|
||||||
|
|
||||||
|
left side has 5*10 rgb values for the billboard, followed by 3 rgb values for the air tower
|
||||||
|
right side has 6*10 rgb values for the billboard, followed by 3 rgb values for the air tower
|
||||||
|
|
||||||
Chunithm uses two chains/boards. One is on the left side and one on the
|
Each rgb value is comprised of 3 bytes in R,G,B order
|
||||||
right side of the cab. Exact layout is TBD. */
|
|
||||||
|
NOTE: billboard strips have alternating direction (bottom to top, top to bottom, ...)
|
||||||
|
|
||||||
|
Minimum API version: 0x0102 */
|
||||||
|
|
||||||
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||||
|
@ -5,6 +5,8 @@ chuniio_lib = static_library(
|
|||||||
implicit_include_directories : false,
|
implicit_include_directories : false,
|
||||||
c_pch : '../precompiled.h',
|
c_pch : '../precompiled.h',
|
||||||
sources : [
|
sources : [
|
||||||
|
'chu2to3.c',
|
||||||
|
'chu2to3.h',
|
||||||
'chuniio.c',
|
'chuniio.c',
|
||||||
'chuniio.h',
|
'chuniio.h',
|
||||||
'config.c',
|
'config.c',
|
||||||
|
@ -39,6 +39,50 @@ const struct dll_bind_sym chuni_dll_syms[] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct dll_bind_sym chu2to3_dll_syms[] = {
|
||||||
|
{
|
||||||
|
.sym = "chu2to3_io_jvs_init",
|
||||||
|
.off = offsetof(struct chuni_dll, jvs_init),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_jvs_poll",
|
||||||
|
.off = offsetof(struct chuni_dll, jvs_poll),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_jvs_read_coin_counter",
|
||||||
|
.off = offsetof(struct chuni_dll, jvs_read_coin_counter),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_slider_init",
|
||||||
|
.off = offsetof(struct chuni_dll, slider_init),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_slider_start",
|
||||||
|
.off = offsetof(struct chuni_dll, slider_start),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_slider_stop",
|
||||||
|
.off = offsetof(struct chuni_dll, slider_stop),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_slider_set_leds",
|
||||||
|
.off = offsetof(struct chuni_dll, slider_set_leds),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_led_init",
|
||||||
|
.off = offsetof(struct chuni_dll, led_init),
|
||||||
|
}, {
|
||||||
|
.sym = "chu2to3_io_led_set_colors",
|
||||||
|
.off = offsetof(struct chuni_dll, led_set_leds),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper function to determine upon dll_bind failure whether the required functions were found
|
||||||
|
NOTE: relies on symbols order declared above */
|
||||||
|
static HRESULT has_enough_symbols(uint16_t version, uint8_t count)
|
||||||
|
{
|
||||||
|
if ( version <= 0x0101 && count == 7 )
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
if ( version >= 0x0102 && count == 9 )
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
struct chuni_dll chuni_dll;
|
struct chuni_dll chuni_dll;
|
||||||
|
|
||||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||||
@ -58,7 +102,12 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
|
|||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|
||||||
if (cfg->path[0] != L'\0') {
|
owned = NULL;
|
||||||
|
src = self;
|
||||||
|
|
||||||
|
if (cfg->chu2to3) {
|
||||||
|
dprintf("Chunithm IO: using chu2to3 engine for IO DLL: %S\n", cfg->path);
|
||||||
|
} else if (cfg->path[0] != L'\0') {
|
||||||
owned = LoadLibraryW(cfg->path);
|
owned = LoadLibraryW(cfg->path);
|
||||||
|
|
||||||
if (owned == NULL) {
|
if (owned == NULL) {
|
||||||
@ -72,12 +121,18 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
|
|||||||
|
|
||||||
dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path);
|
dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path);
|
||||||
src = owned;
|
src = owned;
|
||||||
} else {
|
|
||||||
owned = NULL;
|
|
||||||
src = self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version");
|
if (cfg->chu2to3) {
|
||||||
|
if (chu2to3_load_dll(cfg->path) != 0)
|
||||||
|
dprintf("Could not init chu2to3 engine\n");
|
||||||
|
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "chu2to3_io_get_api_version");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version");
|
||||||
|
}
|
||||||
|
|
||||||
if (get_api_version != NULL) {
|
if (get_api_version != NULL) {
|
||||||
chuni_dll.api_version = get_api_version();
|
chuni_dll.api_version = get_api_version();
|
||||||
@ -97,17 +152,26 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
sym = chuni_dll_syms;
|
sym = cfg->chu2to3 ? chu2to3_dll_syms : chuni_dll_syms;
|
||||||
|
const struct dll_bind_sym *init_sym = &sym[0];
|
||||||
|
|
||||||
hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms));
|
hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms));
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
if (src != self) {
|
if (src != self) {
|
||||||
dprintf("Chunithm IO: Custom IO DLL does not provide function "
|
// Might still be ok depending on external dll API version
|
||||||
"\"%s\". Please contact your IO DLL's developer for "
|
int bind_count = sym - init_sym;
|
||||||
"further assistance.\n",
|
if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK )
|
||||||
sym->sym);
|
{
|
||||||
|
hr = S_OK;
|
||||||
goto end;
|
} else {
|
||||||
|
dprintf("Chunithm IO: Custom IO DLL does not provide function "
|
||||||
|
"\"%s\". Please contact your IO DLL's developer for "
|
||||||
|
"further assistance.\n",
|
||||||
|
sym->sym);
|
||||||
|
dprintf("imported %d symbols\n",bind_count);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ struct chuni_dll {
|
|||||||
|
|
||||||
struct chuni_dll_config {
|
struct chuni_dll_config {
|
||||||
wchar_t path[MAX_PATH];
|
wchar_t path[MAX_PATH];
|
||||||
|
uint8_t chu2to3;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct chuni_dll chuni_dll;
|
extern struct chuni_dll chuni_dll;
|
||||||
|
@ -22,3 +22,13 @@ EXPORTS
|
|||||||
chuni_io_slider_stop
|
chuni_io_slider_stop
|
||||||
chuni_io_led_init
|
chuni_io_led_init
|
||||||
chuni_io_led_set_colors
|
chuni_io_led_set_colors
|
||||||
|
chu2to3_io_get_api_version
|
||||||
|
chu2to3_io_jvs_init
|
||||||
|
chu2to3_io_jvs_poll
|
||||||
|
chu2to3_io_jvs_read_coin_counter
|
||||||
|
chu2to3_io_slider_init
|
||||||
|
chu2to3_io_slider_set_leds
|
||||||
|
chu2to3_io_slider_start
|
||||||
|
chu2to3_io_slider_stop
|
||||||
|
chu2to3_io_led_init
|
||||||
|
chu2to3_io_led_set_colors
|
||||||
|
@ -39,16 +39,27 @@ void chuni_dll_config_load(
|
|||||||
|
|
||||||
// Workaround for x64/x86 external IO dlls
|
// Workaround for x64/x86 external IO dlls
|
||||||
// path32 for 32bit, path64 for 64bit
|
// path32 for 32bit, path64 for 64bit
|
||||||
// for else.. is that possible? idk
|
// path for 32bit only dlls (internal chu2to3 engine)
|
||||||
|
|
||||||
#if defined(ENV32BIT)
|
GetPrivateProfileStringW(
|
||||||
GetPrivateProfileStringW(
|
L"chuniio",
|
||||||
L"chuniio",
|
L"path",
|
||||||
L"path32",
|
L"",
|
||||||
L"",
|
cfg->path,
|
||||||
cfg->path,
|
_countof(cfg->path),
|
||||||
_countof(cfg->path),
|
filename);
|
||||||
filename);
|
if (cfg->path[0] != L'\0') {
|
||||||
|
cfg->chu2to3 = 1;
|
||||||
|
} else {
|
||||||
|
cfg->chu2to3 = 0;
|
||||||
|
#if defined(ENV32BIT)
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"chuniio",
|
||||||
|
L"path32",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
#elif defined(ENV64BIT)
|
#elif defined(ENV64BIT)
|
||||||
GetPrivateProfileStringW(
|
GetPrivateProfileStringW(
|
||||||
L"chuniio",
|
L"chuniio",
|
||||||
@ -60,7 +71,7 @@ void chuni_dll_config_load(
|
|||||||
#else
|
#else
|
||||||
#error "Unknown environment"
|
#error "Unknown environment"
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void slider_config_load(struct slider_config *cfg, const wchar_t *filename)
|
void slider_config_load(struct slider_config *cfg, const wchar_t *filename)
|
||||||
|
@ -129,11 +129,16 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&chusan_hook_cfg.led15093,
|
if ( chuni_dll.led_init == NULL || chuni_dll.led_set_leds == NULL )
|
||||||
chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1);
|
{
|
||||||
|
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, first_port, 2, 2, 1);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
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);
|
||||||
|
6
dist/chusan/segatools.ini
vendored
6
dist/chusan/segatools.ini
vendored
@ -64,7 +64,11 @@ framed=0
|
|||||||
monitor=0
|
monitor=0
|
||||||
|
|
||||||
[chuniio]
|
[chuniio]
|
||||||
; Uncomment this if you have custom chuniio implementation.
|
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
||||||
|
; (will use chu2to3 engine internally)
|
||||||
|
;path=
|
||||||
|
|
||||||
|
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
||||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||||
;path32=
|
;path32=
|
||||||
;path64=
|
;path64=
|
||||||
|
Loading…
Reference in New Issue
Block a user