Compare commits

...

91 Commits

Author SHA1 Message Date
Dniel97 25e954fb55 Merge pull request 'print vfd message instead of dump hex' (#13) from Sucareto/segatools:develop into develop
Reviewed-on: Dniel97/segatools#13
2024-04-29 19:48:35 +00:00
Dniel97 a8c6ac70e4 Merge pull request '[unity] Fix Unity config path' (#12) from beerpsi/segatools:fix/unity/wrong-config-path into develop
Reviewed-on: Dniel97/segatools#12
2024-04-29 19:41:53 +00:00
Dniel97 eb1ec0e261
idac: updated start.bat script 2024-04-29 21:34:30 +02:00
Sucareto 482a6e530a print vfd message 2024-04-30 02:19:10 +08:00
beerpsi 65173e1fa6 [unity] Fix Unity config path 2024-04-29 23:12:10 +07:00
beerpsi 4041844ea9 mai2/mu3/cm: Integrate UnityDoorstop with segatools (#11)
[UnityDoorstop](https://github.com/NeighTools/UnityDoorstop) is a tool to execute managed code (.NET DLLs) before Unity does, useful for modding frameworks such as BepInEx.

This PR integrates parts of its code into segatools, so loading BepInEx is as simple as adding 2 lines to `segatools.ini`:
```ini
[unity]
targetAssembly=BepInEx\core\BepInEx.Preloader.dll
```

This PR also factors out the Unity path redirection hooks to its own module.

Reviewed-on: Dniel97/segatools#11
Co-authored-by: beerpsi <beerpsi@duck.com>
Co-committed-by: beerpsi <beerpsi@duck.com>
2024-04-15 19:30:28 +00:00
Dniel97 47a65e5e51
fixed aime LED firmware 2024-03-17 14:20:13 +01:00
Dniel97 774a639bb7
cxb: fixed configs 2024-03-14 00:14:51 +01:00
Dniel97 097b74d849
cxb: server support added, bugfixes, thanks @Midorica 2024-03-13 21:40:25 +01:00
Dniel97 2590e749ca
config bugfixes 2024-03-07 15:46:43 +01:00
Dniel97 9c66488906
added Move/Replace/Delete hooks
- fixes FGO not correctly switching `START UP MODE`
- fixes SWDC not correctly switching `CABINET SETTING`
2024-02-27 16:54:12 +01:00
Dniel97 f570869946
fixed AMFS path redirect with no E:/ drive present 2024-02-27 16:49:27 +01:00
Dniel97 629ded4018 added AimePay, E-MONEY DNS redirects 2024-02-25 19:03:05 +01:00
Dniel97 ca36a879cb
updated README and added "AM Daemon" window name 2024-02-22 19:12:18 +01:00
Dniel97 ae199502e8
fixed amfs/appdata redirects 2024-02-22 12:02:32 +01:00
Dniel97 e40e1dffe3
improved all `segatools.ini` configs 2024-02-21 21:58:44 +01:00
Dniel97 56e971c6a4
changed default operator buttons to F1, F2 and F3 and fixed subnets 2024-02-06 13:01:26 +01:00
Dniel97 3e9303e043
fgo: ups forgot to add it to Package.mk 2024-02-06 12:34:39 +01:00
Dniel97 451a7ec49d
added VFD toggle to config 2024-02-06 12:34:11 +01:00
Dniel97 dae3018411
doc: added develop dongle hint 2024-01-27 23:10:59 +01:00
Dniel97 cadf20040c
swdc: fixed dinput buttons 2024-01-17 15:52:41 +01:00
Dniel97 cc0b6b0953
swdc: fixed steering wheel buttons, improved start.bat 2024-01-16 17:56:24 +01:00
Dniel97 0affc96e3e
small optimizations 2024-01-16 17:54:06 +01:00
Dniel97 a8bd98706f Merge pull request 'fix(netenv): Print IP addresses properly' (#4) from beerpsi/segatools:fix/print-ip-addresses-properly into develop
Reviewed-on: Dniel97/segatools#4
2024-01-08 18:26:51 +00:00
beerpsi aa2184f947 Merge branch 'develop' into fix/print-ip-addresses-properly 2024-01-07 18:36:04 +00:00
beerpsi d0165b1eb0 fix(netenv): Print IP addresses properly 2024-01-08 01:34:55 +07:00
Dniel97 477dad2667
Merge branch 'chuniio' into develop 2023-12-27 19:29:55 +01:00
Dniel97 63320f8456 Merge pull request 'fix chunihook' (#2) from CrazyRedMachine/segatools:chuniio into chuniio
Reviewed-on: Dniel97/segatools#2
2023-12-27 15:14:07 +00:00
CrazyRedMachine 926493290b fix chunihook 2023-12-26 06:47:19 -05:00
Dniel97 f4a3a5f78d
optimized meson.build to decrease filesize 2023-12-25 15:55:43 +01:00
Dniel97 f5f275c8e9
chuniio: fixed individual IR notes 2023-12-25 15:12:25 +01:00
Dniel97 b38dea23ac
chu2to3: fixed docker compilation, bugfixes 2023-12-25 15:03:44 +01:00
Dniel97 16bbd87c73 Merge pull request 'Include chu2to3 engine' (#1) from CrazyRedMachine/segatools:chuniio into chuniio
Reviewed-on: Dniel97/segatools#1
2023-12-25 14:02:33 +00:00
CrazyRedMachine ee414d122b Include chu2to3 engine 2023-12-24 08:33:30 -05:00
Dniel97 d4372fa5c2
chuniio: use HRESULT instead of int for chuni_io_led_init() 2023-12-21 00:45:41 +01:00
Dniel97 ac9b889d71
chusan/chuni: tower LEDs added 2023-12-19 14:40:02 +01:00
Dniel97 3bf223c04e
chusan: fixed SP/CVT switching 2023-12-19 13:45:06 +01:00
Dniel97 8ebdf67d6e
chuni/chusan: added LED output to DLLs (will break most DLLs)
Credits: somewhatlurker, skogaby
https://dev.s-ul.net/skogaby/segatools/-/blob/ongeki-15093/
2023-12-19 12:48:33 +01:00
Dniel97 ed042176d7
chusan: ledport changed to COM5, fixes VFD 2023-12-17 20:17:26 +01:00
Dniel97 ad154a83e5
chusan: fixed dipsw settings, added aimeio DLL loading 2023-12-17 19:43:00 +01:00
Dniel97 1cbc33d97d
chuasn: fixed coin insert for custom chuniio 2023-12-17 09:26:30 +01:00
Dniel97 72db08ac93
idz, idac, swdc: added FFB centering spring feature 2023-12-11 19:18:25 +01:00
Dniel97 4ffcf25555
added freeplay setting to ALLS games 2023-12-03 22:22:17 +01:00
Dniel97 3dd6054a1e
chusan, fgo, mu3: fixed LED 15093 board 2023-12-03 21:34:38 +01:00
Dniel97 793417e891
added new aime card reader generation
- Added new aime generation: 837-15286 and 837-15396
- New config setting `[aime] gen=3` for 837-15396
- Updated LED information for card reader
- Updated all games with the needed reader generation?
2023-12-03 18:45:42 +01:00
Dniel97 8c12853051
cm: disabled coin selector AS6DB 2023-11-30 00:02:00 +01:00
Dniel97 a3fd2fb926
Merge branch 'master' into develop 2023-11-29 23:07:24 +01:00
Dniel97 8b1d0cfefa
LED board improvements and cleanup 2023-11-25 23:00:05 +01:00
Dniel97 d86baab852
fgo: working FTDI hook by @OLEG
from: 88a0026f0b
2023-11-22 21:43:42 +01:00
Dniel97 b9fd59fd70
idz: added fullscreen patch by @Felix (again) 2023-11-20 18:04:45 +01:00
Dniel97 146fac9287
dns: block more All.NET requests 2023-11-12 21:16:02 +01:00
Dniel97 3cf5cbb793
added LED 15093-06 credits and docs 2023-11-12 19:14:42 +01:00
Dniel97 a2db39c58c
fgo: fgohook finally added
Credits:
- Coburn
- domeori
- Mitsuhide
- OLEG
- rakisaionji
2023-11-11 23:05:11 +01:00
Dniel97 946ea7ef3b
chusan: fixed LED configs 2023-11-11 22:41:04 +01:00
Dniel97 25562e37f9
nusec: fixes keychip not found error 0949 2023-11-02 23:32:13 +01:00
Dniel97 d521eeb43e
idz, idac, swdc: Added separate pedals config, better XInput controls
- Configure separate pedals which are not part of the steering wheel (base)
 - It is now possible to have a different steering wheel, pedal and shifter brand all connected to 3 different USB ports
- XInput does not have a deadzone at the end of the max steering anymore and the `restrict` setting works as intended
2023-10-05 00:46:54 +02:00
Dniel97 6c45d0995b
fix cursor being annoying by @OLEG
95273ccecb
2023-10-05 00:37:25 +02:00
Dniel97 a4bd570cfc
chusan, mai2, mu3, swdc: removed emoney config 2023-10-05 00:35:55 +02:00
Dniel97 37793fc051
Merge branch 'master' into develop 2023-10-05 00:30:24 +02:00
Dniel97 f5a7e5b821
epay: added config because git is dumb 2023-09-15 19:58:46 +02:00
Dniel97 5ef0cf6181
Merge branch 'master' into develop 2023-09-15 19:56:48 +02:00
Dniel97 31203daa09
idz, idac, swdc: fixed `restrict` config setting 2023-09-05 00:24:43 +02:00
Dniel97 80718104f6
swdc: updated config, fixed start.bat 2023-09-05 00:23:17 +02:00
Dniel97 eb2eef927a
idac: added left and right button mapping 2023-09-04 23:31:52 +02:00
Dniel97 9bef9e49f8
swdc: added aime firm to config_hook.json 2023-09-04 02:05:37 +02:00
Dniel97 d5a551482b
idac: mapped left and right thumbstick to dpad left and right 2023-09-04 02:04:42 +02:00
Dniel97 49f729c501
idz, idac, swdc: switched to `[xinput]` config instead of [io] 2023-09-04 02:03:31 +02:00
Dniel97 91f69beae6
idac: fixed config error 2023-08-30 02:24:02 +02:00
Dniel97 51b11469d0
added `aimeGen` as default instead of `feliciaGen` 2023-08-29 22:57:04 +02:00
Dniel97 f0dc51d01e
idac: added config_hook.json 2023-08-29 20:03:33 +02:00
Dniel97 ca4a8bd84d
idz, idac, swdc: Added deadzone config 2023-08-29 02:22:05 +02:00
Dniel97 f6e961d4f4
Removed `-f` from start.bat and fixed idz 2023-08-29 00:49:58 +02:00
Dniel97 a69a9b5917
swdc: disabled built in XInput 2023-08-20 16:21:55 +02:00
Dniel97 97234f26d7
cm, chusan, mai2, mu3, swdc: added emoney config 2023-08-15 22:02:38 +02:00
Dniel97 2277bf7526
all: fix accounting issue (my bad) 2023-08-15 20:23:28 +02:00
Dniel97 80d5fc4bb2
mu3: Added basic keyboard and mouse lever emulation support 2023-08-15 17:40:32 +02:00
Dniel97 608c9ac1a6
chusan, cm, mai2, mu3: Added dipSw support and highBaudrate AiMe 2023-08-15 17:28:19 +02:00
Dniel97 3dc2ec6e69
idac, idz, swdc: Fixed DInput brake/accel, added cubic steering 2023-08-15 17:20:27 +02:00
Dniel97 28ef2d719a
dinput: fixed POV bug 2023-07-19 12:31:57 +02:00
Dniel97 600f795104
disable dipsw by default 2023-07-14 01:07:22 +02:00
Dniel97 e5d17b82b2
updated Package.mk for mai2, cm 2023-07-14 01:03:36 +02:00
Dniel97 0ee081ca1b
mai2: segatools added 2023-07-14 01:00:28 +02:00
Dniel97 01be6ee33c
cardmaker: hook, touch screen hook added
Thanks @domeori https://dev.s-ul.net/domeori/segatools/-/tree/mr-imports
2023-07-14 00:59:24 +02:00
Dniel97 2a6a8bf8b2
chusan: added chusanhook, led board fix, config added
credits go to @domeori https://dev.s-ul.net/domeori/segatools/-/tree/mr-imports
2023-07-14 00:58:02 +02:00
Dniel97 90a6f1be7c
mu3: coin input added 2023-07-14 00:54:30 +02:00
Dniel97 ec072667b3
swdc: first segatools added 2023-07-14 00:52:50 +02:00
Dniel97 89195ed60b
Merge branch 'idac_test' into develop 2023-07-14 00:43:38 +02:00
Dniel97 c27ef9674d
idac: added dipswitch support (beta) 2023-07-14 00:41:23 +02:00
Dniel97 da97d23b51
idac: first segatools support 2023-06-29 11:27:52 +02:00
Dniel97 ee6675dd73
Merge branch 'master' into idac_test 2023-06-27 21:11:45 +02:00
Dniel97 555784258a
idac: test 2023-04-23 16:13:51 +02:00
254 changed files with 18988 additions and 410 deletions

View File

@ -73,6 +73,53 @@ $(BUILD_DIR_ZIP)/idz.zip:
$(V)strip $(BUILD_DIR_ZIP)/idz/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/idz ; zip -r ../idz.zip *
$(BUILD_DIR_ZIP)/fgo.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/fgo
$(V)mkdir -p $(BUILD_DIR_ZIP)/fgo/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/fgohook/fgohook.dll \
$(DIST_DIR)/fgo/segatools.ini \
$(DIST_DIR)/fgo/start.bat \
$(BUILD_DIR_ZIP)/fgo
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/fgo/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/fgo/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/fgo ; zip -r ../fgo.zip *
$(BUILD_DIR_ZIP)/idac.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/idac
$(V)mkdir -p $(BUILD_DIR_ZIP)/idac/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/idachook/idachook.dll \
$(DIST_DIR)/idac/segatools.ini \
$(DIST_DIR)/idac/config_hook.json \
$(DIST_DIR)/idac/start.bat \
$(BUILD_DIR_ZIP)/idac
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/idac/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/idac/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/idac ; zip -r ../idac.zip *
$(BUILD_DIR_ZIP)/swdc.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/swdc
$(V)mkdir -p $(BUILD_DIR_ZIP)/swdc/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/swdchook/swdchook.dll \
$(DIST_DIR)/swdc/segatools.ini \
$(DIST_DIR)/swdc/config_hook.json \
$(DIST_DIR)/swdc/start.bat \
$(BUILD_DIR_ZIP)/swdc
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/swdc/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/swdc/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/swdc ; zip -r ../swdc.zip *
$(BUILD_DIR_ZIP)/mercury.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/mercury
@ -88,6 +135,27 @@ $(BUILD_DIR_ZIP)/mercury.zip:
$(V)strip $(BUILD_DIR_ZIP)/mercury/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/mercury ; zip -r ../mercury.zip *
$(BUILD_DIR_ZIP)/chusan.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/chusan
$(V)mkdir -p $(BUILD_DIR_ZIP)/chusan/DEVICE
$(V)cp $(DIST_DIR)/chusan/segatools.ini \
$(DIST_DIR)/chusan/config_hook.json \
$(DIST_DIR)/chusan/start.bat \
$(BUILD_DIR_ZIP)/chusan
$(V)cp $(BUILD_DIR_32)/chusanhook/chusanhook.dll \
$(BUILD_DIR_ZIP)/chusan/chusanhook_x86.dll
$(V)cp $(BUILD_DIR_64)/chusanhook/chusanhook.dll \
$(BUILD_DIR_ZIP)/chusan/chusanhook_x64.dll
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_ZIP)/chusan/inject_x86.exe
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_ZIP)/chusan/inject_x64.exe
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/chusan/DEVICE
for x in exe dll; do strip $(BUILD_DIR_ZIP)/chusan/*.$$x; done
$(V)cd $(BUILD_DIR_ZIP)/chusan ; zip -r ../chusan.zip *
$(BUILD_DIR_ZIP)/mu3.zip:
$(V)echo ... $@
@ -104,6 +172,37 @@ $(BUILD_DIR_ZIP)/mu3.zip:
$(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip *
$(BUILD_DIR_ZIP)/mai2.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
$(DIST_DIR)/mai2/segatools.ini \
$(DIST_DIR)/mai2/start.bat \
$(BUILD_DIR_ZIP)/mai2
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/mai2/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/mai2/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/mai2 ; zip -r ../mai2.zip *
$(BUILD_DIR_ZIP)/cm.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/cm
$(V)mkdir -p $(BUILD_DIR_ZIP)/cm/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/cmhook/cmhook.dll \
$(DIST_DIR)/cm/config_hook.json \
$(DIST_DIR)/cm/segatools.ini \
$(DIST_DIR)/cm/start.bat \
$(BUILD_DIR_ZIP)/cm
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/cm/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip *
$(BUILD_DIR_ZIP)/doc.zip: \
$(DOC_DIR)/config \
$(DOC_DIR)/chunihook.md \
@ -119,8 +218,14 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
$(BUILD_DIR_ZIP)/diva.zip \
$(BUILD_DIR_ZIP)/doc.zip \
$(BUILD_DIR_ZIP)/idz.zip \
$(BUILD_DIR_ZIP)/idac.zip \
$(BUILD_DIR_ZIP)/swdc.zip \
$(BUILD_DIR_ZIP)/mercury.zip \
$(BUILD_DIR_ZIP)/chusan.zip \
$(BUILD_DIR_ZIP)/mu3.zip \
$(BUILD_DIR_ZIP)/mai2.zip \
$(BUILD_DIR_ZIP)/cm.zip \
$(BUILD_DIR_ZIP)/fgo.zip \
CHANGELOG.md \
README.md \

View File

@ -1,21 +1,33 @@
# Segatools
Version: `v005`
Version: `2024-03-13`
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
## List of supported games
* Chunithm
* [Chunithm (Plus)](doc/chunihook.md)
* [Chunithm Air (Plus)](doc/chunihook.md)
* [Chunithm Star (Plus)](doc/chunihook.md)
* [Chunithm Amazon (Plus)](doc/chunihook.md)
* [Chunithm Crystal (Plus)](doc/chunihook.md)
* CHUNITHM
* up to [CHUNITHM PARADISE LOST](doc/chunihook.md)
* starting from CHUNITHM NEW!!
* crossbeats REV.
* up to crossbeats REV. SUNRISE
* Initial D
* [Initial D Arcade Stage Zero](doc/idzhook.md)
* Wacca
* Wacca Lilly R (WIP)
* Initial D THE ARCADE
* Hatsune Miku: Project DIVA Arcade
* up to Future Tone
* SEGA World Drivers Championship
* SEGA World Drivers Championship 2019
* Fate/Grand Order
* Fate/Grand Order Arcade
* O.N.G.E.K.I.
* starting from O.N.G.E.K.I.
* maimai DX
* starting from maimai DX
* Card Maker
* starting from Card Maker
* WACCA
* starting from WACCA
## End-users

View File

@ -17,6 +17,7 @@ struct aime_io_config {
wchar_t aime_path[MAX_PATH];
wchar_t felica_path[MAX_PATH];
bool felica_gen;
bool aime_gen;
uint8_t vk_scan;
};
@ -40,6 +41,11 @@ static HRESULT aime_io_generate_felica(
uint8_t *bytes,
size_t nbytes);
static HRESULT aime_io_generate_aime(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes);
static void aime_io_config_read(
struct aime_io_config *cfg,
const wchar_t *filename)
@ -62,11 +68,16 @@ static void aime_io_config_read(
cfg->felica_path,
_countof(cfg->felica_path),
filename);
dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError());
cfg->felica_gen = GetPrivateProfileIntW(
L"aime",
L"felicaGen",
0,
filename);
cfg->aime_gen = GetPrivateProfileIntW(
L"aime",
L"aimeGen",
1,
filename);
@ -136,7 +147,7 @@ static HRESULT aime_io_generate_felica(
srand(time(NULL));
for (i = 0 ; i < nbytes ; i++) {
for (i = 0; i < nbytes; i++) {
bytes[i] = rand();
}
@ -151,7 +162,7 @@ static HRESULT aime_io_generate_felica(
return E_FAIL;
}
for (i = 0 ; i < nbytes ; i++) {
for (i = 0; i < nbytes; i++) {
fprintf(f, "%02X", bytes[i]);
}
@ -163,6 +174,47 @@ static HRESULT aime_io_generate_felica(
return S_OK;
}
static HRESULT aime_io_generate_aime(
const wchar_t *path,
uint8_t *bytes,
size_t nbytes)
{
size_t i;
FILE *f;
assert(path != NULL);
assert(bytes != NULL);
assert(nbytes > 0);
srand(time(NULL));
/* AiMe IDs should not start with 3, due to a missing check for BananaPass IDs */
do {
for (i = 0; i < nbytes; i++) {
bytes[i] = rand() % 10 << 4 | rand() % 10;
}
} while (bytes[0] >> 4 == 3);
f = _wfopen(path, L"w");
if (f == NULL) {
dprintf("AimeIO DLL: %S: fopen failed: %i\n", path, (int) errno);
return E_FAIL;
}
for (i = 0; i < nbytes; i++) {
fprintf(f, "%02x", bytes[i]);
}
fprintf(f, "\n");
fclose(f);
dprintf("AimeIO DLL: Generated random AiMe ID\n");
return S_OK;
}
uint16_t aime_io_get_api_version(void)
{
return 0x0100;
@ -210,6 +262,22 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
return S_OK;
}
/* Try generating AiMe IC (if enabled) */
if (aime_io_cfg.aime_gen) {
hr = aime_io_generate_aime(
aime_io_cfg.aime_path,
aime_io_aime_id,
sizeof(aime_io_aime_id));
if (FAILED(hr)) {
return hr;
}
aime_io_aime_id_present = true;
return S_OK;
}
/* Try FeliCa IC */
hr = aime_io_read_id_file(

View File

@ -18,6 +18,7 @@ struct aime_dll {
struct aime_dll_config {
wchar_t path[MAX_PATH];
bool path64;
};
extern struct aime_dll aime_dll;

View File

@ -8,19 +8,61 @@
#include "board/aime-dll.h"
#include "board/config.h"
#include "board/sg-reader.h"
#include "board/vfd.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
static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
// Workaround for x64/x86 external IO dlls
// path32 for 32bit, path64 for 64bit
// for else.. is that possible? idk
if (cfg->path64) {
#if defined(ENV32BIT)
// Always empty, due to amdaemon being 64 bit in 32 bit mode
memset(cfg->path, 0, sizeof(cfg->path));
#elif defined(ENV64BIT)
GetPrivateProfileStringW(
L"aimeio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
#else
#error "Unknown environment"
#endif
} else {
GetPrivateProfileStringW(
L"aimeio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
}
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
@ -30,6 +72,8 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
aime_dll_config_load(&cfg->dll, filename);
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename);
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename);
}
void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
@ -39,3 +83,11 @@ void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename);
}
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename);
}

View File

@ -5,6 +5,8 @@
#include "board/io4.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
void aime_config_load(struct aime_config *cfg, const wchar_t *filename);
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename);

View File

@ -28,7 +28,7 @@ enum {
IO4_CMD_CLEAR_BOARD_STATUS = 0x03,
IO4_CMD_SET_GENERAL_OUTPUT = 0x04,
IO4_CMD_SET_PWM_OUTPUT = 0x05,
IO4_CMD_UNIMPLEMENTED = 0x41,
IO4_CMD_SET_UNIQUE_OUTPUT = 0x41,
IO4_CMD_UPDATE_FIRMWARE = 0x85,
};
@ -40,7 +40,7 @@ struct io4_report_in {
uint16_t buttons[2];
uint8_t system_status;
uint8_t usb_status;
uint8_t unknown[29];
uint8_t unique_input[29];
};
static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
@ -232,15 +232,15 @@ static HRESULT io4_handle_write(struct irp *irp)
return S_OK;
case IO4_CMD_SET_UNIQUE_OUTPUT:
// dprintf("USB I/O: Unique Out\n");
return S_OK;
case IO4_CMD_UPDATE_FIRMWARE:
dprintf("USB I/O: Update firmware..?\n");
return E_FAIL;
case IO4_CMD_UNIMPLEMENTED:
//dprintf("USB I/O: Unimplemented cmd 41\n");
return S_OK;
return E_FAIL;
default:
dprintf("USB I/O: Unknown command %02x\n", out.cmd);
@ -316,7 +316,7 @@ static HRESULT io4_async_poll(void *ctx, struct irp *irp)
/* Delay long enough for the instigating thread in amdaemon to be satisfied
that all queued-up reports have been drained. */
Sleep(1);
// Sleep(1);
/* Call into ops to poll the underlying inputs */

222
board/led15093-cmd.h Normal file
View File

@ -0,0 +1,222 @@
#pragma once
#include "board/led15093-frame.h"
/* Command IDs */
enum {
LED_15093_CMD_RESET = 0x10,
LED_15093_CMD_SET_TIMEOUT = 0x11,
LED_15093_CMD_UNK1 = 0x12,
LED_15093_CMD_SET_DISABLE_RESPONSE = 0x14,
LED_15093_CMD_SET_ID = 0x18,
LED_15093_CMD_CLEAR_ID = 0x19,
LED_15093_CMD_SET_MAX_BRIGHT = 0x3F, // TODO
LED_15093_CMD_UPDATE_LED = 0x80,
LED_15093_CMD_SET_LED = 0x81,
LED_15093_CMD_SET_IMM_LED = 0x82,
LED_15093_CMD_SET_FADE_LED = 0x83,
LED_15093_CMD_SET_FADE_LEVEL = 0x84,
LED_15093_CMD_SET_FADE_SHIFT = 0x85,
LED_15093_CMD_SET_AUTO_SHIFT = 0x86,
LED_15093_CMD_GET_BOARD_INFO = 0xF0,
LED_15093_CMD_GET_BOARD_STATUS = 0xF1,
LED_15093_CMD_GET_FW_SUM = 0xF2,
LED_15093_CMD_GET_PROTOCOL_VER = 0xF3,
LED_15093_CMD_SET_BOOTMODE = 0xFD,
LED_15093_CMD_FW_UPDATE = 0xFE,
};
/* Response codes */
enum {
LED_15093_STATUS_OK = 0x01,
LED_15093_STATUS_ERR_SUM = 0x02,
LED_15093_STATUS_ERR_PARITY = 0x03,
LED_15093_STATUS_ERR_FRAMING = 0x04,
LED_15093_STATUS_ERR_OVERRUN = 0x05,
LED_15093_STATUS_ERR_BUFFER_OVERFLOW = 0x06,
};
enum {
LED_15093_REPORT_OK = 0x01,
LED_15093_REPORT_WAIT = 0x02,
LED_15093_REPORT_ERR1 = 0x03,
LED_15093_REPORT_ERR2 = 0x04,
};
/* Status bitmasks */
enum {
LED_15093_STATUS_UART_ERR_SUM = 0x01,
LED_15093_STATUS_UART_ERR_PARITY = 0x02,
LED_15093_STATUS_UART_ERR_FRAMING = 0x04,
LED_15093_STATUS_UART_ERR_OVERRUN = 0x08,
LED_15093_STATUS_UART_ERR_BUFFER_OVERFLOW = 0x10,
};
enum {
LED_15093_STATUS_BOARD_ERR_WDT = 0x01,
LED_15093_STATUS_BOARD_ERR_TIMEOUT = 0x02,
LED_15093_STATUS_BOARD_ERR_RESET = 0x04,
LED_15093_STATUS_BOARD_ERR_BOR = 0x08,
};
enum {
LED_15093_STATUS_CMD_ERR_BUSY = 0x01,
LED_15093_STATUS_CMD_ERR_UNKNOWN = 0x02,
LED_15093_STATUS_CMD_ERR_PARAM = 0x04,
LED_15093_STATUS_CMD_ERR_EXE = 0x08,
};
/* Status types for internal use */
enum {
LED_15093_STATUS_TYPE_BOARD = 1,
LED_15093_STATUS_TYPE_UART = 2,
LED_15093_STATUS_TYPE_CMD = 3,
};
/* Request data structures */
struct led15093_req_reset {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t r_type;
};
struct led15093_req_set_timeout {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t count;
};
struct led15093_req_set_disable_response {
struct led15093_req_hdr hdr;
uint8_t cmd;
bool sw;
};
struct led15093_req_set_id {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t id;
};
struct led15093_req_set_led {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t data[198];
};
struct led15093_req_set_fade_level {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t depth;
uint8_t cycle;
};
struct led15093_req_set_fade_shift {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t target;
};
struct led15093_req_set_auto_shift {
struct led15093_req_hdr hdr;
uint8_t cmd;
uint8_t count;
uint8_t target;
};
struct led15093_req_get_board_status {
struct led15093_req_hdr hdr;
uint8_t cmd;
bool clear;
};
union led15093_req_any {
struct led15093_req_hdr hdr;
struct led15093_req_reset reset;
struct led15093_req_set_timeout set_timeout;
struct led15093_req_set_disable_response set_disable_response;
struct led15093_req_set_id set_id;
struct led15093_req_set_led set_led;
struct led15093_req_set_fade_level set_fade_level;
struct led15093_req_set_fade_shift set_fade_shift;
struct led15093_req_set_auto_shift set_auto_shift;
struct led15093_req_get_board_status get_board_status;
uint8_t payload[256];
};
/* Response data structures */
struct led15093_resp_any {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t data[32];
};
struct led15093_resp_timeout {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t count_upper;
uint8_t count_lower;
};
struct led15093_resp_fw_sum {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t sum_upper;
uint8_t sum_lower;
};
struct led15093_resp_board_info_legacy {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
char board_num[8];
uint8_t lf; // 0x0A (ASCII LF)
char chip_num[5];
uint8_t endcode; // Always 0xFF
uint8_t fw_ver;
};
struct led15093_resp_board_info {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
char board_num[8];
uint8_t lf; // 0x0A (ASCII LF)
char chip_num[5];
uint8_t endcode; // Always 0xFF
uint8_t fw_ver;
uint8_t rx_buf;
};
struct led15093_resp_protocol_ver {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t mode;
uint8_t major_ver;
uint8_t minor_ver;
};
struct led15093_resp_set_auto_shift {
struct led15093_resp_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t count;
uint8_t target;
};

196
board/led15093-frame.c Normal file
View File

@ -0,0 +1,196 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/led15093-frame.h"
#include "hook/iobuf.h"
static void led15093_frame_sync(struct iobuf *src);
static HRESULT led15093_frame_accept(const struct iobuf *dest);
static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
[0] Sync byte (0xE0)
[1] Destination address
[2] Source Address
[3] Length of data/payload
[4] Data/payload
For requests (host to board):
[0] Command
... Payload
For responses (board to host):
[0] Status
[1] Command
[2] Report
... Payload
[n] Checksum: Sum of all prior bytes (excluding sync byte)
Byte stuffing:
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
static void led15093_frame_sync(struct iobuf *src)
{
size_t i;
for (i = 0 ; i < src->pos && src->bytes[i] != LED_15093_FRAME_SYNC ; i++);
src->pos -= i;
memmove(&src->bytes[0], &src->bytes[i], i);
}
static HRESULT led15093_frame_accept(const struct iobuf *dest)
{
uint8_t checksum;
size_t i;
if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) {
return S_FALSE;
}
checksum = 0;
for (i = 1 ; i < dest->pos - 1 ; i++) {
checksum += dest->bytes[i];
}
// dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]);
if (checksum != dest->bytes[dest->pos - 1]) {
return HRESULT_FROM_WIN32(ERROR_CRC);
}
return S_OK;
}
HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src)
{
uint8_t byte;
bool escape;
size_t i;
HRESULT hr;
assert(dest != NULL);
assert(dest->bytes != NULL || dest->nbytes == 0);
assert(dest->pos <= dest->nbytes);
assert(src != NULL);
assert(src->bytes != NULL || src->nbytes == 0);
assert(src->pos <= src->nbytes);
led15093_frame_sync(src);
dest->pos = 0;
escape = false;
for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) {
/* Step the FSM to unstuff another byte */
byte = src->bytes[i];
if (dest->pos >= dest->nbytes) {
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
} else if (i == 0) {
dest->bytes[dest->pos++] = byte;
} else if (byte == LED_15093_FRAME_SYNC) {
hr = E_FAIL;
} else if (byte == LED_15093_FRAME_ESC) {
if (escape) {
hr = E_FAIL;
}
escape = true;
} else if (escape) {
dest->bytes[dest->pos++] = byte + 1;
escape = false;
} else {
dest->bytes[dest->pos++] = byte;
}
/* Try to accept the packet we've built up so far */
if (SUCCEEDED(hr)) {
hr = led15093_frame_accept(dest);
}
}
/* Handle FSM terminal state */
if (hr != S_FALSE) {
/* Frame was either accepted or rejected, remove it from src */
memmove(&src->bytes[0], &src->bytes[i], src->pos - i);
src->pos -= i;
}
return hr;
}
HRESULT led15093_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes)
{
const uint8_t *src;
uint8_t checksum;
uint8_t byte;
size_t i;
HRESULT hr;
assert(dest != NULL);
assert(dest->bytes != NULL || dest->nbytes == 0);
assert(dest->pos <= dest->nbytes);
assert(ptr != NULL);
src = ptr;
assert(nbytes >= 3 &&
src[0] == LED_15093_FRAME_SYNC &&
src[3] + 4 == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = LED_15093_FRAME_SYNC;
checksum = 0;
// dprintf("%02x ", LED_15093_FRAME_SYNC);
for (i = 1 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
// dprintf("%02x ", byte);
hr = led15093_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
// dprintf("%02x \n", checksum);
return led15093_frame_encode_byte(dest, checksum);
}
static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == LED_15093_FRAME_SYNC || byte == LED_15093_FRAME_ESC) {
if (dest->pos + 2 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = LED_15093_FRAME_ESC;
dest->bytes[dest->pos++] = byte - 1;
} else {
if (dest->pos + 1 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = byte;
}
return S_OK;
}

34
board/led15093-frame.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
LED_15093_FRAME_SYNC = 0xE0,
LED_15093_FRAME_ESC = 0xD0,
};
struct led15093_req_hdr {
uint8_t sync;
uint8_t dest_adr;
uint8_t src_adr;
uint8_t nbytes;
};
struct led15093_resp_hdr {
uint8_t sync;
uint8_t dest_adr;
uint8_t src_adr;
uint8_t nbytes;
};
HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src);
HRESULT led15093_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);

1149
board/led15093.c Normal file

File diff suppressed because it is too large Load Diff

24
board/led15093.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct led15093_config {
bool enable;
bool high_baudrate;
unsigned int port_no;
char board_number[8];
char chip_number[5];
char boot_chip_number[5];
uint8_t fw_ver;
uint16_t fw_sum;
};
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);

View File

@ -20,6 +20,11 @@ board_lib = static_library(
'io3.h',
'io4.c',
'io4.h',
'led15093-cmd.h',
'led15093-frame.c',
'led15093-frame.h',
'led15093.c',
'led15093.h',
'sg-cmd.c',
'sg-cmd.h',
'sg-frame.c',

View File

@ -25,6 +25,13 @@ struct sg_res_header {
uint8_t payload_len;
};
/* struct to save the version string with its length
to fix NUL terminator issues */
struct version_info {
const char *version;
uint8_t length;
};
typedef HRESULT (*sg_dispatch_fn_t)(
void *ctx,
const void *req,

View File

@ -17,7 +17,7 @@ struct sg_led_res_reset {
struct sg_led_res_get_info {
struct sg_res_header res;
uint8_t payload[9];
char payload[12];
};
struct sg_led_req_set_color {

View File

@ -27,14 +27,18 @@ static HRESULT sg_led_cmd_set_color(
const struct sg_led *led,
const struct sg_led_req_set_color *req);
static const uint8_t sg_led_info[] = {
'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12,
static const struct version_info led_version[] = {
{"15084\xFF\x10\x00\x12", 9},
{"000-00000\xFF\x11\x40", 12},
// maybe the same?
{"000-00000\xFF\x11\x40", 12}
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
unsigned int gen,
void *ctx)
{
assert(led != NULL);
@ -43,6 +47,7 @@ void sg_led_init(
led->ops = ops;
led->ops_ctx = ctx;
led->addr = addr;
led->gen = gen;
}
void sg_led_transact(
@ -150,8 +155,11 @@ static HRESULT sg_led_cmd_get_info(
struct sg_led_res_get_info *res)
{
sg_led_dprintf(led, "Get info\n");
sg_res_init(&res->res, req, sizeof(res->payload));
memcpy(res->payload, sg_led_info, sizeof(sg_led_info));
const struct version_info *fw = &led_version[led->gen - 1];
sg_res_init(&res->res, req, fw->length);
memcpy(res->payload, fw->version, fw->length);
return S_OK;
}

View File

@ -15,12 +15,14 @@ struct sg_led {
const struct sg_led_ops *ops;
void *ops_ctx;
uint8_t addr;
unsigned int gen;
};
void sg_led_init(
struct sg_led *led,
uint8_t addr,
const struct sg_led_ops *ops,
unsigned int gen,
void *ctx);
void sg_led_transact(

View File

@ -15,6 +15,7 @@ enum {
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */
SG_NFC_CMD_SEND_HEX_DATA = 0x61,
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
};

View File

@ -65,10 +65,23 @@ static HRESULT sg_nfc_cmd_dummy(
const struct sg_req_header *req,
struct sg_res_header *res);
static const struct version_info hw_version[] = {
{"TN32MSEC003S H/W Ver3.0", 23},
{"837-15286", 9},
{"837-15396", 9}
};
static const struct version_info fw_version[] = {
{"TN32MSEC003S F/W Ver1.2", 23},
{"\x94", 1},
{"\x94", 1}
};
void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
void *ops_ctx)
{
assert(nfc != NULL);
@ -77,6 +90,7 @@ void sg_nfc_init(
nfc->ops = ops;
nfc->ops_ctx = ops_ctx;
nfc->addr = addr;
nfc->gen = gen;
}
#ifdef NDEBUG
@ -176,6 +190,7 @@ static HRESULT sg_nfc_dispatch(
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF:
case SG_NFC_CMD_SEND_HEX_DATA: // TODO: implement?
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default:
@ -202,9 +217,11 @@ static HRESULT sg_nfc_cmd_get_fw_version(
const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res)
{
const struct version_info *fw = &fw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version));
memcpy(res->version, "TN32MSEC003S F/W Ver1.2E", sizeof(res->version));
sg_res_init(&res->res, req, fw->length);
memcpy(res->version, fw->version, fw->length);
return S_OK;
}
@ -214,9 +231,11 @@ static HRESULT sg_nfc_cmd_get_hw_version(
const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res)
{
const struct version_info *hw = &hw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version));
memcpy(res->version, "TN32MSEC003S H/W Ver3.0J", sizeof(res->version));
sg_res_init(&res->res, req, hw->length);
memcpy(res->version, hw->version, hw->length);
return S_OK;
}

View File

@ -22,6 +22,7 @@ struct sg_nfc {
const struct sg_nfc_ops *ops;
void *ops_ctx;
uint8_t addr;
unsigned int gen;
struct felica felica;
struct mifare mifare;
};
@ -30,6 +31,7 @@ void sg_nfc_init(
struct sg_nfc *nfc,
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
void *ops_ctx);
void sg_nfc_transact(

View File

@ -48,6 +48,7 @@ static struct sg_led sg_reader_led;
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int port_no,
unsigned int gen,
HINSTANCE self)
{
HRESULT hr;
@ -65,11 +66,25 @@ HRESULT sg_reader_hook_init(
return hr;
}
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL);
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL);
if (cfg->gen != 0) {
gen = cfg->gen;
}
if (gen < 1 || gen > 3) {
dprintf("NFC Assembly: Invalid reader generation: %u\n", gen);
return E_INVALIDARG;
}
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL);
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL);
InitializeCriticalSection(&sg_reader_lock);
if (!cfg->high_baudrate) {
sg_reader_uart.baud.BaudRate = 38400;
}
uart_init(&sg_reader_uart, port_no);
sg_reader_uart.written.bytes = sg_reader_written_bytes;
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);

View File

@ -9,9 +9,12 @@
struct aime_config {
struct aime_dll_config dll;
bool enable;
bool high_baudrate;
unsigned int gen;
};
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int port_no,
unsigned int gen,
HINSTANCE self);

View File

@ -26,15 +26,25 @@ static HRESULT vfd_handle_irp(struct irp *irp);
static struct uart vfd_uart;
static uint8_t vfd_written[512];
static uint8_t vfd_readable[512];
UINT codepage;
HRESULT vfd_hook_init(unsigned int port_no)
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
{
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
uart_init(&vfd_uart, port_no);
vfd_uart.written.bytes = vfd_written;
vfd_uart.written.nbytes = sizeof(vfd_written);
vfd_uart.readable.bytes = vfd_readable;
vfd_uart.readable.nbytes = sizeof(vfd_readable);
codepage = GetACP();
dprintf("VFD: hook enabled.\n");
return iohook_push_handler(vfd_handle_irp);
}
@ -54,8 +64,60 @@ static HRESULT vfd_handle_irp(struct irp *irp)
return hr;
}
dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written);
uint8_t cmd = 0;
uint8_t str_1[512];
uint8_t str_2[512];
uint8_t str_1_len = 0;
uint8_t str_2_len = 0;
for (size_t i = 0; i < vfd_uart.written.pos; i++) {
if (vfd_uart.written.bytes[i] == 0x1B) {
i++;
cmd = vfd_uart.written.bytes[i];
if (cmd == 0x30) {
i += 3;
}
else if (cmd == 0x50) {
i++;
}
continue;
}
if (cmd == 0x30) {
str_1[str_1_len++] = vfd_uart.written.bytes[i];
}
else if (cmd == 0x50) {
str_2[str_2_len++] = vfd_uart.written.bytes[i];
}
}
if (str_1_len) {
str_1[str_1_len++] = '\0';
if (codepage != 932) {
WCHAR buffer[512];
MultiByteToWideChar(932, 0, (LPCSTR)str_1, str_1_len, buffer, str_1_len);
char str_recode[str_1_len * 3];
WideCharToMultiByte(codepage, 0, buffer, str_1_len, str_recode, str_1_len * 3, NULL, NULL);
dprintf("VFD: %s\n", str_recode);
}
else {
dprintf("VFD: %s\n", str_1);
}
}
if (str_2_len) {
str_2[str_2_len++] = '\0';
if (codepage != 932) {
WCHAR buffer[512];
MultiByteToWideChar(932, 0, (LPCSTR)str_2, str_2_len, buffer, str_2_len);
char str_recode[str_2_len * 3];
WideCharToMultiByte(codepage, 0, buffer, str_2_len, str_recode, str_2_len * 3, NULL, NULL);
dprintf("VFD: %s\n", str_recode);
} else {
dprintf("VFD: %s\n", str_2);
}
}
// dprintf("VFD TX:\n");
// dump_iobuf(&vfd_uart.written);
vfd_uart.written.pos = 0;
return hr;

View File

@ -2,4 +2,9 @@
#include <windows.h>
HRESULT vfd_hook_init(unsigned int port_no);
struct vfd_config {
bool enable;
};
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no);

View File

@ -102,7 +102,7 @@ static DWORD CALLBACK carol_pre_startup(void)
goto fail;
}
hr = sg_reader_hook_init(&carol_hook_cfg.aime, 10, carol_hook_mod);
hr = sg_reader_hook_init(&carol_hook_cfg.aime, 10, 1, carol_hook_mod);
if (FAILED(hr)) {
goto fail;

View File

@ -14,7 +14,7 @@ void carol_io_config_load(
assert(cfg != NULL);
assert(filename != NULL);
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename);
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename);
}

View File

@ -30,9 +30,28 @@ const struct dll_bind_sym chuni_dll_syms[] = {
}, {
.sym = "chuni_io_slider_set_leds",
.off = offsetof(struct chuni_dll, slider_set_leds),
}, {
.sym = "chuni_io_led_init",
.off = offsetof(struct chuni_dll, led_init),
}, {
.sym = "chuni_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;
// Copypasta DLL binding and diagnostic message boilerplate.
@ -92,16 +111,24 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
}
sym = chuni_dll_syms;
const struct dll_bind_sym *init_sym = &sym[0];
hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms));
if (FAILED(hr)) {
if (src != self) {
dprintf("Chunithm IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
// Might still be ok depending on external dll API version
int bind_count = sym - init_sym;
if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK )
{
hr = S_OK;
} 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);
goto end;
goto end;
}
} else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}

View File

@ -13,6 +13,8 @@ struct chuni_dll {
void (*slider_start)(chuni_io_slider_callback_t callback);
void (*slider_stop)(void);
void (*slider_set_leds)(const uint8_t *rgb);
HRESULT (*led_init)(void);
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
};
struct chuni_dll_config {

View File

@ -20,3 +20,5 @@ EXPORTS
chuni_io_slider_set_leds
chuni_io_slider_start
chuni_io_slider_stop
chuni_io_led_init
chuni_io_led_set_colors

View File

@ -43,6 +43,66 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename);
}
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
wchar_t tmpstr[16];
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0;
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);
GetPrivateProfileStringW(
L"led15093",
L"boardNumber",
L"15093-06",
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"led15093",
L"chipNumber",
L"6710 ",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
for (int i = n; i < sizeof(cfg->chip_number); i++)
{
cfg->chip_number[i] = ' ';
}
GetPrivateProfileStringW(
L"led15093",
L"bootChipNumber",
L"6709 ",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
{
cfg->boot_chip_number[i] = ' ';
}
}
void chuni_hook_config_load(
struct chuni_hook_config *cfg,
const wchar_t *filename)
@ -58,4 +118,5 @@ void chuni_hook_config_load(
gfx_config_load(&cfg->gfx, filename);
chuni_dll_config_load(&cfg->dll, filename);
slider_config_load(&cfg->slider, filename);
led15093_config_load(&cfg->led15093, filename);
}

View File

@ -6,6 +6,7 @@
#include "amex/amex.h"
#include "board/sg-reader.h"
#include "board/led15093.h"
#include "chunihook/chuni-dll.h"
#include "chunihook/slider.h"
@ -21,6 +22,7 @@ struct chuni_hook_config {
struct gfx_config gfx;
struct chuni_dll_config dll;
struct slider_config slider;
struct led15093_config led15093;
};
void chuni_dll_config_load(

View File

@ -4,6 +4,7 @@
#include "amex/amex.h"
#include "board/led15093.h"
#include "board/sg-reader.h"
#include "chunihook/config.h"
@ -96,7 +97,19 @@ static DWORD CALLBACK chuni_pre_startup(void)
goto fail;
}
hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, chuni_hook_mod);
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(&chuni_hook_cfg.led15093,
chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1);
if (FAILED(hr)) {
goto fail;
}
}
hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod);
if (FAILED(hr)) {
goto fail;

View File

@ -101,13 +101,13 @@ static void chunithm_jvs_read_switches(void *ctx, struct io3_switch_state *out)
out->p1 = 0x0000;
out->p2 = 0x0000;
if (opbtn & 0x01) {
if (opbtn & CHUNI_IO_OPBTN_TEST) {
out->system = 0x80;
} else {
out->system = 0x00;
}
if (opbtn & 0x02) {
if (opbtn & CHUNI_IO_OPBTN_SERVICE) {
out->p1 |= 0x4000;
}

358
chuniio/chu2to3.c Normal file
View File

@ -0,0 +1,358 @@
#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 (%ld).\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 (%ld).\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 (%ld).\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 (%ld).\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;
g_shared_data.beams = 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(const 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 %ld)\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
View 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(const wchar_t *dllname);

View File

@ -3,9 +3,13 @@
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "chuniio/chuniio.h"
#include "chuniio/config.h"
#include "chuniio/ledoutput.h"
#include "util/dprintf.h"
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx);
@ -18,13 +22,23 @@ static struct chuni_io_config chuni_io_cfg;
uint16_t chuni_io_get_api_version(void)
{
return 0x0101;
return 0x0102;
}
HRESULT chuni_io_jvs_init(void)
{
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
led_init_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (led_init_mutex == NULL)
{
return E_FAIL;
}
return S_OK;
}
@ -34,7 +48,7 @@ void chuni_io_jvs_read_coin_counter(uint16_t *out)
return;
}
if (GetAsyncKeyState(chuni_io_cfg.vk_coin)) {
if (GetAsyncKeyState(chuni_io_cfg.vk_coin) & 0x8000) {
if (!chuni_io_coin) {
chuni_io_coin = true;
chuni_io_coins++;
@ -50,38 +64,52 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
{
size_t i;
if (GetAsyncKeyState(chuni_io_cfg.vk_test)) {
*opbtn |= 0x01; /* Test */
if (GetAsyncKeyState(chuni_io_cfg.vk_test) & 0x8000) {
*opbtn |= CHUNI_IO_OPBTN_TEST;
}
if (GetAsyncKeyState(chuni_io_cfg.vk_service)) {
*opbtn |= 0x02; /* Service */
if (GetAsyncKeyState(chuni_io_cfg.vk_service) & 0x8000) {
*opbtn |= CHUNI_IO_OPBTN_SERVICE;
}
if (GetAsyncKeyState(chuni_io_cfg.vk_ir)) {
if (chuni_io_hand_pos < 6) {
chuni_io_hand_pos++;
if (chuni_io_cfg.vk_ir_emu) {
// Use emulated AIR
if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) {
if (chuni_io_hand_pos < 6) {
chuni_io_hand_pos++;
}
} else {
if (chuni_io_hand_pos > 0) {
chuni_io_hand_pos--;
}
}
for (i = 0 ; i < 6 ; i++) {
if (chuni_io_hand_pos > i) {
*beams |= (1 << i);
}
}
} else {
if (chuni_io_hand_pos > 0) {
chuni_io_hand_pos--;
}
}
for (i = 0 ; i < 6 ; i++) {
if (chuni_io_hand_pos > i) {
*beams |= (1 << i);
// Use actual AIR
for (i = 0; i < 6; i++) {
if(GetAsyncKeyState(chuni_io_cfg.vk_ir[i]) & 0x8000) {
*beams |= (1 << i);
} else {
*beams &= ~(1 << i);
}
}
}
}
HRESULT chuni_io_slider_init(void)
{
return S_OK;
return led_output_init(&chuni_io_cfg); // because of slider LEDs
}
void chuni_io_slider_start(chuni_io_slider_callback_t callback)
{
BOOL status;
if (chuni_io_slider_thread != NULL) {
return;
}
@ -111,6 +139,7 @@ void chuni_io_slider_stop(void)
void chuni_io_slider_set_leds(const uint8_t *rgb)
{
led_output_update(2, rgb);
}
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
@ -136,3 +165,13 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
return 0;
}
HRESULT chuni_io_led_init(void)
{
return led_output_init(&chuni_io_cfg);
}
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb)
{
led_output_update(board, rgb);
}

View File

@ -8,6 +8,7 @@
- 0x0100: Initial API version (assumed if chuni_io_get_api_version is not
exported)
- 0x0101: Fix IR beam mappings
- 0x0102: Add air tower led and billboard support
*/
#include <windows.h>
@ -15,6 +16,12 @@
#include <stdbool.h>
#include <stdint.h>
enum {
CHUNI_IO_OPBTN_TEST = 0x01,
CHUNI_IO_OPBTN_SERVICE = 0x02,
CHUNI_IO_OPBTN_COIN = 0x04,
};
/* Get the version of the Chunithm IO API that this DLL supports. This
function should return a positive 16-bit integer, where the high byte is
the major version and the low byte is the minor version (as defined by the
@ -139,3 +146,30 @@ void chuni_io_slider_stop(void);
Minimum API version: 0x0100 */
void chuni_io_slider_set_leds(const uint8_t *rgb);
/* Initialize LED emulation. This function will be called before any
other chuni_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: 0x0102 */
HRESULT chuni_io_led_init(void);
/* Update the RGB LEDs. rgb is a pointer to an array of up to 63 * 3 = 189 bytes.
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
Each rgb value is comprised of 3 bytes in R,G,B order
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);

View File

@ -3,6 +3,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "chuniio/config.h"
@ -17,20 +18,35 @@ static const int chuni_io_default_cells[] = {
'S', 'S', 'S', 'S',
};
static const int chuni_io_default_ir[] = {
'4', '5', '6', '7', '8', '9'
};
void chuni_io_config_load(
struct chuni_io_config *cfg,
const wchar_t *filename)
{
wchar_t key[16];
int i;
wchar_t port_input[6];
assert(cfg != NULL);
assert(filename != NULL);
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename);
cfg->vk_ir = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename);
// Technically it's io4 but leave this for compatibility with old configs.
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename);
cfg->vk_ir_emu = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename);
for (i = 0 ; i < 6 ; i++) {
swprintf_s(key, _countof(key), L"ir%i", i + 1);
cfg->vk_ir[i] = GetPrivateProfileIntW(
L"ir",
key,
chuni_io_default_ir[i],
filename);
}
for (i = 0 ; i < 32 ; i++) {
swprintf_s(key, _countof(key), L"cell%i", i + 1);
@ -40,4 +56,25 @@ void chuni_io_config_load(
chuni_io_default_cells[i],
filename);
}
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
GetPrivateProfileStringW(
L"led",
L"serialPort",
L"COM5",
port_input,
6,
filename);
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
// with `\\.\`.
wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4);
wcsncat_s(cfg->led_serial_port, 11, port_input, 6);
}

View File

@ -7,8 +7,21 @@ struct chuni_io_config {
uint8_t vk_test;
uint8_t vk_service;
uint8_t vk_coin;
uint8_t vk_ir;
uint8_t vk_ir_emu;
uint8_t vk_ir[6];
uint8_t vk_cell[32];
// Which ways to output LED information are enabled
bool led_output_pipe;
bool led_output_serial;
bool slider_led_output_pipe;
bool slider_led_output_serial;
// The name of a COM port to output LED data on, in serial mode
wchar_t led_serial_port[12];
int32_t led_serial_baud;
};
void chuni_io_config_load(

22
chuniio/leddata.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#define LED_PACKET_FRAMING 0xE0
#define LED_PACKET_ESCAPE 0xD0
#define LED_NUM_MAX 66
#define LED_BOARDS_TOTAL 3
#define LED_OUTPUT_HEADER_SIZE 2
#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped
#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX
// This struct is used to send data related to the slider and billboard LEDs
struct _chuni_led_data_buf_t {
byte framing; // Sync byte
uint8_t board; // LED output the data is for (0-1: billboard, 2: slider)
byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
byte data_len; // How many bytes to output from the buffer
};
static byte chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3};

133
chuniio/ledoutput.c Normal file
View File

@ -0,0 +1,133 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "chuniio/config.h"
#include "chuniio/leddata.h"
#include "chuniio/ledoutput.h"
#include "chuniio/pipeimpl.h"
#include "chuniio/serialimpl.h"
static struct _chuni_led_data_buf_t led_unescaped_buf[LED_BOARDS_TOTAL];
static struct _chuni_led_data_buf_t led_escaped_buf[LED_BOARDS_TOTAL];
static bool led_output_is_init = false;
static struct chuni_io_config* config;
static bool any_outputs_enabled;
HANDLE led_init_mutex;
HRESULT led_output_init(struct chuni_io_config* const cfg)
{
DWORD dwWaitResult = WaitForSingleObject(led_init_mutex, INFINITE);
if (dwWaitResult == WAIT_FAILED)
{
return HRESULT_FROM_WIN32(GetLastError());
// return 1;
}
else if (dwWaitResult != WAIT_OBJECT_0)
{
return E_FAIL;
// return 1;
}
if (!led_output_is_init)
{
config = cfg;
// Setup the framing bytes for the packets
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
led_unescaped_buf[i].framing = LED_PACKET_FRAMING;
led_unescaped_buf[i].board = i;
led_unescaped_buf[i].data_len = chuni_led_board_data_lens[i];
led_escaped_buf[i].framing = LED_PACKET_FRAMING;
led_escaped_buf[i].board = i;
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
}
any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe
|| config->led_output_serial || config->slider_led_output_serial;
if (config->led_output_pipe || config->slider_led_output_pipe)
{
led_pipe_init(); // don't really care about errors here tbh
}
if (config->led_output_serial || config->slider_led_output_serial)
{
led_serial_init(config->led_serial_port, config->led_serial_baud);
}
}
led_output_is_init = true;
ReleaseMutex(led_init_mutex);
return S_OK;
// return 0;
}
struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unescaped)
{
struct _chuni_led_data_buf_t* out_struct = &led_escaped_buf[unescaped->board];
byte* in_buf = unescaped->data;
byte* out_buf = out_struct->data;
int i = 0;
int o = 0;
while (i < unescaped->data_len)
{
byte b = in_buf[i++];
if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE)
{
out_buf[o++] = LED_PACKET_ESCAPE;
b--;
}
out_buf[o++] = b;
}
out_struct->data_len = o;
return out_struct;
}
void led_output_update(uint8_t board, const byte* rgb)
{
if (board < 0 || board > 2 || !any_outputs_enabled)
{
return;
}
memcpy(led_unescaped_buf[board].data, rgb, led_unescaped_buf[board].data_len);
struct _chuni_led_data_buf_t* escaped_data = escape_led_data(&led_unescaped_buf[board]);
if (board < 2)
{
// billboard
if (config->led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->led_output_serial)
{
led_serial_update(escaped_data);
}
}
else
{
// slider
if (config->slider_led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->slider_led_output_serial)
{
led_serial_update(escaped_data);
}
}
}

19
chuniio/ledoutput.h Normal file
View File

@ -0,0 +1,19 @@
/*
LED output functions
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include "chuniio/config.h"
extern HANDLE led_init_mutex;
HRESULT led_output_init(struct chuni_io_config* const cfg);
void led_output_update(uint8_t board, const byte* rgb);

View File

@ -5,9 +5,18 @@ chuniio_lib = static_library(
implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [
'chu2to3.c',
'chu2to3.h',
'chuniio.c',
'chuniio.h',
'config.c',
'config.h',
'leddata.h',
'ledoutput.c',
'ledoutput.h',
'pipeimpl.c',
'pipeimpl.h',
'serialimpl.c',
'serialimpl.h'
],
)

160
chuniio/pipeimpl.c Normal file
View File

@ -0,0 +1,160 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "chuniio/leddata.h"
#include "chuniio/pipeimpl.h"
static bool pipe_update[LED_BOARDS_TOTAL];
// incoming data is copied into these to ensure it isn't written during output
static struct _chuni_led_data_buf_t pipe_write_buf[LED_BOARDS_TOTAL];
static HANDLE pipe_write_mutex;
static HRESULT pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize)
{
*hPipe = INVALID_HANDLE_VALUE;
*hPipe = CreateNamedPipeW(
lpszPipename, // pipe name
PIPE_ACCESS_OUTBOUND, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
dwBufSize, // output buffer size
0, // input buffer size
0, // client time-out
NULL); // default security attribute
if (*hPipe == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
return S_OK;
}
static HRESULT pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize)
{
DWORD cbWritten = 0;
bool fSuccess = WriteFile(
hPipe,
lpBuffer,
dwSize,
&cbWritten,
NULL);
if (!fSuccess || cbWritten != dwSize)
{
DWORD last_err = GetLastError();
return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL;
}
return S_OK;
}
static unsigned int __stdcall chuni_io_led_pipe_thread_proc(void *ctx)
{
HANDLE hPipe;
LPCWSTR lpszPipename = L"\\\\.\\pipe\\chuni_led";
while (true)
{
hPipe = INVALID_HANDLE_VALUE;
if (pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK)
{
continue;
}
// wait for a connection to the pipe
bool fConnected = ConnectNamedPipe(hPipe, NULL) ?
true : (GetLastError() == ERROR_PIPE_CONNECTED);
while (fConnected)
{
if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
{
continue;
}
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
if (pipe_update[i])
{
HRESULT result = pipe_write(
hPipe,
&pipe_write_buf[i],
LED_OUTPUT_HEADER_SIZE + pipe_write_buf[i].data_len);
if (result != S_OK)
{
//if (result == E_ABORT)
//{
fConnected = false;
//}
break;
}
pipe_update[i] = false;
}
}
ReleaseMutex(pipe_write_mutex);
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
}
return 0;
}
HRESULT led_pipe_init()
{
pipe_write_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (pipe_write_mutex == NULL)
{
return E_FAIL;
}
// clear out update bools
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
pipe_update[i] = false;
}
_beginthreadex(
NULL,
0,
chuni_io_led_pipe_thread_proc,
0,
0,
NULL);
return S_OK;
}
void led_pipe_update(struct _chuni_led_data_buf_t* data)
{
if (data->board > 2)
{
return;
}
if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
{
return;
}
memcpy(&pipe_write_buf[data->board], data, sizeof(struct _chuni_led_data_buf_t));
pipe_update[data->board] = true;
ReleaseMutex(pipe_write_mutex);
}

14
chuniio/pipeimpl.h Normal file
View File

@ -0,0 +1,14 @@
/*
Pipe implementation for chuniio
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include "chuniio/leddata.h"
HRESULT led_pipe_init();
void led_pipe_update(struct _chuni_led_data_buf_t* data);

99
chuniio/serialimpl.c Normal file
View File

@ -0,0 +1,99 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "chuniio/leddata.h"
#include "chuniio/serialimpl.h"
#include "util/dprintf.h"
static HANDLE serial_port;
static HANDLE serial_write_mutex;
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud)
{
// Setup the serial communications
BOOL status;
serial_port = CreateFileW(led_com,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (serial_port == INVALID_HANDLE_VALUE)
dprintf("Chunithm Serial LEDs: Failed to open COM port (Attempted on %S)\n", led_com);
else
dprintf("Chunithm Serial LEDs: COM port success!\n");
DCB dcb_serial_params = { 0 };
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
status = GetCommState(serial_port, &dcb_serial_params);
dcb_serial_params.BaudRate = baud;
dcb_serial_params.ByteSize = 8;
dcb_serial_params.StopBits = ONESTOPBIT;
dcb_serial_params.Parity = NOPARITY;
SetCommState(serial_port, &dcb_serial_params);
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
SetCommTimeouts(serial_port, &timeouts);
if (!status)
{
return E_FAIL;
}
serial_write_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (serial_write_mutex == NULL)
{
return E_FAIL;
}
return S_OK;
}
void led_serial_update(struct _chuni_led_data_buf_t* data)
{
if (data->board > 2)
{
return;
}
if (WaitForSingleObject(serial_write_mutex, INFINITE) != WAIT_OBJECT_0)
{
return;
}
BOOL status = true;
DWORD bytes_written = 0;
if (serial_port != INVALID_HANDLE_VALUE) {
status = WriteFile(
serial_port,
data,
LED_OUTPUT_HEADER_SIZE + data->data_len,
&bytes_written,
NULL);
}
if (!status) {
DWORD last_err = GetLastError();
// dprintf("Chunithm Serial LEDs: Serial port write failed -- %d\n", last_err);
}
ReleaseMutex(serial_write_mutex);
}

15
chuniio/serialimpl.h Normal file
View File

@ -0,0 +1,15 @@
/*
Serial LED implementation for chuniio
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include "chuniio/leddata.h"
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud);
void led_serial_update(struct _chuni_led_data_buf_t* data);

189
chusanhook/chuni-dll.c Normal file
View File

@ -0,0 +1,189 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "chuniio/chu2to3.h"
#include "chusanhook/chuni-dll.h"
#include "util/dll-bind.h"
#include "util/dprintf.h"
const struct dll_bind_sym chuni_dll_syms[] = {
{
.sym = "chuni_io_jvs_init",
.off = offsetof(struct chuni_dll, jvs_init),
}, {
.sym = "chuni_io_jvs_poll",
.off = offsetof(struct chuni_dll, jvs_poll),
}, {
.sym = "chuni_io_jvs_read_coin_counter",
.off = offsetof(struct chuni_dll, jvs_read_coin_counter),
}, {
.sym = "chuni_io_slider_init",
.off = offsetof(struct chuni_dll, slider_init),
}, {
.sym = "chuni_io_slider_start",
.off = offsetof(struct chuni_dll, slider_start),
}, {
.sym = "chuni_io_slider_stop",
.off = offsetof(struct chuni_dll, slider_stop),
}, {
.sym = "chuni_io_slider_set_leds",
.off = offsetof(struct chuni_dll, slider_set_leds),
}, {
.sym = "chuni_io_led_init",
.off = offsetof(struct chuni_dll, led_init),
}, {
.sym = "chuni_io_led_set_colors",
.off = offsetof(struct chuni_dll, led_set_leds),
}
};
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;
// Copypasta DLL binding and diagnostic message boilerplate.
// Not much of this lends itself to being easily factored out. Also there
// will be a lot of API-specific branching code here eventually as new API
// versions get defined, so even though these functions all look the same
// now this won't remain the case forever.
HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
{
uint16_t (*get_api_version)(void);
const struct dll_bind_sym *sym;
HINSTANCE owned;
HINSTANCE src;
HRESULT hr;
assert(cfg != NULL);
assert(self != NULL);
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);
if (owned == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("Chunithm IO: Failed to load IO DLL: %lx: %S\n",
hr,
cfg->path);
goto end;
}
dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path);
src = owned;
}
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) {
chuni_dll.api_version = get_api_version();
} else {
chuni_dll.api_version = 0x0100;
dprintf("Custom IO DLL does not expose chuni_io_get_api_version, "
"assuming API version 1.0.\n"
"Please ask the developer to update their DLL.\n");
}
if (chuni_dll.api_version >= 0x0200) {
hr = E_NOTIMPL;
dprintf("Chunithm IO: Custom IO DLL implements an unsupported "
"API version (%#04x). Please update Segatools.\n",
chuni_dll.api_version);
goto end;
}
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));
if (FAILED(hr)) {
if (src != self) {
// Might still be ok depending on external dll API version
int bind_count = sym - init_sym;
if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK )
{
hr = S_OK;
} 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 {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}
}
owned = NULL;
end:
if (owned != NULL) {
FreeLibrary(owned);
}
return hr;
}

27
chusanhook/chuni-dll.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <windows.h>
#include "chuniio/chuniio.h"
struct chuni_dll {
uint16_t api_version;
HRESULT (*jvs_init)(void);
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
void (*jvs_read_coin_counter)(uint16_t *total);
HRESULT (*slider_init)(void);
void (*slider_start)(chuni_io_slider_callback_t callback);
void (*slider_stop)(void);
void (*slider_set_leds)(const uint8_t *rgb);
HRESULT (*led_init)(void);
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
};
struct chuni_dll_config {
wchar_t path[MAX_PATH];
uint8_t chu2to3;
};
extern struct chuni_dll chuni_dll;
HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self);

34
chusanhook/chusanhook.def Normal file
View File

@ -0,0 +1,34 @@
LIBRARY chusanhook
EXPORTS
Direct3DCreate9
aime_io_get_api_version
aime_io_init
aime_io_led_set_color
aime_io_nfc_get_aime_id
aime_io_nfc_get_felica_id
aime_io_nfc_poll
amDllVideoClose @2
amDllVideoGetVBiosVersion @4
amDllVideoOpen @1
amDllVideoSetResolution @3
chuni_io_get_api_version
chuni_io_jvs_init
chuni_io_jvs_poll
chuni_io_jvs_read_coin_counter
chuni_io_slider_init
chuni_io_slider_set_leds
chuni_io_slider_start
chuni_io_slider_stop
chuni_io_led_init
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

167
chusanhook/config.c Normal file
View File

@ -0,0 +1,167 @@
#include <assert.h>
#include <stddef.h>
#include "board/config.h"
#include "hooklib/config.h"
#include "hooklib/dvd.h"
#include "gfxhook/config.h"
#include "platform/config.h"
#include "chusanhook/config.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
void chuni_dll_config_load(
struct chuni_dll_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
// Workaround for x64/x86 external IO dlls
// path32 for 32bit, path64 for 64bit
// path for 32bit only dlls (internal chu2to3 engine)
GetPrivateProfileStringW(
L"chuniio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
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)
GetPrivateProfileStringW(
L"chuniio",
L"path64",
L"",
cfg->path,
_countof(cfg->path),
filename);
#else
#error "Unknown environment"
#endif
}
}
void slider_config_load(struct slider_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename);
}
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
wchar_t tmpstr[16];
bool cvt_port;
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0;
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);
GetPrivateProfileStringW(
L"led15093",
L"boardNumber",
L"15093-06",
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"led15093",
L"chipNumber",
L"6710 ",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
for (int i = n; i < sizeof(cfg->chip_number); i++)
{
cfg->chip_number[i] = ' ';
}
GetPrivateProfileStringW(
L"led15093",
L"bootChipNumber",
L"6709 ",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
{
cfg->boot_chip_number[i] = ' ';
}
}
void chusan_hook_config_load(
struct chusan_hook_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
memset(cfg, 0, sizeof(*cfg));
// Force load the 64bit Aime DLL instead of the 32bit one
cfg->aime.dll.path64 = true;
platform_config_load(&cfg->platform, filename);
aime_config_load(&cfg->aime, filename);
dvd_config_load(&cfg->dvd, filename);
io4_config_load(&cfg->io4, filename);
gfx_config_load(&cfg->gfx, filename);
vfd_config_load(&cfg->vfd, filename);
chuni_dll_config_load(&cfg->dll, filename);
slider_config_load(&cfg->slider, filename);
led15093_config_load(&cfg->led15093, filename);
}

35
chusanhook/config.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include <stddef.h>
#include "board/config.h"
#include "board/led15093.h"
#include "hooklib/dvd.h"
#include "gfxhook/config.h"
#include "platform/config.h"
#include "chusanhook/chuni-dll.h"
#include "chusanhook/slider.h"
struct chusan_hook_config {
struct platform_config platform;
struct aime_config aime;
struct dvd_config dvd;
struct io4_config io4;
struct gfx_config gfx;
struct vfd_config vfd;
struct chuni_dll_config dll;
struct slider_config slider;
struct led15093_config led15093;
};
void chuni_dll_config_load(
struct chuni_dll_config *cfg,
const wchar_t *filename);
void slider_config_load(struct slider_config *cfg, const wchar_t *filename);
void chusan_hook_config_load(
struct chusan_hook_config *cfg,
const wchar_t *filename);

181
chusanhook/dllmain.c Normal file
View File

@ -0,0 +1,181 @@
#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include "amex/amex.h"
#include "board/sg-reader.h"
#include "board/vfd.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 "hooklib/serial.h"
#include "hooklib/spike.h"
#include "platform/platform.h"
#include "util/dprintf.h"
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)
{
HMODULE d3dc;
HMODULE dbghelp;
HRESULT hr;
dprintf("--- Begin chusan_pre_startup ---\n");
/* Pin the D3D shader compiler. This makes startup much faster. */
d3dc = LoadLibraryW(L"D3DCompiler_43.dll");
if (d3dc != NULL) {
dprintf("Pinned shader compiler, hMod=%p\n", d3dc);
} else {
dprintf("Failed to load shader compiler!\n");
}
/* Pin dbghelp so the path hooks apply to it. */
dbghelp = LoadLibraryW(L"dbghelp.dll");
if (dbghelp != NULL) {
dprintf("Pinned debug helper library, hMod=%p\n", dbghelp);
} else {
dprintf("Failed to load debug helper library!\n");
}
/* Config load */
chusan_hook_config_load(&chusan_hook_cfg, L".\\segatools.ini");
/* 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);
serial_hook_init();
/* Initialize emulation hooks */
hr = platform_hook_init(
&chusan_hook_cfg.platform,
"SDHD",
"ACA2",
chusan_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = chuni_dll_init(&chusan_hook_cfg.dll, chusan_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = chusan_io4_hook_init(&chusan_hook_cfg.io4);
if (FAILED(hr)) {
goto fail;
}
hr = slider_hook_init(&chusan_hook_cfg.slider);
if (FAILED(hr)) {
goto fail;
}
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0];
bool is_cvt = dipsw[2];
for (int i = 0; i < 3; i++) {
switch (i) {
case 0:
dprintf("DipSw: NetInstall: %s\n", dipsw[0] ? "Server" : "Client");
break;
case 1:
dprintf("DipSw: Monitor Type: %dFPS\n", dipsw[1] ? 60 : 120);
break;
case 2:
dprintf("DipSw: Cab Type: %s\n", is_cvt ? "CVT" : "SP");
break;
}
}
unsigned int first_port = is_cvt ? 2 : 20;
if (!is_cvt) {
hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2);
if (FAILED(hr)) {
goto fail;
}
}
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, first_port, 2, 2, 1);
if (FAILED(hr)) {
goto fail;
}
}
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod);
if (FAILED(hr)) {
goto fail;
}
/* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini");
dprintf("--- End chusan_pre_startup ---\n");
/* Jump to EXE start address */
return chusan_startup();
fail:
ExitProcess(EXIT_FAILURE);
}
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
{
HRESULT hr;
if (cause != DLL_PROCESS_ATTACH) {
return TRUE;
}
chusan_hook_mod = mod;
hr = process_hijack_startup(chusan_pre_startup, &chusan_startup);
if (!SUCCEEDED(hr)) {
dprintf("Failed to hijack process startup: %x\n", (int) hr);
}
return SUCCEEDED(hr);
}

106
chusanhook/io4.c Normal file
View File

@ -0,0 +1,106 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "board/io4.h"
#include "chusanhook/chuni-dll.h"
#include "util/dprintf.h"
struct chunithm_jvs_ir_mask {
uint16_t p1;
uint16_t p2;
};
// Incorrect IR beam mappings retained for backward compatibility
static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks_v1[] = {
{ 0, 1 << 13 },
{ 1 << 13, 0 },
{ 0, 1 << 12 },
{ 1 << 12, 0 },
{ 0, 1 << 11 },
{ 1 << 11, 0 },
};
static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks[] = {
{ 1 << 13, 0 },
{ 0, 1 << 13 },
{ 1 << 12, 0 },
{ 0, 1 << 12 },
{ 1 << 11, 0 },
{ 0, 1 << 11 },
};
static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state);
static uint16_t coins;
static const struct io4_ops chusan_io4_ops = {
.poll = chusan_io4_poll,
};
HRESULT chusan_io4_hook_init(const struct io4_config* cfg)
{
HRESULT hr;
assert(chuni_dll.jvs_init != NULL);
dprintf("USB I/O: Starting IO backend\n");
hr = chuni_dll.jvs_init();
if (FAILED(hr)) {
dprintf("USB I/O: Backend error, I/O disconnected: %x\n", (int)hr);
return hr;
}
io4_hook_init(cfg, &chusan_io4_ops, NULL);
return S_OK;
}
static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state)
{
const struct chunithm_jvs_ir_mask *masks;
uint8_t opbtn;
uint8_t beams;
size_t i;
memset(state, 0, sizeof(*state));
opbtn = 0;
beams = 0;
chuni_dll.jvs_poll(&opbtn, &beams);
chuni_dll.jvs_read_coin_counter(&coins);
if (chuni_dll.api_version >= 0x0101) {
// Use correct mapping
masks = chunithm_jvs_ir_masks;
} else {
// Use backwards-compatible incorrect mapping
masks = chunithm_jvs_ir_masks_v1;
}
if (opbtn & CHUNI_IO_OPBTN_TEST) {
state->buttons[0] |= IO4_BUTTON_TEST;
}
if (opbtn & CHUNI_IO_OPBTN_SERVICE) {
state->buttons[0] |= IO4_BUTTON_SERVICE;
}
// Update the coin counter with the value from jvs_read_coin_counter
state->chutes[0] = coins << 8;
for (i = 0; i < 6; i++) {
/* Beam "press" is active-low hence the ~ */
if (~beams & (1 << i)) {
state->buttons[0] |= masks[i].p1;
state->buttons[1] |= masks[i].p2;
}
}
return S_OK;
}

5
chusanhook/io4.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <windows.h>
HRESULT chusan_io4_hook_init(const struct io4_config *cfg);

32
chusanhook/meson.build Normal file
View File

@ -0,0 +1,32 @@
shared_library(
'chusanhook',
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
vs_module_defs : 'chusanhook.def',
c_pch : '../precompiled.h',
dependencies : [
capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'),
],
link_with : [
aimeio_lib,
board_lib,
chuniio_lib,
gfxhook_lib,
hooklib_lib,
platform_lib,
util_lib,
],
sources : [
'chuni-dll.c',
'chuni-dll.h',
'config.c',
'config.h',
'dllmain.c',
'io4.c',
'io4.h',
'slider.c',
'slider.h',
],
)

249
chusanhook/slider.c Normal file
View File

@ -0,0 +1,249 @@
#include <windows.h>
#include <assert.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "board/slider-cmd.h"
#include "board/slider-frame.h"
#include "chusanhook/chuni-dll.h"
#include "chusanhook/slider.h"
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
static HRESULT slider_handle_irp(struct irp *irp);
static HRESULT slider_handle_irp_locked(struct irp *irp);
static HRESULT slider_req_dispatch(const union slider_req_any *req);
static HRESULT slider_req_reset(void);
static HRESULT slider_req_get_board_info(void);
static HRESULT slider_req_auto_scan_start(void);
static HRESULT slider_req_auto_scan_stop(void);
static HRESULT slider_req_set_led(const struct slider_req_set_led *req);
static void slider_res_auto_scan(const uint8_t *state);
static CRITICAL_SECTION slider_lock;
static struct uart slider_uart;
static uint8_t slider_written_bytes[520];
static uint8_t slider_readable_bytes[520];
HRESULT slider_hook_init(const struct slider_config *cfg)
{
assert(cfg != NULL);
assert(chuni_dll.slider_init != NULL);
if (!cfg->enable) {
return S_FALSE;
}
InitializeCriticalSection(&slider_lock);
uart_init(&slider_uart, 1);
slider_uart.written.bytes = slider_written_bytes;
slider_uart.written.nbytes = sizeof(slider_written_bytes);
slider_uart.readable.bytes = slider_readable_bytes;
slider_uart.readable.nbytes = sizeof(slider_readable_bytes);
return iohook_push_handler(slider_handle_irp);
}
static HRESULT slider_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&slider_uart, irp)) {
return iohook_invoke_next(irp);
}
EnterCriticalSection(&slider_lock);
hr = slider_handle_irp_locked(irp);
LeaveCriticalSection(&slider_lock);
return hr;
}
static HRESULT slider_handle_irp_locked(struct irp *irp)
{
union slider_req_any req;
struct iobuf req_iobuf;
HRESULT hr;
if (irp->op == IRP_OP_OPEN) {
dprintf("Chunithm slider: Starting backend\n");
hr = chuni_dll.slider_init();
if (FAILED(hr)) {
dprintf("Chunithm slider: Backend error: %x\n", (int) hr);
return hr;
}
}
hr = uart_handle_irp(&slider_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
for (;;) {
#if 0
dprintf("TX Buffer:\n");
dump_iobuf(&slider_uart.written);
#endif
req_iobuf.bytes = req.bytes;
req_iobuf.nbytes = sizeof(req.bytes);
req_iobuf.pos = 0;
hr = slider_frame_decode(&req_iobuf, &slider_uart.written);
if (hr != S_OK) {
if (FAILED(hr)) {
dprintf("Chunithm slider: Deframe error: %x\n", (int) hr);
}
return hr;
}
#if 0
dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf);
#endif
hr = slider_req_dispatch(&req);
if (FAILED(hr)) {
dprintf("Chunithm slider: Processing error: %x\n", (int) hr);
}
}
}
static HRESULT slider_req_dispatch(const union slider_req_any *req)
{
switch (req->hdr.cmd) {
case SLIDER_CMD_RESET:
return slider_req_reset();
case SLIDER_CMD_GET_BOARD_INFO:
return slider_req_get_board_info();
case SLIDER_CMD_SET_LED:
return slider_req_set_led(&req->set_led);
case SLIDER_CMD_AUTO_SCAN_START:
return slider_req_auto_scan_start();
case SLIDER_CMD_AUTO_SCAN_STOP:
return slider_req_auto_scan_stop();
default:
dprintf("Unhandled command %02x\n", req->hdr.cmd);
return S_OK;
}
}
static HRESULT slider_req_reset(void)
{
struct slider_hdr resp;
dprintf("Chunithm slider: Reset\n");
resp.sync = 0xFF;
resp.cmd = SLIDER_CMD_RESET;
resp.nbytes = 0;
return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp));
}
static HRESULT slider_req_get_board_info(void)
{
struct slider_resp_get_board_info resp;
dprintf("Chunithm slider: Get firmware version\n");
memset(&resp, 0, sizeof(resp));
resp.hdr.sync = SLIDER_FRAME_SYNC;
resp.hdr.cmd = SLIDER_CMD_GET_BOARD_INFO;
resp.hdr.nbytes = sizeof(resp.version);
strcpy_s(
resp.version,
sizeof(resp.version),
"15330 \xA0" "06712\xFF" "\x90");
return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp));
}
static HRESULT slider_req_auto_scan_start(void)
{
assert(chuni_dll.slider_start != NULL);
dprintf("Chunithm slider: Start slider notifications\n");
chuni_dll.slider_start(slider_res_auto_scan);
/* This message is not acknowledged */
return S_OK;
}
static HRESULT slider_req_auto_scan_stop(void)
{
struct slider_hdr resp;
assert(chuni_dll.slider_stop != NULL);
dprintf("Chunithm slider: Stop slider notifications\n");
/* IO DLL worker thread might attempt to invoke the callback (which needs
to take slider_lock, which we are currently holding) before noticing that
it needs to shut down. Unlock here so that we don't deadlock in that
situation. */
LeaveCriticalSection(&slider_lock);
chuni_dll.slider_stop();
EnterCriticalSection(&slider_lock);
resp.sync = SLIDER_FRAME_SYNC;
resp.cmd = SLIDER_CMD_AUTO_SCAN_STOP;
resp.nbytes = 0;
return slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp));
}
static HRESULT slider_req_set_led(const struct slider_req_set_led *req)
{
assert(chuni_dll.slider_set_leds != NULL);
chuni_dll.slider_set_leds(req->payload.rgb);
/* This message is not acknowledged */
return S_OK;
}
static void slider_res_auto_scan(const uint8_t *state)
{
struct slider_resp_auto_scan resp;
resp.hdr.sync = SLIDER_FRAME_SYNC;
resp.hdr.cmd = SLIDER_CMD_AUTO_SCAN;
resp.hdr.nbytes = sizeof(resp.pressure);
memcpy(resp.pressure, state, sizeof(resp.pressure));
EnterCriticalSection(&slider_lock);
slider_frame_encode(&slider_uart.readable, &resp, sizeof(resp));
LeaveCriticalSection(&slider_lock);
}

11
chusanhook/slider.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
struct slider_config {
bool enable;
};
HRESULT slider_hook_init(const struct slider_config *cfg);

106
cmhook/cm-dll.c Normal file
View File

@ -0,0 +1,106 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "cmhook/cm-dll.h"
#include "util/dll-bind.h"
#include "util/dprintf.h"
const struct dll_bind_sym cm_dll_syms[] = {
{
.sym = "cm_io_init",
.off = offsetof(struct cm_dll, init),
}, {
.sym = "cm_io_poll",
.off = offsetof(struct cm_dll, poll),
}, {
.sym = "cm_io_get_opbtns",
.off = offsetof(struct cm_dll, get_opbtns),
}
};
struct cm_dll cm_dll;
// Copypasta DLL binding and diagnostic message boilerplate.
// Not much of this lends itself to being easily factored out. Also there
// will be a lot of API-specific branching code here eventually as new API
// versions get defined, so even though these functions all look the same
// now this won't remain the case forever.
HRESULT cm_dll_init(const struct cm_dll_config *cfg, HINSTANCE self)
{
uint16_t (*get_api_version)(void);
const struct dll_bind_sym *sym;
HINSTANCE owned;
HINSTANCE src;
HRESULT hr;
assert(cfg != NULL);
assert(self != NULL);
if (cfg->path[0] != L'\0') {
owned = LoadLibraryW(cfg->path);
if (owned == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("CardMaker IO: Failed to load IO DLL: %lx: %S\n",
hr,
cfg->path);
goto end;
}
dprintf("CardMaker IO: Using custom IO DLL: %S\n", cfg->path);
src = owned;
} else {
owned = NULL;
src = self;
}
get_api_version = (void *) GetProcAddress(src, "cm_io_get_api_version");
if (get_api_version != NULL) {
cm_dll.api_version = get_api_version();
} else {
cm_dll.api_version = 0x0100;
dprintf("Custom IO DLL does not expose cm_io_get_api_version, "
"assuming API version 1.0.\n"
"Please ask the developer to update their DLL.\n");
}
if (cm_dll.api_version >= 0x0200) {
hr = E_NOTIMPL;
dprintf("CardMaker IO: Custom IO DLL implements an unsupported "
"API version (%#04x). Please update Segatools.\n",
cm_dll.api_version);
goto end;
}
sym = cm_dll_syms;
hr = dll_bind(&cm_dll, src, &sym, _countof(cm_dll_syms));
if (FAILED(hr)) {
if (src != self) {
dprintf("CardMaker IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
goto end;
} else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}
}
owned = NULL;
end:
if (owned != NULL) {
FreeLibrary(owned);
}
return hr;
}

20
cmhook/cm-dll.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include "cmio/cmio.h"
struct cm_dll {
uint16_t api_version;
HRESULT (*init)(void);
HRESULT (*poll)(void);
void (*get_opbtns)(uint8_t *opbtn);
};
struct cm_dll_config {
wchar_t path[MAX_PATH];
};
extern struct cm_dll cm_dll;
HRESULT cm_dll_init(const struct cm_dll_config *cfg, HINSTANCE self);

17
cmhook/cmhook.def Normal file
View File

@ -0,0 +1,17 @@
LIBRARY cmhook
EXPORTS
aime_io_get_api_version
aime_io_init
aime_io_led_set_color
aime_io_nfc_get_aime_id
aime_io_nfc_get_felica_id
aime_io_nfc_poll
amDllVideoClose @2
amDllVideoGetVBiosVersion @4
amDllVideoOpen @1
amDllVideoSetResolution @3
cm_io_get_api_version
cm_io_get_opbtns
cm_io_init
cm_io_poll

44
cmhook/config.c Normal file
View File

@ -0,0 +1,44 @@
#include <assert.h>
#include <stddef.h>
#include "board/config.h"
#include "hooklib/config.h"
#include "hooklib/dvd.h"
#include "cmhook/config.h"
#include "platform/config.h"
void cm_dll_config_load(
struct cm_dll_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
L"cmio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
void cm_hook_config_load(
struct cm_hook_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
platform_config_load(&cfg->platform, filename);
aime_config_load(&cfg->aime, filename);
dvd_config_load(&cfg->dvd, filename);
io4_config_load(&cfg->io4, filename);
vfd_config_load(&cfg->vfd, filename);
touch_screen_config_load(&cfg->touch, filename);
cm_dll_config_load(&cfg->dll, filename);
unity_config_load(&cfg->unity, filename);
}

33
cmhook/config.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <stddef.h>
#include "board/config.h"
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "cmhook/cm-dll.h"
#include "platform/config.h"
#include "unityhook/config.h"
struct cm_hook_config {
struct platform_config platform;
struct aime_config aime;
struct dvd_config dvd;
struct io4_config io4;
struct vfd_config vfd;
struct cm_dll_config dll;
struct touch_screen_config touch;
struct unity_config unity;
};
void cm_dll_config_load(
struct cm_dll_config *cfg,
const wchar_t *filename);
void cm_hook_config_load(
struct cm_hook_config *cfg,
const wchar_t *filename);

120
cmhook/dllmain.c Normal file
View File

@ -0,0 +1,120 @@
#include <windows.h>
#include <stdlib.h>
#include "board/io4.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
#include "hook/process.h"
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
#include "hooklib/serial.h"
#include "hooklib/spike.h"
#include "cmhook/config.h"
#include "cmhook/io4.h"
#include "cmhook/cm-dll.h"
#include "platform/platform.h"
#include "unityhook/hook.h"
#include "util/dprintf.h"
static HMODULE cm_hook_mod;
static process_entry_t cm_startup;
static struct cm_hook_config cm_hook_cfg;
static DWORD CALLBACK cm_pre_startup(void)
{
HRESULT hr;
dprintf("--- Begin cm_pre_startup ---\n");
/* Load config */
cm_hook_config_load(&cm_hook_cfg, L".\\segatools.ini");
/* Hook Win32 APIs */
dvd_hook_init(&cm_hook_cfg.dvd, cm_hook_mod);
touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod);
serial_hook_init();
/* Initialize emulation hooks */
hr = platform_hook_init(
&cm_hook_cfg.platform,
"SDED",
"ACA1",
cm_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = vfd_hook_init(&cm_hook_cfg.vfd, 2);
if (FAILED(hr)) {
goto fail;
}
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = cm_io4_hook_init(&cm_hook_cfg.io4);
if (FAILED(hr)) {
goto fail;
}
/* Initialize Unity native plugin DLL hooks
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
hooked earlier in the `cmhook` initialization. */
unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod);
/* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini");
dprintf("--- End cm_pre_startup ---\n");
/* Jump to EXE start address */
return cm_startup();
fail:
ExitProcess(EXIT_FAILURE);
}
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
{
HRESULT hr;
if (cause != DLL_PROCESS_ATTACH) {
return TRUE;
}
cm_hook_mod = mod;
hr = process_hijack_startup(cm_pre_startup, &cm_startup);
if (!SUCCEEDED(hr)) {
dprintf("Failed to hijack process startup: %x\n", (int) hr);
}
return SUCCEEDED(hr);
}

69
cmhook/io4.c Normal file
View File

@ -0,0 +1,69 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "board/io4.h"
#include "cmhook/cm-dll.h"
#include "util/dprintf.h"
static HRESULT cm_io4_poll(void *ctx, struct io4_state *state);
static uint16_t coins;
static const struct io4_ops cm_io4_ops = {
.poll = cm_io4_poll,
};
HRESULT cm_io4_hook_init(const struct io4_config *cfg)
{
HRESULT hr;
assert(cm_dll.init != NULL);
hr = io4_hook_init(cfg, &cm_io4_ops, NULL);
if (FAILED(hr)) {
return hr;
}
return cm_dll.init();
}
static HRESULT cm_io4_poll(void *ctx, struct io4_state *state)
{
uint8_t opbtn;
HRESULT hr;
assert(cm_dll.poll != NULL);
assert(cm_dll.get_opbtns != NULL);
memset(state, 0, sizeof(*state));
hr = cm_dll.poll();
if (FAILED(hr)) {
return hr;
}
opbtn = 0;
cm_dll.get_opbtns(&opbtn);
if (opbtn & CM_IO_OPBTN_TEST) {
state->buttons[0] |= IO4_BUTTON_TEST;
}
if (opbtn & CM_IO_OPBTN_SERVICE) {
state->buttons[0] |= IO4_BUTTON_SERVICE;
}
if (opbtn & CM_IO_OPBTN_COIN) {
coins++;
}
state->chutes[0] = coins << 8;
return S_OK;
}

7
cmhook/io4.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <windows.h>
#include "board/io4.h"
HRESULT cm_io4_hook_init(const struct io4_config *cfg);

31
cmhook/meson.build Normal file
View File

@ -0,0 +1,31 @@
shared_library(
'cmhook',
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
vs_module_defs : 'cmhook.def',
c_pch : '../precompiled.h',
dependencies : [
capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'),
xinput_lib,
],
link_with : [
aimeio_lib,
board_lib,
hooklib_lib,
cmio_lib,
platform_lib,
unityhook_lib,
util_lib,
],
sources : [
'config.c',
'config.h',
'dllmain.c',
'io4.c',
'io4.h',
'cm-dll.c',
'cm-dll.h',
],
)

54
cmio/cmio.c Normal file
View File

@ -0,0 +1,54 @@
#include <windows.h>
#include <xinput.h>
#include <limits.h>
#include <stdint.h>
#include "cmio/cmio.h"
#include "cmio/config.h"
static uint8_t cm_opbtn;
static struct cm_io_config cm_io_cfg;
static bool cm_io_coin;
uint16_t cm_io_get_api_version(void)
{
return 0x0100;
}
HRESULT cm_io_init(void)
{
cm_io_config_load(&cm_io_cfg, L".\\segatools.ini");
return S_OK;
}
HRESULT cm_io_poll(void)
{
cm_opbtn = 0;
if (GetAsyncKeyState(cm_io_cfg.vk_test) & 0x8000) {
cm_opbtn |= CM_IO_OPBTN_TEST;
}
if (GetAsyncKeyState(cm_io_cfg.vk_service) & 0x8000) {
cm_opbtn |= CM_IO_OPBTN_SERVICE;
}
if (GetAsyncKeyState(cm_io_cfg.vk_coin) & 0x8000) {
if (!cm_io_coin) {
cm_io_coin = true;
cm_opbtn |= CM_IO_OPBTN_COIN;
}
} else {
cm_io_coin = false;
}
return S_OK;
}
void cm_io_get_opbtns(uint8_t *opbtn)
{
if (opbtn != NULL) {
*opbtn = cm_opbtn;
}
}

44
cmio/cmio.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <windows.h>
#include <stdint.h>
enum {
CM_IO_OPBTN_TEST = 0x01,
CM_IO_OPBTN_SERVICE = 0x02,
CM_IO_OPBTN_COIN = 0x04,
};
/* Get the version of the CardMaker IO API that this DLL supports. This
function should return a positive 16-bit integer, where the high byte is
the major version and the low byte is the minor version (as defined by the
Semantic Versioning standard).
The latest API version as of this writing is 0x0100. */
uint16_t cm_io_get_api_version(void);
/* Initialize the IO DLL. This is the second function that will be called on
your DLL, after cm_io_get_api_version.
All subsequent calls to this API may originate from arbitrary threads.
Minimum API version: 0x0100 */
HRESULT cm_io_init(void);
/* Send any queued outputs (of which there are currently none, though this may
change in subsequent API versions) and retrieve any new inputs.
Minimum API version: 0x0100 */
HRESULT cm_io_poll(void);
/* Get the state of the cabinet's operator buttons as of the last poll. See
cm_IO_OPBTN enum above: this contains bit mask definitions for button
states returned in *opbtn. All buttons are active-high.
Minimum API version: 0x0100 */
void cm_io_get_opbtns(uint8_t *opbtn);

22
cmio/config.c Normal file
View File

@ -0,0 +1,22 @@
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include "cmio/config.h"
void cm_io_config_load(
struct cm_io_config *cfg,
const wchar_t *filename)
{
wchar_t key[16];
int i;
assert(cfg != NULL);
assert(filename != NULL);
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);
}

16
cmio/config.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct cm_io_config {
uint8_t vk_test;
uint8_t vk_service;
uint8_t vk_coin;
};
void cm_io_config_load(
struct cm_io_config *cfg,
const wchar_t *filename);

13
cmio/meson.build Normal file
View File

@ -0,0 +1,13 @@
cmio_lib = static_library(
'cmio',
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [
'cmio.c',
'cmio.h',
'config.c',
'config.h',
],
)

View File

@ -23,22 +23,32 @@ void cxb_dll_config_load(
struct cxb_dll_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
L"cxbio",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
void revio_config_load(struct revio_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
}
void network_config_load(struct network_config *cfg, const wchar_t *filename)
{
cfg->enable = GetPrivateProfileIntW(L"revio", L"enable", 1, filename);
}
void led_config_load(struct led_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"led", L"enable", 1, filename);
}
void cxb_hook_config_load(
@ -56,6 +66,5 @@ void cxb_hook_config_load(
gfx_config_load(&cfg->gfx, filename);
cxb_dll_config_load(&cfg->dll, filename);
revio_config_load(&cfg->revio, filename);
network_config_load(&cfg->network, filename);
led_config_load(&cfg->led, filename);
}

View File

@ -10,7 +10,6 @@
#include "cxbhook/cxb-dll.h"
#include "cxbhook/revio.h"
#include "cxbhook/led.h"
#include "cxbhook/network.h"
#include "gfxhook/gfx.h"
@ -23,7 +22,6 @@ struct cxb_hook_config {
struct gfx_config gfx;
struct cxb_dll_config dll;
struct revio_config revio;
struct network_config network;
struct led_config led;
};
@ -32,7 +30,6 @@ void cxb_dll_config_load(
const wchar_t *filename);
void revio_config_load(struct revio_config *cfg, const wchar_t *filename);
void network_config_load(struct network_config *cfg, const wchar_t *filename);
void led_config_load(struct led_config *cfg, const wchar_t *filename);
void cxb_hook_config_load(

View File

@ -9,7 +9,6 @@
#include "cxbhook/config.h"
#include "cxbhook/revio.h"
#include "cxbhook/led.h"
#include "cxbhook/network.h"
#include "cxbio/cxbio.h"
@ -91,7 +90,7 @@ static DWORD CALLBACK cxb_pre_startup(void)
goto fail;
}
hr = sg_reader_hook_init(&cxb_hook_cfg.aime, 12, cxb_hook_mod);
hr = sg_reader_hook_init(&cxb_hook_cfg.aime, 12, 1, cxb_hook_mod);
if (FAILED(hr)) {
goto fail;
@ -103,12 +102,6 @@ static DWORD CALLBACK cxb_pre_startup(void)
goto fail;
}
hr = network_hook_init(&cxb_hook_cfg.network);
if (FAILED(hr)) {
goto fail;
}
hr = led_hook_init(&cxb_hook_cfg.led);
if (FAILED(hr)) {

View File

@ -49,7 +49,13 @@ static struct hook_symbol lamp_syms[] = {
HRESULT led_hook_init(struct led_config *cfg)
{
dprintf("LED: Init\n");
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
dprintf("LED: Hook enabled.\n");
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
}

View File

@ -30,7 +30,5 @@ shared_library(
'revio.h',
'led.c',
'led.h',
'network.c',
'network.h',
],
)

View File

@ -1,13 +0,0 @@
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include "cxbhook/network.h"
#include "util/dprintf.h"
HRESULT network_hook_init(struct network_config *cfg)
{
dprintf("Network: Init\n");
return S_OK;
}

View File

@ -1,13 +0,0 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct network_config {
bool enable;
bool disable_ssl;
char title_server[PATH_MAX];
};
HRESULT network_hook_init(struct network_config *cfg);

View File

@ -82,7 +82,13 @@ static struct hook_symbol revio_syms[] = {
HRESULT revio_hook_init(struct revio_config *cfg)
{
dprintf("Revio: Init\n");
assert(cfg != NULL);
if (!cfg->enable) {
return S_FALSE;
}
dprintf("Revio: Hook enabled.\n");
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
}
@ -154,7 +160,7 @@ static int my_cCommIo_GetTrigger()
out &= ~last_triggers;
dprintf("Revio: GetTrigger %X\n", out);
// dprintf("Revio: GetTrigger %X\n", out);
last_triggers = out;
return out;
}
@ -188,7 +194,7 @@ static int my_cCommIo_GetRelease()
out &= ~btns;
dprintf("Revio: GetRelease %X\n", out);
// dprintf("Revio: GetRelease %X\n", out);
last_triggers = btns;
return out;
}

View File

@ -1,23 +1,56 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
; Insert the path to the game Option directory here (contains MOV1, PAR0,
; PAR1, RES0 and RES1 directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment.
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; Chunithm is extremely picky about its LAN environment, so leaving this
; setting enabled is strongly recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[gpio]
; Emulated Nu DIP switch for Distribution Server setting.
;
; If multiple machines are present on the same LAN then set this to 1 on
; exactly one machine and set this to 0 on all others.
dipsw1=1
[keychip]
@ -26,6 +59,10 @@ dipsw1=1
; that subnet must start with 192.168.
subnet=192.168.126.0
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[gfx]
; Force the game to run windowed.
windowed=1
@ -34,15 +71,31 @@ framed=1
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io3]
; Test button virtual-key code. Default is the 1 key.
test=0x31
; Service button virtual-key code. Default is the 2 key.
service=0x32
; Keyboard button to increment coin counter. Default is the 3 key.
coin=0x33
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72

View File

@ -1,3 +1,7 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
@ -8,6 +12,20 @@ option=
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
@ -18,6 +36,14 @@ default=127.0.0.1
; Chunithm is extremely picky about its LAN environment, so leaving this
; setting enabled is strongly recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
@ -25,6 +51,10 @@ enable=1
; that subnet must start with 192.168.
subnet=192.168.139.0
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[gfx]
; Force the game to run windowed.
windowed=1
@ -33,6 +63,10 @@ framed=1
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
@ -43,6 +77,51 @@ path=
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
[led15093]
; Enable emulation of the 15093-06 controlled lights, which handle the air tower
; RGBs and the rear LED panel (billboard) on the cabinet.
enable=1
[led]
; Output billboard LED strip data to a named pipe called "\\.\pipe\chuni_ledstrip"
cabLedOutputPipe=1
; Output billboard LED strip data to serial
cabLedOutputSerial=0
; Output slider LED data to the named pipe
controllerLedOutputPipe=1
; Output slider LED data to the serial port
controllerLedOutputSerial=0
; Serial port to send data to if using serial output. Default is COM5.
;serialPort=COM5
; Baud rate for serial data
;serialBaud=921600
; Data output a sequence of bytes, with JVS-like framing.
; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere,
; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore
; it and use the next sent byte plus one instead.
;
; After the sync is one byte for the board number that was updated, followed by
; the red, green and blue values for each LED.
;
; Board 0 has 53 LEDs:
; [0]-[49]: snakes through left half of billboard (first column starts at top)
; [50]-[52]: left side partition LEDs
;
; Board 1 has 63 LEDs:
; [0]-[59]: right half of billboard (first column starts at bottom)
; [60]-[62]: right side partition LEDs
;
; Board 2 is the slider and has 31 LEDs:
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
@ -56,12 +135,26 @@ path=
; world. An improved solution will be provided later.
[io3]
; Test button virtual-key code. Default is the 1 key.
test=0x31
; Service button virtual-key code. Default is the 2 key.
service=0x32
; Keyboard button to increment coin counter. Default is the 3 key.
coin=0x33
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Set to 0 for enable separate ir control. Deafult is space key.
ir=0x20
[ir]
; Uncomment and complete the following sequence of settings to configure a
; custom ir-cappable controller if you have one.
;ir6=0x53
; ... etc ...
;ir1=0x53
[slider]
; Enable slider emulation. If you have real AC slider, set this to 0.
; Slider serial port must be COM1.
;enable=1
; Key bindings for each of the 32 touch cells. The default key map, depicted
; in left-to-right order, is as follows:
@ -73,8 +166,8 @@ coin=0x33
;
; Uncomment and complete the following sequence of settings to configure a
; custom high-precision touch strip controller if you have one.
[slider]
;cell32=0x53
;cell31=0x53
;cell30=0x53
;cell1=0x53
;cell2=0x53
; ... etc ...
;cell31=0x53
;cell32=0x53

6
dist/chusan/config_hook.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"allnet_auth":
{
"type": "1.0"
}
}

207
dist/chusan/segatools.ini vendored Normal file
View File

@ -0,0 +1,207 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
; Enable high baud rate.
;highBaud=1
[vfd]
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; Chunithm is extremely picky about its LAN environment, so leaving this
; setting enabled is strongly recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.139.0
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
; allow you to start a game in freeplay mode.
freeplay=0
; LAN Install: If multiple machines are present on the same LAN then set
; this to 1 on exactly one machine and set this to 0 on all others.
dipsw1=1
; Monitor type: 0 = 120FPS, 1 = 60FPS
dipsw2=1
; Cab type: 0 = SP, 1 = CVT. SP will enable VFD and eMoney. This setting will switch
; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well.
dipsw3=1
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[gfx]
; Force the game to run windowed.
windowed=1
; Add a frame to the game window if running windowed.
framed=0
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL (x64) enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[chuniio]
; 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.
;path32=
;path64=
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
[led15093]
; Enable emulation of the 15093-06 controlled lights, which handle the air tower
; RGBs and the rear LED panel (billboard) on the cabinet.
enable=1
[led]
; Output billboard LED strip data to a named pipe called "\\.\pipe\chuni_led"
cabLedOutputPipe=1
; Output billboard LED strip data to serial
cabLedOutputSerial=0
; Output slider LED data to the named pipe
controllerLedOutputPipe=1
; Output slider LED data to the serial port
controllerLedOutputSerial=0
; Serial port to send data to if using serial output. Default is COM5.
;serialPort=COM5
; Baud rate for serial data
;serialBaud=921600
; Data output a sequence of bytes, with JVS-like framing.
; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere,
; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore
; it and use the next sent byte plus one instead.
;
; After the sync is one byte for the board number that was updated, followed by
; the red, green and blue values for each LED.
;
; Board 0 has 53 LEDs:
; [0]-[49]: snakes through left half of billboard (first column starts at top)
; [50]-[52]: left side partition LEDs
;
; Board 1 has 63 LEDs:
; [0]-[59]: right half of billboard (first column starts at bottom)
; [60]-[62]: right side partition LEDs
;
; Board 2 is the slider and has 31 LEDs:
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io3]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Set to 0 for enable separate ir control. Deafult is space key.
ir=0x20
[ir]
; Uncomment and complete the following sequence of settings to configure a
; custom ir-cappable controller if you have one.
;ir6=0x53
; ... etc ...
;ir1=0x53
[slider]
; Enable slider emulation. If you have real AC slider, set this to 0.
; Slider serial port must be COM1.
;enable=1
; Key bindings for each of the 32 touch cells. The default key map, depicted
; in left-to-right order, is as follows:
;
; SSSSDDDDFFFFGGGGHHHHJJJJKKKKLLLL
;
; Touch cells are numbered FROM RIGHT TO LEFT! starting from 1. This is in
; order to match the numbering used in the operator menu and service manual.
;
; Uncomment and complete the following sequence of settings to configure a
; custom high-precision touch strip controller if you have one.
;cell1=0x53
;cell2=0x53
; ... etc ...
;cell31=0x53
;cell32=0x53
; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol.
; eg. COM5
;ledport=

12
dist/chusan/start.bat vendored Normal file
View File

@ -0,0 +1,12 @@
@echo off
pushd %~dp0
start "AM Daemon" /min inject_x64 -d -k chusanhook_x64.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_cvt.json config_sp.json config_hook.json
inject_x86 -d -k chusanhook_x86.dll chusanApp.exe
taskkill /f /im amdaemon.exe > nul 2>&1
echo.
echo Game processes have terminated
pause

9
dist/cm/config_hook.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"credit" :
{
"coin_selector_AS6DB" :
{
"enable" : false
}
}
}

103
dist/cm/segatools.ini vendored Normal file
View File

@ -0,0 +1,103 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.100.0
[gpio]
; ALLS DIP switches.
enable=1
; LAN Install: If multiple machines are present on the same LAN then set
; this to 0 on exactly one machine and set this to 1 on all others.
dipsw1=0
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[touch]
; Enable/Disable WinTouch emulation
enable=0
[unity]
; Path to a .NET DLL that should run before the game. Useful for loading
; modding frameworks such as BepInEx.
targetAssembly=
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io4]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72

12
dist/cm/start.bat vendored Normal file
View File

@ -0,0 +1,12 @@
@echo off
pushd %~dp0
start "AM Daemon" /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json
inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920
taskkill /f /im amdaemon.exe > nul 2>&1
echo.
echo Game processes have terminated
pause

107
dist/cxb/segatools.ini vendored
View File

@ -1,3 +1,7 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Make sure theses are full paths and not relative or you will have a bad time
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
@ -9,41 +13,55 @@ option=
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Aime reader emulation
enable=1
; CXB is stupid, so we have to make the paths go back two directories. This
; will load the file from "resource\DEVICE\aime.txt".
aimePath=../DEVICE/aime.txt
[led]
; Emulation for the LED board. Currently it's just dummy responses,
; but if somebody wants to make their keyboard or whatever light
; up with the game they can
enable=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
; Set the title server hostname or IP address here, as the title server
; is hardcoded in the game.
title=https://127.0.0.1:9002
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; Crossbeats is extremely picky about its LAN environment, so leaving this
; setting enabled is strongly recommended.
enable=1
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.100.0
subnet=192.168.150.0
billingCa=../DEVICE/ca.crt
billingPub=../DEVICE/billing.pub
billingType=2
[gfx]
; Force the game to run windowed.
windowed=1
; Add a frame to the game window if running windowed.
framed=1
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
[aime]
; Aime reader emulation
; CXB is stupid, so we have to make the paths go back one
enable=1
aimePath=../DEVICE/aime.txt
felicaPath=../DEVICE/felica.txt
[eeprom]
; See above
path=../DEVICE/eeprom.bin
@ -52,21 +70,54 @@ path=../DEVICE/eeprom.bin
; See above
path=../DEVICE/sram.bin
[led]
; Emulation for the LED board. Currently it's just dummy responses,
; but if somebody wants to make their keyboard or whatever light
; up with the game they can
enable=1
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[gfx]
; Force the game to run windowed.
windowed=1
; Add a frame to the game window if running windowed.
framed=1
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[cxbio]
; To use a custom crossbeats REV. DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[revio]
; Enable emulation of the rev IO board
enabe=1
; Test button virtual-key code. Default is the 1 key.
test=0x31
; Service button virtual-key code. Default is the 2 key.
service=0x32
; Keyboard button to increment coin counter. Default is the 3 key.
coin=0x33
enable=1
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Menu up key. Default is up arrow.
up=0x26
; Menu down key. Default is down arrow.

View File

@ -1,3 +1,7 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
@ -8,6 +12,20 @@ option=
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
@ -19,14 +37,56 @@ default=127.0.0.1
; setting enabled is strongly recommended.
enable=1
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[gpio]
; Emulated Nu DIP switch for Distribution Server setting.
;
; If multiple machines are present on the same LAN then set this to 1 on
; exactly one machine and set this to 0 on all others.
dipsw1=1
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.150.0
subnet=192.168.78.0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[divaio]
; To use a custom Project DIVA Arcade IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io3]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
[slider]
cell1=0x51

161
dist/fgo/segatools.ini vendored Normal file
View File

@ -0,0 +1,161 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
[deckReader]
; 837-15345 RFID deck reader emulation setting.
enable=1
[ftdi]
; FTDI serial to usb adapter emulation for CABINET LED.
enable=1
; COM port number where the LED board is connected to.
portNo=17
[led15093]
; 837-15093-06 LED board emulation setting.
enable=1
; COM port number for the LED board. Has to be the same as the FTDI port.
portNo=17
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.167.0
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
; allow you to start a game in freeplay mode.
freeplay=0
; -----------------------------------------------------------------------------
; Misc. hook settings
; -----------------------------------------------------------------------------
[touch]
; WinTouch emulation setting.
enable=1
remap=1
cursor=1
[printer]
; Sinfonia CHC-C330 printer emulation setting.
enable=1
; Change the printer serial number here.
serial_no="5A-A123"
; Insert the path to the image output directory here.
printerOutPath="DEVICE\print"
; Rotate all printed images by 180 degrees.
rotate180=1
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[fgoio]
; To use a custom Fate/Grand Order Arcade IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in gamepad input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io4]
; Input API selection for JVS input emulator.
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; .·:'''''''''''''''''''''''''''''''''''''''''''''':·.
; : : ______ / \ [] : :
; : : | | _____ \ / Coin : :
; : : |______| { (0) } /--\ Attack. : :
; : : DECK \ / / \ : :
; : : | | > < : :
; : : | | \ / ___ : :
; : : | | \--/ | | : :
; : : JOY Noble. | | : :
; : : |___| : :
; : : AIME. : :
; '·:..............................................:·'
;
; Only XInput is currently supported.
; XInput bindings
;
; Left Stick Joystick
; Left Stick Click Reset Camera
; Left Trigger Dash
; Left Shoulder Switch Target
; A/B Attack
; X/Y Noble Phantasm

11
dist/fgo/start.bat vendored Normal file
View File

@ -0,0 +1,11 @@
@echo off
cd /d %~dp0
inject -d -k fgohook.dll ago.exe
taskkill /f /im amdaemon.exe > nul 2>&1
echo.
echo Game processes have terminated
pause

9
dist/idac/config_hook.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"network" :
{
"property" :
{
"dhcp" : true
}
}
}

217
dist/idac/segatools.ini vendored Normal file
View File

@ -0,0 +1,217 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains MVxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Controls emulation of the Aime card reader assembly.
enable=1
aimePath=DEVICE\aime.txt
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168. Set it to your LAN's subnet if you
; want to play head-to-head using netenv=1.
subnet=192.168.158.0
; Override the keychip's region code. Most games seem to pay attention to the
; DS EEPROM region code and not the keychip region code, and this seems to be
; a bit mask that controls which Nu PCB region codes this keychip is authorized
; for. So it probably only affects the system software and not the game software.
; 1: JPN: Japan, 4: EXP: Export (for Asian markets)
region=4
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
; allow you to start a game in freeplay mode.
freeplay=0
; If multiple machines are present on the same LAN then set this to 1 on
; exactly one machine and set this to 0 on all others.
dipsw1=1
; 0 is the DZero CVT cab and 1 is the SWDC CVT cab.
dipsw2=0
; Enable the Single Seat mode, always requires dipsw1=1.
dipsw3=0
; The next two dip switches are the seat settings in bits, where
; 00 = Seat 1, 10 = Seat 2, 01 = Seat 3 and 11 = Seat 4
dipsw4=0
dipsw5=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[idacio]
; To use a custom Initial D THE ARCADE IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io4]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Input API selection for IO4 input emulator.
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
mode=xinput
; Adjust scaling for steering wheel input.
;
; This setting scales the steering wheel input so that the maximum positive
; and minimum negative steering inputs reported in the operator menu's input
; test screen do not exceed the value below. The maximum possible value is 128,
; and the value that matches the input range of a real cabinet is 128.
;
; NOTE: This is not the same thing as DirectInput steering wheel movement
; range! Segatools cannot control the maximum angle of your physical steering
; wheel controller, this setting is vendor-specific and can only be adjusted
; in the Control Panel.
restrict=128
[xinput]
; XInput bindings
;
; Left Stick Steering
; Right Stick (Steering) when "singleStickSteering" is disabled
; Left Trigger Brake
; Right Trigger Accelerator
; Left Stick Click Left (used for Time Up)
; Right Stick Click Right (used for Time Up)
; Left Shoulder Shift Down
; Right Shoulder Shift Up
; Start/A Start
; Back/B View Change
; X Shift Up
; Y Shift Down
; D-Pad D-Pad
; Left and right thumbsticks are mapped to left and right dpad buttons.
; Press both thumbsticks to trigger "Time Up" and exit the course.
; Automatically reset the simulated shifter to Neutral when XInput Start is
; pressed (e.g. when navigating menus between races).
autoNeutral=1
; Use the left thumbstick for steering instead of both on XInput Controllers.
; Not recommended as it will not give you the precision needed for this game.
singleStickSteering=1
; Use linear steering instead of the default non-linear cubing steering.
linearSteering=1
; Configure deadzones for the left and right thumbsticks.
; The default value for the left stick is 7849, max value is 32767.
leftStickDeadzone=7849
; The default value for the right stick is 8689, max value is 32767.
rightStickDeadzone=8689
[dinput]
; Name of the DirectInput wheel to use (or any text that occurs in its name)
; Example: G29
;
; If this is left blank then the first DirectInput device will be used.
deviceName=
; Name of the DirectInput pedals to use (or any subset thereof).
; Leave blank if you do not have separate pedals; aka the pedals are part of
; the wheel.
;
; The pedals will be mapped to the accelAxis and brakeAxis.
pedalsName=
; Name of the positional shifter to use (or any subset thereof).
; Leave blank if you do not have a positional shifter; a positional shifter
; will be simulated using the configured Shift Down and Shift Up buttons
; in this case.
;
; Can be the same device as the wheel.
;
; Example: G29
shifterName=
; Pedal mappings. Valid axis names are:
;
; X, Y, Z, RX, RY, RZ, U, V
;
; (U and V are old names for Slider 1 and Slider 2).
; The examples below are valid for a Logitech G29.
brakeAxis=RZ
accelAxis=Y
; DirectInput button numbers to map to menu inputs. Note that buttons are
; numbered from 1; some software numbers buttons from 0.
start=1
viewChg=2
; DPad is already emulated, but in order to trigger "Time Up" and exit the
; course you need to press both left and right on the DPad at the same time.
; This is not possible on most devices, so we set the left and right button again.
left=7
right=8
; Button mappings for the simulated six-speed shifter.
shiftDn=6
shiftUp=5
; Button mappings for the positional shifter, if present.
gear1=13
gear2=14
gear3=15
gear4=16
gear5=17
gear6=18
; Invert the accelerator and or brake axis
; (Needed when using DirectInput for the Dualshock 4 for example)
reverseAccelAxis=0
reverseBrakeAxis=0
; Force feedback settings.
; Strength of the force feedback spring effect in percent. Possible values
; are 0-100.
centerSpringStrength=30

40
dist/idac/start.bat vendored Normal file
View File

@ -0,0 +1,40 @@
@echo off
pushd %~dp0
set AMDAEMON_CFG=config_common.json ^
config_ex.json ^
config_jp.json ^
config_laninstall_client_ex.json ^
config_laninstall_client_jp.json ^
config_laninstall_server_ex.json ^
config_laninstall_server_jp.json ^
config_aime_high_ex.json ^
config_aime_high_jp.json ^
config_aime_normal_ex.json ^
config_aime_normal_jp.json ^
config_seat_1_ex.json ^
config_seat_1_jp.json ^
config_seat_2_ex.json ^
config_seat_2_jp.json ^
config_seat_3_ex.json ^
config_seat_3_jp.json ^
config_seat_4_ex.json ^
config_seat_4_jp.json ^
config_seat_single_ex.json ^
config_seat_single_jp.json ^
config_hook.json
start "AM Daemon" /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG%
rem JP
rem inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
rem EXP
inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
taskkill /f /im amdaemon.exe > nul 2>&1
echo.
echo Game processes have terminated
pause

167
dist/idz/segatools.ini vendored
View File

@ -1,3 +1,7 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
@ -8,30 +12,55 @@ option=
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Controls emulation of the Aime card reader assembly.
enable=1
; Necessary for IDZ Version 2+ to work
aimePath=DEVICE\aime.txt
felicaGen=0
aimeGen=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet
; (so, if the keychip subnet is 192.168.32.0 and this value is set to 11,
; then the local host's virtualized LAN IP is 192.168.32.11).
; Needed for in store battle, one needs to set it to 12.
;addrSuffix=12
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.158.0
[ds]
; Region code on the emulated AMEX board DS EEPROM.
; 1: Japan
; 4: Export (some UI elements in English)
;
; NOTE: Changing this setting causes a factory reset.
region=1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.100.0
region=4
[gpio]
; Emulated Nu DIP switch for Distribution Server setting.
@ -40,6 +69,25 @@ subnet=192.168.100.0
; exactly one machine and set this to 0 on all others.
dipsw1=1
; -----------------------------------------------------------------------------
; Misc. hooks settings
; -----------------------------------------------------------------------------
[gfx]
; Enables the graphics hook. This is required for some Initial D Zero versions
; for example v1.31 and v2.11 to run properly in fullscreen.
enable=0
; Force the game to run windowed.
windowed=0
; Add a frame to the game window if running windowed.
framed=1
; Select the monitor to run the game on. (Fullscreen only, 0=primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
@ -50,16 +98,29 @@ path=
; Leave empty if you want to use Segatools built-in gamepad/wheel input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io3]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Input API selection for JVS input emulator.
; Set "xinput" to use a gamepad and "dinput" to use a steering wheel.
mode=xinput
; Automatically reset the simulated shifter to Neutral when XInput Start is
; pressed (e.g. when navigating menus between races).
autoNeutral=1
; Use the left thumbstick for steering instead of both on XInput Controllers.
; Not recommended as it will not give you the precision needed for this game
singleStickSteering=0
; Adjust scaling for steering wheel input.
;
; This setting scales the steering wheel input so that the maximum positive
@ -73,9 +134,38 @@ singleStickSteering=0
; in the Control Panel.
restrict=97
[xinput]
; XInput bindings
;
; Left Stick Steering
; Right Stick (Steering) when "singleStickSteering" is disabled
; Left Trigger Brake
; Right Trigger Accelerator
; Left Shoulder Shift Down
; Right Shoulder Shift Up
; Start/A Start
; Back/B View Change
; X Shift Up
; Y Shift Down
; D-Pad D-Pad
; Automatically reset the simulated shifter to Neutral when XInput Start is
; pressed (e.g. when navigating menus between races).
autoNeutral=1
; Use the left thumbstick for steering instead of both on XInput Controllers.
; Not recommended as it will not give you the precision needed for this game.
singleStickSteering=1
; Use linear steering instead of the default non-linear cubing steering.
linearSteering=1
; Configure deadzones for the left and right thumbsticks.
; The default value for the left stick is 7849, max value is 32767.
leftStickDeadzone=7849
; The default value for the right stick is 8689, max value is 32767.
rightStickDeadzone=8689
[dinput]
; Name of the DirectInput wheel to use (or any text that occurs in its name)
; Example: TMX
; Example: G29
;
; If this is left blank then the first DirectInput device will be used.
deviceName=
@ -86,31 +176,42 @@ deviceName=
;
; Can be the same device as the wheel.
;
; Example: T500
; Example: G29
shifterName=
; Name of the DirectInput pedals to use (or any subset thereof).
; Leave blank if you do not have separate pedals; aka the pedals are part of
; the wheel.
;
; The pedals will be mapped to the accelAxis and brakeAxis.
pedalsName=
; Pedal mappings. Valid axis names are:
;
; X, Y, Z, RX, RY, RZ, U, V
;
; (U and V are old names for Slider 1 and Slider 2).
; The examples below are valid for a Thrustmaster TMX.
brakeAxis=RZ
; The examples below are valid for a Logitech G29.
brakeAxis=U
accelAxis=Y
; DirectInput button numbers to map to menu inputs. Note that buttons are
; numbered from 1; some software numbers buttons from 0.
start=3
viewChg=10
start=1
viewChg=2
; Button mappings for the simulated six-speed shifter.
shiftDn=1
shiftUp=2
shiftDn=5
shiftUp=6
; Button mappings for the positional shifter, if present.
gear1=1
gear2=2
gear3=3
gear4=4
gear5=5
gear6=6
gear1=13
gear2=14
gear3=15
gear4=16
gear5=17
gear6=18
; Invert the accelerator and or brake axis
; (Needed when using DirectInput for the Dualshock 4 for example)
reverseAccelAxis=0
reverseBrakeAxis=0
; Force feedback settings.
; Strength of the force feedback spring effect in percent. Possible values
; are 0-100.
centerSpringStrength=30

8
dist/idz/start.bat vendored
View File

@ -2,8 +2,12 @@
pushd %~dp0
.\inject.exe -k .\idzhook.dll .\InitialD0_DX11_Nu.exe
.\inject.exe -d -k .\idzhook.dll .\amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json
inject -k idzhook.dll InitialD0_DX11_Nu.exe
rem Set dipsw1=0 and uncomment the ServerBox for in store battle?
rem inject -k idzhook.dll ServerBoxD8_Nu_x64.exe
inject -d -k idzhook.dll amdaemon.exe -c configDHCP_Final_Common.json configDHCP_Final_JP.json configDHCP_Final_JP_ST1.json configDHCP_Final_JP_ST2.json configDHCP_Final_EX.json configDHCP_Final_EX_ST1.json configDHCP_Final_EX_ST2.json
taskkill /im ServerBoxD8_Nu_x64.exe > nul 2>&1
echo.
echo Game processes have terminated

133
dist/mai2/segatools.ini vendored Normal file
View File

@ -0,0 +1,133 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about its LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
; If you disable netenv then you must set this to your LAN's IP subnet, and
; that subnet must start with 192.168.
subnet=192.168.172.0
[gpio]
; ALLS DIP switches.
enable=1
; Enable freeplay mode. This will disable the coin slot and set the game to
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
; allow you to start a game in freeplay mode.
freeplay=0
; LAN Install: If multiple machines are present on the same LAN then set
; this to 1 on exactly one machine and set this to 0 on all others.
dipsw1=1
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[mai2io]
; To use a custom maimai DX IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Misc. hook settings
; -----------------------------------------------------------------------------
[unity]
; Path to a .NET DLL that should run before the game. Useful for loading
; modding frameworks such as BepInEx.
targetAssembly=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io4]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Key bindings for buttons around screen. The default key map, depicted
; in clockwise order, is as follows:
;
; Player 1 Ring buttons: WEDCXZAQ, Select button: 3
; Player 2 Ring buttons: (Numpad) 89632147, Select button: (Numpad) *
;
; Select buttons are considered as button 9.
;
; Uncomment and complete the following sequence of settings to configure a
; custom keybinding.
[button]
;1p_btn1=0x53
;1p_btn2=0x53
;1p_btn3=0x53
; ... etc ...
;2p_btn1=0x53
;2p_btn2=0x53
;2p_btn3=0x53
; ... etc ...

12
dist/mai2/start.bat vendored Normal file
View File

@ -0,0 +1,12 @@
@echo off
pushd %~dp0
start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 -popupwindow -screen-width 2160 -screen-height 1920 -silent-crashes
taskkill /f /im amdaemon.exe > nul 2>&1
echo.
echo Game processes have terminated
pause

View File

@ -1,30 +1,54 @@
; -----------------------------------------------------------------------------
; Path settings
; -----------------------------------------------------------------------------
[vfs]
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
amfs=amfs
amfs=
; Insert the path to the game Option directory here (contains Axxx directories)
option=
; Create an empty directory somewhere and insert the path here.
; This directory may be shared between multiple SEGA games.
; NOTE: This has nothing to do with Windows %APPDATA%.
appdata=appdata
option=option
appdata=
; -----------------------------------------------------------------------------
; Device settings
; -----------------------------------------------------------------------------
[aime]
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
; reader.
enable=1
aimePath=DEVICE\aime.txt
[vfd]
; Enable VFD emulation (currently just stubbed). Disable to use a real VFD
; GP1232A02A FUTABA assembly.
enable=1
; -----------------------------------------------------------------------------
; Network settings
; -----------------------------------------------------------------------------
[dns]
; Insert the hostname or IP address of the server you wish to use here.
; Note that 127.0.0.1, localhost etc are specifically rejected.
default=127.0.0.1
[ds]
; Region code on the emulated AMEX board DS EEPROM.
; 1: Japan
; 4: Export (some UI elements in English)
;
; NOTE: Changing this setting causes a factory reset.
region=1
[netenv]
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
; SEGA games are somewhat picky about their LAN environment, so leaving this
; setting enabled is recommended.
enable=1
; The final octet of the local host's IP address on the virtualized subnet (so,
; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the
; local host's virtualized LAN IP is `192.168.32.11`).
addrSuffix=11
; -----------------------------------------------------------------------------
; Board settings
; -----------------------------------------------------------------------------
[keychip]
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
@ -32,16 +56,25 @@ enable=1
; that subnet must start with 192.168.
subnet=192.168.174.0
[gfx]
[gpio]
; ALLS DIP switches.
enable=1
[io4]
; Input API selection for JVS input emulator.
test=0x2D
service=0x2E
coin=0x24
volup=0x26
voldown=0x28
; Enable freeplay mode. This will disable the coin slot and set the game to
; freeplay. Keep in mind that some game modes (e.g. Freedom/Time Modes) will not
; allow you to start a game in freeplay mode.
freeplay=0
; LAN Install: If multiple machines are present on the same LAN then set
; this to 1 on exactly one machine and set this to 0 on all others.
dipsw1=1
; -----------------------------------------------------------------------------
; Misc. hook settings
; -----------------------------------------------------------------------------
[gfx]
enable=1
; Hooks related to the touch boards
[touch]
@ -51,6 +84,41 @@ enable=1
[elisabeth]
enable=1
;[mercuryio]
; Use mercuryio.dll
;path=mercuryio.dll
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[mercuryio]
; To use a custom WACCA IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------
; Keyboard bindings are specified as hexadecimal (prefixed with 0x) or decimal
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
;
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
;
; This is, admittedly, not the most user-friendly configuration method in the
; world. An improved solution will be provided later.
[io4]
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.
service=0x71
; Keyboard button to increment coin counter. Default is the F3 key.
coin=0x72
; Volume up virtual-key code. Default is the "UP" key.
volup=0x26
; Volume down virtual-key code. Default is the "DOWN" key.
voldown=0x28

Some files were not shown because too many files have changed in this diff Show More