Compare commits

..

136 Commits

Author SHA1 Message Date
96bf8cab81 aime: add portNo to config 2024-12-23 21:49:24 +01:00
a3120181be replace hardcoded enums with #define CTL_CODEs 2024-12-23 21:48:30 +01:00
80d4902cfc remove 5gb wasted space by removing precompiled headers 2024-12-23 21:04:51 +01:00
b4f5cdbe59 Merge pull request 'Add automatically apply OpenSSL patch for Intel Gen 10+ CPUs' (#43) from kagaminehaku/segatools:develop into develop
Reviewed-on: Dniel97/segatools#43
2024-12-23 19:43:47 +00:00
25431a9db1 Add "openssl" config key doc 2024-12-24 02:34:44 +07:00
a705ae8748 Merge pull request 'Add changeable config path' (#53) from GEEKiDoS/segatools:develop into develop
Reviewed-on: Dniel97/segatools#53
2024-12-23 18:04:12 +00:00
b52455339f Merge pull request 'dns: add port overriding support' (#52) from t12i/segatools:develop into develop
Reviewed-on: Dniel97/segatools#52
2024-12-23 17:54:38 +00:00
ff21223f06 Removed the unused lines 2024-12-17 10:06:41 +07:00
047733d122 format code 2024-12-16 11:18:00 +08:00
21bb965382 typo 2024-12-16 11:14:14 +08:00
11556a1332 add changeable config path 2024-12-16 11:09:38 +08:00
d8202e1df4 dns: add port overriding support 2024-12-12 02:28:02 +08:00
2d3d6fc2bb Skip the patch when already patched 2024-11-26 01:40:57 +07:00
6d8ffb46ef Merge pull request 'dns: fix msvc build' (#50) from Haruka/segatools:fixmsvc into develop
Reviewed-on: Dniel97/segatools#50
2024-11-17 13:42:53 +00:00
2069b1ea85 dns: fix msvc build 2024-11-14 13:03:13 +01:00
c80f903cf8 Fix build with Microsoft Visual C++, Fix gfxhook and felica issue (#48)
I just wanna say that It is a SHAME that a Windows ONLY project was not able to build without MINGW
Also where's the missing `3mpxsc.h` in diva hook?

This also fixes the window size issue from hook_CreateWindowExA in gfxhook
And Fixes felica issue as described in #45

Reviewed-on: Dniel97/segatools#48
Reviewed-by: Dniel97 <dniel97@noreply.gitea.tendokyu.moe>
Co-authored-by: GEEKiDoS <geek_ds@foxmail.com>
Co-committed-by: GEEKiDoS <geek_ds@foxmail.com>
2024-11-11 16:28:24 +00:00
ceb2b63e8b Modify host header in HTTP requests to bypass domain censorship in China. (#34)
Co-authored-by: Sanheiii <35133371+Sanheiii@users.noreply.github.com>
Reviewed-on: Dniel97/segatools#34
Co-authored-by: Sanhei <sanhei@noreply.gitea.tendokyu.moe>
Co-committed-by: Sanhei <sanhei@noreply.gitea.tendokyu.moe>
2024-11-11 16:24:33 +00:00
83840e0a87 dns: add new WAHLAP url blocked (#49)
Reviewed-on: Dniel97/segatools#49
Co-authored-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
Co-committed-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
2024-11-10 20:47:40 +00:00
e50d6d8ebc Merge pull request 'Throw fatal when vfs option configured but invalid' (#47) from Bottersnike/segatools:feat/vfs-validation into develop
Reviewed-on: Dniel97/segatools#47
2024-11-05 16:36:43 +00:00
e1a47cf365 Throw fatal when vfs option configured but invalid 2024-11-04 22:55:15 +00:00
8aef1cfa79 Change method set environment variable to current process only using "SetEnvironmentVariableW" 2024-11-05 00:48:21 +07:00
8fc24503c8 diva, fgo: added gfx, close #46 2024-11-03 23:00:43 +01:00
ebf0f0b428 Develop a new/better method to detect cpu using intrinsic functions (__cpuid and __cpuidex) 2024-11-02 00:26:31 +07:00
892eb2b859 idz, idac, swdc: fixed rumble effect 2024-10-29 22:06:07 +01:00
b80b9fbc19 Delete useless comment 2024-10-18 13:44:47 +07:00
cef3406691 Add switch for openssl patch in segatools.ini 2024-10-18 13:34:25 +07:00
97d2d6b9bc resolved camelCase and the " :" problem 2024-10-16 15:53:52 +07:00
f39b9ce3a0 resolve dniel97 comments 2024-10-16 15:01:39 +07:00
243bb778d1 Add automatically apply OpenSSL patch for Intel Gen 10+ CPUs 2024-10-16 04:08:54 +07:00
66317a0054 bump capnhook rev to include serial fixes 2024-10-11 07:32:22 +02:00
8c24e04900 Merge pull request 'printer: Add setting to configure "printing time"' (#39) from Haruka/segatools:printerdelay into develop
Reviewed-on: Dniel97/segatools#39
2024-10-04 12:53:26 +00:00
3bb9404a38 printer: add the default waitTime setting to config 2024-10-04 11:43:34 +02:00
6819963f06 Merge branch 'refs/heads/develop' into printerdelay 2024-10-03 12:12:59 +02:00
36849bd09a Merge branch 'feature/ffb' into develop 2024-09-30 23:23:23 +02:00
5f817c8a36 swdc: minor improvements 2024-09-30 23:17:37 +02:00
259b763a13 idz: add ffb and led emulation 2024-09-30 23:10:16 +02:00
2251585ef0 swdc: add ffb and led emulation 2024-09-30 20:23:28 +02:00
c06bb408e7 idac: add ffb emulation 2024-09-30 18:50:46 +02:00
53fb8c28ea Merge pull request 'kemono: only load I/O dll inside amdaemon' (#38) from Haruka/segatools:kemonofr64bit into develop
Reviewed-on: Dniel97/segatools#38
2024-09-28 13:36:06 +00:00
33452394e6 kemono: also only load aimeio dll in x64 process 2024-09-27 17:50:40 +02:00
4fa9abffe8 printer: add ability to delay printing 2024-09-27 11:06:18 +02:00
88a5bdcd14 kemono: only load I/O dll inside amdaemon 2024-09-26 11:52:00 +02:00
bb773a63ce Merge pull request 'Kemono Friends support / 32-bit CHC300 support' (#36) from Haruka/segatools:kemonofr into develop
Reviewed-on: Dniel97/segatools#36
2024-09-21 15:12:05 +00:00
25e79f87c2 Merge pull request 'felica: fix rare card scan error (correct PMm)' (#33) from zaphkito/segatools:develop into develop
Reviewed-on: Dniel97/segatools#33
2024-09-21 15:10:28 +00:00
79592514ba fgo: fix printer 2024-09-20 11:14:41 +02:00
cdfd3bf655 kemono: not sure why that went missing 2024-09-20 11:09:21 +02:00
f6c12fd230 kemono: Pre-generate printer firmware files 2024-09-19 13:46:49 +02:00
86556ed2c8 kemono: Update start.bat 2024-09-16 14:29:49 +02:00
9de48dd6ce kemono: flip declarations 2024-09-13 16:52:55 +02:00
d257887f6e kemono: fix packagefile again 2024-09-12 13:29:17 +02:00
3eef5dd209 kemono: fix LED board check error 2024-09-12 13:25:38 +02:00
599d5e3211 kemono: fix LED hooking, add button LEDs 2024-09-12 13:25:19 +02:00
f18d074c5f kemono: add missed declarations 2024-09-12 12:50:57 +02:00
6bd1bce419 kemono: mention in readme 2024-09-12 12:50:51 +02:00
96bdacfa7c kemono: remove old amdaemon workaround 2024-09-12 12:40:57 +02:00
d4bb7b6e0e kemono: correct keychip IP range 2024-09-12 12:40:10 +02:00
70ac873d11 kemono: add to package creation 2024-09-12 12:39:42 +02:00
068651b6fa kemono: add support 2024-09-11 13:31:23 +02:00
84e9ed3c9a felica: fix rare card scan error (cucorrect PMm)
from real aime card with official card reader
2024-08-31 13:57:18 +00:00
c827b4c212 Merge pull request 'add almost full vfd implementation' (#31) from Haruka/segatools:vfd into develop
Reviewed-on: Dniel97/segatools#31
Reviewed-by: Dniel97 <dniel97@noreply.gitea.tendokyu.moe>
2024-08-24 21:56:38 +00:00
26624f25b1 hide default vfd ports from configs 2024-08-24 11:14:13 +02:00
824bc9abda default vfd port number to zero (use game-specific port) 2024-08-23 17:24:47 +02:00
cc5b87b559 add vfd settings to docs 2024-08-23 17:23:59 +02:00
e6794807a6 add default port fallback for vfd 2024-08-23 17:20:05 +02:00
54cbbffae9 add almost full vfd implementation 2024-08-23 16:30:22 +02:00
ac0f9f0587 aime firmware fix, mu3 keybinding fix 2024-08-21 15:13:09 +02:00
0061158188 printer: changed filename for holo cards 2024-08-20 13:40:47 +02:00
c535f18e40 added support for tokyo 2024-08-20 13:32:35 +02:00
c91c7db3c7 renamed [gpio] dipsw settings to [system] 2024-08-20 10:48:08 +02:00
6a4cae1165 Merge pull request 'Add bounds checking for D3D9 adapter number' (#29) from Bottersnike/segatools:fix/adapter_range into develop
Reviewed-on: Dniel97/segatools#29
2024-08-19 13:54:58 +00:00
383039e16e Add bounds checking for D3D9 adapter number 2024-08-17 21:17:23 +01:00
37c26ecadb chuniio: Add OpeNITHM LED protocol support (#26)
This commit basically copy-pastes the last commits from https://dev.s-ul.net/VeroxZik/segatools/-/commits/master to add OpenITHM LED support. Doesn't need to edit segatools.ini because the relevant config lines are already there for some reason.

Tested with my OpenITHM controller and behaves exactly like the other fork.

Reviewed-on: Dniel97/segatools#26
Co-authored-by: d4nin3u <d4nin3u@gmail.com>
Co-committed-by: d4nin3u <d4nin3u@gmail.com>
2024-08-06 21:35:51 +00:00
686d57d3ee unity: timezone spoofing fixed, close #27 2024-08-06 11:14:27 +02:00
b9204d4765 unity: hopefully fixes timezone spoofing #27 2024-08-05 21:59:59 +02:00
5abc593b46 cm: added printer support 2024-08-05 20:53:56 +02:00
fe14630b3d unity: fixed option loading crash 2024-08-05 20:49:47 +02:00
92fe2751e7 Merge pull request 'dns: added WAHLAP billing DNS block' (#23) from zaphkito/segatools:develop into develop
Reviewed-on: Dniel97/segatools#23
2024-07-06 23:06:31 +00:00
8c839b0d4e dns: added WAHLAP billing DNS block
China have another company named universal service WACCA, but they use same PowerOn and Download Order domain with SEGA official, so we need express `sys-all.cn` is only used for WAHLAP, not all China SEGA games.
WAHLAP have a unused billing domain, just in case, we blocked it now
2024-07-03 18:04:21 +00:00
ccb655a12b Merge pull request 'Add configurable debug logging' (#22) from Bottersnike/segatools:develop into develop
Reviewed-on: Dniel97/segatools#22
2024-07-01 18:42:01 +00:00
ded89f6343 Make fixes based on #22 review 2024-07-01 19:28:23 +01:00
f3e31fc2ae improved doc 2024-06-30 19:37:04 +02:00
965126c68a idac: improved compatibility with newer versions 2024-06-30 14:23:20 +02:00
050951e56f idac: removed unused include 2024-06-24 17:15:29 +02:00
7e5e0f132e idac: 837-15070 board implementation 2024-06-23 21:21:57 +02:00
4e58d3b9a2 added game specific devices documentation 2024-06-23 21:04:08 +02:00
7d3cab256b Add configurable debug logging 2024-06-20 01:22:01 +01:00
b0f307f427 Fixed option loading, thanks @Hay1tsme, close #16 2024-06-09 00:50:54 +02:00
7aa996193c Merge pull request 'dns: added CHN DNS block' (#17) from zaphkito/segatools:develop into develop
Reviewed-on: Dniel97/segatools#17
2024-05-20 19:59:37 +00:00
9353c9872f dns: added CHN DNS block 2024-05-19 09:37:57 +00:00
d8b3d41809 mu3: hotfix for calling mu3_io_led_set_colors 2024-05-16 08:10:05 +02:00
3bfb046afc mu3, chusan: improved library doc 2024-05-15 21:42:15 +02:00
9fe98b227b mu3: added lights hook 2024-05-12 22:06:37 +02:00
b77ce7b457 io3: added basic rotary input support 2024-05-12 19:39:56 +02:00
517469a60c switched to new capnhook, updated unityhook, added LED 15093 to MU3 2024-05-12 19:37:30 +02:00
1069cfee26 Merge pull request 'dns: amlog hook & subdomain wildcard parse' (#14) from Yusen0727/segatools:fix/amlog-dns-hook into develop
Reviewed-on: Dniel97/segatools#14
2024-05-10 04:09:34 +00:00
d3a0faa530 Merge pull request 'unityhook: check for new entrypoint' (#15) from Yusen0727/segatools:fix/new-doorstop-entrypoint into develop
Reviewed-on: Dniel97/segatools#15
2024-05-10 04:04:01 +00:00
00b3d5b7bb unityhook: check for new entrypoint
The new entrypoint has been introduced in UnityDoorstop 4.1.0,
which is used by BepInEx 5.4.23.

This commit check for new entrypoint to support new version
of BepInEx.
2024-05-10 08:24:53 +08:00
04fcd0d09a dns: amlog hook & subdomain wildcard parse 2024-05-09 15:02:22 +08:00
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
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
eb1ec0e261 idac: updated start.bat script 2024-04-29 21:34:30 +02:00
482a6e530a print vfd message 2024-04-30 02:19:10 +08:00
65173e1fa6 [unity] Fix Unity config path 2024-04-29 23:12:10 +07:00
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
47a65e5e51 fixed aime LED firmware 2024-03-17 14:20:13 +01:00
774a639bb7 cxb: fixed configs 2024-03-14 00:14:51 +01:00
097b74d849 cxb: server support added, bugfixes, thanks @Midorica 2024-03-13 21:40:25 +01:00
2590e749ca config bugfixes 2024-03-07 15:46:43 +01:00
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
f570869946 fixed AMFS path redirect with no E:/ drive present 2024-02-27 16:49:27 +01:00
629ded4018 added AimePay, E-MONEY DNS redirects 2024-02-25 19:03:05 +01:00
ca36a879cb updated README and added "AM Daemon" window name 2024-02-22 19:12:18 +01:00
ae199502e8 fixed amfs/appdata redirects 2024-02-22 12:02:32 +01:00
e40e1dffe3 improved all segatools.ini configs 2024-02-21 21:58:44 +01:00
56e971c6a4 changed default operator buttons to F1, F2 and F3 and fixed subnets 2024-02-06 13:01:26 +01:00
3e9303e043 fgo: ups forgot to add it to Package.mk 2024-02-06 12:34:39 +01:00
451a7ec49d added VFD toggle to config 2024-02-06 12:34:11 +01:00
dae3018411 doc: added develop dongle hint 2024-01-27 23:10:59 +01:00
cadf20040c swdc: fixed dinput buttons 2024-01-17 15:52:41 +01:00
cc0b6b0953 swdc: fixed steering wheel buttons, improved start.bat 2024-01-16 17:56:24 +01:00
0affc96e3e small optimizations 2024-01-16 17:54:06 +01:00
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
aa2184f947 Merge branch 'develop' into fix/print-ip-addresses-properly 2024-01-07 18:36:04 +00:00
d0165b1eb0 fix(netenv): Print IP addresses properly 2024-01-08 01:34:55 +07:00
477dad2667 Merge branch 'chuniio' into develop 2023-12-27 19:29:55 +01:00
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
926493290b fix chunihook 2023-12-26 06:47:19 -05:00
f4a3a5f78d optimized meson.build to decrease filesize 2023-12-25 15:55:43 +01:00
f5f275c8e9 chuniio: fixed individual IR notes 2023-12-25 15:12:25 +01:00
b38dea23ac chu2to3: fixed docker compilation, bugfixes 2023-12-25 15:03:44 +01:00
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
ee414d122b Include chu2to3 engine 2023-12-24 08:33:30 -05:00
d4372fa5c2 chuniio: use HRESULT instead of int for chuni_io_led_init() 2023-12-21 00:45:41 +01:00
ac9b889d71 chusan/chuni: tower LEDs added 2023-12-19 14:40:02 +01:00
3bf223c04e chusan: fixed SP/CVT switching 2023-12-19 13:45:06 +01:00
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
372 changed files with 16656 additions and 2975 deletions

4
.clang-format Normal file
View File

@ -0,0 +1,4 @@
---
BasedOnStyle: Google
IndentWidth: 4
---

3
.gitignore vendored
View File

@ -18,3 +18,6 @@ build/
# External dependencies # External dependencies
subprojects/capnhook subprojects/capnhook
# For enabling debug logging on local builds
MesonLocalOptions.mk

View File

@ -11,6 +11,11 @@ DOC_DIR := doc
DIST_DIR := dist DIST_DIR := dist
# Add "-D[option]=[value]" here as necessary
MESON_OPTIONS :=
# For options that shouldn't be committed
-include MesonLocalOptions.mk
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Targets # Targets
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -19,9 +24,9 @@ include Package.mk
.PHONY: build # Build the project .PHONY: build # Build the project
build: build:
$(V)meson --cross cross-mingw-32.txt $(BUILD_DIR_32) $(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-32.txt $(BUILD_DIR_32)
$(V)ninja -C $(BUILD_DIR_32) $(V)ninja -C $(BUILD_DIR_32)
$(V)meson --cross cross-mingw-64.txt $(BUILD_DIR_64) $(V)meson setup $(MESON_OPTIONS) --cross cross-mingw-64.txt $(BUILD_DIR_64)
$(V)ninja -C $(BUILD_DIR_64) $(V)ninja -C $(BUILD_DIR_64)
.PHONY: dist # Build and create a zip distribution package .PHONY: dist # Build and create a zip distribution package

View File

@ -111,6 +111,7 @@ $(BUILD_DIR_ZIP)/swdc.zip:
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/swdchook/swdchook.dll \ $(BUILD_DIR_64)/swdchook/swdchook.dll \
$(DIST_DIR)/swdc/segatools.ini \ $(DIST_DIR)/swdc/segatools.ini \
$(DIST_DIR)/swdc/config_hook.json \
$(DIST_DIR)/swdc/start.bat \ $(DIST_DIR)/swdc/start.bat \
$(BUILD_DIR_ZIP)/swdc $(BUILD_DIR_ZIP)/swdc
$(V)cp pki/billing.pub \ $(V)cp pki/billing.pub \
@ -202,6 +203,43 @@ $(BUILD_DIR_ZIP)/cm.zip:
$(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll} $(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip * $(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip *
$(BUILD_DIR_ZIP)/tokyo.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo
$(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo/DEVICE
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/tokyohook/tokyohook.dll \
$(DIST_DIR)/tokyo/config_hook.json \
$(DIST_DIR)/tokyo/segatools.ini \
$(DIST_DIR)/tokyo/start.bat \
$(BUILD_DIR_ZIP)/tokyo
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/tokyo/DEVICE
$(V)strip $(BUILD_DIR_ZIP)/tokyo/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/tokyo ; zip -r ../tokyo.zip *
$(BUILD_DIR_ZIP)/kemono.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/kemono
$(V)mkdir -p $(BUILD_DIR_ZIP)/kemono/DEVICE
$(V)cp $(DIST_DIR)/kemono/segatools.ini \
$(DIST_DIR)/kemono/start.bat \
$(BUILD_DIR_ZIP)/kemono
$(V)cp $(BUILD_DIR_32)/kemonohook/kemonohook.dll \
$(BUILD_DIR_ZIP)/kemono/kemonohook_x86.dll
$(V)cp $(BUILD_DIR_64)/kemonohook/kemonohook.dll \
$(BUILD_DIR_ZIP)/kemono/kemonohook_x64.dll
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_ZIP)/kemono/inject_x86.exe
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_ZIP)/kemono/inject_x64.exe
$(V)cp pki/billing.pub \
pki/ca.crt \
$(BUILD_DIR_ZIP)/kemono/DEVICE
for x in exe dll; do strip $(BUILD_DIR_ZIP)/kemono/*.$$x; done
$(V)cd $(BUILD_DIR_ZIP)/kemono ; zip -r ../kemono.zip *
$(BUILD_DIR_ZIP)/doc.zip: \ $(BUILD_DIR_ZIP)/doc.zip: \
$(DOC_DIR)/config \ $(DOC_DIR)/config \
$(DOC_DIR)/chunihook.md \ $(DOC_DIR)/chunihook.md \
@ -224,6 +262,9 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
$(BUILD_DIR_ZIP)/mu3.zip \ $(BUILD_DIR_ZIP)/mu3.zip \
$(BUILD_DIR_ZIP)/mai2.zip \ $(BUILD_DIR_ZIP)/mai2.zip \
$(BUILD_DIR_ZIP)/cm.zip \ $(BUILD_DIR_ZIP)/cm.zip \
$(BUILD_DIR_ZIP)/tokyo.zip \
$(BUILD_DIR_ZIP)/fgo.zip \
$(BUILD_DIR_ZIP)/kemono.zip \
CHANGELOG.md \ CHANGELOG.md \
README.md \ README.md \

View File

@ -1,33 +1,37 @@
# Segatools # Segatools
Version: `2023-11-22` Version: `2024-09-30`
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms. Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
## List of supported games ## List of supported games
* Chunithm * Card Maker
* [Chunithm (Plus)](doc/chunihook.md) * starting from Card Maker
* [Chunithm Air (Plus)](doc/chunihook.md) * CHUNITHM
* [Chunithm Star (Plus)](doc/chunihook.md) * up to [CHUNITHM PARADISE LOST](doc/chunihook.md)
* [Chunithm Amazon (Plus)](doc/chunihook.md) * starting from CHUNITHM NEW!!
* [Chunithm Crystal (Plus)](doc/chunihook.md) * crossbeats REV.
* Chunithm SUN * up to crossbeats REV. SUNRISE
* Fate/Grand Order
* Fate/Grand Order Arcade
* Hatsune Miku: Project DIVA Arcade
* up to Future Tone
* Initial D * Initial D
* [Initial D Arcade Stage Zero](doc/idzhook.md) * [Initial D Arcade Stage Zero](doc/idzhook.md)
* Initial D THE ARCADE * Initial D THE ARCADE
* SEGA World Drivers Championship
* up to SEGA World Drivers Championship 2019
* Fate/Grand Order
* Fate/Grand Order Arcade
* ONGEKI
* up to bright MEMORY
* maimai DX * maimai DX
* up to maimai DX FESTiVAL PLUS * starting from maimai DX
* Card Maker * Mario & Sonic
* up to Card Maker 1.35 * Mario & Sonic at the Tokyo 2020 Olympics Arcade
* Wacca * O.N.G.E.K.I.
* up to WACCA Reverse * starting from O.N.G.E.K.I.
* SEGA World Drivers Championship
* SEGA World Drivers Championship 2019
* WACCA
* starting from WACCA
* Kemono Friends
* Kemono Friends 3: Planet Tours
## End-users ## End-users

View File

@ -12,6 +12,7 @@
#include "util/crc.h" #include "util/crc.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
struct aime_io_config { struct aime_io_config {
wchar_t aime_path[MAX_PATH]; wchar_t aime_path[MAX_PATH];
@ -68,7 +69,6 @@ static void aime_io_config_read(
cfg->felica_path, cfg->felica_path,
_countof(cfg->felica_path), _countof(cfg->felica_path),
filename); filename);
dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError());
cfg->felica_gen = GetPrivateProfileIntW( cfg->felica_gen = GetPrivateProfileIntW(
L"aime", L"aime",
@ -223,7 +223,7 @@ uint16_t aime_io_get_api_version(void)
HRESULT aime_io_init(void) HRESULT aime_io_init(void)
{ {
aime_io_config_read(&aime_io_cfg, L".\\segatools.ini"); aime_io_config_read(&aime_io_cfg, get_config_path());
return S_OK; return S_OK;
} }

View File

@ -3,7 +3,6 @@ aimeio_lib = static_library(
name_prefix : '', name_prefix : '',
include_directories: inc, include_directories: inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
link_with : [ link_with : [
util_lib, util_lib,
], ],

View File

@ -1,10 +1,11 @@
#include <windows.h> #include <windows.h>
#include <devioctl.h> #include <devioctl.h>
#include <ntdddisk.h> #include <winioctl.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "amex/ds.h" #include "amex/ds.h"
@ -19,13 +20,11 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/str.h" #include "util/str.h"
#pragma pack(push, 1) #define DS_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
#define DS_IOCTL_SETUP CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define DS_IOCTL_READ_SECTOR CTL_CODE(0x8000, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS)
enum { #pragma pack(push, 1)
DS_IOCTL_GET_ABI_VERSION = 0x80006000,
DS_IOCTL_SETUP = 0x80006004,
DS_IOCTL_READ_SECTOR = 0x80006010,
};
struct ds_eeprom { struct ds_eeprom {
uint32_t crc32; uint32_t crc32;

View File

@ -6,7 +6,7 @@
#include <winnt.h> #include <winnt.h>
#endif #endif
#include <devioctl.h> #include <devioctl.h>
#include <ntdddisk.h> #include <winioctl.h>
#include <assert.h> #include <assert.h>
@ -20,9 +20,7 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/str.h" #include "util/str.h"
enum { #define EEPROM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
EEPROM_IOCTL_GET_ABI_VERSION = 0x80006000,
};
static HRESULT eeprom_handle_irp(struct irp *irp); static HRESULT eeprom_handle_irp(struct irp *irp);
static HRESULT eeprom_handle_open(struct irp *irp); static HRESULT eeprom_handle_open(struct irp *irp);

View File

@ -1,5 +1,6 @@
#include <windows.h> #include <windows.h>
#include <ntstatus.h> #include <ntstatus.h>
#include <winioctl.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -13,12 +14,10 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/str.h" #include "util/str.h"
enum { #define GPIO_IOCTL_SET_LEDS CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS)
GPIO_IOCTL_SET_LEDS = 0x8000A004, #define GPIO_IOCTL_GET_PSW CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
GPIO_IOCTL_GET_PSW = 0x80006008, #define GPIO_IOCTL_GET_DIPSW CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
GPIO_IOCTL_GET_DIPSW = 0x8000600C, #define GPIO_IOCTL_DESCRIBE CTL_CODE(0x8000, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
GPIO_IOCTL_DESCRIBE = 0x80006014,
};
enum { enum {
GPIO_TYPE_NONE = 0, GPIO_TYPE_NONE = 0,

View File

@ -4,6 +4,7 @@
#include <winternl.h> #include <winternl.h>
#include <ntstatus.h> #include <ntstatus.h>
#include <winioctl.h>
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
@ -21,11 +22,9 @@
#include "util/dump.h" #include "util/dump.h"
#include "util/str.h" #include "util/str.h"
enum { #define JVS_IOCTL_HELLO CTL_CODE(0x8000, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
JVS_IOCTL_HELLO = 0x80006004, #define JVS_IOCTL_TRANSACT CTL_CODE(0x8000, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
JVS_IOCTL_SENSE = 0x8000600C, #define JVS_IOCTL_SENSE CTL_CODE(0x8000, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
JVS_IOCTL_TRANSACT = 0x8000E008,
};
static HRESULT jvs_handle_irp(struct irp *irp); static HRESULT jvs_handle_irp(struct irp *irp);
static HRESULT jvs_handle_open(struct irp *irp); static HRESULT jvs_handle_open(struct irp *irp);
@ -185,14 +184,14 @@ static HRESULT jvs_ioctl_sense(struct irp *irp)
static HRESULT jvs_ioctl_transact(struct irp *irp) static HRESULT jvs_ioctl_transact(struct irp *irp)
{ {
#if 0 #if defined(LOG_JVS)
dprintf("\nJVS Port: Outbound frame:\n"); dprintf("\nJVS Port: Outbound frame:\n");
dump_const_iobuf(&irp->write); dump_const_iobuf(&irp->write);
#endif #endif
jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read); jvs_bus_transact(jvs_root, irp->write.bytes, irp->write.nbytes, &irp->read);
#if 0 #if defined(LOG_JVS)
dprintf("JVS Port: Inbound frame:\n"); dprintf("JVS Port: Inbound frame:\n");
dump_iobuf(&irp->read); dump_iobuf(&irp->read);
dprintf("\n"); dprintf("\n");

View File

@ -2,7 +2,6 @@ amex_lib = static_library(
'amex', 'amex',
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
], ],

View File

@ -6,7 +6,7 @@
#include <winnt.h> #include <winnt.h>
#endif #endif
#include <devioctl.h> #include <devioctl.h>
#include <ntdddisk.h> #include <winioctl.h>
#include <assert.h> #include <assert.h>
@ -20,9 +20,7 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/str.h" #include "util/str.h"
enum { #define SRAM_IOCTL_GET_ABI_VERSION CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
SRAM_IOCTL_GET_ABI_VERSION = 0x80006000,
};
static HRESULT sram_handle_irp(struct irp *irp); static HRESULT sram_handle_irp(struct irp *irp);
static HRESULT sram_handle_open(struct irp *irp); static HRESULT sram_handle_open(struct irp *irp);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <stdbool.h>
#include "aimeio/aimeio.h" #include "aimeio/aimeio.h"

View File

@ -8,6 +8,7 @@
#include "board/aime-dll.h" #include "board/aime-dll.h"
#include "board/config.h" #include "board/config.h"
#include "board/sg-reader.h" #include "board/sg-reader.h"
#include "board/vfd.h"
#include "util/dprintf.h" #include "util/dprintf.h"
@ -71,7 +72,8 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
aime_dll_config_load(&cfg->dll, filename); aime_dll_config_load(&cfg->dll, filename);
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highbaud", 1, filename); cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename);
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename); cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename);
} }
@ -82,3 +84,21 @@ void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, 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);
cfg->port_no = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename);
cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename);
}
void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"ffb", L"enable", 1, filename);
}

View File

@ -5,6 +5,10 @@
#include "board/io4.h" #include "board/io4.h"
#include "board/sg-reader.h" #include "board/sg-reader.h"
#include "board/vfd.h"
#include "board/ffb.h"
void aime_config_load(struct aime_config *cfg, const wchar_t *filename); 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 io4_config_load(struct io4_config *cfg, const wchar_t *filename);
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename);
void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename);

235
board/ffb.c Normal file
View File

@ -0,0 +1,235 @@
/*
Force Feedback Board (FFB)
This board is used by many SEGA games to provide force feedback to the player.
It is driven by the game software over a serial connection and is used by many
games such as SEGA World Drivers Championship, Initial D Arcade, ...
Part number in schematics is "838-15069 MOTOR DRIVE BD RS232/422 Board".
Some observations:
The maximal strength for any effect is 127, except Damper which maxes out at 40.
The period for rumble effects is in the range 0-40.
*/
#include "board/ffb.h"
#include <assert.h>
#include <stdint.h>
#include <windows.h>
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "util/dprintf.h"
#include "util/dump.h"
// request format:
// 0x?? - sync + command
// 0x?? - direction/additional command
// 0x?? - strength
// 0x?? - checksum (sum of everything except the sync byte)
enum {
FFB_CMD_TOGGLE = 0x80,
FFB_CMD_CONSTANT_FORCE = 0x84,
FFB_CMD_RUMBLE = 0x85,
FFB_CMD_DAMPER = 0x86,
};
struct ffb_hdr {
uint8_t cmd;
};
union ffb_req_any {
struct ffb_hdr hdr;
uint8_t bytes[3];
};
static HRESULT ffb_handle_irp(struct irp *irp);
static HRESULT ffb_req_dispatch(const union ffb_req_any *req);
static HRESULT ffb_req_toggle(const uint8_t *bytes);
static HRESULT ffb_req_constant_force(const uint8_t *bytes);
static HRESULT ffb_req_rumble(const uint8_t *bytes);
static HRESULT ffb_req_damper(const uint8_t *bytes);
static const struct ffb_ops *ffb_ops;
static struct uart ffb_uart;
static bool ffb_started;
static HRESULT ffb_start_hr;
static uint8_t ffb_written[4];
static uint8_t ffb_readable[4];
/* Static variables to store maximum strength values */
static uint8_t max_constant_force = 0;
static uint8_t max_rumble = 0;
static uint8_t max_period = 0;
static uint8_t max_damper = 0;
HRESULT ffb_hook_init(
const struct ffb_config *cfg,
const struct ffb_ops *ops,
unsigned int port_no)
{
assert(cfg != NULL);
assert(ops != NULL);
if (!cfg->enable) {
return S_FALSE;
}
ffb_ops = ops;
uart_init(&ffb_uart, port_no);
ffb_uart.written.bytes = ffb_written;
ffb_uart.written.nbytes = sizeof(ffb_written);
ffb_uart.readable.bytes = ffb_readable;
ffb_uart.readable.nbytes = sizeof(ffb_readable);
dprintf("FFB: hook enabled.\n");
return iohook_push_handler(ffb_handle_irp);
}
static HRESULT ffb_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (!uart_match_irp(&ffb_uart, irp)) {
return iohook_invoke_next(irp);
}
hr = uart_handle_irp(&ffb_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr;
}
assert(&ffb_uart.written != NULL);
assert(ffb_uart.written.bytes != NULL || ffb_uart.written.nbytes == 0);
assert(ffb_uart.written.pos <= ffb_uart.written.nbytes);
// dprintf("FFB TX:\n");
hr = ffb_req_dispatch((const union ffb_req_any *) ffb_uart.written.bytes);
if (FAILED(hr)) {
dprintf("FFB: Processing error: %x\n", (int)hr);
}
// dump_iobuf(&ffb_uart.written);
ffb_uart.written.pos = 0;
return hr;
}
static HRESULT ffb_req_dispatch(const union ffb_req_any *req)
{
switch (req->hdr.cmd) {
case FFB_CMD_TOGGLE:
return ffb_req_toggle(req->bytes);
case FFB_CMD_CONSTANT_FORCE:
return ffb_req_constant_force(req->bytes);
case FFB_CMD_RUMBLE:
return ffb_req_rumble(req->bytes);
case FFB_CMD_DAMPER:
return ffb_req_damper(req->bytes);
/* There are some test mode specfic commands which doesn't seem to be used in
game at all. The same is true for the initialization phase. */
default:
dprintf("FFB: Unhandled command %02x\n", req->hdr.cmd);
return S_OK;
}
}
static HRESULT ffb_req_toggle(const uint8_t *bytes)
{
uint8_t activate = bytes[2];
if (activate == 0x01) {
dprintf("FFB: Activated\n");
} else {
dprintf("FFB: Deactivated\n");
}
if (ffb_ops->toggle != NULL) {
ffb_ops->toggle(activate == 0x01);
}
return S_OK;
}
static HRESULT ffb_req_constant_force(const uint8_t *bytes)
{
// dprintf("FFB: Constant force\n");
uint8_t direction = bytes[1];
uint8_t force = bytes[2];
if (direction == 0x0) {
// Right
force = 128 - force;
}
// Update max strength if the current force is greater
if (force > max_constant_force) {
max_constant_force = force;
}
// dprintf("FFB: Constant Force Strength: %d (Max: %d)\n", force, max_constant_force);
if (ffb_ops->constant_force != NULL) {
ffb_ops->constant_force(direction, force);
}
return S_OK;
}
static HRESULT ffb_req_rumble(const uint8_t *bytes)
{
// dprintf("FFB: Rumble\n");
uint8_t force = bytes[1];
uint8_t period = bytes[2];
// Update max strength if the current force is greater
if (force > max_rumble) {
max_rumble = force;
}
if (period > max_period) {
max_period = period;
}
// dprintf("FFB: Rumble Period: %d (Max %d), Strength: %d (Max: %d)\n", period, max_period, force, max_rumble);
if (ffb_ops->rumble != NULL) {
ffb_ops->rumble(force, period);
}
return S_OK;
}
static HRESULT ffb_req_damper(const uint8_t *bytes)
{
// dprintf("FFB: Damper\n");
uint8_t force = bytes[2];
// Update max strength if the current force is greater
if (force > max_damper) {
max_damper = force;
}
// dprintf("FFB: Damper Strength: %d (Max: %d)\n", force, max_damper);
if (ffb_ops->damper != NULL) {
ffb_ops->damper(force);
}
return S_OK;
}

21
board/ffb.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct ffb_config {
bool enable;
};
struct ffb_ops {
void (*toggle)(bool active);
void (*constant_force)(uint8_t direction, uint8_t force);
void (*rumble)(uint8_t force, uint8_t period);
void (*damper)(uint8_t force);
};
HRESULT ffb_hook_init(
const struct ffb_config *cfg,
const struct ffb_ops *ops,
unsigned int port_no);

View File

@ -16,6 +16,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "board/io3.h" #include "board/io3.h"
@ -79,6 +80,11 @@ static HRESULT io3_cmd_read_analogs(
struct const_iobuf *req_buf, struct const_iobuf *req_buf,
struct iobuf *resp_buf); struct iobuf *resp_buf);
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_write_gpio( static HRESULT io3_cmd_write_gpio(
struct io3 *io3, struct io3 *io3,
struct const_iobuf *req_buf, struct const_iobuf *req_buf,
@ -116,6 +122,13 @@ static uint8_t io3_features[] = {
0x03, 8, 10, 0, 0x03, 8, 10, 0,
/* Feature : 0x04 : Rotary inputs
Param1 : 4 : Number of rotary channels
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x04, 4, 0, 0,
/* Feature : 0x12 : GPIO outputs /* Feature : 0x12 : GPIO outputs
Param1 : 3 : Number of ports (8 bits per port) Param1 : 3 : Number of ports (8 bits per port)
Param2 : 0 : N/A Param2 : 0 : N/A
@ -219,6 +232,9 @@ static HRESULT io3_cmd(
case JVS_CMD_READ_ANALOGS: case JVS_CMD_READ_ANALOGS:
return io3_cmd_read_analogs(io3, req, resp); return io3_cmd_read_analogs(io3, req, resp);
case JVS_CMD_READ_ROTARYS:
return io3_cmd_read_rotarys(io3, req, resp);
case JVS_CMD_WRITE_GPIO: case JVS_CMD_WRITE_GPIO:
return io3_cmd_write_gpio(io3, req, resp); return io3_cmd_write_gpio(io3, req, resp);
@ -375,7 +391,7 @@ static HRESULT io3_cmd_read_switches(
return hr; return hr;
} }
#if 0 #if defined(LOG_IO3)
dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n", dprintf("JVS I/O: Read switches, np=%i, bpp=%i\n",
req.num_players, req.num_players,
req.bytes_per_player); req.bytes_per_player);
@ -536,6 +552,60 @@ static HRESULT io3_cmd_read_analogs(
} }
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_rotarys req;
uint16_t rotarys[4];
uint8_t i;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
if (req.nrotarys > _countof(rotarys)) {
dprintf("JVS I/O: Invalid analog count %i\n", req.nrotarys);
return E_FAIL;
}
//dprintf("JVS I/O: Read rotarys, nrotarys=%i\n", req.nrotarys);
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write analogs */
memset(rotarys, 0, sizeof(rotarys));
if (io3->ops->read_rotarys != NULL) {
io3->ops->read_rotarys(io3->ops_ctx, rotarys, req.nrotarys);
}
for (i = 0 ; i < req.nrotarys ; i++) {
hr = iobuf_write_be16(resp_buf, rotarys[i]);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_write_gpio( static HRESULT io3_cmd_write_gpio(
struct io3 *io3, struct io3 *io3,
struct const_iobuf *req_buf, struct const_iobuf *req_buf,

View File

@ -18,6 +18,7 @@ struct io3_ops {
void (*write_gpio)(void *ctx, uint32_t state); void (*write_gpio)(void *ctx, uint32_t state);
void (*read_switches)(void *ctx, struct io3_switch_state *out); void (*read_switches)(void *ctx, struct io3_switch_state *out);
void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs); void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs);
void (*read_rotarys)(void *ctx, uint16_t *rotaries, uint8_t nrotaries);
void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out); void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out);
}; };

View File

@ -7,6 +7,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "board/config.h" #include "board/config.h"
#include "board/guid.h" #include "board/guid.h"
@ -48,7 +49,7 @@ static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
struct io4_report_out { struct io4_report_out {
uint8_t report_id; uint8_t report_id;
uint8_t cmd; uint8_t cmd;
uint8_t payload[62]; uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN];
}; };
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size"); static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
@ -223,7 +224,11 @@ static HRESULT io4_handle_write(struct irp *irp)
return S_OK; return S_OK;
case IO4_CMD_SET_GENERAL_OUTPUT: case IO4_CMD_SET_GENERAL_OUTPUT:
dprintf("USB I/O: GPIO Out\n"); // dprintf("USB I/O: GPIO Out\n");
if (io4_ops->write_gpio != NULL) {
return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
}
return S_OK; return S_OK;

View File

@ -3,6 +3,9 @@
#include <windows.h> #include <windows.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#define IO4_REPORT_OUT_PAYLOAD_LEN 62
enum { enum {
/* System buttons in button[0] */ /* System buttons in button[0] */
@ -24,6 +27,7 @@ struct io4_state {
struct io4_ops { struct io4_ops {
HRESULT (*poll)(void *ctx, struct io4_state *state); HRESULT (*poll)(void *ctx, struct io4_state *state);
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
}; };
HRESULT io4_hook_init( HRESULT io4_hook_init(

81
board/led15070-cmd.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include "board/led15070-frame.h"
/* Command IDs */
enum {
LED_15070_CMD_RESET = 0x10,
LED_15070_CMD_SET_INPUT = 0x28, // No known use case
LED_15070_CMD_SET_NORMAL_12BIT = 0x30, // TODO
LED_15070_CMD_SET_NORMAL_8BIT = 0x31,
LED_15070_CMD_SET_MULTI_FLASH_8BIT = 0x32,
LED_15070_CMD_SET_MULTI_FADE_8BIT = 0x33,
LED_15070_CMD_SET_PALETTE_7_NORMAL_LED = 0x34, // No known use case
LED_15070_CMD_SET_PALETTE_6_FLASH_LED = 0x35, // No known use case
LED_15070_CMD_SET_15DC_OUT = 0x36, // No known use case
LED_15070_CMD_SET_15GS_OUT = 0x37, // No known use case
LED_15070_CMD_SET_PSC_MAX = 0x38, // No known use case
LED_15070_CMD_SET_FET_OUTPUT = 0x39,
LED_15070_CMD_SET_GS_PALETTE = 0x3A,
LED_15070_CMD_DC_UPDATE = 0x3B,
LED_15070_CMD_GS_UPDATE = 0x3C,
LED_15070_CMD_ROTATE = 0x3E, // No known use case, wtf is this?
LED_15070_CMD_SET_DC_DATA = 0x3F,
LED_15070_CMD_EEPROM_WRITE = 0x7B,
LED_15070_CMD_EEPROM_READ = 0x7C,
LED_15070_CMD_ACK_ON = 0x7D,
LED_15070_CMD_ACK_OFF = 0x7E,
LED_15070_CMD_BOARD_INFO = 0xF0,
LED_15070_CMD_BOARD_STATUS = 0xF1,
LED_15070_CMD_FW_SUM = 0xF2,
LED_15070_CMD_PROTOCOL_VER = 0xF3,
LED_15070_CMD_TO_BOOT_MODE = 0xFD,
LED_15070_CMD_FW_UPDATE = 0xFE,
};
/* Response codes */
enum {
LED_15070_STATUS_OK = 0x01,
LED_15070_STATUS_SUM_ERR = 0x02,
LED_15070_STATUS_PARITY_ERR = 0x03,
LED_15070_STATUS_FRAMING_ERR = 0x04,
LED_15070_STATUS_OVERRUN_ERR = 0x05,
LED_15070_STATUS_BUFFER_OVERFLOW = 0x06,
};
enum {
LED_15070_REPORT_OK = 0x01,
LED_15070_REPORT_WAIT = 0x02,
LED_15070_REPORT_ERR1 = 0x03,
LED_15070_REPORT_ERR2 = 0x04,
};
/* Request data structures */
struct led15070_req_any {
struct led15070_hdr hdr;
uint8_t cmd;
uint8_t payload[256];
};
/* Response data structures */
struct led15070_resp_any {
struct led15070_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
uint8_t data[32];
};
struct led15070_resp_board_info {
struct led15070_hdr hdr;
uint8_t status;
uint8_t cmd;
uint8_t report;
char board_num[8];
uint8_t endcode; // Always 0xFF
uint8_t fw_ver;
};

194
board/led15070-frame.c Normal file
View File

@ -0,0 +1,194 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "board/led15070-frame.h"
#include "hook/iobuf.h"
static void led15070_frame_sync(struct iobuf *src);
static HRESULT led15070_frame_accept(const struct iobuf *dest);
static HRESULT led15070_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 led15070_frame_sync(struct iobuf *src)
{
size_t i;
for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++);
src->pos -= i;
memmove(&src->bytes[0], &src->bytes[i], i);
}
static HRESULT led15070_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 led15070_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);
led15070_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 == 0xE0) {
hr = E_FAIL;
} else if (byte == 0xD0) {
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 = led15070_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 led15070_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] == 0xE0 && src[3] + 4 == nbytes);
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xE0;
checksum = 0;
// dprintf("%02x ", 0xe0);
for (i = 1 ; i < nbytes ; i++) {
byte = src[i];
checksum += byte;
// dprintf("%02x ", byte);
hr = led15070_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
// dprintf("%02x \n", checksum);
return led15070_frame_encode_byte(dest, checksum);
}
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte)
{
if (byte == 0xE0 || byte == 0xD0) {
if (dest->pos + 2 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = 0xD0;
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;
}

26
board/led15070-frame.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
LED_15070_FRAME_SYNC = 0xE0,
};
struct led15070_hdr {
uint8_t sync;
uint8_t dest_adr;
uint8_t src_adr;
uint8_t nbytes;
};
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src);
HRESULT led15070_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);

1251
board/led15070.c Normal file

File diff suppressed because it is too large Load Diff

29
board/led15070.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
struct led15070_config {
bool enable;
unsigned int port_no;
char board_number[8];
uint8_t fw_ver;
uint16_t fw_sum;
wchar_t eeprom_path[MAX_PATH];
};
typedef HRESULT (*io_led_init_t)(void);
typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb);
typedef void (*io_led_dc_update_t)(const uint8_t *rgb);
typedef void (*io_led_gs_update_t)(const uint8_t *rgb);
HRESULT led15070_hook_init(
const struct led15070_config *cfg,
io_led_init_t _led_init,
io_led_set_fet_output_t _led_set_fet_output,
io_led_dc_update_t _led_dc_update,
io_led_gs_update_t _led_gs_update,
unsigned int first_port,
unsigned int num_boards);

View File

@ -88,7 +88,7 @@ struct led15093_req_reset {
struct led15093_req_set_timeout { struct led15093_req_set_timeout {
struct led15093_req_hdr hdr; struct led15093_req_hdr hdr;
uint8_t cmd; uint8_t cmd;
uint8_t count; uint16_t count;
}; };
struct led15093_req_set_disable_response { struct led15093_req_set_disable_response {
@ -199,7 +199,7 @@ struct led15093_resp_board_info {
char chip_num[5]; char chip_num[5];
uint8_t endcode; // Always 0xFF uint8_t endcode; // Always 0xFF
uint8_t fw_ver; uint8_t fw_ver;
uint8_t rx_buf; uint16_t rx_buf;
}; };
struct led15093_resp_protocol_ver { struct led15093_resp_protocol_ver {

View File

@ -1,6 +1,6 @@
/* /*
SEGA 837-15093-XX LED Controller Board emulator SEGA 837-15093-XX LED Controller Board emulator
Supported variants: Supported variants:
837-15093 837-15093
@ -20,6 +20,7 @@
#include <process.h> #include <process.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "board/led15093-cmd.h" #include "board/led15093-cmd.h"
@ -103,11 +104,16 @@ static uint16_t led15093_fw_sum;
static uint8_t led15093_board_adr = 1; static uint8_t led15093_board_adr = 1;
static uint8_t led15093_host_adr = 1; static uint8_t led15093_host_adr = 1;
HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, static io_led_init_t led_init;
unsigned int num_boards, uint8_t board_adr, uint8_t host_adr) static io_led_set_leds_t set_leds;
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)
{ {
assert(cfg != NULL); assert(cfg != NULL);
assert(_led_init != NULL);
assert(_set_leds != NULL);
if (!cfg->enable) { if (!cfg->enable) {
return S_FALSE; return S_FALSE;
@ -117,6 +123,8 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first
first_port = cfg->port_no; first_port = cfg->port_no;
} }
led_init = _led_init;
set_leds = _set_leds;
led15093_board_adr = board_adr; led15093_board_adr = board_adr;
led15093_host_adr = host_adr; led15093_host_adr = host_adr;
@ -207,9 +215,9 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
if (!v->started) { if (!v->started) {
dprintf("LED 15093: Starting LED backend\n"); dprintf("LED 15093: Starting LED backend\n");
// hr = fgo_dll.led_init(); hr = led_init();
hr = S_OK;
// hr = S_OK;
v->started = true; v->started = true;
v->start_hr = hr; v->start_hr = hr;
@ -230,6 +238,29 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
} }
*/ */
if (irp->op == IRP_OP_OPEN) {
dprintf("LED 15093: Starting backend DLL\n");
// int res = led_init();
hr = led_init();
/*
if (res != 0) {
dprintf("LED 15093: Backend error, LED board disconnected: "
"%d\n",
res);
return E_FAIL;
}
*/
if (FAILED(hr)) {
dprintf("LED 15093: Backend error, LED board disconnected: "
"%x\n",
(int) hr);
return hr;
}
}
hr = uart_handle_irp(boarduart, irp); hr = uart_handle_irp(boarduart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) { if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
@ -237,12 +268,12 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
} }
for (;;) { for (;;) {
#if 0 #if defined(LOG_LED15093)
dprintf("TX Buffer:\n"); dprintf("TX Buffer:\n");
dump_iobuf(&boarduart->written); dump_iobuf(&boarduart->written);
#endif #endif
req_iobuf.bytes = (byte*)&req; req_iobuf.bytes = (uint8_t*)&req;
req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.payload); req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.payload);
req_iobuf.pos = 0; req_iobuf.pos = 0;
@ -264,7 +295,7 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
return hr; return hr;
} }
#if 0 #if defined(LOG_LED15093)
dprintf("Deframe Buffer:\n"); dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf); dump_iobuf(&req_iobuf);
#endif #endif
@ -657,8 +688,20 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set
return E_INVALIDARG; return E_INVALIDARG;
} }
memcpy(v->led, req->data, req->hdr.nbytes - 1); /*
if (board == 0) {
dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0x96], req->data[0x97], req->data[0x98]);
}
else if (board == 1)
{
dprintf("board %d: red: %d, green: %d, blue: %d\n", board, req->data[0xb4], req->data[0xb5], req->data[0xb6]);
}
*/
// Return the current LED data, remove const qualifier
set_leds(board, (uint8_t *) req->data);
memcpy(v->led, req->data, req->hdr.nbytes - 1);
// fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led);
if (!v->enable_response) if (!v->enable_response)
@ -675,7 +718,7 @@ static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set
resp.status = v->status_code; resp.status = v->status_code;
if (req->cmd == LED_15093_CMD_SET_IMM_LED) { if (req->cmd == LED_15093_CMD_SET_IMM_LED) {
resp.cmd = LED_15093_CMD_SET_IMM_LED; resp.cmd = LED_15093_CMD_SET_IMM_LED;
} }
// else { // else {
// resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY; // resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY;
// } // }

View File

@ -16,6 +16,9 @@ struct led15093_config {
uint16_t fw_sum; uint16_t fw_sum;
}; };
HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port, typedef HRESULT (*io_led_init_t)(void);
unsigned int num_boards, uint8_t board_adr, uint8_t host_adr); 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

@ -2,7 +2,6 @@ board_lib = static_library(
'board', 'board',
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
], ],
@ -25,6 +24,11 @@ board_lib = static_library(
'led15093-frame.h', 'led15093-frame.h',
'led15093.c', 'led15093.c',
'led15093.h', 'led15093.h',
'led15070-cmd.h',
'led15070-frame.c',
'led15070-frame.h',
'led15070.c',
'led15070.h',
'sg-cmd.c', 'sg-cmd.c',
'sg-cmd.h', 'sg-cmd.h',
'sg-frame.c', 'sg-frame.c',
@ -42,5 +46,10 @@ board_lib = static_library(
'slider-frame.h', 'slider-frame.h',
'vfd.c', 'vfd.c',
'vfd.h', 'vfd.h',
'vfd-cmd.h',
'vfd-frame.c',
'vfd-frame.h',
'ffb.c',
'ffb.h'
], ],
) )

View File

@ -25,6 +25,13 @@ struct sg_res_header {
uint8_t payload_len; 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)( typedef HRESULT (*sg_dispatch_fn_t)(
void *ctx, void *ctx,
const void *req, const void *req,

View File

@ -27,11 +27,11 @@ static HRESULT sg_led_cmd_set_color(
const struct sg_led *led, const struct sg_led *led,
const struct sg_led_req_set_color *req); const struct sg_led_req_set_color *req);
const char *sg_led_info[] = { static const struct version_info led_version[] = {
"15084\xFF\x10\x00\x12", {"15084\xFF\x10\x00\x12", 9},
"000-00000\xFF\x11\x40", {"000-00000\xFF\x11\x40", 12},
// maybe the same? // maybe the same?
"000-00000\xFF\x11\x40" {"000-00000\xFF\x11\x40", 12}
}; };
void sg_led_init( void sg_led_init(
@ -156,10 +156,10 @@ static HRESULT sg_led_cmd_get_info(
{ {
sg_led_dprintf(led, "Get info\n"); sg_led_dprintf(led, "Get info\n");
unsigned int len = strlen(sg_led_info[led->gen - 1]); const struct version_info *fw = &led_version[led->gen - 1];
sg_res_init(&res->res, req, len); sg_res_init(&res->res, req, fw->length);
memcpy(res->payload, sg_led_info[led->gen - 1], len); memcpy(res->payload, fw->version, fw->length);
return S_OK; return S_OK;
} }

View File

@ -5,19 +5,21 @@
#pragma pack(push, 1) #pragma pack(push, 1)
enum { enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30, SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32, SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40, SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41, SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42, SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54,
SG_NFC_CMD_SEND_HEX_DATA = 0x61, SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55,
SG_NFC_CMD_RESET = 0x62, SG_NFC_CMD_TO_UPDATE_MODE = 0x60,
SG_NFC_CMD_FELICA_ENCAP = 0x71, SG_NFC_CMD_SEND_HEX_DATA = 0x61,
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
}; };
struct sg_nfc_res_get_fw_version { struct sg_nfc_res_get_fw_version {
@ -32,7 +34,7 @@ struct sg_nfc_res_get_hw_version {
struct sg_nfc_req_mifare_set_key { struct sg_nfc_req_mifare_set_key {
struct sg_req_header req; struct sg_req_header req;
uint8_t key_a[6]; uint8_t key[6];
}; };
struct sg_nfc_req_mifare_50 { struct sg_nfc_req_mifare_50 {

View File

@ -60,21 +60,26 @@ static HRESULT sg_nfc_cmd_felica_encap(
const struct sg_nfc_req_felica_encap *req, const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res); struct sg_nfc_res_felica_encap *res);
static HRESULT sg_nfc_cmd_send_hex_data(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_dummy( static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_res_header *res); struct sg_res_header *res);
static const char *hw_version[] = { static const struct version_info hw_version[] = {
"TN32MSEC003S H/W Ver3.0", {"TN32MSEC003S H/W Ver3.0", 23},
"837-15286", {"837-15286", 9},
"837-15396" {"837-15396", 9}
}; };
static const char *fw_version[] = { static const struct version_info fw_version[] = {
"TN32MSEC003S F/W Ver1.2", {"TN32MSEC003S F/W Ver1.2", 23},
"\x94", {"\x94", 1},
"\x94" {"\x94", 1}
}; };
void sg_nfc_init( void sg_nfc_init(
@ -184,13 +189,17 @@ static HRESULT sg_nfc_dispatch(
&req->felica_encap, &req->felica_encap,
&res->felica_encap); &res->felica_encap);
case SG_NFC_CMD_MIFARE_AUTHENTICATE: case SG_NFC_CMD_MIFARE_AUTHENTICATE_A:
case SG_NFC_CMD_MIFARE_AUTHENTICATE_B:
case SG_NFC_CMD_SEND_HEX_DATA:
return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_MIFARE_SELECT_TAG: case SG_NFC_CMD_MIFARE_SELECT_TAG:
case SG_NFC_CMD_MIFARE_SET_KEY_AIME: case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_SET_KEY_BANA: case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON: case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF: case SG_NFC_CMD_RADIO_OFF:
case SG_NFC_CMD_SEND_HEX_DATA: // TODO: implement? case SG_NFC_CMD_TO_UPDATE_MODE:
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default: default:
@ -217,11 +226,11 @@ static HRESULT sg_nfc_cmd_get_fw_version(
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res) struct sg_nfc_res_get_fw_version *res)
{ {
unsigned int len = strlen(fw_version[nfc->gen - 1]); const struct version_info *fw = &fw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */ /* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, len); sg_res_init(&res->res, req, fw->length);
memcpy(res->version, fw_version[nfc->gen - 1], len); memcpy(res->version, fw->version, fw->length);
return S_OK; return S_OK;
} }
@ -231,11 +240,11 @@ static HRESULT sg_nfc_cmd_get_hw_version(
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res) struct sg_nfc_res_get_hw_version *res)
{ {
unsigned int len = strlen(hw_version[nfc->gen - 1]); const struct version_info *hw = &hw_version[nfc->gen - 1];
/* Dest version is not NUL terminated, this is intentional */ /* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, len); sg_res_init(&res->res, req, hw->length);
memcpy(res->version, hw_version[nfc->gen - 1], len); memcpy(res->version, hw->version, hw->length);
return S_OK; return S_OK;
} }
@ -345,13 +354,13 @@ static HRESULT sg_nfc_poll_felica(
felica->type = 0x20; felica->type = 0x20;
felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm); felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm);
felica->IDm = _byteswap_uint64(IDm); felica->IDm = _byteswap_uint64(IDm);
felica->PMm = _byteswap_uint64(felica_get_generic_PMm()); felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm());
/* Initialize FeliCa IC emulator */ /* Initialize FeliCa IC emulator */
nfc->felica.IDm = IDm; nfc->felica.IDm = IDm;
nfc->felica.PMm = felica_get_generic_PMm(); nfc->felica.PMm = felica_get_amusement_ic_PMm();
nfc->felica.system_code = 0x0000; nfc->felica.system_code = 0x88b4;
return S_OK; return S_OK;
} }
@ -420,7 +429,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
f_res.nbytes = sizeof(res->payload); f_res.nbytes = sizeof(res->payload);
f_res.pos = 1; f_res.pos = 1;
#if 0 #if defined(LOG_NFC)
dprintf("FELICA OUTBOUND:\n"); dprintf("FELICA OUTBOUND:\n");
dump_const_iobuf(&f_req); dump_const_iobuf(&f_req);
#endif #endif
@ -434,7 +443,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
sg_res_init(&res->res, &req->req, f_res.pos); sg_res_init(&res->res, &req->req, f_res.pos);
res->payload[0] = f_res.pos; res->payload[0] = f_res.pos;
#if 0 #if defined(LOG_NFC)
dprintf("FELICA INBOUND:\n"); dprintf("FELICA INBOUND:\n");
dump_iobuf(&f_res); dump_iobuf(&f_res);
#endif #endif
@ -442,6 +451,22 @@ static HRESULT sg_nfc_cmd_felica_encap(
return S_OK; return S_OK;
} }
static HRESULT sg_nfc_cmd_send_hex_data(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_res_init(res, req, 0);
/* Firmware checksum length? */
if (req->payload_len == 0x2b) {
/* The firmware is identical flag? */
res->status = 0x20;
}
return S_OK;
}
static HRESULT sg_nfc_cmd_dummy( static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,

View File

@ -47,7 +47,7 @@ static struct sg_led sg_reader_led;
HRESULT sg_reader_hook_init( HRESULT sg_reader_hook_init(
const struct aime_config *cfg, const struct aime_config *cfg,
unsigned int port_no, unsigned int default_port_no,
unsigned int gen, unsigned int gen,
HINSTANCE self) HINSTANCE self)
{ {
@ -66,6 +66,11 @@ HRESULT sg_reader_hook_init(
return hr; return hr;
} }
unsigned int port_no = cfg->port_no;
if (port_no == 0){
port_no = default_port_no;
}
if (cfg->gen != 0) { if (cfg->gen != 0) {
gen = cfg->gen; gen = cfg->gen;
} }
@ -85,6 +90,7 @@ HRESULT sg_reader_hook_init(
sg_reader_uart.baud.BaudRate = 38400; sg_reader_uart.baud.BaudRate = 38400;
} }
dprintf("NFC Assembly: enabling (port=%d)\n", port_no);
uart_init(&sg_reader_uart, port_no); uart_init(&sg_reader_uart, port_no);
sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.bytes = sg_reader_written_bytes;
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);
@ -115,14 +121,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
{ {
HRESULT hr; HRESULT hr;
#if 0 #if defined(LOG_NFC)
if (irp->op == IRP_OP_WRITE) { if (irp->op == IRP_OP_WRITE) {
dprintf("WRITE:\n"); dprintf("WRITE:\n");
dump_const_iobuf(&irp->write); dump_const_iobuf(&irp->write);
} }
#endif #endif
#if 0 #if defined(LOG_NFC)
if (irp->op == IRP_OP_READ) { if (irp->op == IRP_OP_READ) {
dprintf("READ:\n"); dprintf("READ:\n");
dump_iobuf(&sg_reader_uart.readable); dump_iobuf(&sg_reader_uart.readable);

View File

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

123
board/vfd-cmd.h Normal file
View File

@ -0,0 +1,123 @@
#pragma once
#include "board/vfd-frame.h"
enum {
VFD_CMD_GET_VERSION = 0x5B,
VFD_CMD_RESET = 0x0B,
VFD_CMD_CLEAR_SCREEN = 0x0C,
VFD_CMD_SET_BRIGHTNESS = 0x20,
VFD_CMD_SET_SCREEN_ON = 0x21,
VFD_CMD_SET_H_SCROLL = 0x22,
VFD_CMD_DRAW_IMAGE = 0x2E,
VFD_CMD_SET_CURSOR = 0x30,
VFD_CMD_SET_ENCODING = 0x32,
VFD_CMD_SET_TEXT_WND = 0x40,
VFD_CMD_SET_TEXT_SPEED = 0x41,
VFD_CMD_WRITE_TEXT = 0x50,
VFD_CMD_ENABLE_SCROLL = 0x51,
VFD_CMD_DISABLE_SCROLL = 0x52,
VFD_CMD_ROTATE = 0x5D,
VFD_CMD_CREATE_CHAR = 0xA3,
VFD_CMD_CREATE_CHAR2 = 0xA4,
};
enum {
VFD_ENC_GB2312 = 0,
VFD_ENC_BIG5 = 1,
VFD_ENC_SHIFT_JIS = 2,
VFD_ENC_KSC5601 = 3,
VFD_ENC_MAX = 3,
};
struct vfd_req_hdr {
uint8_t sync;
uint8_t cmd;
};
struct vfd_req_any {
struct vfd_req_hdr hdr;
uint8_t payload[2054];
};
struct vfd_req_board_info {
struct vfd_req_hdr hdr;
uint8_t unk1;
};
struct vfd_resp_board_info { // \x0201.20\x03
uint8_t unk1;
char version[5];
uint8_t unk2;
};
struct vfd_req_reset {
struct vfd_req_hdr hdr;
};
struct vfd_req_cls {
struct vfd_req_hdr hdr;
};
struct vfd_req_brightness {
struct vfd_req_hdr hdr;
uint8_t brightness;
};
struct vfd_req_power {
struct vfd_req_hdr hdr;
uint8_t power_state;
};
struct vfd_req_hscroll {
struct vfd_req_hdr hdr;
uint8_t x_pos;
};
struct vfd_req_draw {
struct vfd_req_hdr hdr;
uint16_t x0;
uint8_t y0;
uint16_t x1;
uint8_t y1;
uint8_t image[2048];
};
struct vfd_req_cursor {
struct vfd_req_hdr hdr;
uint16_t x;
uint8_t y;
};
struct vfd_req_encoding {
struct vfd_req_hdr hdr;
uint8_t encoding;
};
struct vfd_req_wnd {
struct vfd_req_hdr hdr;
uint16_t x0;
uint8_t y0;
uint16_t x1;
uint8_t y1;
};
struct vfd_req_speed {
struct vfd_req_hdr hdr;
uint8_t encoding;
};
struct vfd_req_scroll {
struct vfd_req_hdr hdr;
};
struct vfd_req_rotate {
struct vfd_req_hdr hdr;
uint8_t unk1;
};
struct vfd_req_create_char {
struct vfd_req_hdr hdr;
uint8_t type;
uint8_t pixels[32];
};

88
board/vfd-frame.c Normal file
View File

@ -0,0 +1,88 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define SUPER_VERBOSE 1
#include "board/vfd-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte);
/* Frame structure:
REQUEST:
[0] Sync byte (0x1A or 0x1B)
[1] Packet ID
[2...n-1] Data/payload
--- OR ---
if no sync byte is given, plain static text in the currently configured encoding is expected.
RESPONSE:
This thing never responds, unless it's VFD_CMD_GET_VERSION
*/
bool vfd_frame_sync(struct const_iobuf *src) {
return src->bytes[src->pos] == VFD_SYNC_BYTE || src->bytes[src->pos] == VFD_SYNC_BYTE2;
}
HRESULT vfd_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes) {
const uint8_t *src;
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;
if (dest->pos >= dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#if SUPER_VERBOSE
dprintf("VFD: RX Buffer:\n");
#endif
for (i = 1; i < nbytes; i++) {
byte = src[i];
#if SUPER_VERBOSE
dprintf("%02x ", byte);
#endif
hr = vfd_frame_encode_byte(dest, byte);
if (FAILED(hr)) {
return hr;
}
}
#if SUPER_VERBOSE
dprintf("\n");
#endif
return hr;
}
static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte) {
if (dest->pos + 1 > dest->nbytes) {
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
dest->bytes[dest->pos++] = byte;
return S_OK;
}

20
board/vfd-frame.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "hook/iobuf.h"
enum {
VFD_SYNC_BYTE = 0x1B,
VFD_SYNC_BYTE2 = 0x1A,
};
bool vfd_frame_sync(struct const_iobuf *src);
HRESULT vfd_frame_encode(
struct iobuf *dest,
const void *ptr,
size_t nbytes);

View File

@ -2,17 +2,17 @@
directly by amdaemon, and it has something to do with displaying the status directly by amdaemon, and it has something to do with displaying the status
of electronic payments. of electronic payments.
Part number in schematics is "VFD GP1232A02A FUTABA". Part number in schematics is "VFD GP1232A02A FUTABA". */
Little else about this board is known. Black-holing the RS232 comms that it
receives seems to be sufficient for the time being. */
#include <windows.h> #include <windows.h>
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "board/config.h"
#include "board/vfd.h" #include "board/vfd.h"
#include "board/vfd-cmd.h"
#include "hook/iohook.h" #include "hook/iohook.h"
@ -21,14 +21,50 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.h" #include "util/dump.h"
#define SUPER_VERBOSE 0
static HRESULT vfd_handle_irp(struct irp *irp); static HRESULT vfd_handle_irp(struct irp *irp);
static struct uart vfd_uart; static struct uart vfd_uart;
static uint8_t vfd_written[512]; static uint8_t vfd_written[4096];
static uint8_t vfd_readable[512]; static uint8_t vfd_readable[4096];
HRESULT vfd_hook_init(unsigned int port_no) static int encoding = VFD_ENC_SHIFT_JIS;
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
static bool utf_enabled;
HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no)
{ {
if (!cfg->enable){
return S_FALSE;
}
utf_enabled = cfg->utf_conversion;
unsigned int port_no = cfg->port_no;
if (port_no == 0){
port_no = default_port_no;
}
dprintf("VFD: enabling (port=%d)\n", port_no);
uart_init(&vfd_uart, port_no); uart_init(&vfd_uart, port_no);
vfd_uart.written.bytes = vfd_written; vfd_uart.written.bytes = vfd_written;
vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.written.nbytes = sizeof(vfd_written);
@ -38,6 +74,48 @@ HRESULT vfd_hook_init(unsigned int port_no)
return iohook_push_handler(vfd_handle_irp); return iohook_push_handler(vfd_handle_irp);
} }
const char* get_encoding_name(int b){
switch (b){
case 0: return "gb2312";
case 1: return "big5";
case 2: return "shift-jis";
case 3: return "ks_c_5601-1987";
default: return "unknown";
}
}
void print_vfd_text(const char* str, int len){
if (utf_enabled){
wchar_t encoded[1024];
memset(encoded, 0, 1024 * sizeof(wchar_t));
int codepage = 0;
if (encoding == VFD_ENC_GB2312){
codepage = 936;
} else if (encoding == VFD_ENC_BIG5){
codepage = 950;
} else if (encoding == VFD_ENC_SHIFT_JIS){
codepage = 932;
} else if (encoding == VFD_ENC_KSC5601) {
codepage = 949;
}
if (!MultiByteToWideChar(codepage, MB_USEGLYPHCHARS, str, len, encoded, 1024)){
dprintf("VFD: Text conversion failed: %ld", GetLastError());
return;
}
dprintf("VFD: Text: %ls\n", encoded);
} else {
dprintf("VFD: Text: %s\n", str);
}
}
static HRESULT vfd_handle_irp(struct irp *irp) static HRESULT vfd_handle_irp(struct irp *irp)
{ {
HRESULT hr; HRESULT hr;
@ -48,15 +126,274 @@ static HRESULT vfd_handle_irp(struct irp *irp)
return iohook_invoke_next(irp); return iohook_invoke_next(irp);
} }
if (irp->op == IRP_OP_OPEN){
dprintf("VFD: Open\n");
} else if (irp->op == IRP_OP_CLOSE){
dprintf("VFD: Close\n");
}
hr = uart_handle_irp(&vfd_uart, irp); hr = uart_handle_irp(&vfd_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) { if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr; return hr;
} }
#if SUPER_VERBOSE
dprintf("VFD TX:\n"); dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written); dump_iobuf(&vfd_uart.written);
#endif
struct const_iobuf reader;
iobuf_flip(&reader, &vfd_uart.written);
struct iobuf* writer = &vfd_uart.readable;
for (; reader.pos < reader.nbytes ; ){
if (vfd_frame_sync(&reader)) {
reader.pos++; // get the sync byte out of the way
uint8_t cmd;
iobuf_read_8(&reader, &cmd);
if (cmd == VFD_CMD_GET_VERSION) {
hr = vfd_handle_get_version(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_RESET) {
hr = vfd_handle_reset(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CLEAR_SCREEN) {
hr = vfd_handle_clear_screen(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_BRIGHTNESS) {
hr = vfd_handle_set_brightness(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_SCREEN_ON) {
hr = vfd_handle_set_screen_on(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_H_SCROLL) {
hr = vfd_handle_set_h_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_DRAW_IMAGE) {
hr = vfd_handle_draw_image(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_CURSOR) {
hr = vfd_handle_set_cursor(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_ENCODING) {
hr = vfd_handle_set_encoding(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_TEXT_WND) {
hr = vfd_handle_set_text_wnd(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_SET_TEXT_SPEED) {
hr = vfd_handle_set_text_speed(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_WRITE_TEXT) {
hr = vfd_handle_write_text(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_ENABLE_SCROLL) {
hr = vfd_handle_enable_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_DISABLE_SCROLL) {
hr = vfd_handle_disable_scroll(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_ROTATE) {
hr = vfd_handle_rotate(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CREATE_CHAR) {
hr = vfd_handle_create_char(&reader, writer, &vfd_uart);
} else if (cmd == VFD_CMD_CREATE_CHAR2) {
hr = vfd_handle_create_char2(&reader, writer, &vfd_uart);
} else {
dprintf("VFD: Unknown command 0x%x\n", cmd);
dump_const_iobuf(&reader);
hr = S_FALSE;
}
} else {
// if no sync byte is sent, we are just getting plain text...
if (reader.pos < reader.nbytes){
int len = 0;
// read chars until we hit a new sync byte or the data ends
while (reader.pos + len + 1 < reader.nbytes && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE2){
len++;
}
char* str = malloc(len);
memset(str, 0, len);
iobuf_read(&reader, str, len);
print_vfd_text(str, len);
free(str);
reader.pos += len;
}
}
if (!SUCCEEDED(hr)){
return hr;
}
}
vfd_uart.written.pos = 0; vfd_uart.written.pos = 0;
return hr; return hr;
} }
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Get Version\n");
struct vfd_resp_board_info resp;
memset(&resp, 0, sizeof(resp));
resp.unk1 = 2;
strcpy(resp.version, "01.20");
resp.unk2 = 1;
return vfd_frame_encode(writer, &resp, sizeof(resp));
}
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Reset\n");
encoding = VFD_ENC_SHIFT_JIS;
return S_FALSE;
}
HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Clear Screen\n");
return S_FALSE;
}
HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
if (b > 4){
dprintf("VFD: Brightness, invalid argument\n");
return E_FAIL;
}
dprintf("VFD: Brightness, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
if (b > 1){
dprintf("VFD: Screen Power, invalid argument\n");
return E_FAIL;
}
dprintf("VFD: Screen Power, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t x;
iobuf_read_8(reader, &x);
dprintf("VFD: Horizontal Scroll, X=%d\n", x);
return S_FALSE;
}
HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
int w, h;
uint16_t x0, x1;
uint8_t y0, y1;
uint8_t image[2048];
iobuf_read_be16(reader, &x0);
iobuf_read_8(reader, &y0);
iobuf_read_be16(reader, &x1);
iobuf_read_8(reader, &y1);
w = x1 - x0;
h = y1 - y0;
iobuf_read(reader, image, w*h);
dprintf("VFD: Draw image, %dx%d\n", w, h);
return S_FALSE;
}
HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint16_t x;
uint8_t y;
iobuf_read_be16(reader, &x);
iobuf_read_8(reader, &y);
dprintf("VFD: Set Cursor, x=%d,y=%d\n", x, y);
return S_FALSE;
}
HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Set Encoding, %d (%s)\n", b, get_encoding_name(b));
if (b < 0 || b > VFD_ENC_MAX){
dprintf("Invalid encoding specified\n");
return E_FAIL;
}
encoding = b;
return S_FALSE;
}
HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint16_t x0, x1;
uint8_t y0, y1;
iobuf_read_be16(reader, &x0);
iobuf_read_8(reader, &y0);
iobuf_read_be16(reader, &x1);
iobuf_read_8(reader, &y1);
dprintf("VFD: Set Text Window, p0:%d,%d, p1:%d,%d\n", x0, y0, x1, y1);
return S_FALSE;
}
HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Set Text Speed, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t len;
iobuf_read_8(reader, &len);
char* str = malloc(len);
iobuf_read(reader, str, len);
print_vfd_text(str, len);
free(str);
return S_FALSE;
}
HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Enable Scrolling\n");
return S_FALSE;
}
HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
dprintf("VFD: Disable Scrolling\n");
return S_FALSE;
}
HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
dprintf("VFD: Rotate, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b;
iobuf_read_8(reader, &b);
char buf[32];
iobuf_read(reader, buf, 32);
dprintf("VFD: Create character, %d\n", b);
return S_FALSE;
}
HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
uint8_t b, b2;
iobuf_read_8(reader, &b);
iobuf_read_8(reader, &b2);
char buf[16];
iobuf_read(reader, buf, 16);
dprintf("VFD: Create character, %d, %d\n", b, b2);
return S_FALSE;
}

View File

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

View File

@ -78,7 +78,7 @@ static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobu
uint8_t checksum_pos = src->pos - 1; uint8_t checksum_pos = src->pos - 1;
uint8_t calculated_checksum = 0; uint8_t calculated_checksum = 0;
uint8_t checksum = 0; uint8_t checksum = 0;
if (src->pos < 6) { if (src->pos < 6) {
dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos); dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos);
return SEC_E_BUFFER_TOO_SMALL; return SEC_E_BUFFER_TOO_SMALL;
@ -137,7 +137,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
for (;;) { for (;;) {
if (controlbd_uart.written.bytes[0] == 0xE0) { if (controlbd_uart.written.bytes[0] == 0xE0) {
#if 0 #if defined(LOG_CAROL_CONTROL_BD)
dprintf("Control Board: TX Buffer:\n"); dprintf("Control Board: TX Buffer:\n");
dump_iobuf(&controlbd_uart.written); dump_iobuf(&controlbd_uart.written);
#endif #endif
@ -147,12 +147,12 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
return hr; return hr;
} }
hr = controlbd_req_dispatch(&req); hr = controlbd_req_dispatch(&req);
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
return hr; return hr;
} }
#if 0 #if defined(LOG_CAROL_CONTROL_BD)
dprintf("Control Board: RX Buffer:\n"); dprintf("Control Board: RX Buffer:\n");
dump_iobuf(&controlbd_uart.readable); dump_iobuf(&controlbd_uart.readable);
#endif #endif
@ -206,7 +206,7 @@ static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
case CONTROLBD_CMD_FIRM_SUM: case CONTROLBD_CMD_FIRM_SUM:
return controlbd_req_firmware_checksum(); return controlbd_req_firmware_checksum();
case CONTROLBD_CMD_TIMEOUT: case CONTROLBD_CMD_TIMEOUT:
dprintf("Control Board: Acknowledge Timeout\n"); dprintf("Control Board: Acknowledge Timeout\n");
return controlbd_req_ack_any(req->hdr.cmd); return controlbd_req_ack_any(req->hdr.cmd);
@ -278,7 +278,7 @@ static HRESULT controlbd_req_get_board_info(void)
resp.rev = 0x90; resp.rev = 0x90;
resp.bfr_size = 0x0001; resp.bfr_size = 0x0001;
resp.ack = 1; resp.ack = 1;
strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 "); strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 ");
strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 "); strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 ");
resp.chip_no[5] = 0xFF; resp.chip_no[5] = 0xFF;
@ -317,7 +317,7 @@ static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
resp.unk7 = 3; resp.unk7 = 3;
resp.unk8 = 1; resp.unk8 = 1;
resp.unk9 = 1; resp.unk9 = 1;
resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge
resp.coord_x = 0x0; resp.coord_x = 0x0;
resp.coord_y = 0x0; resp.coord_y = 0x0;

View File

@ -1,3 +1,31 @@
/*
"Wonderland Wars" (carol*) hook
Devices:
JVS: 837-14572 "Type 3" I/O Board
[Satellite]
USB: "WinTouch" Controller Board
^ (DIPSW2 ON, Version 5.xx.xx or above)
COM1: 3M Touch Systems 78-0011-2353-4 Touch Controller Board
^ (DIPSW2 OFF)
COM10: TN32MSEC003S "Gen 1" Aime Reader
OR
837-15286 "Gen 2" Aime Reader
^ (Version 1.6x.xx or above)
COM11: 837-15070-02 LED Controller Board
COM12: 837-15312 Pen Controller I/O Board
[Terminal]
COM10: 837-15286 "Gen 2" Aime Reader
*: SEGA's abbreviation for Lewis Carroll, author of Alice's Adventures in
Wonderland.
*/
#include <windows.h> #include <windows.h>
#include <stdlib.h> #include <stdlib.h>
@ -25,6 +53,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static HMODULE carol_hook_mod; static HMODULE carol_hook_mod;
static process_entry_t carol_startup; static process_entry_t carol_startup;
@ -72,7 +101,7 @@ static DWORD CALLBACK carol_pre_startup(void)
/* Config load */ /* Config load */
carol_hook_config_load(&carol_hook_cfg, L".\\segatools.ini"); carol_hook_config_load(&carol_hook_cfg, get_config_path());
/* Hook Win32 APIs */ /* Hook Win32 APIs */
@ -136,7 +165,7 @@ static DWORD CALLBACK carol_pre_startup(void)
} }
/* Initialize debug helpers */ /* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini"); spike_hook_init(get_config_path());
dprintf("--- End carol_pre_startup ---\n"); dprintf("--- End carol_pre_startup ---\n");

View File

@ -94,7 +94,7 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 0 #if defined(LOG_CAROL_LED_BD)
dprintf("LED Board: TX Buffer:\n"); dprintf("LED Board: TX Buffer:\n");
dump_iobuf(&ledbd_uart.written); dump_iobuf(&ledbd_uart.written);
#endif #endif
@ -165,4 +165,4 @@ static HRESULT ledbd_req_unkF0(uint8_t cmd)
iobuf_write(&ledbd_uart.readable, resp, 16); iobuf_write(&ledbd_uart.readable, resp, 16);
return S_OK; return S_OK;
} }

View File

@ -4,7 +4,6 @@ shared_library(
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
vs_module_defs : 'carolhook.def', vs_module_defs : 'carolhook.def',
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'), capnhook.get_variable('hooklib_dep'),

View File

@ -54,7 +54,7 @@ HRESULT touch_hook_init(const struct touch_config *cfg)
if (!cfg->enable) { if (!cfg->enable) {
return S_OK; return S_OK;
} }
InitializeCriticalSection(&touch_lock); InitializeCriticalSection(&touch_lock);
uart_init(&touch_uart, 1); uart_init(&touch_uart, 1);
@ -112,7 +112,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 0 #if defined(LOG_CAROL_TOUCH)
dprintf("Touchscreen: TX Buffer:\n"); dprintf("Touchscreen: TX Buffer:\n");
dump_iobuf(&touch_uart.written); dump_iobuf(&touch_uart.written);
#endif #endif
@ -188,7 +188,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
resp.touches[0].touch_id = 1; resp.touches[0].touch_id = 1;
tmp_x = mouse_x & 0x7FFF; tmp_x = mouse_x & 0x7FFF;
tmp_y = mouse_y & 0x7FFF; tmp_y = mouse_y & 0x7FFF;
resp.touches[0].x1 = tmp_x & 0x7F; resp.touches[0].x1 = tmp_x & 0x7F;
resp.touches[0].x2 = (tmp_x >> 7) & 0x7F; resp.touches[0].x2 = (tmp_x >> 7) & 0x7F;
resp.touches[0].y1 = tmp_y & 0x7F; resp.touches[0].y1 = tmp_y & 0x7F;
@ -201,7 +201,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2); dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2);
#endif #endif
last_x1 = resp.touches[0].x1; last_x1 = resp.touches[0].x1;
last_x2 = resp.touches[0].x2; last_x2 = resp.touches[0].x2;
last_y1 = resp.touches[0].y1; last_y1 = resp.touches[0].y1;
@ -220,7 +220,7 @@ static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const
iobuf_write(&touch_uart.readable, &resp, sizeof(resp)); iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
LeaveCriticalSection(&touch_lock); LeaveCriticalSection(&touch_lock);
#if 0 #if defined(LOG_CAROL_TOUCH)
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos); dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
dump_iobuf(&touch_uart.readable); dump_iobuf(&touch_uart.readable);
#endif #endif

View File

@ -8,6 +8,7 @@
#include "carolio/carolio.h" #include "carolio/carolio.h"
#include "carolio/config.h" #include "carolio/config.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx); static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx);
@ -25,7 +26,7 @@ uint16_t carol_io_get_api_version(void)
HRESULT carol_io_jvs_init(void) HRESULT carol_io_jvs_init(void)
{ {
carol_io_config_load(&carol_io_cfg, L".\\segatools.ini"); carol_io_config_load(&carol_io_cfg, get_config_path());
return S_OK; return S_OK;
} }
@ -178,4 +179,4 @@ static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx)
} }
return 0; return 0;
} }

View File

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

View File

@ -3,7 +3,6 @@ carolio_lib = static_library(
name_prefix : '', name_prefix : '',
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [ sources : [
'carolio.c', 'carolio.c',
'carolio.h', 'carolio.h',

View File

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

View File

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

View File

@ -3,6 +3,7 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "amex/amex.h" #include "amex/amex.h"
#include "amex/config.h" #include "amex/config.h"
@ -56,7 +57,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0; cfg->port_no = 0;
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename);

View File

@ -1,9 +1,22 @@
/*
"CHUNITHM" (chuni) hook
Devices
JVS: 837-14572 "Type 3" I/O Board
COM1: 837-15330 Ground Slider
COM10: 837-15093-06 LED Controller Board
COM11: 837-15093-06 LED Controller Board
COM12: TN32MSEC003S "Gen 1" Aime Reader
*/
#include <windows.h> #include <windows.h>
#include <stdlib.h> #include <stdlib.h>
#include "amex/amex.h" #include "amex/amex.h"
#include "board/led15093.h"
#include "board/sg-reader.h" #include "board/sg-reader.h"
#include "chunihook/config.h" #include "chunihook/config.h"
@ -23,6 +36,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static HMODULE chuni_hook_mod; static HMODULE chuni_hook_mod;
static process_entry_t chuni_startup; static process_entry_t chuni_startup;
@ -58,7 +72,7 @@ static DWORD CALLBACK chuni_pre_startup(void)
/* Config load */ /* Config load */
chuni_hook_config_load(&chuni_hook_cfg, L".\\segatools.ini"); chuni_hook_config_load(&chuni_hook_cfg, get_config_path());
/* Hook Win32 APIs */ /* Hook Win32 APIs */
@ -96,10 +110,16 @@ static DWORD CALLBACK chuni_pre_startup(void)
goto fail; goto fail;
} }
hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 2, 2, 1); 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)) { if (FAILED(hr)) {
goto fail; goto fail;
}
} }
hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod); hr = sg_reader_hook_init(&chuni_hook_cfg.aime, 12, 1, chuni_hook_mod);
@ -110,7 +130,7 @@ static DWORD CALLBACK chuni_pre_startup(void)
/* Initialize debug helpers */ /* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini"); spike_hook_init(get_config_path());
dprintf("--- End chuni_pre_startup ---\n"); dprintf("--- End chuni_pre_startup ---\n");

View File

@ -4,7 +4,6 @@ shared_library(
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
vs_module_defs : 'chunihook.def', vs_module_defs : 'chunihook.def',
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'), capnhook.get_variable('hooklib_dep'),

View File

@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 0 #if defined(LOG_CHUNI_SLIDER)
dprintf("TX Buffer:\n"); dprintf("TX Buffer:\n");
dump_iobuf(&slider_uart.written); dump_iobuf(&slider_uart.written);
#endif #endif
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
return hr; return hr;
} }
#if 0 #if defined(LOG_CHUNI_SLIDER)
dprintf("Deframe Buffer:\n"); dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf); dump_iobuf(&req_iobuf);
#endif #endif

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

@ -4,11 +4,14 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "chuniio/chuniio.h" #include "chuniio/chuniio.h"
#include "chuniio/config.h" #include "chuniio/config.h"
#include "chuniio/ledoutput.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx); static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx);
@ -18,17 +21,26 @@ static uint8_t chuni_io_hand_pos;
static HANDLE chuni_io_slider_thread; static HANDLE chuni_io_slider_thread;
static bool chuni_io_slider_stop_flag; static bool chuni_io_slider_stop_flag;
static struct chuni_io_config chuni_io_cfg; static struct chuni_io_config chuni_io_cfg;
static HANDLE chuni_io_slider_led_port;
uint16_t chuni_io_get_api_version(void) uint16_t chuni_io_get_api_version(void)
{ {
return 0x0101; return 0x0102;
} }
HRESULT chuni_io_jvs_init(void) HRESULT chuni_io_jvs_init(void)
{ {
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini"); chuni_io_config_load(&chuni_io_cfg, get_config_path());
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; return S_OK;
} }
@ -81,19 +93,19 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
} }
} else { } else {
// Use actual AIR // Use actual AIR
// IR format is beams[5:0] = {b5,b6,b3,b4,b1,b2}; for (i = 0; i < 6; i++) {
for (i = 0 ; i < 3 ; i++) { if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i]) & 0x8000) {
if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2]) & 0x8000) *beams |= (1 << i);
*beams |= (1 << (i*2+1)); } else {
if (GetAsyncKeyState(chuni_io_cfg.vk_ir[i*2+1]) & 0x8000) *beams &= ~(1 << i);
*beams |= (1 << (i*2)); }
} }
} }
} }
HRESULT chuni_io_slider_init(void) 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) void chuni_io_slider_start(chuni_io_slider_callback_t callback)
@ -111,39 +123,6 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback)
callback, callback,
0, 0,
NULL); NULL);
chuni_io_slider_led_port = CreateFileW(chuni_io_cfg.led_com,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (chuni_io_slider_led_port == INVALID_HANDLE_VALUE)
dprintf("Chunithm LEDs: Failed to open COM port (Attempted on %S)\n", chuni_io_cfg.led_com);
else
dprintf("Chunithm LEDs: COM Port Success!\n");
DCB dcb_serial_params = { 0 };
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
status = GetCommState(chuni_io_slider_led_port, &dcb_serial_params);
dcb_serial_params.BaudRate = CBR_115200; // Setting BaudRate = 115200
dcb_serial_params.ByteSize = 8; // Setting ByteSize = 8
dcb_serial_params.StopBits = ONESTOPBIT;// Setting StopBits = 1
dcb_serial_params.Parity = NOPARITY; // Setting Parity = None
SetCommState(chuni_io_slider_led_port, &dcb_serial_params);
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50; // in milliseconds
timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds
timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds
timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds
timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds
SetCommTimeouts(chuni_io_slider_led_port, &timeouts);
} }
void chuni_io_slider_stop(void) void chuni_io_slider_stop(void)
@ -158,34 +137,11 @@ void chuni_io_slider_stop(void)
CloseHandle(chuni_io_slider_thread); CloseHandle(chuni_io_slider_thread);
chuni_io_slider_thread = NULL; chuni_io_slider_thread = NULL;
chuni_io_slider_stop_flag = false; chuni_io_slider_stop_flag = false;
dprintf("Chunithm LEDs: Closing COM port\n");
CloseHandle(chuni_io_slider_led_port);
} }
void chuni_io_slider_set_leds(const uint8_t *rgb) void chuni_io_slider_set_leds(const uint8_t *rgb)
{ {
if (chuni_io_slider_led_port != INVALID_HANDLE_VALUE) led_output_update(2, rgb);
{
char led_buffer[100];
DWORD bytes_to_write; // No of bytes to write into the port
DWORD bytes_written = 0; // No of bytes written to the port
bytes_to_write = sizeof(led_buffer);
BOOL status;
led_buffer[0] = 0xAA;
led_buffer[1] = 0xAA;
memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96);
led_buffer[98] = 0xDD;
led_buffer[99] = 0xDD;
status = WriteFile(chuni_io_slider_led_port, // Handle to the Serial port
led_buffer, // Data to be written to the port
bytes_to_write, //No of bytes to write
&bytes_written, //Bytes written
NULL);
}
} }
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
@ -211,3 +167,13 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
return 0; 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 - 0x0100: Initial API version (assumed if chuni_io_get_api_version is not
exported) exported)
- 0x0101: Fix IR beam mappings - 0x0101: Fix IR beam mappings
- 0x0102: Add air tower led and billboard support
*/ */
#include <windows.h> #include <windows.h>
@ -138,10 +139,46 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback);
void chuni_io_slider_stop(void); void chuni_io_slider_stop(void);
/* Update the RGB lighting on the slider. A pointer to an array of 32 * 3 = 96 /* Update the RGB lighting on the slider. A pointer to an array of 32 * 3 = 96
bytes is supplied. The illuminated areas on the touch slider are some bytes is supplied, organized in BRG format.
combination of rectangular regions and dividing lines between these regions The first set of bytes is the right-most slider key, and from there the bytes
but the exact mapping of this lighting control buffer is still TBD. alternate between the dividers and the keys until the left-most key.
There are 31 illuminated sections in total.
Minimum API version: 0x0100 */ Minimum API version: 0x0100 */
void chuni_io_slider_set_leds(const uint8_t *rgb); 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
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
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 <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "chuniio/config.h" #include "chuniio/config.h"
@ -34,9 +35,9 @@ void chuni_io_config_load(
assert(filename != NULL); assert(filename != NULL);
// Technically it's io4 but leave this for compatibility with old configs. // Technically it's io4 but leave this for compatibility with old configs.
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", VK_F1, filename);
cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", VK_F2, filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", VK_F3, filename);
cfg->vk_ir_emu = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename); cfg->vk_ir_emu = GetPrivateProfileIntW(L"io3", L"ir", VK_SPACE, filename);
for (i = 0 ; i < 6 ; i++) { for (i = 0 ; i < 6 ; i++) {
@ -57,7 +58,26 @@ void chuni_io_config_load(
filename); filename);
} }
GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename); cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
wcsncpy(cfg->led_com, L"\\\\.\\", 4); cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
wcsncat_s(cfg->led_com, 11, port_input, 6);
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
cfg->controller_led_output_openithm = GetPrivateProfileIntW(L"led", L"controllerLedOutputOpeNITHM", 0, filename);
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
GetPrivateProfileStringW(
L"led",
L"serialPort",
L"COM5",
port_input,
_countof(port_input),
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

@ -2,6 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
struct chuni_io_config { struct chuni_io_config {
uint8_t vk_test; uint8_t vk_test;
@ -10,7 +11,19 @@ struct chuni_io_config {
uint8_t vk_ir_emu; uint8_t vk_ir_emu;
uint8_t vk_ir[6]; uint8_t vk_ir[6];
uint8_t vk_cell[32]; uint8_t vk_cell[32];
wchar_t led_com[12];
// Which ways to output LED information are enabled
bool cab_led_output_pipe;
bool cab_led_output_serial;
bool controller_led_output_pipe;
bool controller_led_output_serial;
bool controller_led_output_openithm;
// 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( 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 {
uint8_t framing; // Sync byte
uint8_t board; // LED output the data is for (0-1: billboard, 2: slider)
uint8_t data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
uint8_t data_len; // How many bytes to output from the buffer
};
static uint8_t chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3};

137
chuniio/ledoutput.c Normal file
View File

@ -0,0 +1,137 @@
#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->cab_led_output_pipe || config->controller_led_output_pipe
|| config->cab_led_output_serial || config->controller_led_output_serial;
if (config->cab_led_output_pipe || config->controller_led_output_pipe)
{
led_pipe_init(); // don't really care about errors here tbh
}
if (config->cab_led_output_serial || config->controller_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];
uint8_t* in_buf = unescaped->data;
uint8_t* out_buf = out_struct->data;
int i = 0;
int o = 0;
while (i < unescaped->data_len)
{
uint8_t 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 uint8_t* 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 (cab)
if (config->cab_led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->cab_led_output_serial)
{
led_serial_update(escaped_data);
}
}
else
{
// slider
if (config->controller_led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->controller_led_output_serial)
{
if (config->controller_led_output_openithm){
led_serial_update_openithm(rgb);
} else {
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 uint8_t* rgb);

View File

@ -3,11 +3,20 @@ chuniio_lib = static_library(
name_prefix : '', name_prefix : '',
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [ sources : [
'chu2to3.c',
'chu2to3.h',
'chuniio.c', 'chuniio.c',
'chuniio.h', 'chuniio.h',
'config.c', 'config.c',
'config.h', '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);
}

15
chuniio/pipeimpl.h Normal file
View File

@ -0,0 +1,15 @@
/*
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);

123
chuniio/serialimpl.c Normal file
View File

@ -0,0 +1,123 @@
#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);
}
void led_serial_update_openithm(const uint8_t* rgb)
{
if (serial_port != INVALID_HANDLE_VALUE)
{
char led_buffer[100];
DWORD bytes_to_write; // No of bytes to write into the port
DWORD bytes_written = 0; // No of bytes written to the port
bytes_to_write = sizeof(led_buffer);
BOOL status;
led_buffer[0] = 0xAA;
led_buffer[1] = 0xAA;
memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96);
led_buffer[98] = 0xDD;
led_buffer[99] = 0xDD;
status = WriteFile(serial_port, // Handle to the Serial port
led_buffer, // Data to be written to the port
bytes_to_write, // No of bytes to write
&bytes_written, // Bytes written
NULL);
}
}

17
chuniio/serialimpl.h Normal file
View File

@ -0,0 +1,17 @@
/*
Serial LED implementation for chuniio
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include <stdint.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);
void led_serial_update_openithm(const uint8_t* rgb);

View File

@ -2,7 +2,9 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdlib.h>
#include "chuniio/chu2to3.h"
#include "chusanhook/chuni-dll.h" #include "chusanhook/chuni-dll.h"
#include "util/dll-bind.h" #include "util/dll-bind.h"
@ -30,9 +32,59 @@ const struct dll_bind_sym chuni_dll_syms[] = {
}, { }, {
.sym = "chuni_io_slider_set_leds", .sym = "chuni_io_slider_set_leds",
.off = offsetof(struct chuni_dll, 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; struct chuni_dll chuni_dll;
// Copypasta DLL binding and diagnostic message boilerplate. // Copypasta DLL binding and diagnostic message boilerplate.
@ -52,7 +104,12 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
assert(cfg != NULL); assert(cfg != NULL);
assert(self != NULL); assert(self != NULL);
if (cfg->path[0] != L'\0') { owned = NULL;
src = self;
if (cfg->chu2to3) {
dprintf("Chunithm IO: using chu2to3 engine for IO DLL: %S\n", cfg->path);
} else if (cfg->path[0] != L'\0') {
owned = LoadLibraryW(cfg->path); owned = LoadLibraryW(cfg->path);
if (owned == NULL) { if (owned == NULL) {
@ -66,12 +123,18 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path); dprintf("Chunithm IO: Using custom IO DLL: %S\n", cfg->path);
src = owned; src = owned;
} else {
owned = NULL;
src = self;
} }
get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version"); if (cfg->chu2to3) {
if (chu2to3_load_dll(cfg->path) != 0)
dprintf("Could not init chu2to3 engine\n");
get_api_version = (void *) GetProcAddress(src, "chu2to3_io_get_api_version");
}
else
{
get_api_version = (void *) GetProcAddress(src, "chuni_io_get_api_version");
}
if (get_api_version != NULL) { if (get_api_version != NULL) {
chuni_dll.api_version = get_api_version(); chuni_dll.api_version = get_api_version();
@ -91,17 +154,26 @@ HRESULT chuni_dll_init(const struct chuni_dll_config *cfg, HINSTANCE self)
goto end; goto end;
} }
sym = chuni_dll_syms; sym = cfg->chu2to3 ? chu2to3_dll_syms : chuni_dll_syms;
const struct dll_bind_sym *init_sym = &sym[0];
hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms)); hr = dll_bind(&chuni_dll, src, &sym, _countof(chuni_dll_syms));
if (FAILED(hr)) { if (FAILED(hr)) {
if (src != self) { if (src != self) {
dprintf("Chunithm IO: Custom IO DLL does not provide function " // Might still be ok depending on external dll API version
"\"%s\". Please contact your IO DLL's developer for " int bind_count = sym - init_sym;
"further assistance.\n", if ( has_enough_symbols(chuni_dll.api_version, bind_count) == S_OK )
sym->sym); {
hr = S_OK;
goto end; } else {
dprintf("Chunithm IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
dprintf("imported %d symbols\n", bind_count);
goto end;
}
} else { } else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym); dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
} }

View File

@ -13,10 +13,13 @@ struct chuni_dll {
void (*slider_start)(chuni_io_slider_callback_t callback); void (*slider_start)(chuni_io_slider_callback_t callback);
void (*slider_stop)(void); void (*slider_stop)(void);
void (*slider_set_leds)(const uint8_t *rgb); 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 { struct chuni_dll_config {
wchar_t path[MAX_PATH]; wchar_t path[MAX_PATH];
uint8_t chu2to3;
}; };
extern struct chuni_dll chuni_dll; extern struct chuni_dll chuni_dll;

View File

@ -20,3 +20,15 @@ EXPORTS
chuni_io_slider_set_leds chuni_io_slider_set_leds
chuni_io_slider_start chuni_io_slider_start
chuni_io_slider_stop 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

View File

@ -1,5 +1,6 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "board/config.h" #include "board/config.h"
@ -39,16 +40,27 @@ void chuni_dll_config_load(
// Workaround for x64/x86 external IO dlls // Workaround for x64/x86 external IO dlls
// path32 for 32bit, path64 for 64bit // path32 for 32bit, path64 for 64bit
// for else.. is that possible? idk // path for 32bit only dlls (internal chu2to3 engine)
#if defined(ENV32BIT) GetPrivateProfileStringW(
GetPrivateProfileStringW( L"chuniio",
L"chuniio", L"path",
L"path32", L"",
L"", cfg->path,
cfg->path, _countof(cfg->path),
_countof(cfg->path), filename);
filename); if (cfg->path[0] != L'\0') {
cfg->chu2to3 = 1;
} else {
cfg->chu2to3 = 0;
#if defined(ENV32BIT)
GetPrivateProfileStringW(
L"chuniio",
L"path32",
L"",
cfg->path,
_countof(cfg->path),
filename);
#elif defined(ENV64BIT) #elif defined(ENV64BIT)
GetPrivateProfileStringW( GetPrivateProfileStringW(
L"chuniio", L"chuniio",
@ -60,7 +72,7 @@ void chuni_dll_config_load(
#else #else
#error "Unknown environment" #error "Unknown environment"
#endif #endif
}
} }
void slider_config_load(struct slider_config *cfg, const wchar_t *filename) void slider_config_load(struct slider_config *cfg, const wchar_t *filename)
@ -85,7 +97,7 @@ void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = 0; cfg->port_no = 0;
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename);
@ -149,6 +161,7 @@ void chusan_hook_config_load(
dvd_config_load(&cfg->dvd, filename); dvd_config_load(&cfg->dvd, filename);
io4_config_load(&cfg->io4, filename); io4_config_load(&cfg->io4, filename);
gfx_config_load(&cfg->gfx, filename); gfx_config_load(&cfg->gfx, filename);
vfd_config_load(&cfg->vfd, filename);
chuni_dll_config_load(&cfg->dll, filename); chuni_dll_config_load(&cfg->dll, filename);
slider_config_load(&cfg->slider, filename); slider_config_load(&cfg->slider, filename);
led15093_config_load(&cfg->led15093, filename); led15093_config_load(&cfg->led15093, filename);

View File

@ -20,6 +20,7 @@ struct chusan_hook_config {
struct dvd_config dvd; struct dvd_config dvd;
struct io4_config io4; struct io4_config io4;
struct gfx_config gfx; struct gfx_config gfx;
struct vfd_config vfd;
struct chuni_dll_config dll; struct chuni_dll_config dll;
struct slider_config slider; struct slider_config slider;
struct led15093_config led15093; struct led15093_config led15093;

View File

@ -1,3 +1,27 @@
/*
"CHUNITHM NEW" (chusan) hook
Devices
USB: 837-15257-02 "Type 4" I/O Board
COM1: 837-15330 Ground Slider
[CVT mode (DIPSW2 ON)]
COM2: 837-15093-06 LED Controller Board
COM3: 837-15093-06 LED Controller Board
COM4: 837-15286 "Gen 2" Aime Reader
[SP mode (DIPSW2 OFF)]
USB: 837-15067-02 USB Serial I/F Board
connected to
837-15093-06 LED Controller Board (COM20)
837-15093-06 LED Controller Board (COM21)
COM2: 200-6275 VFD GP1232A02A FUTABA Board
COM4: 837-15396 "Gen 3" Aime Reader
*/
#include <windows.h> #include <windows.h>
#include <stddef.h> #include <stddef.h>
@ -25,6 +49,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static HMODULE chusan_hook_mod; static HMODULE chusan_hook_mod;
static process_entry_t chusan_startup; static process_entry_t chusan_startup;
@ -60,7 +85,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
/* Config load */ /* Config load */
chusan_hook_config_load(&chusan_hook_cfg, L".\\segatools.ini"); chusan_hook_config_load(&chusan_hook_cfg, get_config_path());
/* Hook Win32 APIs */ /* Hook Win32 APIs */
@ -99,8 +124,8 @@ static DWORD CALLBACK chusan_pre_startup(void)
goto fail; goto fail;
} }
bool *dipsw = &chusan_hook_cfg.platform.dipsw.dipsw[0]; bool *dipsw = &chusan_hook_cfg.platform.system.dipsw[0];
bool *is_sp = dipsw + 2; bool is_cvt = dipsw[2];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
switch (i) { switch (i) {
@ -113,29 +138,35 @@ static DWORD CALLBACK chusan_pre_startup(void)
break; break;
case 2: case 2:
dprintf("DipSw: Cab Type: %s\n", is_sp ? "SP" : "CVT"); dprintf("DipSw: Cab Type: %s\n", is_cvt ? "CVT" : "SP");
break; break;
} }
} }
unsigned int first_port = is_sp ? 20 : 2; unsigned int first_port = is_cvt ? 2 : 20;
if (is_sp) { if (!is_cvt) {
hr = vfd_hook_init(2); hr = vfd_hook_init(&chusan_hook_cfg.vfd, 2);
if (FAILED(hr)) { if (FAILED(hr)) {
goto fail; goto fail;
} }
} }
hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1); 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)) { if (FAILED(hr)) {
goto fail; goto fail;
}
} }
hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_sp ? 3: 2, chusan_hook_mod); hr = sg_reader_hook_init(&chusan_hook_cfg.aime, 4, is_cvt ? 2: 3, chusan_hook_mod);
if (FAILED(hr)) { if (FAILED(hr)) {
goto fail; goto fail;
@ -143,7 +174,7 @@ static DWORD CALLBACK chusan_pre_startup(void)
/* Initialize debug helpers */ /* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini"); spike_hook_init(get_config_path());
dprintf("--- End chusan_pre_startup ---\n"); dprintf("--- End chusan_pre_startup ---\n");

View File

@ -1,16 +0,0 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
struct led1509306_config {
bool enable;
bool cvt_port;
char board_number[8];
char chip_number[5];
uint8_t fw_ver;
uint16_t fw_sum;
};
HRESULT led1509306_hook_init(const struct led1509306_config *cfg);

View File

@ -4,7 +4,6 @@ shared_library(
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
vs_module_defs : 'chusanhook.def', vs_module_defs : 'chusanhook.def',
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'), capnhook.get_variable('hooklib_dep'),

View File

@ -98,7 +98,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 0 #if defined(LOG_CHUSAN_SLIDER)
dprintf("TX Buffer:\n"); dprintf("TX Buffer:\n");
dump_iobuf(&slider_uart.written); dump_iobuf(&slider_uart.written);
#endif #endif
@ -117,7 +117,7 @@ static HRESULT slider_handle_irp_locked(struct irp *irp)
return hr; return hr;
} }
#if 0 #if defined(LOG_CHUSAN_SLIDER)
dprintf("Deframe Buffer:\n"); dprintf("Deframe Buffer:\n");
dump_iobuf(&req_iobuf); dump_iobuf(&req_iobuf);
#endif #endif

View File

@ -15,3 +15,59 @@ EXPORTS
cm_io_get_opbtns cm_io_get_opbtns
cm_io_init cm_io_init
cm_io_poll cm_io_poll
CFW_init
CFW_term
CFW_open
CFW_close
CFW_listupPrinter
CFW_listupPrinterSN
CFW_selectPrinter
CFW_selectPrinterSN
CFW_getPrinterInfo
CFW_status
CFW_statusAll
CFW_resetPrinter
CFW_updateFirmware
CFW_getFirmwareInfo
CHCUSB_init
CHCUSB_term
CHCUSB_MakeThread
CHCUSB_open
CHCUSB_close
CHCUSB_ReleaseThread
CHCUSB_listupPrinter
CHCUSB_listupPrinterSN
CHCUSB_selectPrinter
CHCUSB_selectPrinterSN
CHCUSB_getPrinterInfo
CHCUSB_imageformat
CHCUSB_setmtf
CHCUSB_makeGamma
CHCUSB_setIcctableProfile
CHCUSB_setIcctable
CHCUSB_copies
CHCUSB_status
CHCUSB_statusAll
CHCUSB_startpage
CHCUSB_endpage
CHCUSB_write
CHCUSB_writeLaminate
CHCUSB_writeHolo
CHCUSB_setPrinterInfo
CHCUSB_setPrinterToneCurve
CHCUSB_getGamma
CHCUSB_getMtf
CHCUSB_cancelCopies
CHCUSB_getPrinterToneCurve
CHCUSB_blinkLED
CHCUSB_resetPrinter
CHCUSB_AttachThreadCount
CHCUSB_getPrintIDStatus
CHCUSB_setPrintStandby
CHCUSB_testCardFeed
CHCUSB_exitCard
CHCUSB_getCardRfidTID
CHCUSB_commCardRfidReader
CHCUSB_updateCardRfidReader
CHCUSB_getErrorLog
CHCUSB_getErrorStatus

View File

@ -1,5 +1,6 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "board/config.h" #include "board/config.h"
@ -37,6 +38,9 @@ void cm_hook_config_load(
aime_config_load(&cfg->aime, filename); aime_config_load(&cfg->aime, filename);
dvd_config_load(&cfg->dvd, filename); dvd_config_load(&cfg->dvd, filename);
io4_config_load(&cfg->io4, filename); io4_config_load(&cfg->io4, filename);
vfd_config_load(&cfg->vfd, filename);
touch_screen_config_load(&cfg->touch, filename); touch_screen_config_load(&cfg->touch, filename);
printer_config_load(&cfg->printer, filename);
cm_dll_config_load(&cfg->dll, filename); cm_dll_config_load(&cfg->dll, filename);
unity_config_load(&cfg->unity, filename);
} }

View File

@ -6,18 +6,24 @@
#include "hooklib/dvd.h" #include "hooklib/dvd.h"
#include "hooklib/touch.h" #include "hooklib/touch.h"
#include "hooklib/printer.h"
#include "cmhook/cm-dll.h" #include "cmhook/cm-dll.h"
#include "platform/config.h" #include "platform/config.h"
#include "unityhook/config.h"
struct cm_hook_config { struct cm_hook_config {
struct platform_config platform; struct platform_config platform;
struct aime_config aime; struct aime_config aime;
struct dvd_config dvd; struct dvd_config dvd;
struct io4_config io4; struct io4_config io4;
struct vfd_config vfd;
struct cm_dll_config dll; struct cm_dll_config dll;
struct touch_screen_config touch; struct touch_screen_config touch;
struct printer_config printer;
struct unity_config unity;
}; };
void cm_dll_config_load( void cm_dll_config_load(

View File

@ -1,3 +1,16 @@
/*
"Card Maker" (cm) hook
Devices
USB: 837-15257-01 "Type 4" I/O Board
USB: 838-20006 "WinTouch" Controller Board
USB: 630-00009 Sinfonia CHC-C310 Printer
COM1: 837-15396 "Gen 3" Aime Reader
COM2: 200-6275 VFD GP1232A02A FUTABA Board
COM3: 220-5872 AS-6DB Coin Selector
*/
#include <windows.h> #include <windows.h>
#include <stdlib.h> #include <stdlib.h>
@ -16,11 +29,13 @@
#include "cmhook/config.h" #include "cmhook/config.h"
#include "cmhook/io4.h" #include "cmhook/io4.h"
#include "cmhook/cm-dll.h" #include "cmhook/cm-dll.h"
#include "cmhook/unity.h"
#include "platform/platform.h" #include "platform/platform.h"
#include "unityhook/hook.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static HMODULE cm_hook_mod; static HMODULE cm_hook_mod;
static process_entry_t cm_startup; static process_entry_t cm_startup;
@ -34,7 +49,7 @@ static DWORD CALLBACK cm_pre_startup(void)
/* Load config */ /* Load config */
cm_hook_config_load(&cm_hook_cfg, L".\\segatools.ini"); cm_hook_config_load(&cm_hook_cfg, get_config_path());
/* Hook Win32 APIs */ /* Hook Win32 APIs */
@ -42,6 +57,10 @@ static DWORD CALLBACK cm_pre_startup(void)
touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod); touch_screen_hook_init(&cm_hook_cfg.touch, cm_hook_mod);
serial_hook_init(); serial_hook_init();
/* Hook external DLL APIs */
printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod);
/* Initialize emulation hooks */ /* Initialize emulation hooks */
hr = platform_hook_init( hr = platform_hook_init(
@ -54,19 +73,19 @@ static DWORD CALLBACK cm_pre_startup(void)
goto fail; goto fail;
} }
hr = cm_dll_init(&cm_hook_cfg.dll, cm_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod); hr = sg_reader_hook_init(&cm_hook_cfg.aime, 1, 1, cm_hook_mod);
if (FAILED(hr)) { if (FAILED(hr)) {
goto fail; goto fail;
} }
hr = vfd_hook_init(2); 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)) { if (FAILED(hr)) {
goto fail; goto fail;
@ -83,11 +102,11 @@ static DWORD CALLBACK cm_pre_startup(void)
There seems to be an issue with other DLL hooks if `LoadLibraryW` is There seems to be an issue with other DLL hooks if `LoadLibraryW` is
hooked earlier in the `cmhook` initialization. */ hooked earlier in the `cmhook` initialization. */
unity_hook_init(); unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod, NULL);
/* Initialize debug helpers */ /* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini"); spike_hook_init(get_config_path());
dprintf("--- End cm_pre_startup ---\n"); dprintf("--- End cm_pre_startup ---\n");

View File

@ -4,7 +4,6 @@ shared_library(
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
vs_module_defs : 'cmhook.def', vs_module_defs : 'cmhook.def',
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'), capnhook.get_variable('hooklib_dep'),
@ -16,6 +15,7 @@ shared_library(
hooklib_lib, hooklib_lib,
cmio_lib, cmio_lib,
platform_lib, platform_lib,
unityhook_lib,
util_lib, util_lib,
], ],
sources : [ sources : [
@ -26,7 +26,5 @@ shared_library(
'io4.h', 'io4.h',
'cm-dll.c', 'cm-dll.c',
'cm-dll.h', 'cm-dll.h',
'unity.h',
'unity.c',
], ],
) )

View File

@ -1,95 +0,0 @@
#include <stdbool.h>
#include <windows.h>
#include "hook/table.h"
#include "hooklib/dll.h"
#include "hooklib/path.h"
#include "util/dprintf.h"
static void dll_hook_insert_hooks(HMODULE target);
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
static const struct hook_symbol unity_kernel32_syms[] = {
{
.name = "LoadLibraryW",
.patch = my_LoadLibraryW,
.link = (void **) &next_LoadLibraryW,
},
};
static const wchar_t *target_modules[] = {
L"mono.dll",
L"cri_ware_unity.dll",
};
static const size_t target_modules_len = _countof(target_modules);
void unity_hook_init(void)
{
dll_hook_insert_hooks(NULL);
}
static void dll_hook_insert_hooks(HMODULE target)
{
hook_table_apply(
target,
"kernel32.dll",
unity_kernel32_syms,
_countof(unity_kernel32_syms));
}
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
{
const wchar_t *name_end;
const wchar_t *target_module;
bool already_loaded;
HMODULE result;
size_t name_len;
size_t target_module_len;
if (name == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// Check if the module is already loaded
already_loaded = GetModuleHandleW(name) != NULL;
// Must call the next handler so the DLL reference count is incremented
result = next_LoadLibraryW(name);
if (!already_loaded && result != NULL) {
name_len = wcslen(name);
for (size_t i = 0; i < target_modules_len; i++) {
target_module = target_modules[i];
target_module_len = wcslen(target_module);
// Check if the newly loaded library is at least the length of
// the name of the target module
if (name_len < target_module_len) {
continue;
}
name_end = &name[name_len - target_module_len];
// Check if the name of the newly loaded library is one of the
// modules the path hooks should be injected into
if (_wcsicmp(name_end, target_module) != 0) {
continue;
}
dprintf("Unity: Loaded %S\n", target_module);
dll_hook_insert_hooks(result);
path_hook_insert_hooks(result);
}
}
return result;
}

View File

@ -1,3 +0,0 @@
#pragma once
void unity_hook_init(void);

View File

@ -6,6 +6,7 @@
#include "cmio/cmio.h" #include "cmio/cmio.h"
#include "cmio/config.h" #include "cmio/config.h"
#include "util/env.h"
static uint8_t cm_opbtn; static uint8_t cm_opbtn;
static struct cm_io_config cm_io_cfg; static struct cm_io_config cm_io_cfg;
@ -18,7 +19,7 @@ uint16_t cm_io_get_api_version(void)
HRESULT cm_io_init(void) HRESULT cm_io_init(void)
{ {
cm_io_config_load(&cm_io_cfg, L".\\segatools.ini"); cm_io_config_load(&cm_io_cfg, get_config_path());
return S_OK; return S_OK;
} }

View File

@ -36,9 +36,9 @@ HRESULT cm_io_init(void);
HRESULT cm_io_poll(void); HRESULT cm_io_poll(void);
/* Get the state of the cabinet's operator buttons as of the last poll. See /* 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 CM_IO_OPBTN enum above: this contains bit mask definitions for button
states returned in *opbtn. All buttons are active-high. states returned in *opbtn. All buttons are active-high.
Minimum API version: 0x0100 */ Minimum API version: 0x0100 */
void cm_io_get_opbtns(uint8_t *opbtn); void cm_io_get_opbtns(uint8_t *opbtn);

View File

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

View File

@ -3,7 +3,6 @@ cmio_lib = static_library(
name_prefix : '', name_prefix : '',
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
c_pch : '../precompiled.h',
sources : [ sources : [
'cmio.c', 'cmio.c',
'cmio.h', 'cmio.h',

View File

@ -3,6 +3,7 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "amex/amex.h" #include "amex/amex.h"
#include "amex/config.h" #include "amex/config.h"
@ -23,22 +24,32 @@ void cxb_dll_config_load(
struct cxb_dll_config *cfg, struct cxb_dll_config *cfg,
const wchar_t *filename) 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) void revio_config_load(struct revio_config *cfg, const wchar_t *filename)
{ {
assert(cfg != NULL);
assert(filename != NULL);
} cfg->enable = GetPrivateProfileIntW(L"revio", L"enable", 1, 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 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( void cxb_hook_config_load(
@ -56,6 +67,5 @@ void cxb_hook_config_load(
gfx_config_load(&cfg->gfx, filename); gfx_config_load(&cfg->gfx, filename);
cxb_dll_config_load(&cfg->dll, filename); cxb_dll_config_load(&cfg->dll, filename);
revio_config_load(&cfg->revio, filename); revio_config_load(&cfg->revio, filename);
network_config_load(&cfg->network, filename);
led_config_load(&cfg->led, filename); led_config_load(&cfg->led, filename);
} }

View File

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

View File

@ -9,7 +9,6 @@
#include "cxbhook/config.h" #include "cxbhook/config.h"
#include "cxbhook/revio.h" #include "cxbhook/revio.h"
#include "cxbhook/led.h" #include "cxbhook/led.h"
#include "cxbhook/network.h"
#include "cxbio/cxbio.h" #include "cxbio/cxbio.h"
@ -24,6 +23,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static HMODULE cxb_hook_mod; static HMODULE cxb_hook_mod;
static process_entry_t cxb_startup; static process_entry_t cxb_startup;
@ -59,7 +59,7 @@ static DWORD CALLBACK cxb_pre_startup(void)
/* Config load */ /* Config load */
cxb_hook_config_load(&cxb_hook_cfg, L".\\segatools.ini"); cxb_hook_config_load(&cxb_hook_cfg, get_config_path());
/* Hook Win32 APIs */ /* Hook Win32 APIs */
@ -103,12 +103,6 @@ static DWORD CALLBACK cxb_pre_startup(void)
goto fail; goto fail;
} }
hr = network_hook_init(&cxb_hook_cfg.network);
if (FAILED(hr)) {
goto fail;
}
hr = led_hook_init(&cxb_hook_cfg.led); hr = led_hook_init(&cxb_hook_cfg.led);
if (FAILED(hr)) { if (FAILED(hr)) {
@ -117,7 +111,7 @@ static DWORD CALLBACK cxb_pre_startup(void)
/* Initialize debug helpers */ /* Initialize debug helpers */
spike_hook_init(L".\\segatools.ini"); spike_hook_init(get_config_path());
dprintf("--- End cxb_pre_startup ---\n"); dprintf("--- End cxb_pre_startup ---\n");

View File

@ -1,11 +1,14 @@
#include <windows.h> #include <windows.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "cxbhook/led.h" #include "cxbhook/led.h"
#include "cxbhook/cxb-dll.h" #include "cxbhook/cxb-dll.h"
#include "hooklib/procaddr.h" #include "hook/procaddr.h"
#include "hook/table.h" #include "hook/table.h"
@ -49,8 +52,14 @@ static struct hook_symbol lamp_syms[] = {
HRESULT led_hook_init(struct led_config *cfg) HRESULT led_hook_init(struct led_config *cfg)
{ {
dprintf("LED: Init\n"); assert(cfg != NULL);
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
if (!cfg->enable) {
return S_FALSE;
}
dprintf("LED: Hook enabled.\n");
return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms));
} }
static int my_cCommLamp_Open(char *port) static int my_cCommLamp_Open(char *port)

View File

@ -4,7 +4,6 @@ shared_library(
include_directories : inc, include_directories : inc,
implicit_include_directories : false, implicit_include_directories : false,
vs_module_defs : 'cxbhook.def', vs_module_defs : 'cxbhook.def',
c_pch : '../precompiled.h',
dependencies : [ dependencies : [
capnhook.get_variable('hook_dep'), capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'), capnhook.get_variable('hooklib_dep'),
@ -30,7 +29,5 @@ shared_library(
'revio.h', 'revio.h',
'led.c', 'led.c',
'led.h', '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

@ -1,12 +1,15 @@
#include <windows.h> #include <windows.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <winuser.h> #include <winuser.h>
#include "cxbhook/revio.h" #include "cxbhook/revio.h"
#include "cxbhook/cxb-dll.h" #include "cxbhook/cxb-dll.h"
#include "hooklib/procaddr.h" #include "hook/procaddr.h"
#include "hook/table.h" #include "hook/table.h"
@ -82,8 +85,14 @@ static struct hook_symbol revio_syms[] = {
HRESULT revio_hook_init(struct revio_config *cfg) HRESULT revio_hook_init(struct revio_config *cfg)
{ {
dprintf("Revio: Init\n"); assert(cfg != NULL);
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
if (!cfg->enable) {
return S_FALSE;
}
dprintf("Revio: Hook enabled.\n");
return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms));
} }
static int my_cCommIo_Open(char *port) static int my_cCommIo_Open(char *port)
@ -154,7 +163,7 @@ static int my_cCommIo_GetTrigger()
out &= ~last_triggers; out &= ~last_triggers;
dprintf("Revio: GetTrigger %X\n", out); // dprintf("Revio: GetTrigger %X\n", out);
last_triggers = out; last_triggers = out;
return out; return out;
} }
@ -188,7 +197,7 @@ static int my_cCommIo_GetRelease()
out &= ~btns; out &= ~btns;
dprintf("Revio: GetRelease %X\n", out); // dprintf("Revio: GetRelease %X\n", out);
last_triggers = btns; last_triggers = btns;
return out; return out;
} }

View File

@ -8,6 +8,7 @@
#include "cxbio/config.h" #include "cxbio/config.h"
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/env.h"
static bool cxb_io_coin; static bool cxb_io_coin;
static int cxb_io_coins; static int cxb_io_coins;
@ -21,7 +22,7 @@ uint16_t cxb_io_get_api_version(void)
HRESULT cxb_io_revio_init(void) HRESULT cxb_io_revio_init(void)
{ {
dprintf("CXB IO: REVIO init\n"); dprintf("CXB IO: REVIO init\n");
cxb_io_config_load(&cxb_io_cfg, L".\\segatools.ini"); cxb_io_config_load(&cxb_io_cfg, get_config_path());
return S_OK; return S_OK;
} }
@ -75,4 +76,4 @@ HRESULT cxb_io_led_init(void)
} }
void cxb_io_led_update(int id, int color) void cxb_io_led_update(int id, int color)
{} {}

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