Compare commits

...

50 Commits
5.34 ... 5.35

Author SHA1 Message Date
Will Xyen
54e7d783ef Update changelog for 5.35 2021-06-23 11:17:29 -07:00
CrazyRedMachine
4ea1397af2 aciodrv: add PANB support (+ aciotest handler)
add aciodrv-proc module

explanation : PANB works differently from other acio devices ; you send
one "start auto input" command without expecting a reply, and then the
piano keeps spamming "recv poll" commands on the acio bus and never replies
to any other commands.. failure to process these messages quickly enough
will saturate the serial buffer and cause checksum errors after a while.

for this reason, aciodrv-proc module was added in order to create a
thread which manages these recv poll commands and keeps the latest
known button state in memory so that it can be retrieved easily.
2021-05-03 20:14:21 +02:00
icex2
fb593df4a1 Update Bug.md, fix comment not closing 2021-05-02 10:54:45 +00:00
icex2
f0c33663e9 Update bug template, add info to run with default config 2021-05-02 10:54:24 +00:00
icex2
87ee37d059 Fix typo in log message 2021-05-02 10:39:55 +00:00
Will Xyen
5688fb7319 aciodrv: refactor aciodrv_device_init function 2021-05-01 10:42:55 -07:00
Will Xyen
d529ee484f aciodrv: Update aciodrv_device_init to properly reset the device 2021-05-01 10:30:02 -07:00
Will Xyen
7c43fb7163 doc: Make doc.zip include the whole folder
Also update vigem docs
2021-04-30 20:24:13 -07:00
Will Xyen
652d2ef633 aciodrv: fix pointer logging 2021-04-26 12:50:22 -07:00
Will Toohey
78884aebad Clarify how eamio-icca works with jbio-p4io 2021-04-06 21:04:34 +10:00
Will Toohey
549f00bfb3 Add default jbio-h44b.conf to /dist 2021-04-06 20:58:47 +10:00
Will T
aab45f145f Add missing backticks in jbio-p4io.md 2021-04-06 10:54:20 +00:00
Will Toohey
6171f0dc60 Make h44b light mapping explicit 2021-04-06 20:52:19 +10:00
Will Toohey
2f05760f4e Add enum p4io_roundplug_type for clarity 2021-04-06 20:35:14 +10:00
Will Toohey
7b5e4772ea Clarify p4io_cmd_init's lack of response checking 2021-04-06 20:30:47 +10:00
Will Toohey
e266aed1f9 p4io/usb: clarify jamma reads use interrupt handle 2021-04-06 20:28:08 +10:00
Will Toohey
0b0e7faef0 jbio-magicbox: comment nonfunctional jb_io_set_panel_mode 2021-04-06 20:25:07 +10:00
Will Toohey
53866130cb p4io: change magic AA to P4IO_SOF 2021-04-06 20:23:01 +10:00
Will Toohey
dbb8c45a9f H44B drv: add missed deinit code, comments 2021-04-06 20:19:19 +10:00
Will Toohey
8ed7d6db71 remove spurious warning 2021-04-04 18:35:21 +10:00
Will Toohey
4c746df6a8 Fix warnings on format strings 2021-04-04 17:19:16 +10:00
Will Toohey
7d485e7c7e Improve robustness of p4iodrv/usb 2021-04-04 17:16:19 +10:00
Will Toohey
deb6e5cf77 Fix const warning in aciodrv-icca 2021-04-04 16:41:59 +10:00
Will Toohey
2a03690772 Update jbio for testmenu support and add jbio-p4io 2021-04-04 16:41:45 +10:00
Will Xyen
6ce4cce500 eamio-icca: Fix state being mis-fired during felica poll (causing errors in IIDX13-18) 2021-03-21 04:19:39 +00:00
ab3a6534ca292e2c3580175f809ec08257496a8e
c6e59bae9b Updates dev.s-ul.eu URLs and fixes bad doc link for vigem 2021-03-19 18:09:07 +00:00
Will Xyen
31e15ec5ea sdvxhook: re-order hooks so eamio-icca can be used 2021-03-17 16:06:31 -07:00
Will Xyen
9cef7c03d0 aciodrv: address some magic numbers with felica polling 2021-03-17 14:42:14 -07:00
Will Xyen
f9b37c7a72 aciodrv: Add wavepass support to ICCA (#1)
Tested with:
aciotest / eamiotest:
 - DDR Slotted: Node 1: type 3, flag 0, version 1.1.0, product ICCA, build date: Oct 26 2005 13:55:03
 - DDR Slotted: Node 2: type 3, flag 0, version 1.1.0, product ICCA, build date: Oct 26 2005 13:55:03
(tested with just 1, as well as a pair)

aciotest / eamiotest / IIDX10,12,27:
 - IIDX Wavepass: Node 1: type 3, flag 0, version 1.5.1, product ICCB, build date: Apr 12 2010 09:29:00
 - IIDX Wavepass: Node 2: type 3, flag 0, version 1.5.1, product ICCB, build date: Apr 12 2010 09:29:00
(IIDX13 errors on card-in, probably issue with how eamio is being used as previously eamio-icca had no use on it)

aciotest / eamiotest / sdvx1-5:
 - SDVX Wavepass: Node 1: type 3, flag 0, version 1.5.1, product ICCB, build date: Apr 12 2010 09:29:00

aciotest:
 - Jubeat Wavepass:  Node 1: type 3, flag 0, version 1.7.3, product ICCC, build date: Oct 05 2012 20:26:53
 - Museca Wavepass:  Node 2: type 3, flag 0, version 1.7.4, product ICCC, build date: Feb 27 2013 16:44:51
2021-03-17 10:34:30 -07:00
Will Xyen
609c19b0ca sdvxio-kfca: fix build 2021-03-16 16:51:10 -07:00
Will Xyen
75b27d5992 aciomgr: move internal init stuff to manager-init.h 2021-03-16 22:06:21 +00:00
Will Xyen
965df98093 aciomgr: cleanup and address comments 2021-03-16 22:06:21 +00:00
Will Xyen
0c06d224cc eamio-icca: fix config prefix 2021-03-16 22:06:21 +00:00
Will Xyen
fb3d2ea312 eamio-icca: add config to allow port to be set
also fixes issue where no logging would show up in eamiotest
2021-03-16 22:06:21 +00:00
Will Xyen
089253a537 aciomgr: Add acio manager dll 2021-03-16 22:06:21 +00:00
Will Xyen
a4436747de aciodrv: fix build warnings for logging format strings 2021-03-16 22:06:21 +00:00
a5a845f95bba57bc03c1a6bfabfbca25c2de8e01
43b11c8778 doc: minor update to bio2-sub-io-turntable-bypass-cable 2021-03-16 00:48:47 +00:00
Will Xyen
dd7fd860b5 launcher: add 2.15.9 def
(same as 2.15.8 except with new kbt, and different log ordinals)
2021-02-12 02:11:07 -08:00
Will Xyen
18842a1dd3 d3d9ex: override adapter mode information when all the info is pre-provided by the user
This speeds up IIDX load times, as well as allows you to use "unsupported" resolutions/refresh rates on weird monitors
2021-02-06 16:25:33 -08:00
Will Xyen
18f6d9ef70 d3d9ex: add windowed position setting 2021-02-04 23:38:54 -08:00
Will Xyen
592967e191 d3d9ex: revert previous window size fix, and fix it properly 2021-02-04 23:04:56 -08:00
Will Xyen
6614cc801e d3d9ex: fix framed and window sizes for IIDX 2021-02-04 22:57:29 -08:00
Will Xyen
8e1151ac02 aciodrv: address review
also some formatting fixes
2021-01-19 21:10:34 -08:00
Will Xyen
4b60cb6c6c aciodrv: fix pointer format, and missing close context 2021-01-14 11:05:46 -08:00
Will Xyen
770bae4169 aciodrv: support multi-sized response packets by divining the packet size 2021-01-14 10:57:38 -08:00
Will Xyen
49d0bc638b aciodrv: refactor to support multiple active drivers (with specified ports) 2021-01-14 10:02:27 -08:00
icex2
837affc66c Readme: Update with release process steps for devs 2021-01-07 22:01:52 +01:00
icex2
ec76ba075f gitlab-ci: Fix pipeline to include build step for tagged release 2021-01-07 20:30:09 +00:00
icex2
f438f04f2a gitlab-ci: Build + automatic upload of tagged releases 2021-01-07 21:05:41 +01:00
icex2
865980991e Bump version to 5.35 2021-01-06 22:17:30 +01:00
104 changed files with 3342 additions and 553 deletions

View File

@@ -11,57 +11,45 @@ before_script:
stages:
- build
- create-release-package
- releasetag
- upload-release
build:
build-master:
stage: build
before_script:
- apk update && apk add make > /dev/null
script:
- make build-docker
- mv build/docker/bemanitools.zip bemanitools.zip
artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths:
- build
- bemanitools.zip
only:
refs:
- master
create-release-package:
stage: create-release-package
variables:
GIT_STRATEGY: none
dependencies:
- build
build-tags:
stage: build
before_script:
- apk update && apk add zip > /dev/null
- apk update && apk add make > /dev/null
script:
- mv build/docker/bemanitools.zip ./bemanitools.zip
- rm -r build
- find . -mindepth 1 ! -regex '^./bemanitools.zip' -delete
- unzip bemanitools.zip
- rm bemanitools.zip
- make build-docker
- mv build/docker/bemanitools.zip bemanitools.zip
artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths:
- ./*
- bemanitools.zip
only:
refs:
- master
releasetag:
stage: releasetag
dependencies: []
- tags
upload-release:
stage: upload-release
dependencies:
- build-tags
before_script:
- apk update && apk add curl > /dev/null
script:
- |
curl --silent --show-error \
--data "{\"tag_name\": \"${CI_COMMIT_TAG}\", \"name\": \"${CI_PROJECT_NAME}-${CI_COMMIT_TAG}\", \"description\": \"${CI_COMMIT_TAG_MESSAGE:-No release notes.}\"}" \
--header "Content-Type: application/json" \
--header "Private-Token: ${CI_PRIVATE_TOKEN}" \
--request POST \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases"
- echo "Uploading ${CI_PROJECT_NAME}-${CI_COMMIT_TAG}..."
- curl --silent --show-error -F "key=${CI_UPLOAD_KEY}" -F "filename=${CI_PROJECT_NAME}-v${CI_COMMIT_TAG}.zip" -F "file=@./bemanitools.zip" ${CI_UPLOAD_URL}
only:
- tags

View File

@@ -12,6 +12,8 @@
necessary -->
## Steps to reproduce
<!-- Try running the game with a default configuration as well. If that also causes issues, please point that out here in the report. This might speed up the debugging process.-->
<!--- Provide a detailed step by step description how to reproduce this issue -->
1.
2.

View File

@@ -1,4 +1,12 @@
# Release history
## 5.35
* Jubeat: Add jbio-p4io
* Nostalgia: Add nostio-panb
* Misc: Refactor aciodrv to support multiple devices using the same port (with aciomgr)
* Misc: Fix d3d9ex windowed hook not behaving correctly (size/framed)
* Misc: Fix docs not being included with release
* Various bugfixes
## 5.34
* IIDX: Support IO and card reader feature switches to disable emulation in iidxhook4-7
* Jubeat: jbio implementation for magicbox hardware

View File

@@ -72,12 +72,14 @@ cflags += \
# that is still ABI-compatible with the real build its target links against.
avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 803 0
avsvers_64 := 1700 1603 1601 1508
avsvers_64 := 1700 1603 1601 1509 1508
imps += avs avs-ea3
include src/main/aciodrv/Module.mk
include src/main/aciodrv-proc/Module.mk
include src/main/acioemu/Module.mk
include src/main/aciomgr/Module.mk
include src/main/aciotest/Module.mk
include src/main/asio/Module.mk
include src/main/bio2drv/Module.mk
@@ -136,6 +138,7 @@ include src/main/inject/Module.mk
include src/main/jbhook/Module.mk
include src/main/jbhook1/Module.mk
include src/main/jbio-magicbox/Module.mk
include src/main/jbio-p4io/Module.mk
include src/main/jbio/Module.mk
include src/main/jbiotest/Module.mk
include src/main/launcher/Module.mk
@@ -143,6 +146,7 @@ include src/main/mempatch-hook/Module.mk
include src/main/mm/Module.mk
include src/main/p3io/Module.mk
include src/main/p3ioemu/Module.mk
include src/main/p4iodrv/Module.mk
include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk
@@ -378,6 +382,7 @@ $(zipdir)/iidx-27.zip: \
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/iidxio-bio2.dll \
build/bin/indep-32/iidxio-ezusb.dll \
@@ -390,6 +395,7 @@ $(zipdir)/iidx-hwio-x86.zip: \
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/iidxio-bio2.dll \
build/bin/indep-64/iidxio-ezusb.dll \
@@ -441,6 +447,17 @@ $(zipdir)/jb-08.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-hwio.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/jbio-magicbox.dll \
build/bin/indep-32/jbio-p4io.dll \
dist/jb/jbio-h44b.conf \
dist/jb/eamio-icc.conf \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-01-to-04.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/sdvxhook.dll \
@@ -483,6 +500,8 @@ $(zipdir)/sdvx-05-cn.zip: \
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/sdvxio-kfca.dll \
build/bin/indep-32/sdvxio-bio2.dll \
build/bin/indep-32/vigem-sdvxio.exe \
@@ -491,6 +510,8 @@ $(zipdir)/sdvx-hwio-x86.zip: \
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/sdvxio-kfca.dll \
build/bin/indep-64/sdvxio-bio2.dll \
build/bin/indep-64/vigem-sdvxio.exe \
@@ -549,10 +570,7 @@ $(zipdir)/bst.zip: \
$(V)zip -j $@ $^
$(zipdir)/doc.zip: \
doc/iidxhook \
doc/sdvxhook \
doc/jbhook \
doc/tools \
doc/ \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -r $@ $^
@@ -602,6 +620,7 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/jb-01.zip \
$(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \
$(zipdir)/jb-hwio.zip \
$(zipdir)/sdvx-01-to-04.zip \
$(zipdir)/sdvx-05.zip \
$(zipdir)/sdvx-05-cn.zip \

View File

@@ -1,7 +1,7 @@
# Bemanitools 5
[![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master)
[![pipeline status](https://dev.s-ul.net/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.net/djhackers/bemanitools/commits/master)
Version: 5.34
Version: 5.35
[Release history](CHANGELOG.md)
@@ -73,7 +73,7 @@ The tl;dr version and golden rules of the sections in the document:
Play your favorite non-bemani arcade games with any hardware, e.g. real cabinet hardware, that
implements BT5 APIs.
See the dedicated [readme](docs/vigem/README.md) for details.
See the dedicated [readme](doc/vigem/README.md) for details.
## Supported platforms
Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware
@@ -110,6 +110,34 @@ important aspects you should know before you get started with development.
### API
Please refer to the [API documentation](doc/api.md).
## Release process
Steps for the release process:
1. Update the corresponding section in the [changelog](CHANGELOG.md) with bullet points reflecting
major features merged into master since the previous release
1. Make sure you have the latest `master` state pulled to your local copy
1. Tag the release with the next release number which also be found at the
[top of the readme](#bemanitools-5) as it always reflects the current version beinged worked on
on the `master` branch , e.g. 5.35: `git tag 5.35`
1. Push the tag to upstream: `git push origin 5.35`
1. The [build pipeline](https://dev.s-ul.net/djhackers/bemanitools/-/pipelines) should start
automatically once the tag is pushed including the steps `build` and `upload-release`
1. Once completed successfully, the release is uploaded
1. Take the changelog of the published version and notify the pigs in the stall about it:
1. New post in thread
```
<insert version here> released: <direct link to published version>
Changelog:
<paste changelog here>
```
1. Update the OP title by bumping the version number in it
1. Update the OP post by extending it accordingly (see previous entries)
1. Bump the version number at the [top of this readme](#bemanitools-5) and add a new empty section
in the [changelog](CHANGELOG.md) with the new version number as title. Commit changes and push to
`master` branch
1. Continue developing and merging MRs until you decide its time for another release
## License
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the
[LICENSE file](LICENSE) included with the source code.

View File

@@ -34,7 +34,7 @@ gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse coursor to window
# Confine mouse cursor to window
gfx.confined=false
# Windowed width, -1 for default size
@@ -43,6 +43,12 @@ gfx.window_width=-1
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed X, -1 for default X position
gfx.window_x=-1
# Windowed Y, -1 for default Y position
gfx.window_y=-1
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
gfx.forced_refresh_rate=-1

5
dist/jb/eamio-icc.conf vendored Normal file
View File

@@ -0,0 +1,5 @@
# ICCA serial port
icc.port=COM2
# ICCA bus baudrate (real devices expect 57600)
icc.baud=57600

5
dist/jb/jbio-h44b.conf vendored Normal file
View File

@@ -0,0 +1,5 @@
# H44B serial port
h44b.port=COM2
# H44B bus baudrate (real devices expect 57600)
h44b.baud=57600

View File

@@ -19,7 +19,7 @@ gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse coursor to window
# Confine mouse cursor to window
gfx.confined=false
# Windowed width, -1 for default size
@@ -28,6 +28,12 @@ gfx.window_width=1080
# Windowed height, -1 for default size
gfx.window_height=1920
# Windowed X, -1 for default X position
gfx.window_x=-1
# Windowed Y, -1 for default Y position
gfx.window_y=-1
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
gfx.forced_refresh_rate=-1

View File

@@ -1,14 +1,15 @@
# BIO2 sub IO turntable bypass cable
If you upgraded a C02/IO2 wired cabinet, the turntables are connected to the
If you upgraded a C02 wired cabinet, the turntables are connected to the
sub IO via a serial line that goes to another sub IO behind the front panel
next to the 16seg display. This introduces additional latency as the input
data needs to pass through multiple systems/PCBs until it reaches the game.
This can be reduced by using a so-called "bypass" cable, that connects the
turntables directly to the BIO2 sub IO board reducing latency significantly.
turntables directly to the BIO2 sub IO board by emulating the wiring of a
D01 cabinet, reducing latency significantly.
This cable could be ordered with any IIDX upgrade kit including the BIO sub IO
board but can also be easily created from scratch.
This cable could be ordered with the IIDX Rootage upgrade kit but can also
be easily created from scratch.
## Parts
* Some wires
@@ -51,4 +52,4 @@ Pins of the two connectors need to be connected like this:
| 5 | 5 |
| 6 | 4 |
| 7 | 8 |
| 8 | 8 |
| 8 | 8 |

18
doc/jbhook/jbio-p4io.md Normal file
View File

@@ -0,0 +1,18 @@
This library talks to a P4IO (panel) and H44B through ACIO (lights) of a jubeat cab and implements the jbio API of BT5.
Thus, it allows you to use a modern jubeat cab with *any* version of jubeat that is supported by BT5.
# Setup
* Rename `jbio-p4io.dll` to `jbio.dll`.
* Make sure `jbio.dll` is in the same folder as both `jbhook.dll`, `aciomgr.dll` and `jubeat.dll`
* If you want IC card support via eamio-icca, ensure you also rename `eamio-icca.dll` to `eamio.dll`
* Ensure that your `gamestart.bat` actually injects the appropriate jbhook dll
for example:
```
launcher -K jbhook.dll jubeat.dll ...*
```
or that the application otherwise uses `jbio.dll`
* If you have P4IO but no H44B, lights will be disabled
* You can change the port and baudrate of the H44B node by editing the `jbio-h44b.conf` that should be created by default
* If you are using IC card support, you can edit `eamio-icc.conf` to change the port and baudrate
* If you are playing on a real cab, the port and baud of H44B and ICCA should be identical

View File

@@ -58,5 +58,5 @@ Turntables are either in absolute or relative mode depending on how it's defined
* Make sure that you follow the instructions exactly from the release page
([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
* If you get an error while trying to install KB3033929, re-enable windows update
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be
done once)
* If you can't find some of these files, see bemanitools-supplements
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once)

View File

@@ -19,6 +19,8 @@ Thus, it allows you to use a real cab with *any* game that supports xinput.
* VOL LR are mapped to L thumbstick X/Y (either in absolute or relative mode depending on the config)
# Additional Notes For Cabinets (Running on embedded Windows 7):
* Make sure that you follow the instructions exactly from the release page ([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
* Make sure that you follow the instructions exactly from the release page
([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
* If you get an error while trying to install KB3033929, re-enable windows update
* If you can't find some of these files, see bemanitools-supplements
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once)

View File

@@ -0,0 +1,7 @@
LIBRARY libavs-win64-ea3
EXPORTS
ea3_boot @8 NONAME
ea3_get_boot_status @11 NONAME
ea3_get_pp_status @10 NONAME
ea3_shutdown @9 NONAME

View File

@@ -0,0 +1,32 @@
LIBRARY libavs-win64
EXPORTS
avs_boot @285 NONAME
avs_fs_close @65 NONAME
avs_fs_lseek @59 NONAME
avs_fs_lseek64 @60 NONAME
avs_fs_open @58 NONAME
avs_fs_read @61 NONAME
avs_net_ctrl @98 NONAME
avs_shutdown @286 NONAME
avs_thread_create @6 NONAME
avs_thread_destroy @8 NONAME
avs_thread_exit @12 NONAME
avs_thread_join @13 NONAME
log_body_fatal @357 NONAME
log_body_info @359 NONAME
log_body_misc @360 NONAME
log_body_warning @358 NONAME
property_create @127 NONAME
property_desc_to_buffer @129 NONAME
property_destroy @128 NONAME
property_insert_read @131 NONAME
property_node_create @145 NONAME
property_node_refer @158 NONAME
property_node_remove @146 NONAME
property_psmap_export @162 NONAME
property_psmap_import @161 NONAME
property_read_query_memsize @159 NONAME
property_search @144 NONAME
std_getenv @207 NONAME
std_setenv @208 NONAME

View File

@@ -5,9 +5,11 @@
#include <stdint.h>
#include <stdlib.h>
#include "acio/h44b.h"
#include "acio/hdxs.h"
#include "acio/icca.h"
#include "acio/kfca.h"
#include "acio/panb.h"
#define AC_IO_SOF 0xAA
#define AC_IO_ESCAPE 0xFF
@@ -37,6 +39,7 @@ enum ac_io_node_type {
AC_IO_NODE_TYPE_KFCA = 0x09060000,
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
AC_IO_NODE_TYPE_RVOL = 0x09060001,
AC_IO_NODE_TYPE_PANB = 0x090E0000,
};
#pragma pack(push, 1)
@@ -69,12 +72,17 @@ struct ac_io_message {
uint8_t param;
struct ac_io_version version;
struct ac_io_h44b_output h44b_output;
struct ac_io_icca_misc icca_misc;
struct ac_io_icca_state icca_state;
struct ac_io_kfca_poll_in kfca_poll_in;
struct ac_io_kfca_poll_out kfca_poll_out;
struct ac_io_panb_poll_in panb_poll_in;
struct ac_io_panb_poll_out panb_poll_out;
struct ac_io_hdxs_output hdxs_output;
};
} cmd;

View File

@@ -14,6 +14,6 @@ struct ac_io_h44b_output {
uint8_t right_rgb[3];
uint8_t title_rgb[3];
uint8_t woofer_rgb[3];
};
} __attribute__((__packed__));
#endif
#endif

View File

@@ -29,6 +29,14 @@ enum ac_io_icca_sensor_state {
AC_IO_ICCA_SENSOR_MASK_BACK_ON = (1 << 5)
};
enum ac_io_icca_status_code {
AC_IO_ICCA_STATUS_FAULT = 0x00,
AC_IO_ICCA_STATUS_IDLE = 0x01,
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04,
AC_IO_ICCA_STATUS_BUSY_NEW = 0x01,
};
enum ac_io_icca_keypad_mask {
AC_IO_ICCA_KEYPAD_MASK_EMPTY = (1 << 0),
AC_IO_ICCA_KEYPAD_MASK_3 = (1 << 1),

42
src/main/acio/panb.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef AC_IO_PANB_H
#define AC_IO_PANB_H
#include <stdint.h>
#define AC_IO_CMD_PANB_POLL_REPLY 0x0110
#define AC_IO_CMD_PANB_SEND_LAMP 0x0111
#define AC_IO_CMD_PANB_START_AUTO_INPUT 0x0115
#define AC_IO_PANB_NUM_NODES 4
#define AC_IO_PANB_MAX_KEYS (7*AC_IO_PANB_NUM_NODES)
#define AC_IO_PANB_MAX_KEYPAIRS (AC_IO_PANB_MAX_KEYS/2)
struct ac_io_panb_keypair {
uint8_t key2 : 4;
uint8_t key1 : 4;
};
#pragma pack(push, 1)
struct ac_io_panb_poll_in {
/* last received command sequence number (start_auto_input / send_lamp) */
uint8_t sub_seq1;
/* auto-increment sequence number for autopoll reports */
uint8_t sub_seq2;
struct ac_io_panb_keypair keypair[AC_IO_PANB_MAX_KEYPAIRS];
};
#pragma pack(pop)
struct ac_io_panb_color {
uint8_t red;
uint8_t green;
uint8_t blue;
};
#pragma pack(push, 1)
struct ac_io_panb_poll_out {
struct ac_io_panb_color key[AC_IO_PANB_MAX_KEYS];
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,7 @@
libs += aciodrv-proc
libs_aciodrv-proc := \
src_aciodrv-proc := \
panb.c \

View File

@@ -0,0 +1,90 @@
#define LOG_MODULE "aciodrv-proc-panb"
#include <string.h>
#include "aciodrv/device.h"
#include "aciodrv/panb.h"
#include "util/thread.h"
#include "util/log.h"
static int auto_poll_proc(void *auto_poll_param);
static int auto_poll_threadid;
static CRITICAL_SECTION keypair_lock;
static struct ac_io_panb_keypair _keypair[AC_IO_PANB_MAX_KEYPAIRS];
static CRITICAL_SECTION auto_poll_stop_lock;
static bool auto_poll_stop;
static int auto_poll_proc(void * param)
{
struct aciodrv_device_ctx * device = (struct aciodrv_device_ctx *) param;
struct ac_io_panb_poll_in poll_in;
bool stop;
do {
aciodrv_panb_recv_poll(device, &poll_in);
EnterCriticalSection(&keypair_lock);
memcpy(_keypair, poll_in.keypair, AC_IO_PANB_MAX_KEYPAIRS);
LeaveCriticalSection(&keypair_lock);
EnterCriticalSection(&auto_poll_stop_lock);
stop = auto_poll_stop;
LeaveCriticalSection(&auto_poll_stop_lock);
} while (!stop);
return 0;
}
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device)
{
log_assert(device);
if (!aciodrv_panb_start_auto_input(device, 0, AC_IO_PANB_NUM_NODES)) {
return false;
}
auto_poll_stop = false;
InitializeCriticalSection(&keypair_lock);
InitializeCriticalSection(&auto_poll_stop_lock);
auto_poll_threadid = thread_create(auto_poll_proc, (void *)device, 0x4000, 0);
return true;
}
bool aciodrv_proc_panb_get_state(uint8_t *button_state)
{
struct ac_io_panb_keypair keypair[AC_IO_PANB_MAX_KEYPAIRS];
EnterCriticalSection(&keypair_lock);
memcpy(keypair, _keypair, AC_IO_PANB_MAX_KEYPAIRS);
LeaveCriticalSection(&keypair_lock);
/* splice the keypairs into separate button values */
for (int i=0; i<AC_IO_PANB_MAX_KEYPAIRS; i++) {
uint8_t but1 = keypair[i].key1;
uint8_t but2 = keypair[i].key2;
button_state[2*i] = but1;
button_state[2*i+1] = but2;
}
return true;
}
void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device)
{
EnterCriticalSection(&auto_poll_stop_lock);
auto_poll_stop = true;
LeaveCriticalSection(&auto_poll_stop_lock);
thread_join(auto_poll_threadid, NULL);
thread_destroy(auto_poll_threadid);
DeleteCriticalSection(&keypair_lock);
DeleteCriticalSection(&auto_poll_stop_lock);
/* reset is the only way to disable the auto polling on device side */
aciodrv_device_reset(device);
}

View File

@@ -0,0 +1,32 @@
#ifndef ACIODRV_PROC_PANB_H
#define ACIODRV_PROC_PANB_H
#include "aciodrv/panb.h"
/**
* Initialize a PANB device. This will take care of setting up the auto-poll and processing
* the poll messages in a separate thread (this is necessary as failing to process messages
* fast enough will cause the device to malfunction).
*
* @param device Context of opened device
* @return True if successful, false on error.
* @note This function spawns a thread. Caller must call aciodrv_proc_panb_fini to properly
* terminate.
*/
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device);
/**
* Retrieve latest known button state from the PANB device.
*
* @param button_state 28 cell array to store button state
* (mandatory, upon calling the array contains values between 0 to 15 indicating the keys velocity).
* @return True on success, false on error.
*/
bool aciodrv_proc_panb_get_state(uint8_t *button_state);
/**
* Properly terminate the thread and reset the device (this is the only way to stop the auto polling).
*/
void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device);
#endif

View File

@@ -1,10 +1,12 @@
libs += aciodrv
libs_aciodrv := \
src_aciodrv := \
device.c \
h44b.c \
icca.c \
kfca.c \
panb.c \
port.c \

View File

@@ -1,5 +1,6 @@
#define LOG_MODULE "aciodrv-device"
#include <inttypes.h>
#include <string.h>
#include "aciodrv/device.h"
@@ -8,34 +9,64 @@
#include "util/hex.h"
#include "util/log.h"
#include "util/mem.h"
/* Enable to dump all data to the logger */
//#define AC_IO_MSG_LOG
static uint8_t aciodrv_device_msg_counter = 1;
static uint8_t aciodrv_device_node_count;
static char aviodrv_device_node_products[16][4];
#define ACIO_MAX_NODES_PER_PORT 16
static bool aciodrv_device_init(void)
struct aciodrv_device_ctx {
HANDLE fd;
struct aciodrv_device_node_version node_versions[ACIO_MAX_NODES_PER_PORT];
uint8_t msg_counter;
uint8_t node_count;
};
bool aciodrv_device_reset(struct aciodrv_device_ctx *device)
{
uint8_t reset_seq[525] = {0};
/* init/reset the device by sending 525 NULL bytes */
log_info("Resetting device");
if (aciodrv_port_write(device->fd, reset_seq, sizeof(reset_seq)) <= 0) {
return false;
}
/* signal to device for a reset */
EscapeCommFunction(device->fd, SETBREAK);
Sleep(1450);
EscapeCommFunction(device->fd, CLRBREAK);
Sleep(1200);
/* ignore the next 100 reads (of whatever length) */
for (size_t i = 0; i < 100; ++i) {
aciodrv_port_read(device->fd, reset_seq, sizeof(reset_seq));
}
return true;
}
static bool aciodrv_device_sof_flush(struct aciodrv_device_ctx *device)
{
uint8_t init_seq[1] = {AC_IO_SOF};
uint8_t read_buff[1] = {0x00};
uint8_t read_buff[1] = {0};
/* init/reset the device by sending 0xAA until 0xAA is returned */
/* wait for reset to finish */
int read = 0;
do {
if (aciodrv_port_write(init_seq, sizeof(init_seq)) <= 0) {
if (aciodrv_port_write(device->fd, init_seq, sizeof(init_seq)) <= 0) {
return false;
}
read = aciodrv_port_read(read_buff, sizeof(read_buff));
read = aciodrv_port_read(device->fd, read_buff, sizeof(read_buff));
} while ((read <= 0) || (read_buff[0] != init_seq[0]));
if (read > 0) {
log_warning("Obtained SOF, clearing out buffer now");
log_info("Obtained SOF, clearing out buffer now");
/* empty buffer by reading all data */
while (read > 0) {
read = aciodrv_port_read(init_seq, sizeof(init_seq));
read = aciodrv_port_read(device->fd, init_seq, sizeof(init_seq));
}
log_warning("Cleared buffer, init done");
@@ -46,30 +77,39 @@ static bool aciodrv_device_init(void)
}
}
static bool aciodrv_device_init(struct aciodrv_device_ctx *device)
{
if (!aciodrv_device_reset(device)) {
log_warning("Reset failed");
return false;
}
return aciodrv_device_sof_flush(device);
}
#ifdef AC_IO_MSG_LOG
static void
aciodrv_device_log_buffer(const char *msg, const uint8_t *buffer, int length)
aciodrv_device_log_buffer(struct aciodrv_device_ctx *device, const char *msg, const uint8_t *buffer, int length)
{
char str[4096];
hex_encode_uc((const void *) buffer, length, str, sizeof(str));
log_misc("%s, length %d: %s", msg, length, str);
log_misc("[%p] %s, length %d: %s", device->fd, msg, length, str);
}
#endif
static bool aciodrv_device_send(const uint8_t *buffer, int length)
static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t *buffer, int length)
{
uint8_t send_buf[512];
int send_buf_pos = 0;
uint8_t checksum = 0;
if (length > sizeof(send_buf)) {
log_warning("Send buffer overflow");
log_warning("[%p] Send buffer overflow", device->fd);
return false;
}
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Send (1)", buffer, length);
aciodrv_device_log_buffer(device, "Send (1)", buffer, length);
#endif
send_buf[send_buf_pos++] = AC_IO_SOF;
@@ -95,18 +135,18 @@ static bool aciodrv_device_send(const uint8_t *buffer, int length)
}
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Send (2)", send_buf, send_buf_pos);
aciodrv_device_log_buffer(device, "Send (2)", send_buf, send_buf_pos);
#endif
if (aciodrv_port_write(send_buf, send_buf_pos) != send_buf_pos) {
log_warning("Sending data with length %d failed", send_buf_pos);
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) != send_buf_pos) {
log_warning("[%p] Sending data with length %d failed", device->fd, send_buf_pos);
return false;
}
return true;
}
static int aciodrv_device_receive(uint8_t *buffer, int size)
static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *buffer, int max_resp_size)
{
uint8_t recv_buf[512];
int recv_size = 0;
@@ -118,16 +158,14 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
of 0xAAs before we get a valid message. */
recv_buf[0] = AC_IO_SOF;
do {
read = aciodrv_port_read(recv_buf, 1);
read = aciodrv_port_read(device->fd, recv_buf, 1);
} while (recv_buf[0] == AC_IO_SOF);
if (read > 0) {
size += 1;
if (read > 0) {
/* recv_buf[0] is already the first byte of the message.
now read until nothing's left */
recv_size++;
size--;
/* important: we have to know how much data we expect
and have to read until we reach the requested amount.
@@ -135,9 +173,10 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
need to handle escaping (which relies on an up to
date recv_buf[recv_size]) we loop until we get a
non-zero read. */
while (size > 0) {
size_t expected_size = offsetof(struct ac_io_message, cmd.nbytes) + 1;
while (recv_size < expected_size) {
do {
read = aciodrv_port_read(recv_buf + recv_size, 1);
read = aciodrv_port_read(device->fd, recv_buf + recv_size, 1);
} while (read == 0);
if (read < 0) {
@@ -150,7 +189,8 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
/* next byte is our real data
overwrite escape byte */
do {
read = aciodrv_port_read(recv_buf + recv_size, 1);
read = aciodrv_port_read(
device->fd, recv_buf + recv_size, 1);
} while (read == 0);
if (read < 0) {
@@ -161,15 +201,23 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
}
recv_size += read;
size -= read;
if (recv_size > offsetof(struct ac_io_message, cmd.nbytes)) {
// header + data + checksum
expected_size = offsetof(struct ac_io_message, cmd.raw) + ((struct ac_io_message*)recv_buf)->cmd.nbytes + 1;
}
}
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Recv (1)", recv_buf, recv_size);
log_warning("Expected %d got %d", recv_buf[4], recv_size - 6);
aciodrv_device_log_buffer(device, "Recv (1)", recv_buf, recv_size);
log_warning("Expected %d got %d", max_resp_size - 6, recv_buf[4]);
#endif
/* recv_size - 1: omit checksum for checksum calc */
if ((recv_size - 1) > max_resp_size) {
log_warning("[%p] Expected %d got %d", device->fd, max_resp_size - 6, recv_buf[4]);
return -1;
}
for (int i = 0; i < recv_size - 1; i++) {
checksum += recv_buf[i];
buffer[i] = recv_buf[i];
@@ -178,12 +226,13 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
result_size = recv_size - 1;
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Recv (2)", buffer, result_size);
aciodrv_device_log_buffer(device, "Recv (2)", buffer, result_size);
#endif
if (checksum != recv_buf[recv_size - 1]) {
log_warning(
"Invalid message checksum: %02X != %02X",
"[%p] Invalid message checksum: %02X != %02X",
device->fd,
checksum,
recv_buf[recv_size - 1]);
return -1;
@@ -195,7 +244,7 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
return -1;
}
static uint8_t aciodrv_device_enum_nodes(void)
static uint8_t aciodrv_device_enum_nodes(struct aciodrv_device_ctx *device)
{
struct ac_io_message msg;
@@ -205,7 +254,9 @@ static uint8_t aciodrv_device_enum_nodes(void)
msg.cmd.count = 0;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Enumerating nodes failed");
return 0;
}
@@ -215,7 +266,7 @@ static uint8_t aciodrv_device_enum_nodes(void)
return msg.cmd.count;
}
static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
static bool aciodrv_device_get_version(struct aciodrv_device_ctx *device, uint8_t node_id, struct aciodrv_device_node_version *version)
{
struct ac_io_message msg;
@@ -224,6 +275,7 @@ static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
msg.cmd.nbytes = 0;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) +
sizeof(struct ac_io_version))) {
@@ -247,12 +299,15 @@ static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
msg.cmd.version.date,
msg.cmd.version.time);
memcpy(product, msg.cmd.version.product_code, 4);
memcpy(version->product, msg.cmd.version.product_code, ACIO_NODE_PRODUCT_CODE_LEN);
version->major = msg.cmd.version.major;
version->minor = msg.cmd.version.minor;
version->revision = msg.cmd.version.revision;
return true;
}
static bool aciodrv_device_start_node(uint8_t node_id)
static bool aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
@@ -261,7 +316,9 @@ static bool aciodrv_device_start_node(uint8_t node_id)
msg.cmd.nbytes = 0;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting node %d failed", node_id);
return false;
}
@@ -270,80 +327,127 @@ static bool aciodrv_device_start_node(uint8_t node_id)
return true;
}
bool aciodrv_device_open(const char *port, int baud)
// deprecated name
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
{
if (!aciodrv_port_open(port, baud)) {
return aciodrv_device_open_path(port_path, baud);
}
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud)
{
HANDLE port = aciodrv_port_open(port_path, baud);
if (!port) {
return NULL;
}
struct aciodrv_device_ctx *device = xmalloc(sizeof(struct aciodrv_device_ctx));
memset(device, 0, sizeof(struct aciodrv_device_ctx));
device->fd = port;
device->msg_counter = 1;
if (!aciodrv_device_init(device)) {
aciodrv_device_close(device);
return NULL;
}
device->node_count = aciodrv_device_enum_nodes(device);
if (device->node_count == 0) {
aciodrv_device_close(device);
return false;
}
if (!aciodrv_device_init()) {
return false;
}
aciodrv_device_node_count = aciodrv_device_enum_nodes();
if (aciodrv_device_node_count == 0) {
return false;
}
for (uint8_t i = 0; i < aciodrv_device_node_count; i++) {
for (uint8_t i = 0; i < device->node_count; i++) {
if (!aciodrv_device_get_version(
i + 1, aviodrv_device_node_products[i])) {
return false;
device, i + 1, &device->node_versions[i])) {
aciodrv_device_close(device);
return NULL;
}
}
for (uint8_t i = 0; i < aciodrv_device_node_count; i++) {
if (!aciodrv_device_start_node(i + 1)) {
return false;
for (uint8_t i = 0; i < device->node_count; i++) {
if (!aciodrv_device_start_node(device, i + 1)) {
aciodrv_device_close(device);
return NULL;
}
}
return true;
log_info("Opening ACIO device on [%p]", device->fd);
return device;
}
uint8_t aciodrv_device_get_node_count(void)
uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device)
{
return aciodrv_device_node_count;
return device->node_count;
}
bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4])
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN])
{
if (aciodrv_device_node_count == 0 || node_id > aciodrv_device_node_count) {
if (device->node_count == 0 || node_id > device->node_count) {
return false;
}
memcpy(product, aviodrv_device_node_products[node_id], 4);
memcpy(product, device->node_versions[node_id].product, ACIO_NODE_PRODUCT_CODE_LEN);
return true;
}
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
const struct aciodrv_device_node_version *aciodrv_device_get_node_product_version(struct aciodrv_device_ctx *device, uint8_t node_id)
{
msg->cmd.seq_no = aciodrv_device_msg_counter++;
if (device->node_count == 0 || node_id > device->node_count) {
return NULL;
}
return &device->node_versions[node_id];
}
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg)
{
msg->cmd.seq_no = device->msg_counter++;
int send_size = offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes;
#ifdef AC_IO_MSG_LOG
log_info(
"Beginning send on %d: %04x (%d b)",
"[%p] Beginning send on %d: %04x (%d b)",
device->fd,
msg->addr,
msg->cmd.code,
send_size);
#endif
if (aciodrv_device_send((uint8_t *) msg, send_size) <= 0) {
if (aciodrv_device_send(device, (uint8_t *) msg, send_size) <= 0) {
return false;
}
return true;
}
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
{
#ifdef AC_IO_MSG_LOG
log_info("[%p] Beginning recv: (%d b)", device->fd, max_resp_size);
#endif
if (aciodrv_device_receive(device, (uint8_t *) msg, max_resp_size) <= 0) {
return false;
}
return true;
}
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
{
if (!aciodrv_send(device, msg)) {
return false;
}
uint16_t req_code = msg->cmd.code;
#ifdef AC_IO_MSG_LOG
log_info("Beginning recv: (%d b)", resp_size);
#endif
if (aciodrv_device_receive((uint8_t *) msg, resp_size) <= 0) {
if (!aciodrv_recv(device, msg, max_resp_size)) {
return false;
}
if (req_code != msg->cmd.code) {
log_warning(
"Received invalid response %04X for request %04X",
"[%p] Received invalid response %04X for request %04X",
device->fd,
msg->cmd.code,
req_code);
return false;
@@ -352,7 +456,13 @@ bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
return true;
}
void aciodrv_device_close(void)
void aciodrv_device_close(struct aciodrv_device_ctx *device)
{
aciodrv_port_close();
log_assert(device);
log_info("Closing ACIO on [%p]", device->fd);
aciodrv_port_close(device->fd);
free(device);
}

View File

@@ -5,48 +5,109 @@
#include "acio/acio.h"
#include "windows.h"
#define ACIO_NODE_PRODUCT_CODE_LEN 4
struct aciodrv_device_ctx;
struct aciodrv_device_node_version {
char product[ACIO_NODE_PRODUCT_CODE_LEN];
uint8_t major;
uint8_t minor;
uint8_t revision;
};
/**
* Open an ACIO device connected to a serial port.
*
* @param port Port the device is connected to (e.g. "COM1")
* @param baud Baud rate for communication (e.g. 57600 for ICCA)
* @return True if opening the port and resetting the device was successful,
* false on error.
* @return opened device context, NULL on error
*/
bool aciodrv_device_open(const char *port, int baud);
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
#ifdef __GNUC__
__attribute__((deprecated("Use aciomgr instead if device is shareable, else aciodrv_device_open_path")))
#endif
;
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud);
/**
* Get the node count on the opened device.
*
* @param device Context of opened device
* @return Total num of nodes enumerated on the ACIO device.
*/
uint8_t aciodrv_device_get_node_count(void);
uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device);
/**
* Get the product identifier of an enumerated node.
*
* @param device Context of opened device
* @param node_id Id of the node. Needs to be in range of the total node count.
* @param product Buffer to return the product id to.
* @return True on success, false on error. If True the variable product
* contains the identifier of the queried node.
*/
bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4]);
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN]);
/**
* Get the product version of an enumerated node.
*
* @param device Context of opened device
* @param node_id Id of the node. Needs to be in range of the total node count.
* @return Pointer to the version struct
*/
const struct aciodrv_device_node_version *aciodrv_device_get_node_product_version(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Send a message to the ACIO bus and receive an answer.
* Use this to implement the protocol for each type of device that can be
* part of the bus.
*
* @param device Context of opened device
* @param msg Msg to send to the bus. Make sure that the buffer backing
* this message is big enough to receive the response as well.
* @param resp_size Size of the expecting response.
* @return True on success, false on error.
*/
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size);
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
/**
* Send a message to the ACIO bus.
*
* @param device Context of opened device
* @param msg Msg to send to the bus.
* @return True on success, false on error.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for commands which don't trigger a reply.
*/
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg);
/**
* Read a message from the ACIO bus.
*
* @param device Context of opened device
* @param msg Msg to send to the bus. Make sure that the buffer
* is big enough to receive the response.
* @return True on success, false on error.
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for unsollicited incoming messages.
*/
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
/**
* Reset an opened device.
*
* @param device Context of opened device
* @return Total num of nodes enumerated on the ACIO device.
*/
bool aciodrv_device_reset(struct aciodrv_device_ctx *device);
/**
* Close the previously opened ACIO device.
*
* @param device Context of opened device
*/
void aciodrv_device_close(void);
void aciodrv_device_close(struct aciodrv_device_ctx *device);
#endif

45
src/main/aciodrv/h44b.c Normal file
View File

@@ -0,0 +1,45 @@
#define LOG_MODULE "aciodrv-h44b"
#include <stdio.h>
#include <string.h>
#include "acio/h44b.h"
#include "aciodrv/device.h"
#include "util/log.h"
bool aciodrv_h44b_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
// unlike input devices like KFCA, H44B has no watchdog or special init code
// requirements - shared ACIO node initialisation is enough
return true;
}
bool aciodrv_h44b_lights(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_h44b_output *lights)
{
struct ac_io_message msg;
log_assert(device);
log_assert(lights);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_H44B_CMD_SET_OUTPUTS);
msg.cmd.nbytes = sizeof(*lights);
msg.cmd.h44b_output = *lights;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
return true;
}

32
src/main/aciodrv/h44b.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef ACIODRV_H44B_H
#define ACIODRV_H44B_H
#include "aciodrv/device.h"
#include "acio/h44b.h"
/**
* Initialize an H44B node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_h44b_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Set the H44B LEDs
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param lights Packed lights struct to send
* @return True on success, false on error.
*/
bool aciodrv_h44b_lights(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_h44b_output *lights);
#endif

View File

@@ -3,20 +3,27 @@
#include <string.h>
#include "aciodrv/device.h"
#include "aciodrv/icca.h"
#include "util/log.h"
static bool aciodrv_icca_queue_loop_start(uint8_t node_id)
static bool aciodrv_icca_queue_loop_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id;
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_QUEUE_LOOP_START);
msg.cmd.nbytes = 1;
msg.cmd.status = 0;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting queue loop failed");
return false;
}
@@ -27,9 +34,11 @@ static bool aciodrv_icca_queue_loop_start(uint8_t node_id)
return true;
}
bool aciodrv_icca_init(uint8_t node_id)
bool aciodrv_icca_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
if (!aciodrv_icca_queue_loop_start(node_id + 1)) {
log_assert(device);
if (!aciodrv_icca_queue_loop_start(device, node_id + 1)) {
return false;
}
@@ -37,10 +46,15 @@ bool aciodrv_icca_init(uint8_t node_id)
}
bool aciodrv_icca_set_state(
uint8_t node_id, int slot_state, struct ac_io_icca_state *state)
struct aciodrv_device_ctx *device,
uint8_t node_id,
int slot_state,
struct ac_io_icca_state *state)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_SET_SLOT_STATE);
msg.cmd.nbytes = 2;
@@ -49,7 +63,9 @@ bool aciodrv_icca_set_state(
msg.cmd.raw[1] = slot_state;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.raw[0])) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.raw[0])) {
log_warning("Setting state of node %d failed", node_id + 1);
return false;
}
@@ -61,10 +77,15 @@ bool aciodrv_icca_set_state(
return true;
}
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
bool aciodrv_icca_get_state(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_icca_state *state)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_POLL);
msg.cmd.nbytes = 1;
@@ -72,7 +93,9 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
msg.cmd.count = sizeof(struct ac_io_icca_state);
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
log_warning("Getting state of node %d failed", node_id + 1);
return false;
}
@@ -84,10 +107,15 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
return true;
}
bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
bool aciodrv_icca_read_card(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_icca_state *state)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_ENGAGE);
msg.cmd.nbytes = 1;
@@ -95,7 +123,9 @@ bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
msg.cmd.count = sizeof(struct ac_io_icca_state);
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
log_warning("Reading card of node %d failed", node_id + 1);
return false;
}
@@ -105,4 +135,53 @@ bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
}
return true;
}
}
bool aciodrv_icca_is_slotted(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
const struct aciodrv_device_node_version *version;
version = aciodrv_device_get_node_product_version(device, node_id);
// current heuristic is to check if version >= 1.5
if (version) {
if (version->major == 1) {
if (version->minor >= 5) {
return false;
}
}
}
return true;
}
bool aciodrv_icca_poll_felica(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_POLL_FELICA);
msg.cmd.nbytes = 4;
/* buffer size of data we expect */
msg.cmd.count = 1;
// additional data, not sure
msg.cmd.raw[1] = 0x03;
msg.cmd.raw[2] = 0xFF;
msg.cmd.raw[3] = 0xFF;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
log_warning("Reading card of node %d failed", node_id + 1);
return false;
}
return true;
}

View File

@@ -6,17 +6,19 @@
/**
* Initialize an ICCA node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_init(uint8_t node_id);
bool aciodrv_icca_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Set the state of on ICCA node.
*
* @param device Context of opened device
* @param node_id Id of the node to set the state for (0 based).
* @param slot_state State of the slot (refer to corresponding enum).
* @param state Pointer to a state struct to return the current state to
@@ -27,11 +29,15 @@ bool aciodrv_icca_init(uint8_t node_id);
* @see driver.h
*/
bool aciodrv_icca_set_state(
uint8_t node_id, int slot_state, struct ac_io_icca_state *state);
struct aciodrv_device_ctx *device,
uint8_t node_id,
int slot_state,
struct ac_io_icca_state *state);
/**
* Get the current state of an ICCA node.
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
@@ -40,7 +46,10 @@ bool aciodrv_icca_set_state(
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
bool aciodrv_icca_get_state(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_icca_state *state);
/**
* Trigger a card read action on the ICCA reader. Make sure to call this
@@ -48,6 +57,7 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
* to get the most recent card data. Make sure to re-get the state after
* a read call. The state returned here might not be up to date for some reason.
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
@@ -56,6 +66,46 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state);
bool aciodrv_icca_read_card(
struct aciodrv_device_ctx *device,
uint8_t node_id,
struct ac_io_icca_state *state);
#endif
/**
* Uses some heruistics based on the product ident to determine if the detected
* device is a slotted (true) or wavepass reader (false).
*
* This function will also return false if the provided node_id is invalid.
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @return True on slotted, false on wavepass.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_is_slotted(
struct aciodrv_device_ctx *device,
uint8_t node_id);
/**
* Polls the felica chip on wavepass readers. This will cause the state of the
* reader to be AC_IO_ICCA_STATUS_BUSY_NEW for a few polls, before returning
* either: AC_IO_ICCA_STATUS_IDLE_NEW or AC_IO_ICCA_STATUS_GOT_UID.
*
* The user should take care to call this every so often to actually get new
* felica UIDs, instead of just old NFC idents. The game seems to do it every
* 5 or so polls after the last AC_IO_ICCA_STATUS_BUSY_NEW poll.
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @return True on success, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_poll_felica(
struct aciodrv_device_ctx *device,
uint8_t node_id);
#endif

View File

@@ -7,37 +7,35 @@
#include "util/log.h"
static bool aciodrv_kfca_watchdog_start(uint8_t node_id)
static bool aciodrv_kfca_watchdog_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
return true;
/*
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
msg.cmd.nbytes = 2;
msg.cmd.nbytes = 2;
// uint16_t: 6000
msg.cmd.raw[0] = 23;
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) +
2)) { log_warning("Starting watchdog failed"); return false;
if (!aciodrv_send_and_recv(
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2)) {
log_warning("Starting watchdog failed"); return false;
}
log_warning("Started watchdog of node %d, status: %d",
node_id, msg.cmd.status);
log_warning("Started watchdog of node %d, sz: %d, status: %d",
node_id, msg.cmd.nbytes, msg.cmd.status);
return true;
*/
}
bool aciodrv_kfca_amp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t primary,
uint8_t headphone,
@@ -46,6 +44,8 @@ bool aciodrv_kfca_amp(
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
@@ -56,7 +56,9 @@ bool aciodrv_kfca_amp(
msg.cmd.raw[3] = subwoofer;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
@@ -66,13 +68,17 @@ bool aciodrv_kfca_amp(
return true;
}
bool aciodrv_kfca_init(uint8_t node_id)
bool aciodrv_kfca_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
if (!aciodrv_kfca_watchdog_start(node_id)) {
log_assert(device);
if (!aciodrv_kfca_watchdog_start(device, node_id)) {
return false;
}
if (!aciodrv_kfca_amp(node_id, 0, 0, 0, 0)) {
if (!aciodrv_kfca_amp(device, node_id, 0, 0, 0, 0)) {
return false;
}
@@ -80,12 +86,15 @@ bool aciodrv_kfca_init(uint8_t node_id)
}
bool aciodrv_kfca_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_kfca_poll_out *pout,
struct ac_io_kfca_poll_in *pin)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
@@ -93,7 +102,9 @@ bool aciodrv_kfca_poll(
msg.cmd.kfca_poll_out = *pout;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@@ -6,17 +6,19 @@
/**
* Initialize an KFCA node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_kfca_init(uint8_t node_id);
bool aciodrv_kfca_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Poll the KFCA io board
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
@@ -26,6 +28,7 @@ bool aciodrv_kfca_init(uint8_t node_id);
* @see driver.h
*/
bool aciodrv_kfca_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_kfca_poll_out *pout,
struct ac_io_kfca_poll_in *pin);
@@ -33,6 +36,7 @@ bool aciodrv_kfca_poll(
/**
* Set the KFCA digital amp level
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param primary primary volume (96-0)
* @param headphone headphone volume (96-0)
@@ -42,6 +46,7 @@ bool aciodrv_kfca_poll(
* @note Note 96 (or 100?) is lowest volume level, 0 is highest
*/
bool aciodrv_kfca_amp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t primary,
uint8_t headphone,

80
src/main/aciodrv/panb.c Normal file
View File

@@ -0,0 +1,80 @@
#define LOG_MODULE "aciodrv-panb"
#include <string.h>
#include "aciodrv/device.h"
#include "aciodrv/panb.h"
#include "util/thread.h"
#include "util/log.h"
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count)
{
log_assert(device);
struct ac_io_message msg;
/* only the first node is handling the commands */
if (node_id != 0) {
return true;
}
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_START_AUTO_INPUT);
msg.cmd.nbytes = 1;
msg.cmd.count = node_count;
if (!aciodrv_send(device, &msg)) {
log_warning("Starting auto input failed");
return false;
}
log_info("Started auto input for %d nodes", node_count);
return true;
}
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in)
{
log_assert(device);
struct ac_io_message msg;
struct ac_io_panb_poll_in *poll_res = (struct ac_io_panb_poll_in *) &msg.cmd.raw;
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_POLL_REPLY);
msg.cmd.nbytes = sizeof(struct ac_io_panb_poll_in);
if (!aciodrv_recv(device,
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.nbytes + 1)) {
log_warning("Getting state failed");
return false;
}
if (poll_in != NULL){
memcpy(poll_in, poll_res, sizeof(struct ac_io_panb_poll_in));
}
return true;
}
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device,
uint8_t node_id, struct ac_io_panb_poll_out *state)
{
log_assert(device);
struct ac_io_message msg;
/* only the first node is handling the commands */
if (node_id != 0) {
return true;
}
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_SEND_LAMP);
msg.cmd.nbytes = 0x54;
memcpy(&msg.cmd.raw, state, sizeof(struct ac_io_panb_poll_out));
if (!aciodrv_send(device, &msg)) {
log_warning("Sending lamp state failed");
return false;
}
return true;
}

56
src/main/aciodrv/panb.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef ACIODRV_PANB_H
#define ACIODRV_PANB_H
#include "acio/panb.h"
/**
* Send the AC_IO_CMD_PANB_START_AUTO_INPUT command on a PANB device.
*
* @param device Context of opened device.
* @param node_id node_id Id of the node to query (0 based).
* @param node_count The number of nodes to poll.
* @return True if successful, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note Upon calling, the device will stop replying to commands and just keep sending
* AC_IO_CMD_PANB_POLL_REPLY messages indefinitely. Failure to retrieve them fast enough
* will cause the device to malfunction. It is thus advised to make use of the aciodrv-proc
* module to spawn a thread that will handle these messages and provide an easy access to the
* latest input state.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count);
/**
* Retrieve a AC_IO_CMD_PANB_POLL_REPLY message from a PANB device. This assumes that there
* is such message incoming (ie. that start_auto_input has been called prior).
*
* @param device Context of opened device.
* @param poll_in Buffer to hold the received message, or NULL.
* @return True if successful, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note Failure to retrieve the incoming messages fast enough will cause the device to malfunction.
* It is thus advised to make use of the aciodrv-proc module to spawn a thread that will handle these
* messages and provide an easy access to the latest input state.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in);
/**
* Light lamps on a PANB device.
*
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a lamp state struct
* (mandatory).
* @return True on success, false on error.
* @note node_id should be 0, PANB internally manages the other nodes.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device, uint8_t node_id, struct ac_io_panb_poll_out *state);
#endif

View File

@@ -1,5 +1,6 @@
#define LOG_MODULE "aciodrv-port"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
@@ -7,17 +8,15 @@
#include "util/log.h"
static HANDLE aciodrv_port_fd;
bool aciodrv_port_open(const char *port, int baud)
HANDLE aciodrv_port_open(const char *port_path, int baud)
{
COMMTIMEOUTS ct;
DCB dcb;
log_info("Opening ACIO on %s at %d baud", port, baud);
log_info("Opening ACIO on %s at %d baud", port_path, baud);
aciodrv_port_fd = CreateFile(
port,
HANDLE port_fd = CreateFile(
port_path,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
@@ -25,26 +24,26 @@ bool aciodrv_port_open(const char *port, int baud)
FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL,
NULL);
if (aciodrv_port_fd == INVALID_HANDLE_VALUE) {
log_warning("Failed to open %s", port);
if (port_fd == INVALID_HANDLE_VALUE) {
log_warning("Failed to open %s", port_path);
goto early_fail;
}
if (!SetCommMask(aciodrv_port_fd, EV_RXCHAR)) {
if (!SetCommMask(port_fd, EV_RXCHAR)) {
log_warning("SetCommMask failed");
goto fail;
}
if (!SetupComm(aciodrv_port_fd, 0x1000, 0x1000)) {
if (!SetupComm(port_fd, 0x1000, 0x1000)) {
log_warning("SetupComm failed");
goto fail;
}
if (!PurgeComm(
aciodrv_port_fd,
port_fd,
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
log_warning("PurgeComm failed");
@@ -57,7 +56,7 @@ bool aciodrv_port_open(const char *port, int baud)
ct.ReadTotalTimeoutMultiplier = 0;
ct.WriteTotalTimeoutMultiplier = 0;
if (!SetCommTimeouts(aciodrv_port_fd, &ct)) {
if (!SetCommTimeouts(port_fd, &ct)) {
log_warning("SetCommTimeouts failed");
goto fail;
@@ -65,7 +64,7 @@ bool aciodrv_port_open(const char *port, int baud)
dcb.DCBlength = sizeof(dcb);
if (!GetCommState(aciodrv_port_fd, &dcb)) {
if (!GetCommState(port_fd, &dcb)) {
log_warning("GetCommState failed");
goto fail;
@@ -90,46 +89,47 @@ bool aciodrv_port_open(const char *port, int baud)
dcb.XonLim = 100;
dcb.XoffLim = 100;
if (!SetCommState(aciodrv_port_fd, &dcb)) {
if (!SetCommState(port_fd, &dcb)) {
log_warning("SetCommState failed");
goto fail;
}
if (!EscapeCommFunction(aciodrv_port_fd, SETDTR)) {
if (!EscapeCommFunction(port_fd, SETDTR)) {
log_warning("SETDTR failed: err = %lu", GetLastError());
goto fail;
}
log_info("Opened ACIO device on %s", port);
log_info("[%p] Opened ACIO device on %s", port_fd, port_path);
return true;
return port_fd;
fail:
CloseHandle(aciodrv_port_fd);
CloseHandle(port_fd);
early_fail:
aciodrv_port_fd = NULL;
return false;
return NULL;
}
int aciodrv_port_read(void *bytes, int nbytes)
int aciodrv_port_read(HANDLE port_fd, void *bytes, int nbytes)
{
DWORD nread;
if (aciodrv_port_fd == NULL) {
log_assert(bytes);
if (port_fd == NULL) {
return -1;
}
if (!ClearCommError(aciodrv_port_fd, NULL, NULL)) {
log_warning("ClearCommError failed");
if (!ClearCommError(port_fd, NULL, NULL)) {
log_warning("[%p] ClearCommError failed", port_fd);
return -1;
}
if (!ReadFile(aciodrv_port_fd, bytes, nbytes, &nread, NULL)) {
log_warning("ReadFile failed: err = %lu", GetLastError());
if (!ReadFile(port_fd, bytes, nbytes, &nread, NULL)) {
log_warning("[%p] ReadFile failed: err = %lu", port_fd, GetLastError());
return -1;
}
@@ -137,16 +137,18 @@ int aciodrv_port_read(void *bytes, int nbytes)
return nread;
}
int aciodrv_port_write(const void *bytes, int nbytes)
int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes)
{
DWORD nwrit;
if (aciodrv_port_fd == NULL) {
log_assert(bytes);
if (port_fd == NULL) {
return -1;
}
if (!WriteFile(aciodrv_port_fd, bytes, nbytes, &nwrit, NULL)) {
log_warning("WriteFile failed: err = %lu", GetLastError());
if (!WriteFile(port_fd, bytes, nbytes, &nwrit, NULL)) {
log_warning("[%p] WriteFile failed: err = %lu", port_fd, GetLastError());
return -1;
}
@@ -154,9 +156,9 @@ int aciodrv_port_write(const void *bytes, int nbytes)
return nwrit;
}
void aciodrv_port_close(void)
void aciodrv_port_close(HANDLE port_fd)
{
if (aciodrv_port_fd != NULL) {
CloseHandle(aciodrv_port_fd);
if (port_fd != NULL) {
CloseHandle(port_fd);
}
}

View File

@@ -4,39 +4,45 @@
#include <stdbool.h>
#include <stdint.h>
#include <windows.h>
/**
* Open a serial port for communication with a ACIO device.
*
* @param port Port the device is connected to (e.g. "COM1")
* @param baud Baud rate for communication (e.g. 57600 for ICCA)
* @return True if opening the com port was successful, false on error.
* @return HANDLE of the port, NULL on error
* @note This will open and setup the com port, only.
*/
bool aciodrv_port_open(const char *port, int baud);
HANDLE aciodrv_port_open(const char *port_path, int baud);
/**
* Read data from the opened com port.
*
* @param port_fd HANDLE of opened serial port
* @param bytes Pointer to an allocated buffer to read the data into.
* @param nbytes Number of bytes to read. Has to be less or equal the allocated
* buffer size.
* @return Number of bytes read on success or -1 on error.
*/
int aciodrv_port_read(void *bytes, int nbytes);
int aciodrv_port_read(HANDLE port_fd, void *bytes, int nbytes);
/**
* Write data to the opened com port.
*
* @param port_fd HANDLE of opened serial port
* @param bytes Pointer to an allocated buffer with data to write.
* @param nbytes Number of bytes to write. Has to be equal or less the size
* of the allocated buffer.
* @return Number of bytes written on success or -1 on error.
*/
int aciodrv_port_write(const void *bytes, int nbytes);
int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes);
/**
* Close the previously opened com port.
*
* @param port_fd HANDLE of opened serial port
*/
void aciodrv_port_close(void);
void aciodrv_port_close(HANDLE port_fd);
#endif

View File

@@ -134,6 +134,7 @@ static HRESULT ac_io_emu_write(struct ac_io_emu *emu, struct irp *irp)
break;
}
// this supplies a single SOF byte per byte read
ac_io_in_supply(&emu->in, NULL, 0);
ac_io_out_consume_message(&emu->out);
}

View File

@@ -61,7 +61,7 @@ void ac_io_emu_h44b_dispatch_request(
req->cmd.raw[i * 3 + 2]);
}
jb_io_write_outputs();
jb_io_write_lights();
ac_io_emu_h44b_send_status(h44b, req, 0x00);

View File

@@ -29,13 +29,6 @@ enum ac_io_icca_flag {
AC_IO_ICCA_FLAG_SOLENOID = 0x40
};
enum ac_io_icca_status_code {
AC_IO_ICCA_STATUS_FAULT = 0x00,
AC_IO_ICCA_STATUS_IDLE = 0x01,
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04
};
static void ac_io_emu_icca_cmd_send_version(
struct ac_io_emu_icca *icca, const struct ac_io_message *req);

View File

@@ -169,6 +169,10 @@ static void ac_io_emu_iccb_send_state(
/* state update */
if (!eam_io_poll(iccb->unit_no)) {
log_warning("Polling eamio failed");
}
sensor = eam_io_get_sensor_state(iccb->unit_no);
if (sensor != iccb->last_sensor) {

View File

@@ -0,0 +1,9 @@
dlls += aciomgr
libs_aciomgr := \
aciodrv \
util \
src_aciomgr := \
dllmain.c \
manager.c \

View File

@@ -0,0 +1,12 @@
LIBRARY aciomgr
EXPORTS
aciomgr_set_loggers
aciomgr_port_init
aciomgr_port_fini
aciomgr_get_node_count
aciomgr_get_node_product_ident
aciomgr_port_submit_packet
aciomgr_port_checkout
aciomgr_port_checkin
DllMain@12 @1 NONAME

View File

@@ -0,0 +1,16 @@
#include <windows.h>
#include "manager-init.h"
BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
{
if (reason == DLL_PROCESS_ATTACH) {
_aciomgr_init();
}
if (reason == DLL_PROCESS_DETACH) {
_aciomgr_fini();
}
return TRUE;
}

View File

@@ -0,0 +1,8 @@
#ifndef ACIOMGR_MANAGER_INIT_H
#define ACIOMGR_MANAGER_INIT_H
// internal, used by DllMain
void _aciomgr_init();
void _aciomgr_fini();
#endif

210
src/main/aciomgr/manager.c Normal file
View File

@@ -0,0 +1,210 @@
#define LOG_MODULE "aciomgr-manager"
#include <windows.h>
#include <stdatomic.h>
#include "aciomgr/manager-init.h"
#include "aciomgr/manager.h"
#include "acio/acio.h"
#include "aciodrv/device.h"
#include "util/array.h"
#include "util/log.h"
#define MAX_PORT_PATH_LENGTH 256
struct aciomgr_port_dispatcher {
CRITICAL_SECTION cs;
atomic_size_t references;
struct aciodrv_device_ctx *device;
char path[MAX_PORT_PATH_LENGTH];
int baud;
bool has_failure;
};
static void _aciomgr_setup_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher, const char *path, int baud);
static void
_aciomgr_destroy_port_dispatcher(struct aciomgr_port_dispatcher *dispatcher);
// DLL-globals
static atomic_bool running;
static CRITICAL_SECTION mgr_cs;
static struct array active_ports;
static void _aciomgr_setup_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher, const char *path, int baud)
{
InitializeCriticalSection(&dispatcher->cs);
strcpy(dispatcher->path, path);
dispatcher->baud = baud;
dispatcher->device = aciodrv_device_open_path(path, baud);
dispatcher->has_failure = false;
if (dispatcher->device == NULL) {
log_info("Opening ACIO device on %s failed", path);
dispatcher->has_failure = true;
}
dispatcher->references = 0;
}
static void
_aciomgr_destroy_port_dispatcher(struct aciomgr_port_dispatcher *dispatcher)
{
aciodrv_device_close(dispatcher->device);
DeleteCriticalSection(&dispatcher->cs);
}
void _aciomgr_init()
{
if (running) {
log_warning("_aciomgr_init called when already running");
_aciomgr_fini();
}
InitializeCriticalSection(&mgr_cs);
array_init(&active_ports);
running = true;
}
void _aciomgr_fini()
{
if (!running) {
log_warning("_aciomgr_fini called when not running");
}
running = false;
DeleteCriticalSection(&mgr_cs);
array_fini(&active_ports);
}
void aciomgr_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
log_to_external(misc, info, warning, fatal);
}
struct aciomgr_port_dispatcher *aciomgr_port_init(const char *path, int baud)
{
if (!running) {
log_warning("aciomgr_port_init: called when not running");
return NULL;
}
if (strlen(path) >= MAX_PORT_PATH_LENGTH) {
log_warning("aciomgr_port_init: path too long");
return NULL;
}
struct aciomgr_port_dispatcher *entry;
EnterCriticalSection(&mgr_cs);
for (size_t i = 0; i < active_ports.nitems; i++) {
entry = array_item(struct aciomgr_port_dispatcher, &active_ports, i);
if (strcmp(entry->path, path) == 0) {
// found
if (entry->baud != baud) {
log_warning(
"Device at %s opened with baud of %d, but requested %d",
path,
entry->baud,
baud);
}
goto done;
}
}
entry = array_append(struct aciomgr_port_dispatcher, &active_ports);
_aciomgr_setup_port_dispatcher(entry, path, baud);
done:
if (!entry->has_failure) {
entry->references++;
}
LeaveCriticalSection(&mgr_cs);
if (entry->has_failure) {
return NULL;
}
return entry;
}
void aciomgr_port_fini(struct aciomgr_port_dispatcher *dispatcher)
{
if (!running) {
log_warning("aciomgr_port_fini: called when not running");
return;
}
EnterCriticalSection(&mgr_cs);
dispatcher->references--;
LeaveCriticalSection(&mgr_cs);
if (dispatcher->references == 0) {
_aciomgr_destroy_port_dispatcher(dispatcher);
}
}
// this function don't require the lock
uint8_t aciomgr_get_node_count(struct aciomgr_port_dispatcher *dispatcher)
{
return aciodrv_device_get_node_count(dispatcher->device);
}
// this function don't require the lock
bool aciomgr_get_node_product_ident(
struct aciomgr_port_dispatcher *dispatcher,
uint8_t node_id,
char product[ACIOMGR_NODE_PRODUCT_CODE_LEN])
{
return aciodrv_device_get_node_product_ident(
dispatcher->device, node_id, product);
}
bool aciomgr_port_submit_packet(
struct aciomgr_port_dispatcher *dispatcher,
struct ac_io_message *msg,
int max_resp_size)
{
// CS's although lightweight, may still be a burden, short circuit
if (dispatcher->references > 1) {
EnterCriticalSection(&dispatcher->cs);
bool response =
aciodrv_send_and_recv(dispatcher->device, msg, max_resp_size);
LeaveCriticalSection(&dispatcher->cs);
return response;
}
return aciodrv_send_and_recv(dispatcher->device, msg, max_resp_size);
}
struct aciodrv_device_ctx *
aciomgr_port_checkout(struct aciomgr_port_dispatcher *dispatcher)
{
if (dispatcher->references > 1) {
EnterCriticalSection(&dispatcher->cs);
}
return dispatcher->device;
}
void aciomgr_port_checkin(struct aciomgr_port_dispatcher *dispatcher)
{
if (dispatcher->references > 1) {
LeaveCriticalSection(&dispatcher->cs);
}
}

View File

@@ -0,0 +1,86 @@
#ifndef ACIOMGR_MANAGER_H
#define ACIOMGR_MANAGER_H
#include <stdbool.h>
#include "bemanitools/glue.h"
#define ACIOMGR_NODE_PRODUCT_CODE_LEN 4
struct ac_io_message;
struct aciodrv_device_ctx;
struct aciomgr_port_dispatcher;
/**
* The first function that will be called on your DLL. You will be supplied
* with four function pointers that may be used to log messages to the game's
* log file. See comments in glue.h for further information.
*/
void aciomgr_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal);
/**
* Init and open, or return the existing handle to an acio port
*
* @param path Port the device is connected to (e.g. "COM1")
* @return opened port dispatcher context, NULL on error
*/
struct aciomgr_port_dispatcher *aciomgr_port_init(const char *path, int baud);
void aciomgr_port_fini(struct aciomgr_port_dispatcher *dispatcher);
/**
* Get the node count on the opened device.
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @return Total num of nodes enumerated on the ACIO device.
*/
uint8_t aciomgr_get_node_count(struct aciomgr_port_dispatcher *dispatcher);
/**
* Get the product identifier of an enumerated node.
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @param node_id Id of the node. Needs to be in range of the total node count.
* @param product Buffer to return the product id to.
* @return True on success, false on error. If True the variable product
* contains the identifier of the queried node.
*/
bool aciomgr_get_node_product_ident(
struct aciomgr_port_dispatcher *dispatcher,
uint8_t node_id,
char product[ACIOMGR_NODE_PRODUCT_CODE_LEN]);
/**
* Submit and wait for the response of the specified packet
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @param msg pointer to the message buffer to read from / write to
* @param max_resp_size pointer to the max size response we expect
* @return false on error
*/
bool aciomgr_port_submit_packet(
struct aciomgr_port_dispatcher *dispatcher,
struct ac_io_message *msg,
int max_resp_size);
/**
* Checkout the device handler for this port dispatcher on this thread
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @return the device context
*/
struct aciodrv_device_ctx *
aciomgr_port_checkout(struct aciomgr_port_dispatcher *dispatcher);
/**
* Checkin the device handler that this thread holds
*
* @param dispatcher dispatcher context from aciomgr_port_init
*/
void aciomgr_port_checkin(struct aciomgr_port_dispatcher *dispatcher);
#endif

View File

@@ -3,10 +3,12 @@ exes += aciotest
libs_aciotest := \
bio2drv \
aciodrv \
aciodrv-proc \
util \
src_aciotest := \
icca.c \
kfca.c \
bi2a-sdvx.c \
panb.c \
main.c \

View File

@@ -8,22 +8,24 @@
#include "bio2drv/bi2a-sdvx.h"
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx)
bool aciotest_bi2a_sdvx_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t *) *ctx) = 0;
return bio2drv_bi2a_sdvx_init(node_id);
return bio2drv_bi2a_sdvx_init(device, node_id);
}
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx)
bool aciotest_bi2a_sdvx_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
struct bi2a_sdvx_state_in pin;
struct bi2a_sdvx_state_out pout;
memset(&pout, 0, sizeof(pout));
if (!bio2drv_bi2a_sdvx_poll(node_id, &pout, &pin)) {
if (!bio2drv_bi2a_sdvx_poll(device, node_id, &pout, &pin)) {
return false;
}

View File

@@ -4,7 +4,11 @@
#include <stdbool.h>
#include <stdint.h>
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx);
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx);
#include "aciodrv/device.h"
bool aciotest_bi2a_sdvx_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_bi2a_sdvx_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
#endif

View File

@@ -1,6 +1,8 @@
#ifndef ACIOTEST_HANDLER_H
#define ACIOTEST_HANDLER_H
#include "aciodrv/device.h"
static const uint8_t aciotest_handler_max = 16;
/**
@@ -8,8 +10,10 @@ static const uint8_t aciotest_handler_max = 16;
*/
struct aciotest_handler_node_handler {
void *ctx;
bool (*init)(uint8_t node_id, void **ctx);
bool (*update)(uint8_t node_id, void *ctx);
bool (*init)(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool (*update)(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
};
#endif

View File

@@ -5,29 +5,52 @@
#include "aciodrv/icca.h"
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t *) *ctx) = 0;
return aciodrv_icca_init(node_id);
#define IDLE_RESPONSES_BETWEEN_FELICA_POLLS 5
struct icca_handler_ctx {
bool init;
bool slotted_reader;
uint8_t last_poll;
};
bool aciotest_icca_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(struct icca_handler_ctx));
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)*ctx;
icca_ctx->init = false;
icca_ctx->slotted_reader = true;
icca_ctx->last_poll = 0;
icca_ctx->slotted_reader = aciodrv_icca_is_slotted(device, node_id);
return aciodrv_icca_init(device, node_id);
}
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx)
bool aciotest_icca_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
if (*((uint32_t *) ctx) == 0) {
*((uint32_t *) ctx) = 1;
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)ctx;
/* eject cards that were left in the reader */
if (!aciodrv_icca_set_state(
node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
return false;
if (icca_ctx->init == false) {
icca_ctx->init = true;
if (icca_ctx->slotted_reader) {
/* eject cards that were left in the reader */
if (!aciodrv_icca_set_state(
device, node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
return false;
}
}
}
struct ac_io_icca_state state;
if (!aciodrv_icca_get_state(node_id, &state)) {
if (!aciodrv_icca_get_state(device, node_id, &state)) {
return false;
}
@@ -58,33 +81,48 @@ bool aciotest_icca_handler_update(uint8_t node_id, void *ctx)
state.key_events[0],
state.key_events[1]);
/* eject card with "empty" key */
if (state.key_state & AC_IO_ICCA_KEYPAD_MASK_EMPTY) {
if (!aciodrv_icca_set_state(
node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
return false;
}
}
/* allow new card to be inserted when slot is clear */
if (!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
if (!aciodrv_icca_set_state(
node_id, AC_IO_ICCA_SLOT_STATE_OPEN, NULL)) {
return false;
}
}
/* lock the card when fully inserted */
if ((state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
if (!aciodrv_icca_set_state(
node_id, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL)) {
return false;
if (icca_ctx->slotted_reader) {
/* eject card with "empty" key */
if (state.key_state & AC_IO_ICCA_KEYPAD_MASK_EMPTY) {
if (!aciodrv_icca_set_state(
device, node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
return false;
}
}
if (!aciodrv_icca_read_card(node_id, NULL)) {
return false;
/* allow new card to be inserted when slot is clear */
if (!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
if (!aciodrv_icca_set_state(
device, node_id, AC_IO_ICCA_SLOT_STATE_OPEN, NULL)) {
return false;
}
}
/* lock the card when fully inserted */
if ((state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
if (!aciodrv_icca_set_state(
device, node_id, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL)) {
return false;
}
if (!aciodrv_icca_read_card(device, node_id, NULL)) {
return false;
}
}
} else {
// wavepass reader, see eamio-icca for why this is done this way
if (state.status_code != AC_IO_ICCA_STATUS_BUSY_NEW) {
++icca_ctx->last_poll;
}
if (icca_ctx->last_poll >= IDLE_RESPONSES_BETWEEN_FELICA_POLLS) {
if (!aciodrv_icca_poll_felica(device, node_id)) {
return false;
}
icca_ctx->last_poll = 0;
}
}

View File

@@ -4,7 +4,11 @@
#include <stdbool.h>
#include <stdint.h>
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx);
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx);
#include "aciodrv/device.h"
bool aciotest_icca_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_icca_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
#endif

View File

@@ -8,15 +8,17 @@
#include "aciodrv/kfca.h"
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx)
bool aciotest_kfca_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t *) *ctx) = 0;
return aciodrv_kfca_init(node_id);
return aciodrv_kfca_init(device, node_id);
}
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx)
bool aciotest_kfca_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
struct ac_io_kfca_poll_in pin;
struct ac_io_kfca_poll_out pout;
@@ -28,7 +30,7 @@ bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx)
pout.gpio |= 1 << gpio_test_pin;
pout.gpio = ac_io_u32(pout.gpio);
if (!aciodrv_kfca_poll(node_id, &pout, &pin)) {
if (!aciodrv_kfca_poll(device, node_id, &pout, &pin)) {
return false;
}

View File

@@ -4,7 +4,11 @@
#include <stdbool.h>
#include <stdint.h>
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx);
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx);
#include "aciodrv/device.h"
bool aciotest_kfca_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_kfca_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
#endif

View File

@@ -10,6 +10,7 @@
#include "aciotest/handler.h"
#include "aciotest/icca.h"
#include "aciotest/kfca.h"
#include "aciotest/panb.h"
#include "util/log.h"
@@ -37,6 +38,13 @@ static bool aciotest_assign_handler(
return true;
}
if (!memcmp(product, "PANB", 4)) {
handler->init = aciotest_panb_handler_init;
handler->update = aciotest_panb_handler_update;
return true;
}
if (!memcmp(product, "BI2A", 4)) {
if (bi2a_mode == 0) {
handler->init = aciotest_bi2a_sdvx_handler_init;
@@ -70,14 +78,17 @@ int main(int argc, char **argv)
log_to_writer(log_writer_stdout, NULL);
if (!aciodrv_device_open(argv[1], atoi(argv[2]))) {
struct aciodrv_device_ctx *device = aciodrv_device_open_path(argv[1], atoi(argv[2]));
if (!device) {
printf("Opening acio device failed\n");
return -1;
}
printf("Opening acio device successful\n");
uint8_t node_count = aciodrv_device_get_node_count();
uint8_t node_count = aciodrv_device_get_node_count(device);
printf("Enumerated %d nodes\n", node_count);
struct aciotest_handler_node_handler handler[aciotest_handler_max];
@@ -88,7 +99,7 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciodrv_device_get_node_product_ident(i, product);
aciodrv_device_get_node_product_ident(device, i, product);
printf(
"> %d: %c%c%c%c\n",
i + 1,
@@ -110,7 +121,7 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].init != NULL) {
if (!handler[i].init(i, &handler[i].ctx)) {
if (!handler[i].init(device, i, &handler[i].ctx)) {
printf("ERROR: Initializing node %d failed\n", i);
handler[i].update = NULL;
}
@@ -129,7 +140,7 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].update != NULL) {
if (!handler[i].update(i, handler[i].ctx)) {
if (!handler[i].update(device, i, handler[i].ctx)) {
printf("ERROR: Updating node %d, removed from loop\n", i);
handler[i].update = NULL;
Sleep(5000);

76
src/main/aciotest/panb.c Normal file
View File

@@ -0,0 +1,76 @@
#include "aciotest/panb.h"
#include <stdio.h>
#include <stdlib.h>
#include "aciodrv/panb.h"
#include "aciodrv-proc/panb.h"
struct panb_handler_ctx {
bool running;
};
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
if (node_id != 0) {
return true;
}
*ctx = malloc(sizeof(struct panb_handler_ctx));
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx*)*ctx;
panb_ctx->running = true;
return aciodrv_proc_panb_init(device);
}
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
uint8_t button[AC_IO_PANB_MAX_KEYS];
struct ac_io_panb_poll_out state;
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx *) ctx;
if (node_id != 0) {
return true;
}
if (!panb_ctx->running) {
printf(">>> PANB:\nDevice has been closed. Press Ctrl+C to exit.");
return true;
}
if (!aciodrv_proc_panb_get_state(button)) {
return false;
}
printf(">>> PANB:\nPress first and last keys to close device\n");
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
printf("%01X ", button[i]);
}
printf("\n");
/* I added a key combo to properly close the module.
* Leaving the PANB device in autopolling state without ever
* reading packets from the serial interface eventually
* makes it fall into a state where it doesn't send anything anymore
* and won't even respond to a reset, thus requiring a power cycle.
*/
if (button[0] && button[AC_IO_PANB_MAX_KEYS-1]) {
aciodrv_proc_panb_fini(device);
panb_ctx->running = false;
return true;
}
/* light the panel */
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
state.key[i].green = (button[i])? 0x7F : 0;
state.key[i].red = 0;
state.key[i].blue = (button[i])? 0x23 : 0;
}
if (!aciodrv_panb_send_lamp(device, node_id, &state)) {
return false;
}
return true;
}

12
src/main/aciotest/panb.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef ACIOTEST_PANB_H
#define ACIOTEST_PANB_H
#include <stdbool.h>
#include <stdint.h>
#include "aciodrv/device.h"
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
#endif

View File

@@ -29,6 +29,17 @@ enum jb_io_panel_bit {
JB_IO_PANEL_16 = 0x0F,
};
/* input "single button mode" mappings. Allows you to check each corner of each
button to determine any flaky inputs
*/
enum jb_io_panel_mode {
JB_IO_PANEL_MODE_ALL = 0, // any of the four corners will trigger a panel
JB_IO_PANEL_MODE_TOP_LEFT = 1,
JB_IO_PANEL_MODE_TOP_RIGHT = 2,
JB_IO_PANEL_MODE_BOTTOM_RIGHT = 3,
JB_IO_PANEL_MODE_BOTTOM_LEFT = 4,
};
/* Bit mappings for "system" inputs */
enum jb_io_sys_bit {
JB_IO_SYS_TEST = 0x00,
@@ -73,17 +84,36 @@ bool jb_io_init(
void jb_io_fini(void);
/* TODO doc */
/* Read input state */
bool jb_io_read_inputs(void);
bool jb_io_write_outputs(void);
/* Get state of coin, test, service inputs */
uint8_t jb_io_get_sys_inputs(void);
/* Get panel button state. Will return either any button being pressed, or a
particular panel corner depending on previous call to jb_io_set_panel_mode */
uint16_t jb_io_get_panel_inputs(void);
/* Set state of a PWM (dimmable) light */
void jb_io_set_rgb_led(
enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b);
/* Transmit the light state to the IOPCB */
bool jb_io_write_lights(void);
/* Select operating mode for the panel. Should be immediately sent to the IOPCB */
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode);
/* Open or close the coin chute - true will redirect all coins to the return
slot. Required for jb_io_set_panel_mode to operate correctly on p4io.
Should be immediately sent to the IOPCB */
bool jb_io_set_coin_blocker(bool blocked);
#endif

View File

@@ -14,17 +14,23 @@
// in all inputs and outputs (over sub IO) other than 14 keys to not work.
static const uint8_t _BIO2DR_BI2A_IIDX_INIT_DATA = 0x2D;
static bool bio2drv_bi2a_iidx_init_io(uint8_t node_id)
static bool bio2drv_bi2a_iidx_init_io(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_INIT);
msg.cmd.nbytes = 1;
msg.cmd.param = _BIO2DR_BI2A_IIDX_INIT_DATA;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
@@ -34,8 +40,12 @@ static bool bio2drv_bi2a_iidx_init_io(uint8_t node_id)
return 1;
}
static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
static bool bio2drv_bi2a_iidx_watchdog_start(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
log_assert(device);
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
@@ -47,14 +57,13 @@ static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
msg.cmd.nbytes = 2;
msg.cmd.nbytes = 2;
// uint16_t: 6000
msg.cmd.raw[0] = 23;
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2
)) {
log_warning("Starting watchdog failed"); return false;
}
@@ -66,13 +75,15 @@ static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
*/
}
bool bio2drv_bi2a_iidx_init(uint8_t node_id)
bool bio2drv_bi2a_iidx_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
if (!bio2drv_bi2a_iidx_init_io(node_id)) {
log_assert(device);
if (!bio2drv_bi2a_iidx_init_io(device, node_id)) {
return false;
}
if (!bio2drv_bi2a_iidx_watchdog_start(node_id)) {
if (!bio2drv_bi2a_iidx_watchdog_start(device, node_id)) {
return false;
}
@@ -80,12 +91,15 @@ bool bio2drv_bi2a_iidx_init(uint8_t node_id)
}
bool bio2drv_bi2a_iidx_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct bi2a_iidx_state_out *pout,
struct bi2a_iidx_state_in *pin)
{
struct ac_io_message msg;
// log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_POLL);
msg.cmd.nbytes = sizeof(*pout);
@@ -93,7 +107,9 @@ bool bio2drv_bi2a_iidx_poll(
*(struct bi2a_iidx_state_out *) msg.cmd.raw = *pout;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@@ -1,22 +1,28 @@
#ifndef BIO2DRV_BI2A_IIDX_H
#define BIO2DRV_BI2A_IIDX_H
#include "aciodrv/device.h"
#include "bio2/bi2a-iidx.h"
/**
* Initialize a BI2A node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_iidx_init(uint8_t node_id);
bool bio2drv_bi2a_iidx_init(
struct aciodrv_device_ctx *device,
uint8_t node_id);
/**
* Poll the BI2A board
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
@@ -26,6 +32,7 @@ bool bio2drv_bi2a_iidx_init(uint8_t node_id);
* @see driver.h
*/
bool bio2drv_bi2a_iidx_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct bi2a_iidx_state_out *pout,
struct bi2a_iidx_state_in *pin);

View File

@@ -12,17 +12,21 @@
static const uint8_t _BIO2DR_BI2A_SDVX_INIT_DATA = 0x3B;
// this is probably InitIO
static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
static bool bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t node_id)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_INIT);
msg.cmd.nbytes = 1;
msg.cmd.param = _BIO2DR_BI2A_SDVX_INIT_DATA;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
@@ -32,8 +36,10 @@ static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
return 1;
}
static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
static bool bio2drv_bi2a_sdvx_watchdog_start(struct aciodrv_device_ctx *device, uint8_t node_id)
{
log_assert(device);
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
@@ -52,7 +58,7 @@ static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2
)) {
log_warning("Starting watchdog failed"); return false;
}
@@ -65,6 +71,7 @@ static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
}
bool bio2drv_bi2a_sdvx_amp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,
@@ -73,6 +80,8 @@ bool bio2drv_bi2a_sdvx_amp(
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
@@ -86,7 +95,9 @@ bool bio2drv_bi2a_sdvx_amp(
msg.cmd.raw[3] = right;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
@@ -96,17 +107,19 @@ bool bio2drv_bi2a_sdvx_amp(
return true;
}
bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
bool bio2drv_bi2a_sdvx_init(struct aciodrv_device_ctx *device, uint8_t node_id)
{
if (!bio2drv_bi2a_sdvx_init_io(node_id)) {
log_assert(device);
if (!bio2drv_bi2a_sdvx_init_io(device, node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_watchdog_start(node_id)) {
if (!bio2drv_bi2a_sdvx_watchdog_start(device, node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_amp(node_id, 0, 0, 0, 0)) {
if (!bio2drv_bi2a_sdvx_amp(device, node_id, 0, 0, 0, 0)) {
return false;
}
@@ -114,12 +127,15 @@ bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
}
bool bio2drv_bi2a_sdvx_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin)
{
struct ac_io_message msg;
// log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
@@ -127,7 +143,9 @@ bool bio2drv_bi2a_sdvx_poll(
*(struct bi2a_sdvx_state_out *) msg.cmd.raw = *pout;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@@ -1,22 +1,28 @@
#ifndef BIO2DRV_BI2A_H
#define BIO2DRV_BI2A_H
#ifndef BIO2DRV_BI2A_SDVX_H
#define BIO2DRV_BI2A_SDVX_H
#include "aciodrv/device.h"
#include "bio2/bi2a-sdvx.h"
/**
* Initialize a BI2A node.
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
bool bio2drv_bi2a_sdvx_init(
struct aciodrv_device_ctx *device,
uint8_t node_id);
/**
* Poll the board
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
@@ -26,6 +32,7 @@ bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin);
@@ -33,6 +40,7 @@ bool bio2drv_bi2a_sdvx_poll(
/**
* Set the BIO2 BI2A SDVX digital amp level
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param primary primary volume (96-0)
* @param headphone headphone volume (96-0)
@@ -42,6 +50,7 @@ bool bio2drv_bi2a_sdvx_poll(
* @note Note 96 is lowest volume level, 0 is highest
*/
bool bio2drv_bi2a_sdvx_amp(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,

View File

@@ -341,14 +341,14 @@ static HRESULT my_MFEnumDeviceSources(
for (UINT32 i = 0; i < nsrcs; ++i) {
api = (*pppSourceActivate)[i];
ret = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
if (ret != S_OK) {
log_warning("Wrapping com proxy failed: %08lx", ret);
return ret;
}
api_vtbl = api_proxy->vptr;
real_GetAllocatedString = api_vtbl->GetAllocatedString;

View File

@@ -13,6 +13,8 @@
#define D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY "gfx.confined"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_WIDTH_KEY "gfx.window_width"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_HEIGHT_KEY "gfx.window_height"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY "gfx.window_x"
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY "gfx.window_y"
#define D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY "gfx.forced_refresh_rate"
#define D3D9EXHOOK_CONFIG_GFX_DEVICE_ADAPTER_KEY "gfx.device_adapter"
#define D3D9EXHOOK_CONFIG_GFX_FORCE_ORIENTATION_KEY "gfx.force_orientation"
@@ -24,6 +26,8 @@
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE false
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCED_RR_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_DEVICE_ADAPTER_VALUE -1
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCE_ORIENTATION_VALUE -1
@@ -62,6 +66,18 @@ void d3d9exhook_config_gfx_init(struct cconfig *config)
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE,
"Windowed height, -1 for default size");
cconfig_util_set_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE,
"Windowed X, -1 for default X position");
cconfig_util_set_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE,
"Windowed Y, -1 for default Y position");
cconfig_util_set_int(
config,
D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY,
@@ -161,6 +177,30 @@ void d3d9exhook_config_gfx_get(
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE);
}
if (!cconfig_util_get_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
&config_gfx->window_x,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE);
}
if (!cconfig_util_get_int(
config,
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
&config_gfx->window_y,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE);
}
if (!cconfig_util_get_int(
config,
D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY,

View File

@@ -15,6 +15,8 @@ struct d3d9exhook_config_gfx {
bool confined;
int32_t window_width;
int32_t window_height;
int32_t window_x;
int32_t window_y;
int32_t forced_refresh_rate;
int32_t device_adapter;
int32_t force_orientation;

View File

@@ -45,6 +45,18 @@ static HRESULT STDCALL my_CreateDeviceEx(
D3DDISPLAYMODEEX *fdm,
IDirect3DDevice9Ex **pdev);
static HRESULT STDCALL my_EnumAdapterModes(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format,
UINT Mode,
D3DDISPLAYMODE *pMode);
static UINT STDCALL my_GetAdapterModeCount(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format);
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api);
static WNDPROC real_WndProc;
@@ -88,12 +100,25 @@ static bool d3d9ex_confined;
static int32_t d3d9ex_force_refresh_rate = -1;
static int32_t d3d9ex_window_width = -1;
static int32_t d3d9ex_window_height = -1;
static int32_t d3d9ex_window_x = -1;
static int32_t d3d9ex_window_y = -1;
static bool d3d9ex_window_framed;
static int32_t d3d9ex_device_adapter = -1;
static int32_t d3d9ex_force_orientation = -1;
static int32_t d3d9ex_force_screen_res_width = -1;
static int32_t d3d9ex_force_screen_res_height = -1;
static bool check_d3d9ex_force_enum()
{
if (d3d9ex_force_refresh_rate != -1 &&
d3d9ex_force_screen_res_width != -1 &&
d3d9ex_force_screen_res_height != -1) {
return true;
}
return false;
}
/* ------------------------------------------------------------------------- */
static const struct hook_symbol d3d9ex_hook_syms[] = {
@@ -130,11 +155,16 @@ static HWND STDCALL my_CreateWindowExA(
HINSTANCE hInstance,
LPVOID lpParam)
{
if (d3d9ex_windowed && d3d9ex_window_framed) {
/* use a different style */
dwStyle |= WS_OVERLAPPEDWINDOW;
/* also show mouse cursor */
ShowCursor(TRUE);
if (d3d9ex_windowed) {
if (d3d9ex_window_framed) {
/* use a different style */
dwStyle |= WS_OVERLAPPEDWINDOW;
/* also show mouse cursor */
ShowCursor(TRUE);
} else {
dwStyle = dwStyle & ~WS_OVERLAPPEDWINDOW;
ShowCursor(FALSE);
}
}
HWND hwnd = real_CreateWindowExA(
@@ -157,11 +187,7 @@ static HWND STDCALL my_CreateWindowExA(
static BOOL STDCALL
my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
{
if (d3d9ex_windowed && d3d9ex_window_framed) {
/* we have to adjust the window size, because the window needs to be a
slightly bigger than the rendering resolution (window caption and
stuff is included in the window size) */
if (d3d9ex_windowed) {
if (d3d9ex_window_width != -1 && d3d9ex_window_height != -1) {
log_misc(
"Overriding window size from %dx%d with %dx%d",
@@ -173,14 +199,31 @@ my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
nWidth = d3d9ex_window_width;
nHeight = d3d9ex_window_height;
}
if (d3d9ex_window_x != -1 && d3d9ex_window_y != -1) {
log_misc(
"Overriding window position from %dx%d with %dx%d",
X,
Y,
d3d9ex_window_x,
d3d9ex_window_y);
WINDOWPOS wp;
calc_win_size_with_framed(hWnd, X, Y, nWidth, nHeight, &wp);
SetWindowPos(hWnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
X = wp.x;
Y = wp.y;
nWidth = wp.cx;
nHeight = wp.cy;
X = d3d9ex_window_x;
Y = d3d9ex_window_y;
}
if (d3d9ex_window_framed) {
/* we have to adjust the window size, because the window needs to
be a slightly bigger than the rendering resolution (window caption
and stuff is included in the window size) */
WINDOWPOS wp;
calc_win_size_with_framed(hWnd, X, Y, nWidth, nHeight, &wp);
SetWindowPos(hWnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
X = wp.x;
Y = wp.y;
nWidth = wp.cx;
nHeight = wp.cy;
}
}
BOOL result = real_MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
@@ -392,6 +435,54 @@ static HRESULT STDCALL my_CreateDeviceEx(
return hr;
}
static HRESULT STDCALL my_EnumAdapterModes(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format,
UINT Mode,
D3DDISPLAYMODE *pMode)
{
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
HRESULT hr;
if (d3d9ex_device_adapter>= 0) {
Adapter = d3d9ex_device_adapter;
}
hr = IDirect3D9Ex_EnumAdapterModes(real, Adapter, Format, Mode, pMode);
if (check_d3d9ex_force_enum()) {
log_info("EnumAdapterModes: Forcing mode");
pMode->Width = d3d9ex_force_screen_res_width;
pMode->Height = d3d9ex_force_screen_res_height;
pMode->RefreshRate = d3d9ex_force_refresh_rate;
}
return hr;
}
static UINT STDCALL my_GetAdapterModeCount(
IDirect3D9Ex *self,
UINT Adapter,
D3DFORMAT Format)
{
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
UINT res;
if (d3d9ex_device_adapter>= 0) {
Adapter = d3d9ex_device_adapter;
}
res = IDirect3D9Ex_GetAdapterModeCount(real, Adapter, Format);
if (check_d3d9ex_force_enum()) {
log_info("GetAdapterModeCount: Forcing single return");
res = 1;
}
return res;
}
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
{
HRESULT hr;
@@ -414,6 +505,8 @@ static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDeviceEx = my_CreateDeviceEx;
api_vtbl->EnumAdapterModes = my_EnumAdapterModes;
api_vtbl->GetAdapterModeCount = my_GetAdapterModeCount;
*api = (IDirect3D9Ex *) api_proxy;
@@ -451,6 +544,8 @@ void d3d9ex_configure(struct d3d9exhook_config_gfx *gfx_config)
d3d9ex_window_framed = gfx_config->framed;
d3d9ex_window_width = gfx_config->window_width;
d3d9ex_window_height = gfx_config->window_height;
d3d9ex_window_x = gfx_config->window_x;
d3d9ex_window_y = gfx_config->window_y;
d3d9ex_force_refresh_rate = gfx_config->forced_refresh_rate;
d3d9ex_device_adapter = gfx_config->device_adapter;

View File

@@ -3,7 +3,10 @@ dlls += \
libs_eamio-icca := \
aciodrv \
aciomgr \
cconfig \
util \
src_eamio-icca := \
config-icc.c \
eamio-icca.c \

View File

@@ -0,0 +1,55 @@
#include "cconfig/cconfig-util.h"
#include "eamio-icca/config-icc.h"
#include "util/log.h"
#define EAMIO_ICCA_CONFIG_ICC_PORT_KEY "icc.port"
#define EAMIO_ICCA_CONFIG_ICC_BAUD_KEY "icc.baud"
#define EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE "COM1"
#define EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE 57600
void eamio_icca_config_icc_init(struct cconfig *config)
{
cconfig_util_set_str(
config,
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE,
"ICCA serial port");
cconfig_util_set_int(
config,
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE,
"ICCA bus baudrate (real devices expect 57600)");
}
void eamio_icca_config_icc_get(
struct icc_config *config_icc, struct cconfig *config)
{
if (!cconfig_util_get_str(
config,
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
config_icc->port,
sizeof(config_icc->port) - 1,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE);
}
if (!cconfig_util_get_int(
config,
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
&config_icc->baud,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE);
}
}

View File

@@ -0,0 +1,18 @@
#ifndef EAMIO_ICCA_CONFIG_ICC_H
#define EAMIO_ICCA_CONFIG_ICC_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct icc_config {
char port[64];
int32_t baud;
};
void eamio_icca_config_icc_init(struct cconfig *config);
void eamio_icca_config_icc_get(
struct icc_config *config_icc, struct cconfig *config);
#endif

View File

@@ -8,13 +8,21 @@
#include <stdint.h>
#include <stdio.h>
#include "aciomgr/manager.h"
#include "aciodrv/device.h"
#include "aciodrv/icca.h"
#include "bemanitools/eamio.h"
#include "cconfig/cconfig-main.h"
#include "eamio-icca/config-icc.h"
#include "util/log.h"
#define IDLE_RESPONSES_BETWEEN_FELICA_POLLS 5
#define NUMBER_OF_EMULATED_READERS 2
#define INVALID_NODE_ID -1
static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_3,
EAM_IO_KEYPAD_6,
@@ -32,7 +40,16 @@ static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_5,
EAM_IO_KEYPAD_8};
static struct ac_io_icca_state eam_io_icca_state[2];
static struct ac_io_icca_state eam_io_icca_state[NUMBER_OF_EMULATED_READERS];
static struct aciomgr_port_dispatcher *acio_manager_ctx;
static int32_t icca_node_id[NUMBER_OF_EMULATED_READERS];
static bool icca_is_slotted[NUMBER_OF_EMULATED_READERS];
static int32_t icca_poll_counter[NUMBER_OF_EMULATED_READERS];
static uint8_t icca_last_nonbusy_state[NUMBER_OF_EMULATED_READERS];
void eam_io_set_loggers(
log_formatter_t misc,
@@ -40,30 +57,113 @@ void eam_io_set_loggers(
log_formatter_t warning,
log_formatter_t fatal)
{
aciomgr_set_loggers(misc, info, warning, fatal);
log_to_external(misc, info, warning, fatal);
}
// all of these are referred to internally as ICCA
static bool check_if_icca(int node_id)
{
char product[ACIOMGR_NODE_PRODUCT_CODE_LEN];
aciomgr_get_node_product_ident(acio_manager_ctx, node_id, product);
if (!memcmp(product, "ICCA", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
return true;
}
if (!memcmp(product, "ICCB", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
return true;
}
if (!memcmp(product, "ICCC", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
return true;
}
return false;
}
bool eam_io_init(
thread_create_t create, thread_join_t join, thread_destroy_t destroy)
{
if (!aciodrv_device_open("COM1", 57600)) {
log_warning("Opening acio device on COM1 failed");
struct cconfig *config;
struct icc_config config_icc;
config = cconfig_init();
eamio_icca_config_icc_init(config);
if (!cconfig_main_config_init(
config,
"--icc-config",
"eamio-icc.conf",
"--help",
"-h",
"eamio-icca",
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
cconfig_finit(config);
exit(EXIT_FAILURE);
}
eamio_icca_config_icc_get(&config_icc, config);
cconfig_finit(config);
acio_manager_ctx = aciomgr_port_init(config_icc.port, config_icc.baud);
if (acio_manager_ctx == NULL) {
log_warning("Opening acio device on %s failed", config_icc.port);
return false;
}
for (uint8_t i = 0; i < 2; i++) {
if (!aciodrv_icca_init(i)) {
log_warning("Initializing icca %d failed", i);
return false;
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
for (uint8_t i = 0; i < NUMBER_OF_EMULATED_READERS; i++) {
icca_node_id[i] = INVALID_NODE_ID;
for (uint8_t nid = 0; nid < aciomgr_get_node_count(acio_manager_ctx); ++nid) {
if (check_if_icca(nid)) {
bool existing_reader = false;
for (uint8_t j = 0; j < i; j++) {
if (nid == icca_node_id[j]) {
existing_reader = true;
break;
}
}
if (existing_reader) {
continue;
}
icca_node_id[i] = nid;
icca_poll_counter[i] = 0;
icca_is_slotted[i] = aciodrv_icca_is_slotted(device, nid);
icca_last_nonbusy_state[i] = 0;
log_misc("ICC reader %d is_slotted: %d", nid, icca_is_slotted[i]);
if (!aciodrv_icca_init(device, icca_node_id[i])) {
log_warning("Initializing icca %d failed", i);
icca_node_id[i] = INVALID_NODE_ID;
continue;
}
break;
}
}
}
if (icca_node_id[0] == INVALID_NODE_ID) {
log_warning("No ICC readers detected");
return false;
}
aciomgr_port_checkin(acio_manager_ctx);
return true;
}
void eam_io_fini(void)
{
aciodrv_device_close();
aciomgr_port_fini(acio_manager_ctx);
}
uint16_t eam_io_get_keypad_state(uint8_t unit_no)
@@ -85,13 +185,31 @@ uint8_t eam_io_get_sensor_state(uint8_t unit_no)
{
uint8_t sensors = 0;
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_BACK);
}
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_FRONT);
if (icca_is_slotted[unit_no]) {
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_BACK);
}
if ((eam_io_icca_state[unit_no].sensor_state &
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
sensors |= (1 << EAM_IO_SENSOR_FRONT);
}
} else {
// wavepass readers always report (EAM_IO_SENSOR_BACK + EAM_IO_SENSOR_FRONT) + type
// but because we can't report status_code back directly
// and libacio actually just ignores the sensor_state other then the type
// we just return this state like we're a slotted reader so the emulation takes card of it
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_GOT_UID) {
sensors |= (1 << EAM_IO_SENSOR_BACK);
sensors |= (1 << EAM_IO_SENSOR_FRONT);
}
// continue reporting last state during busy
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_BUSY_NEW) {
sensors = icca_last_nonbusy_state[unit_no];
} else {
icca_last_nonbusy_state[unit_no] = sensors;
}
}
return sensors;
@@ -109,33 +227,78 @@ uint8_t eam_io_read_card(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes)
bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd)
{
// this node is not setup, just return "success""
if (icca_node_id[unit_no] == INVALID_NODE_ID) {
return true;
}
// ignore these for wavepass
if (!icca_is_slotted[unit_no]) {
return true;
}
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
bool response = false;
switch (cmd) {
case EAM_IO_CARD_SLOT_CMD_CLOSE:
return aciodrv_icca_set_state(
unit_no, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
case EAM_IO_CARD_SLOT_CMD_OPEN:
return aciodrv_icca_set_state(
unit_no, AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
case EAM_IO_CARD_SLOT_CMD_EJECT:
return aciodrv_icca_set_state(
unit_no, AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
response = aciodrv_icca_set_state(
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
case EAM_IO_CARD_SLOT_CMD_READ:
return aciodrv_icca_read_card(unit_no, NULL) &&
aciodrv_icca_get_state(unit_no, &eam_io_icca_state[unit_no]);
response = aciodrv_icca_read_card(device, icca_node_id[unit_no], NULL) &&
aciodrv_icca_get_state(
device, icca_node_id[unit_no], &eam_io_icca_state[unit_no]);
default:
break;
}
aciomgr_port_checkin(acio_manager_ctx);
return false;
return response;
}
bool eam_io_poll(uint8_t unit_no)
{
return aciodrv_icca_get_state(unit_no, &eam_io_icca_state[unit_no]);
// this node is not setup, just return "success""
if (icca_node_id[unit_no] == INVALID_NODE_ID) {
return true;
}
bool response = aciodrv_icca_get_state(
aciomgr_port_checkout(acio_manager_ctx),
icca_node_id[unit_no],
&eam_io_icca_state[unit_no]);
aciomgr_port_checkin(acio_manager_ctx);
if (response && !icca_is_slotted[unit_no]) {
// we handle wavepass a bit differently to handle polling felica
if (eam_io_icca_state[unit_no].status_code != AC_IO_ICCA_STATUS_BUSY_NEW) {
++icca_poll_counter[unit_no];
}
// we must manually call this every few polls to actually update the felica state
// we don't do it every poll, since card polling isn't that time sensitive of an operation
// libacio does it every 5ish polls after the last AC_IO_ICCA_STATUS_BUSY_NEW message
if (icca_poll_counter[unit_no] >= IDLE_RESPONSES_BETWEEN_FELICA_POLLS) {
response = aciodrv_icca_poll_felica(
aciomgr_port_checkout(acio_manager_ctx),
icca_node_id[unit_no]);
aciomgr_port_checkin(acio_manager_ctx);
icca_poll_counter[unit_no] = 0;
}
}
return response;
}
const struct eam_io_config_api *eam_io_get_config_api(void)

View File

@@ -15,6 +15,8 @@
*/
int main(int argc, char **argv)
{
log_to_writer(log_writer_stdout, NULL);
eam_io_set_loggers(
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);

View File

@@ -25,16 +25,11 @@ struct file_entry {
static struct array hooked_files;
static CRITICAL_SECTION hooked_files_cs;
BOOL my_GetFileInformationByHandle(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
BOOL (*real_GetFileInformationByHandle)(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
BOOL (*real_GetFileInformationByHandle)
(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
static const struct hook_symbol memfile_hook_kernel32_syms[] = {
{.name = "GetFileInformationByHandle",
@@ -42,7 +37,6 @@ static const struct hook_symbol memfile_hook_kernel32_syms[] = {
.link = (void **) &real_GetFileInformationByHandle},
};
void memfile_hook_init(void)
{
array_init(&hooked_files);
@@ -82,7 +76,10 @@ void memfile_hook_fini(void)
}
void memfile_hook_add_fd(
const char *path, enum memfile_hook_path_mode path_mode, const void *data, uint32_t sz)
const char *path,
enum memfile_hook_path_mode path_mode,
const void *data,
uint32_t sz)
{
log_assert(path != NULL);
@@ -110,7 +107,11 @@ void memfile_hook_add_fd(
LeaveCriticalSection(&hooked_files_cs);
log_misc("memfile_hook_add_fd: path %s, mode %d, data size %d", path, path_mode, sz);
log_misc(
"memfile_hook_add_fd: path %s, mode %d, data size %d",
path,
path_mode,
sz);
}
static struct file_entry *memfile_hook_match_irp(const struct irp *irp)
@@ -155,7 +156,10 @@ static HRESULT memfile_hook_irp_read(struct file_entry *entry, struct irp *irp)
size_t nread = min(entry->sz - entry->pos, irp->read.nbytes);
if (nread > 0) {
memcpy(irp->read.bytes + irp->read.pos, (uint8_t*)entry->data + entry->pos, nread);
memcpy(
irp->read.bytes + irp->read.pos,
(uint8_t *) entry->data + entry->pos,
nread);
entry->pos += nread;
irp->read.pos += nread;
@@ -248,9 +252,7 @@ HRESULT memfile_hook_dispatch_irp(struct irp *irp)
// this isn't a standard iohook IRP atm.
BOOL my_GetFileInformationByHandle(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
)
HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
{
struct file_entry *entry;
for (size_t i = 0; i < hooked_files.nitems; i++) {

View File

@@ -32,7 +32,10 @@ enum memfile_hook_path_mode {
* @param sz size of file
*/
void memfile_hook_add_fd(
const char *path, enum memfile_hook_path_mode path_mode, const void *data, uint32_t sz);
const char *path,
enum memfile_hook_path_mode path_mode,
const void *data,
uint32_t sz);
/**
* iohook dispatch function. Needs to be installed.

View File

@@ -38,6 +38,8 @@ static struct bi2a_iidx_state_in pin_cur;
static struct bi2a_iidx_state_out pout_staging;
static struct bi2a_iidx_state_out pout_ready;
static struct aciodrv_device_ctx *bio2_device_ctx;
static bool _bio2_iidx_io_poll(
const struct bi2a_iidx_state_out *pout, struct bi2a_iidx_state_in *pin)
{
@@ -47,7 +49,7 @@ static bool _bio2_iidx_io_poll(
processing_io = true;
if (!bio2drv_bi2a_iidx_poll(bio2_node_id, pout, pin)) {
if (!bio2drv_bi2a_iidx_poll(bio2_device_ctx, bio2_node_id, pout, pin)) {
processing_io = false;
return false;
}
@@ -114,14 +116,17 @@ bool iidx_io_init(
}
}
if (!aciodrv_device_open(selected_port, config_bio2.baud)) {
// BIO2's cannot share a bus with anything else, so use device directly
bio2_device_ctx = aciodrv_device_open_path(selected_port, config_bio2.baud);
if (bio2_device_ctx == NULL) {
log_info("Opening BIO2 device on [%s] failed", selected_port);
return 0;
}
log_info("Opening BIO2 device on [%s] successful", selected_port);
uint8_t node_count = aciodrv_device_get_node_count();
uint8_t node_count = aciodrv_device_get_node_count(bio2_device_ctx);
log_info("Enumerated %d nodes", node_count);
bio2_node_id = -1;
@@ -129,7 +134,7 @@ bool iidx_io_init(
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciodrv_device_get_node_product_ident(i, product);
aciodrv_device_get_node_product_ident(bio2_device_ctx, i, product);
log_info(
"> %d: %c%c%c%c\n",
@@ -150,7 +155,7 @@ bool iidx_io_init(
if (bio2_node_id != -1) {
log_warning("Using BI2A on node: %d", bio2_node_id);
if (!bio2drv_bi2a_iidx_init(bio2_node_id)) {
if (!bio2drv_bi2a_iidx_init(bio2_device_ctx, bio2_node_id)) {
log_warning("Unable to start BI2A on node: %d", bio2_node_id);
return false;
}
@@ -182,7 +187,7 @@ void iidx_io_fini(void)
Sleep(1);
}
aciodrv_device_close();
aciodrv_device_close(bio2_device_ctx);
}
void iidx_io_ep1_set_deck_lights(uint16_t deck_lights)

View File

@@ -222,7 +222,7 @@ static bool debugger_create_process(
if (!ok) {
log_warning(
"ERRPR: Failed to launch hooked EXE: %08x", (unsigned int) GetLastError());
"ERROR: Failed to launch hooked EXE: %08x", (unsigned int) GetLastError());
free(cmd_line);
@@ -592,4 +592,4 @@ void debugger_finit(bool failure)
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}

View File

@@ -42,9 +42,10 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info("--- Begin jbhook dll_entry_init ---");
if (!options.disable_p4ioemu) {
p4ioemu_init(jbhook_io_init());
iohook_push_handler(p4ioemu_dispatch_irp);
iohook_push_handler(ac_io_port_dispatch_irp);
if (!options.disable_p4ioemu) {
log_info("Starting up jubeat IO backend");
jb_io_set_loggers(
@@ -56,11 +57,12 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
if (!jb_io_ok) {
goto fail;
}
hook_setupapi_init(&p4ioemu_setupapi_data);
p4ioemu_init(jbhook_io_init());
}
if (!options.disable_cardemu) {
ac_io_port_init();
log_info("Starting up card reader backend");
eam_io_set_loggers(
@@ -72,6 +74,9 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
if (!eam_io_ok) {
goto fail;
}
rs232_hook_init();
ac_io_port_init();
}
log_info("--- End jbhook dll_entry_init ---");
@@ -128,21 +133,10 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
app_hook_init(my_dll_entry_init, my_dll_entry_main);
iohook_push_handler(p4ioemu_dispatch_irp);
iohook_push_handler(ac_io_port_dispatch_irp);
if (!options.disable_adapteremu) {
adapter_hook_init();
}
if (!options.disable_cardemu) {
rs232_hook_init();
}
if (!options.disable_p4ioemu) {
hook_setupapi_init(&p4ioemu_setupapi_data);
}
gfx_hook_init();
jbhook_eamuse_hook_init();

View File

@@ -8,16 +8,10 @@
#include "jbhook/io.h"
#include "p4io/cmd.h"
#include "util/log.h"
enum jbhook_io_p4io_command {
JUHOOK_IO_P4IO_CMD_OUTPUTS = 0x18,
};
struct jbhook_io_p4io_outputs {
uint32_t outputs;
};
static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes);
static uint32_t jbhook_command_handle(
uint8_t cmd,
@@ -91,6 +85,7 @@ static const uint32_t jbhook_io_panel_mappings[] = {
static const uint32_t jbhook_io_sys_button_mappings[] = {
(1 << 28),
(1 << 25),
(1 << 24),
};
static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes)
@@ -116,7 +111,7 @@ static void jbhook_io_jamma2_read(void *resp, uint32_t nbytes)
}
}
for (uint8_t i = 0; i < 2; i++) {
for (uint8_t i = 0; i < 3; i++) {
if (buttons & (1 << i)) {
*inputs |= jbhook_io_sys_button_mappings[i];
}
@@ -131,19 +126,56 @@ static uint32_t jbhook_command_handle(
uint32_t resp_max_len)
{
switch (cmd) {
case JUHOOK_IO_P4IO_CMD_OUTPUTS: {
// const struct jbhook_io_p4io_outputs* req =
// (const struct jbhook_io_p4io_outputs*) payload;
// log_misc("JUHOOK_IO_P4IO_CMD_OUTPUTS: 0x%X", req->outputs);
/* coin blocker: off 0x20, on 0x00 */
case P4IO_CMD_COINSTOCK: {
// on is 0x00, off is either 0x10 or 0x20 depending on whether it's
// during gameplay (0x10) or test menu (0x20). Both seem to have the
// same effect
jb_io_set_coin_blocker(*(uint8_t*)payload == 0x00);
// this actually returns the coinstock, don't care for it
memset(resp, 0, 4);
return 4;
}
case P4IO_CMD_SET_PORTOUT: {
const struct p4io_req_panel_mode *req =
(const struct p4io_req_panel_mode *) payload;
// always fallback to ALL if input is unknown
enum jb_io_panel_mode mode = JB_IO_PANEL_MODE_ALL;
if(req->is_single) {
switch(req->mode) {
case 0x0001:
mode = JB_IO_PANEL_MODE_TOP_LEFT;
break;
case 0x0000:
mode = JB_IO_PANEL_MODE_TOP_RIGHT;
break;
case 0x0101:
mode = JB_IO_PANEL_MODE_BOTTOM_LEFT;
break;
case 0x0100:
mode = JB_IO_PANEL_MODE_BOTTOM_RIGHT;
break;
default:
mode = JB_IO_PANEL_MODE_ALL;
break;
}
}
jb_io_set_panel_mode(mode);
memset(resp, 0, 1);
return 1;
}
default:
return 0xFFFFFFFF;
}

View File

@@ -8,4 +8,6 @@ EXPORTS
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_rgb_led
jb_io_write_outputs
jb_io_set_coin_blocker
jb_io_set_panel_mode
jb_io_write_lights

View File

@@ -119,7 +119,7 @@ bool jb_io_read_inputs(void)
return true;
}
bool jb_io_write_outputs(void)
bool jb_io_write_lights(void)
{
return true;
}
@@ -139,3 +139,14 @@ void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
// I mean I guess there's reactive LEDs on the sides? I'm not going to the
// effort to work out if they're controllable or not
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
// panel always returns merged input state, no corner support
return true;
}
bool jb_io_set_coin_blocker(bool blocked)
{
return true;
}

View File

@@ -0,0 +1,16 @@
dlls += jbio-p4io
ldflags_jbio-p4io := \
-lsetupapi
src_jbio-p4io := \
config-h44b.c \
h44b.c \
jbio.c \
libs_jbio-p4io := \
aciodrv \
aciomgr \
cconfig \
p4iodrv \
util \

View File

@@ -0,0 +1,55 @@
#include "cconfig/cconfig-util.h"
#include "jbio-p4io/config-h44b.h"
#include "util/log.h"
#define JBIO_CONFIG_H44B_PORT_KEY "h44b.port"
#define JBIO_CONFIG_H44B_BAUD_KEY "h44b.baud"
#define JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE "COM2"
#define JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE 57600
void jbio_config_h44b_init(struct cconfig *config)
{
cconfig_util_set_str(
config,
JBIO_CONFIG_H44B_PORT_KEY,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE,
"H44B serial port");
cconfig_util_set_int(
config,
JBIO_CONFIG_H44B_BAUD_KEY,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE,
"H44B bus baudrate (real devices expect 57600)");
}
void jbio_config_h44b_get(
struct h44b_config *config_h44b, struct cconfig *config)
{
if (!cconfig_util_get_str(
config,
JBIO_CONFIG_H44B_PORT_KEY,
config_h44b->port,
sizeof(config_h44b->port) - 1,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
JBIO_CONFIG_H44B_PORT_KEY,
JBIO_CONFIG_H44B_DEFAULT_PORT_VALUE);
}
if (!cconfig_util_get_int(
config,
JBIO_CONFIG_H44B_BAUD_KEY,
&config_h44b->baud,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
JBIO_CONFIG_H44B_BAUD_KEY,
JBIO_CONFIG_H44B_DEFAULT_BAUD_VALUE);
}
}

View File

@@ -0,0 +1,18 @@
#ifndef JBIO_CONFIG_H44B_H
#define JBIO_CONFIG_H44B_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct h44b_config {
char port[64];
int32_t baud;
};
void jbio_config_h44b_init(struct cconfig *config);
void jbio_config_h44b_get(
struct h44b_config *config_h44b, struct cconfig *config);
#endif

101
src/main/jbio-p4io/h44b.c Normal file
View File

@@ -0,0 +1,101 @@
#define LOG_MODULE "jbio-h44b"
#include <stdatomic.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "aciodrv/h44b.h"
#include "aciomgr/manager.h"
#include "util/log.h"
static int16_t h44b_node_id;
static atomic_bool running;
static struct aciomgr_port_dispatcher *acio_manager_ctx;
bool jb_io_h44b_init(const char *port, int32_t baud) {
acio_manager_ctx = aciomgr_port_init(port, baud);
if (acio_manager_ctx == NULL) {
log_info("Opening acio device on [%s] failed", port);
return false;
}
log_info("Opening acio device successful");
uint8_t node_count = aciomgr_get_node_count(acio_manager_ctx);
log_info("Enumerated %d nodes", node_count);
h44b_node_id = -1;
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciomgr_get_node_product_ident(acio_manager_ctx, i, product);
log_info(
"> %d: %c%c%c%c",
i,
product[0],
product[1],
product[2],
product[3]);
if (!memcmp(product, "H44B", 4)) {
if (h44b_node_id != -1) {
log_warning("Multiple H44B found! Using highest node id.");
}
h44b_node_id = i;
}
}
if (h44b_node_id != -1) {
log_warning("Using H44B on node: %d", h44b_node_id);
bool init_result = aciodrv_h44b_init(
aciomgr_port_checkout(acio_manager_ctx),
h44b_node_id);
aciomgr_port_checkin(acio_manager_ctx);
if (!init_result) {
log_warning("Unable to start H44B on node: %d", h44b_node_id);
return false;
}
running = true;
log_warning("jbio-h44b now running");
} else {
log_warning("No H44B device found");
}
return running;
}
bool jb_io_h44b_fini(void) {
aciomgr_port_fini(acio_manager_ctx);
return true;
}
bool jb_io_h44b_write_lights(struct ac_io_h44b_output *lights) {
if (!running) {
return false;
}
bool amp_result = aciodrv_h44b_lights(
aciomgr_port_checkout(acio_manager_ctx),
h44b_node_id,
lights);
aciomgr_port_checkin(acio_manager_ctx);
if (!amp_result) {
return false;
}
return true;
}

View File

@@ -0,0 +1,7 @@
#include <stdbool.h>
#include "acio/h44b.h"
bool jb_io_h44b_init(const char *port, int32_t baud);
bool jb_io_h44b_fini(void);
bool jb_io_h44b_write_lights(struct ac_io_h44b_output *lights);

View File

@@ -0,0 +1,13 @@
LIBRARY jbio
EXPORTS
jb_io_fini
jb_io_get_panel_inputs
jb_io_get_sys_inputs
jb_io_init
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_rgb_led
jb_io_set_panel_mode
jb_io_set_coin_blocker
jb_io_write_lights

229
src/main/jbio-p4io/jbio.c Normal file
View File

@@ -0,0 +1,229 @@
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <setupapi.h>
#include <stdlib.h>
// clang-format on
#include "aciomgr/manager.h"
#include "cconfig/cconfig-main.h"
#include "bemanitools/jbio.h"
#include "jbio-p4io/config-h44b.h"
#include "jbio-p4io/h44b.h"
#include "p4iodrv/device.h"
#include "util/log.h"
static struct p4iodrv_ctx *p4io_ctx;
static uint16_t jb_io_panels;
static uint8_t jb_io_sys_buttons;
static bool lights_present;
static struct ac_io_h44b_output jb_io_lights;
static struct ac_io_h44b_output jb_io_new_lights;
static bool coin_blocked;
void jb_io_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
aciomgr_set_loggers(misc, info, warning, fatal);
log_to_external(misc, info, warning, fatal);
}
bool jb_io_init(
thread_create_t thread_create,
thread_join_t thread_join,
thread_destroy_t thread_destroy)
{
struct cconfig *config;
struct h44b_config config_h44b;
config = cconfig_init();
jbio_config_h44b_init(config);
if (!cconfig_main_config_init(
config,
"--h44b-config",
"jbio-h44b.conf",
"--help",
"-h",
"jbio-h44b",
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
cconfig_finit(config);
exit(EXIT_FAILURE);
}
jbio_config_h44b_get(&config_h44b, config);
cconfig_finit(config);
p4io_ctx = p4iodrv_open();
if(!p4io_ctx) {
return false;
}
// some people use p4io just for inputs and have no lights. Soft fail when
// h44b is not able to be connected instead of returning false
lights_present = jb_io_h44b_init(config_h44b.port, config_h44b.baud);
if(!lights_present) {
log_warning("Could not connect to H44B, lights disabled");
}
return true;
}
void jb_io_fini(void)
{
p4iodrv_close(p4io_ctx);
}
static const uint32_t jb_io_panel_mappings[] = {
(1 << 5),
(1 << 1),
(1 << 13),
(1 << 9),
(1 << 6),
(1 << 2),
(1 << 14),
(1 << 10),
(1 << 7),
(1 << 3),
(1 << 15),
(1 << 11),
(1 << 16),
(1 << 4),
(1 << 20),
(1 << 12),
};
static const uint32_t jb_io_sys_button_mappings[] = {
(1 << 28),
(1 << 25),
};
bool jb_io_read_inputs(void)
{
uint32_t jamma[4];
if(!p4iodrv_read_jamma(p4io_ctx, jamma)) {
return false;
}
jb_io_panels = 0;
jb_io_sys_buttons = 0;
// panel is active low
uint32_t panel_in = ~jamma[0];
for (uint8_t i = 0; i < 16; i++) {
if (panel_in & jb_io_panel_mappings[i]) {
jb_io_panels |= 1 << i;
}
}
// sys is active high
for (uint8_t i = 0; i < 2; i++) {
if (jamma[0] & jb_io_sys_button_mappings[i]) {
jb_io_sys_buttons |= 1 << i;
}
}
return true;
}
bool jb_io_write_lights(void)
{
if(lights_present && memcmp(&jb_io_lights, &jb_io_new_lights, sizeof(jb_io_lights))) {
memcpy(&jb_io_lights, &jb_io_new_lights, sizeof(jb_io_lights));
return jb_io_h44b_write_lights(&jb_io_lights);
}
return true;
}
uint8_t jb_io_get_sys_inputs(void)
{
return jb_io_sys_buttons;
}
uint16_t jb_io_get_panel_inputs(void)
{
return jb_io_panels;
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
struct p4io_req_panel_mode panel_mode = {0};
panel_mode.is_single = 1;
switch(mode) {
case JB_IO_PANEL_MODE_ALL:
panel_mode.is_single = 0;
panel_mode.mode = 0;
break;
case JB_IO_PANEL_MODE_TOP_LEFT:
panel_mode.mode = 0x0001;
break;
case JB_IO_PANEL_MODE_TOP_RIGHT:
panel_mode.mode = 0x0000;
break;
case JB_IO_PANEL_MODE_BOTTOM_LEFT:
panel_mode.mode = 0x0101;
break;
case JB_IO_PANEL_MODE_BOTTOM_RIGHT:
panel_mode.mode = 0x0100;
break;
}
return p4iodrv_cmd_portout(p4io_ctx, (uint8_t*)&panel_mode);
}
void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
{
uint8_t *light;
switch(unit) {
case JB_IO_RGB_LED_FRONT:
light = jb_io_new_lights.front_rgb;
break;
case JB_IO_RGB_LED_TOP:
light = jb_io_new_lights.top_rgb;
break;
case JB_IO_RGB_LED_LEFT:
light = jb_io_new_lights.left_rgb;
break;
case JB_IO_RGB_LED_RIGHT:
light = jb_io_new_lights.right_rgb;
break;
case JB_IO_RGB_LED_TITLE:
light = jb_io_new_lights.title_rgb;
break;
case JB_IO_RGB_LED_WOOFER:
light = jb_io_new_lights.woofer_rgb;
break;
default:
return;
}
light[0] = r;
light[1] = g;
light[2] = b;
}
bool jb_io_set_coin_blocker(bool blocked) {
coin_blocked = blocked;
uint8_t coin[4] = {0};
coin[0] = coin_blocked ? 0x00 : 0x20;
return p4iodrv_cmd_coinstock(p4io_ctx, coin);
}

View File

@@ -102,7 +102,7 @@ bool jb_io_read_inputs(void)
return true;
}
bool jb_io_write_outputs(void)
bool jb_io_write_lights(void)
{
/* The generic input stack currently initiates lighting sends and input
reads simultaneously, though this might change later. Perform all of our
@@ -122,9 +122,20 @@ uint16_t jb_io_get_panel_inputs(void)
return jb_io_panels;
}
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode)
{
// geninput only uses 1 switch per panel, so ignore alternate modes
return true;
}
bool jb_io_set_coin_blocker(bool blocked)
{
return true;
}
void jb_io_set_rgb_led(enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b)
{
mapper_write_light(unit * 3, r);
mapper_write_light(unit * 3 + 1, g);
mapper_write_light(unit * 3 + 2, b);
}
}

View File

@@ -7,5 +7,7 @@ EXPORTS
jb_io_init
jb_io_read_inputs
jb_io_set_loggers
jb_io_set_panel_mode
jb_io_set_rgb_led
jb_io_write_outputs
jb_io_set_coin_blocker
jb_io_write_lights

View File

@@ -51,8 +51,13 @@ int main(int argc, char **argv)
rgb_t lights[6] = {0};
bool loop = true;
uint8_t cnt = 0;
uint16_t cnt = 0;
enum jbio_light_mode light_mode = LIGHTS_OFF;
enum jb_io_panel_mode panel_mode = JB_IO_PANEL_MODE_ALL;
bool panel_corners_animate = false;
char *all_text;
char top_left, top_right, bottom_left, bottom_right;
while (loop) {
if (!jb_io_read_inputs()) {
@@ -60,6 +65,39 @@ int main(int argc, char **argv)
return -2;
}
if(panel_corners_animate && (cnt % 50) == 0) {
panel_mode++;
panel_mode %= 5;
// skip the all state
if(panel_mode == JB_IO_PANEL_MODE_ALL) {
panel_mode++;
}
jb_io_set_panel_mode(panel_mode);
}
all_text = " ";
top_left = top_right = bottom_left = bottom_right = ' ';
switch(panel_mode) {
case JB_IO_PANEL_MODE_ALL:
all_text = "ALL";
top_left = top_right = bottom_left = bottom_right = '*';
break;
case JB_IO_PANEL_MODE_TOP_LEFT:
top_left = '*';
break;
case JB_IO_PANEL_MODE_TOP_RIGHT:
top_right = '*';
break;
case JB_IO_PANEL_MODE_BOTTOM_LEFT:
bottom_left = '*';
break;
case JB_IO_PANEL_MODE_BOTTOM_RIGHT:
bottom_right = '*';
break;
}
/* get inputs */
input_sys = jb_io_get_sys_inputs();
input_panel = jb_io_get_panel_inputs();
@@ -85,12 +123,12 @@ int main(int argc, char **argv)
"\n"
" Test: %d Service: %d Coin: %d\n"
" .___.___.___.___.\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d |\n"
" |---|---|---|---|\n"
" | %d | %d | %d | %d | Corner\n"
" |---|---|---|---| .___.\n"
" | %d | %d | %d | %d | |%c %c|\n"
" |---|---|---|---| |%s|\n"
" | %d | %d | %d | %d | |%c %c|\n"
" |---|---|---|---| `---`\n"
" | %d | %d | %d | %d |\n"
" `---`---`---`---`\n",
cnt,
@@ -126,10 +164,19 @@ int main(int argc, char **argv)
IS_BIT_SET(input_panel, JB_IO_PANEL_06),
IS_BIT_SET(input_panel, JB_IO_PANEL_07),
IS_BIT_SET(input_panel, JB_IO_PANEL_08),
top_left,
top_right,
all_text,
IS_BIT_SET(input_panel, JB_IO_PANEL_09),
IS_BIT_SET(input_panel, JB_IO_PANEL_10),
IS_BIT_SET(input_panel, JB_IO_PANEL_11),
IS_BIT_SET(input_panel, JB_IO_PANEL_12),
bottom_left,
bottom_right,
IS_BIT_SET(input_panel, JB_IO_PANEL_13),
IS_BIT_SET(input_panel, JB_IO_PANEL_14),
IS_BIT_SET(input_panel, JB_IO_PANEL_15),
@@ -165,7 +212,7 @@ int main(int argc, char **argv)
jb_io_set_rgb_led(i, lights[i].r, lights[i].g, lights[i].b);
}
if (!jb_io_write_outputs()) {
if (!jb_io_write_lights()) {
printf("ERROR: Writing outputs failed\n");
return -4;
}
@@ -185,6 +232,7 @@ int main(int argc, char **argv)
" 2: Set all lights on (cleared by pressing any panel)\n"
" 3: Tie each R/G/B to inputs (panels + test + service)\n"
" 4: Set all lights off\n"
" 5: Toggle switch corner test mode\n"
"Waiting for input: ");
char c = getchar();
@@ -195,7 +243,7 @@ int main(int argc, char **argv)
jb_io_set_rgb_led(i, 0, 0, 0);
}
if (!jb_io_write_outputs()) {
if (!jb_io_write_lights()) {
printf("ERROR: Writing outputs failed\n");
return -4;
}
@@ -219,6 +267,15 @@ int main(int argc, char **argv)
break;
}
case '5': {
panel_corners_animate = !panel_corners_animate;
if(!panel_corners_animate) {
panel_mode = JB_IO_PANEL_MODE_ALL;
jb_io_set_panel_mode(panel_mode);
}
break;
}
case '0':
default:
break;

View File

@@ -64,7 +64,7 @@ struct property *boot_property_load(const char *filename)
nbytes = property_read_query_memsize(boot_property_fread, f_keyhole, 0, 0);
if (nbytes < 0) {
log_fatal("%s: Error parsing configuration file", filename);
log_fatal("%s: Error querying configuration file", filename);
}
buffer = xmalloc(nbytes);
@@ -76,7 +76,7 @@ struct property *boot_property_load(const char *filename)
rewind(f);
if (!property_insert_read(prop, 0, boot_property_fread, f_keyhole)) {
log_fatal("%s: Error parsing configuration file", filename);
log_fatal("%s: Error reading configuration file", filename);
}
TlsFree(f_keyhole);

View File

@@ -35,7 +35,7 @@ static void *STDCALL my_GetProcAddress(HMODULE dll, const char *name);
static void bt_get_ikey_status(struct ikey_status *ik);
#if AVS_VERSION >= 1600
#if AVS_VERSION >= 1509
static void bt_get_fucked(bt_get_fucked_t callback, uint32_t ctx);
#endif
@@ -48,7 +48,7 @@ static HMODULE(STDCALL *real_GetModuleHandleW)(const wchar_t *name);
static void *(STDCALL *real_GetProcAddress)(HMODULE dll, const char *name);
static struct stub stub_list[] = {
#if AVS_VERSION >= 1600
#if AVS_VERSION >= 1509
{"k_bt0001", bt_get_ikey_status},
{"k_bt0002", bt_get_fucked},
#else
@@ -134,7 +134,7 @@ static void bt_get_ikey_status(struct ikey_status *ik)
ik[1].cert_valid_end = -1;
}
#if AVS_VERSION >= 1600
#if AVS_VERSION >= 1509
static void bt_get_fucked(bt_get_fucked_t callback, uint32_t ctx)
{
log_info(">>> k_bt0002");

67
src/main/p4io/cmd.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef P4IO_CMD_H
#define P4IO_CMD_H
#include <stdint.h>
#define P4IO_SOF 0xAA
enum p4io_command {
P4IO_CMD_INIT = 0x00,
P4IO_CMD_GET_DEVICE_INFO = 0x01,
P4IO_CMD_SET_PORTOUT = 0x12,
P4IO_CMD_COINSTOCK = 0x18,
P4IO_CMD_RESET_WTD = 0x1C,
P4IO_CMD_SCI_MNG_OPEN = 0x20,
P4IO_CMD_SCI_UPDATE = 0x21,
/* SCI = serial communication interface */
P4IO_CMD_SCI_MNG_BREAK = 0x24,
/* Read round plug id over one-wire */
P4IO_CMD_DALLAS_READ_ID = 0x40,
/* Read round plug mem over one-wire */
P4IO_CMD_DALLAS_READ_MEM = 0x41
};
enum p4io_roundplug_type {
P4IO_ROUNDPLUG_BLACK = 0,
P4IO_ROUNDPLUG_WHITE = 1,
};
#define P4IO_CMD_HEADER_LEN 4
#define P4IO_MAX_PAYLOAD 60
struct p4io_cmd_header {
uint8_t sof;
uint8_t cmd;
uint8_t seq_num;
uint8_t payload_len;
};
struct p4io_cmd_package {
struct p4io_cmd_header header;
uint8_t payload[P4IO_MAX_PAYLOAD];
};
struct p4io_req_read_roundplug {
// see enum p4io_roundplug_type
uint8_t type;
};
struct p4io_req_panel_mode {
uint16_t mode;
uint8_t is_single;
uint8_t padding[13];
} __attribute__((__packed__));
struct p4io_resp_device_info {
uint32_t type;
uint8_t padding;
uint8_t version_major;
uint8_t version_minor;
uint8_t version_revision;
char product_code[4];
char build_date[16];
char build_time[16];
};
#endif

13
src/main/p4io/guid.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef P4IO_GUID_H
#define P4IO_GUID_H
#include <windows.h>
static const GUID p4io_guid = {
0x8B7250A5,
0x4F61,
0x46C9,
{0x84, 0x3A, 0xE6, 0x68, 0x06, 0x47, 0x6A, 0x20}
};
#endif

42
src/main/p4io/ioctl.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef P4IO_IOCTL_H
#define P4IO_IOCTL_H
/* can't seem to #include the requisite DDK headers from usermode code,
so we have to redefine these macros here */
#ifndef CTL_CODE
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#endif
#ifndef METHOD_BUFFERED
#define METHOD_BUFFERED 0
#endif
#ifndef FILE_ANY_ACCESS
#define FILE_ANY_ACCESS 0x00
#endif
#ifndef FILE_DEVICE_UNKNOWN
#define FILE_DEVICE_UNKNOWN 0x22
#endif
#define P4IO_FUNCTION_READ_JAMMA_2 0x801
#define P4IO_FUNCTION_GET_DEVICE_NAME 0x803
// 0x22200Cu sent to bulk handle
#define P4IO_IOCTL_GET_DEVICE_NAME \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_GET_DEVICE_NAME, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
// 0x222004 sent to int handle
#define P4IO_IOCTL_READ_JAMMA_2 \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_READ_JAMMA_2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#endif

View File

@@ -0,0 +1,6 @@
libs += p4iodrv
src_p4iodrv := \
device.c \
usb.c \

133
src/main/p4iodrv/device.c Normal file
View File

@@ -0,0 +1,133 @@
#define LOG_MODULE "p4iodrv-device"
#include <windows.h>
#include "p4io/cmd.h"
#include "p4iodrv/device.h"
#include "p4iodrv/usb.h"
#include "util/log.h"
#include "util/mem.h"
struct p4iodrv_ctx {
HANDLE jamma_handle;
HANDLE bulk_handle;
uint8_t seq_no;
};
static void p4io_cmd_init(struct p4iodrv_ctx *ctx);
static bool p4io_print_version(struct p4iodrv_ctx *ctx);
static bool p4io_transfer(
struct p4iodrv_ctx *ctx,
uint8_t cmd,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t resp_payload_len
) {
size_t transferred_response_payload = resp_payload_len;
bool ret = p4io_usb_transfer(ctx->bulk_handle, cmd, ctx->seq_no,
req_payload, req_payload_len,
resp_payload, &transferred_response_payload);
ctx->seq_no++;
if(!ret) {
return false;
}
if(resp_payload_len && transferred_response_payload != resp_payload_len) {
log_warning("Asked for %u bytes got %u", (unsigned)resp_payload_len,
(unsigned)transferred_response_payload);
return false;
}
return true;
}
struct p4iodrv_ctx *p4iodrv_open(void) {
struct p4iodrv_ctx *ctx = xcalloc(sizeof(struct p4iodrv_ctx));
// jamma is read as fast as possible in its own thread, so having them be
// separate files is absolutely essential to avoid the bulk handle being
// starved
ctx->jamma_handle = p4io_usb_open();
ctx->bulk_handle = p4io_usb_open();
ctx->seq_no = 0;
if(ctx->jamma_handle == INVALID_HANDLE_VALUE || ctx->bulk_handle == INVALID_HANDLE_VALUE) {
free(ctx);
return NULL;
}
p4io_cmd_init(ctx);
if(!p4io_print_version(ctx)) {
free(ctx);
return NULL;
}
return ctx;
}
void p4iodrv_close(struct p4iodrv_ctx *ctx) {
p4io_usb_close(ctx->jamma_handle);
p4io_usb_close(ctx->bulk_handle);
free(ctx);
}
bool p4iodrv_read_jamma(struct p4iodrv_ctx *ctx, uint32_t jamma[4]) {
return p4io_usb_read_jamma(ctx->jamma_handle, jamma);
}
// send something you don't expect a response for
static bool p4io_send(struct p4iodrv_ctx *ctx, uint8_t cmd) {
return p4io_transfer(ctx, cmd, NULL, 0, NULL, 0);
}
// Real IO does not check the return value, so neither do we.
// Even if we were to check the return value here, the reset command returns a 0
// byte response - not even an "OK" status, 0 bytes in total. That technically
// should be raising an error, but because reset is a special case it's ignored
static void p4io_cmd_init(struct p4iodrv_ctx *ctx) {
p4io_send(ctx, P4IO_CMD_INIT);
}
static bool p4io_print_version(struct p4iodrv_ctx *ctx) {
char p4io_name[128];
if(!p4io_usb_read_device_name(ctx->bulk_handle, p4io_name)) {
return false;
}
struct p4io_resp_device_info dev_info;
if(!p4iodrv_cmd_device_info(ctx, &dev_info)) {
log_warning("p4io get_device_info failed");
return false;
}
dev_info.build_date[15] = '\0';
dev_info.build_time[15] = '\0';
log_info("p4io name: %s", p4io_name);
log_info("p4io type: %08X", dev_info.type);
log_info("p4io version: %d.%d.%d", dev_info.version_major, dev_info.version_minor, dev_info.version_revision);
log_info("p4io product: %.4s", dev_info.product_code);
log_info("p4io build date: %.16s", dev_info.build_date);
log_info("p4io build time: %.16s", dev_info.build_time);
return true;
}
bool p4iodrv_cmd_device_info(struct p4iodrv_ctx *ctx, struct p4io_resp_device_info *info) {
return p4io_transfer(ctx, P4IO_CMD_GET_DEVICE_INFO, NULL, 0, info, sizeof(*info));
}
bool p4iodrv_cmd_portout(struct p4iodrv_ctx *ctx, const uint8_t buffer[16]) {
return p4io_transfer(ctx, P4IO_CMD_SET_PORTOUT, buffer, 16, NULL, 0);
}
bool p4iodrv_cmd_coinstock(struct p4iodrv_ctx *ctx, const uint8_t buffer[4]) {
return p4io_transfer(ctx, P4IO_CMD_COINSTOCK, buffer, 4, NULL, 0);
}

18
src/main/p4iodrv/device.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef P4IODRV_DEVICE_H
#define P4IODRV_DEVICE_H
#include <stdbool.h>
#include <stdint.h>
#include "p4io/cmd.h"
struct p4iodrv_ctx;
struct p4iodrv_ctx *p4iodrv_open(void);
void p4iodrv_close(struct p4iodrv_ctx *ctx);
bool p4iodrv_cmd_device_info(struct p4iodrv_ctx *ctx, struct p4io_resp_device_info *info);
bool p4iodrv_cmd_portout(struct p4iodrv_ctx *ctx, const uint8_t buffer[16]);
bool p4iodrv_cmd_coinstock(struct p4iodrv_ctx *ctx, const uint8_t buffer[4]);
bool p4iodrv_read_jamma(struct p4iodrv_ctx *ctx, uint32_t jamma[4]);
#endif

162
src/main/p4iodrv/usb.c Normal file
View File

@@ -0,0 +1,162 @@
#define LOG_MODULE "p4iodrv-usb"
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <setupapi.h>
// clang-format on
#include "p4io/cmd.h"
#include "p4io/guid.h"
#include "p4io/ioctl.h"
#include "p4iodrv/usb.h"
#include "util/log.h"
#include "util/str.h"
HANDLE p4io_usb_open(void) {
HANDLE handle = INVALID_HANDLE_VALUE;
wchar_t p4io_filename[MAX_PATH]; // game uses 1024, but it shouldn't be that long
PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail_data = NULL;
HDEVINFO dev_info_set;
dev_info_set = SetupDiGetClassDevsW(&p4io_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if(dev_info_set == INVALID_HANDLE_VALUE) {
log_warning("SetupDiGetClassDevs fail, is p4io device connected and driver installed?");
return INVALID_HANDLE_VALUE;
}
SP_DEVICE_INTERFACE_DATA interface_data;
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(!SetupDiEnumDeviceInterfaces(dev_info_set, NULL, &p4io_guid, 0, &interface_data)) {
log_warning("SetupDiEnumDeviceInterfaces fail");
goto CLEANUP;
}
DWORD required_size;
SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, NULL, 0, &required_size, NULL);
detail_data = malloc(required_size);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
if(!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, detail_data, required_size, NULL, NULL)) {
log_warning("SetupDiGetDeviceInterfaceDetailW fail");
goto CLEANUP;
}
wstr_cpy(p4io_filename, MAX_PATH, detail_data->DevicePath);
wstr_cat(p4io_filename, MAX_PATH, L"\\p4io");
log_info("p4io found at path %ls", p4io_filename);
handle = CreateFileW(p4io_filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(handle == INVALID_HANDLE_VALUE) {
log_warning("CreateFileW fail");
goto CLEANUP;
}
CLEANUP:
free(detail_data);
SetupDiDestroyDeviceInfoList(dev_info_set);
return handle;
}
void p4io_usb_close(HANDLE p4io_handle) {
if(p4io_handle != INVALID_HANDLE_VALUE) {
CloseHandle(p4io_handle);
}
p4io_handle = INVALID_HANDLE_VALUE;
}
bool p4io_usb_read_jamma(HANDLE interrupt_handle, uint32_t jamma[4]) {
DWORD bytes_returned;
if(!DeviceIoControl(interrupt_handle, P4IO_IOCTL_READ_JAMMA_2, NULL, 0, jamma, sizeof(uint32_t[4]), &bytes_returned, NULL)) {
log_warning("jamma read failed");
return false;
}
return true;
}
bool p4io_usb_read_device_name(HANDLE bulk_handle, char name[128]) {
DWORD bytes_returned;
if(!DeviceIoControl(bulk_handle, P4IO_IOCTL_GET_DEVICE_NAME, NULL, 0, name, 128, &bytes_returned, NULL)) {
log_warning("p4io does not support get_name cmd");
return false;
}
return true;
}
bool p4io_usb_transfer(
HANDLE bulk_handle,
uint8_t cmd,
uint8_t seq_no,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t *resp_payload_len
) {
DWORD bytes_requested;
DWORD bytes_xferred;
struct p4io_cmd_package cmd_buf;
if(bulk_handle == INVALID_HANDLE_VALUE) {
log_warning("p4io not open");
return false;
}
if(req_payload_len > sizeof(cmd_buf.payload)) {
log_warning("request too big");
return false;
}
cmd_buf.header.sof = P4IO_SOF;
cmd_buf.header.cmd = cmd;
cmd_buf.header.seq_num = seq_no;
cmd_buf.header.payload_len = req_payload_len;
memcpy(cmd_buf.payload, req_payload, req_payload_len);
bytes_requested = P4IO_CMD_HEADER_LEN + req_payload_len;
if(!WriteFile(bulk_handle, &cmd_buf, bytes_requested, &bytes_xferred, 0)) {
log_warning("WriteFile failed");
return false;
}
if(bytes_xferred != bytes_requested) {
log_warning("WriteFile didn't finish");
return false;
}
// must be 65 bytes or requests can stall - only 64 will ever be returned
if(!ReadFile(bulk_handle, &cmd_buf, 65, &bytes_xferred, 0)) {
log_warning("ReadFile (%u) failed", (unsigned)bytes_requested);
return false;
}
if(bytes_xferred >= sizeof(struct p4io_cmd_header)) {
memcpy(resp_payload, cmd_buf.payload, *resp_payload_len);
*resp_payload_len = cmd_buf.header.payload_len;
if(cmd_buf.header.sof != P4IO_SOF) {
log_warning("Response bad header");
return false;
}
if(seq_no != cmd_buf.header.seq_num) {
log_warning("seq_num mismatch (ours %d != theirs %d)", seq_no, cmd_buf.header.seq_num);
return false;
}
} else {
*resp_payload_len = 0;
}
return true;
}

22
src/main/p4iodrv/usb.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef P4IODRV_USB_H
#define P4IODRV_USB_H
#include <stdbool.h>
#include <stddef.h>
#include <windows.h>
HANDLE p4io_usb_open(void);
void p4io_usb_close(HANDLE p4io_handle);
bool p4io_usb_read_jamma(HANDLE interrupt_handle, uint32_t jamma[4]);
bool p4io_usb_read_device_name(HANDLE bulk_handle, char name[128]);
bool p4io_usb_transfer(
HANDLE bulk_handle,
uint8_t cmd,
uint8_t seq_no,
const void *req_payload,
size_t req_payload_len,
void *resp_payload,
size_t *resp_payload_len
);
#endif

View File

@@ -7,78 +7,14 @@
#include <windows.h>
#include "hook/iohook.h"
#include "p4io/cmd.h"
#include "p4io/ioctl.h"
#include "util/hex.h"
#include "util/log.h"
#include "util/str.h"
//#define P4IOEMU_DEBUG_DUMP
/* can't seem to #include the requisite DDK headers from usermode code,
so we have to redefine these macros here */
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define METHOD_BUFFERED 0
#define FILE_ANY_ACCESS 0x00
#define FILE_DEVICE_UNKNOWN 0x22
#define P4IO_FUNCTION_READ_JAMMA_2 0x801
#define P4IO_FUNCTION_GET_DEVICE_NAME 0x803
#define IOCTL_P4IO_GET_DEVICE_NAME \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_GET_DEVICE_NAME, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_P4IO_READ_JAMMA_2 \
CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
P4IO_FUNCTION_READ_JAMMA_2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
enum p4ioemu_p4io_command {
P4IOEMU_P4IO_CMD_INIT = 0x00,
P4IOEMU_P4IO_CMD_GET_DEVICE_INFO = 0x01,
P4IOEMU_P4IO_CMD_UNKNOWN = 0x12,
P4IOEMU_P4IO_CMD_RESET_WTD = 0x1C,
P4IOEMU_P4IO_CMD_SCI_MNG_OPEN = 0x20,
P4IOEMU_P4IO_CMD_SCI_UPDATE = 0x21,
/* SCI = serial communication interface */
P4IOEMU_P4IO_CMD_SCI_MNG_BREAK = 0x24,
/* Read round plug id over one-wire */
P4IOEMU_P4IO_CMD_DALLAS_READ_ID = 0x40,
/* Read round plug mem over one-wire */
P4IOEMU_P4IO_CMD_DALLAS_READ_MEM = 0x41
};
struct p4ioemu_p4io_cmd_package {
uint8_t header_AA;
uint8_t cmd;
uint8_t seq_num;
uint8_t payload_len;
};
struct p4ioemu_p4io_device_info_resp {
uint32_t type;
uint8_t padding;
uint8_t version_major;
uint8_t version_minor;
uint8_t version_revision;
char product_code[4];
char build_date[16];
char build_time[16];
};
struct p4ioemu_p4io_read_roundplug_req {
/* 0 = black, 1 = white */
uint8_t type;
};
static const struct p4ioemu_device_msg_hook *p4ioemu_device_msg_hook;
static HANDLE p4ioemu_p4io_fd;
@@ -95,7 +31,7 @@ static uint32_t p4ioemu_p4io_command_handle(
uint32_t resp_max_len)
{
switch (cmd) {
case P4IOEMU_P4IO_CMD_INIT: {
case P4IO_CMD_INIT: {
log_misc("P4IOEMU_P4IO_CMD_INIT");
/* no data to send to host */
@@ -104,11 +40,11 @@ static uint32_t p4ioemu_p4io_command_handle(
return 0;
}
case P4IOEMU_P4IO_CMD_GET_DEVICE_INFO: {
case P4IO_CMD_GET_DEVICE_INFO: {
log_misc("P4IOEMU_P4IO_CMD_GET_DEVICE_INFO");
struct p4ioemu_p4io_device_info_resp *info =
(struct p4ioemu_p4io_device_info_resp *) resp;
struct p4io_resp_device_info *info =
(struct p4io_resp_device_info *) resp;
info->type = 0x37133713;
info->version_major = 5;
@@ -118,12 +54,12 @@ static uint32_t p4ioemu_p4io_command_handle(
memcpy(info->build_date, "build_date", 11);
memcpy(info->build_time, "build_time", 11);
return sizeof(struct p4ioemu_p4io_device_info_resp);
return sizeof(struct p4io_resp_device_info);
}
case P4IOEMU_P4IO_CMD_DALLAS_READ_ID: {
const struct p4ioemu_p4io_read_roundplug_req *req =
(const struct p4ioemu_p4io_read_roundplug_req *) payload;
case P4IO_CMD_DALLAS_READ_ID: {
const struct p4io_req_read_roundplug *req =
(const struct p4io_req_read_roundplug *) payload;
log_misc("P4IOEMU_P4IO_CMD_DALLAS_READ_ID: %d", req->type);
@@ -136,9 +72,9 @@ static uint32_t p4ioemu_p4io_command_handle(
return 8;
}
case P4IOEMU_P4IO_CMD_DALLAS_READ_MEM: {
const struct p4ioemu_p4io_read_roundplug_req *req =
(const struct p4ioemu_p4io_read_roundplug_req *) payload;
case P4IO_CMD_DALLAS_READ_MEM: {
const struct p4io_req_read_roundplug *req =
(const struct p4io_req_read_roundplug *) payload;
log_misc("P4IOEMU_P4IO_CMD_DALLAS_READ_MEM: %d", req->type);
@@ -152,13 +88,7 @@ static uint32_t p4ioemu_p4io_command_handle(
return 32;
}
case P4IOEMU_P4IO_CMD_UNKNOWN: {
log_misc("P4IOEMU_P4IO_CMD_UNKNOWN: %d", payload_len);
return 0;
}
case P4IOEMU_P4IO_CMD_SCI_UPDATE: {
case P4IO_CMD_SCI_UPDATE: {
// log_misc("P4IOEMU_P4IO_CMD_SCI_UPDATE");
// TODO we need a game which uses it
@@ -167,7 +97,7 @@ static uint32_t p4ioemu_p4io_command_handle(
return 0;
}
case P4IOEMU_P4IO_CMD_RESET_WTD: {
case P4IO_CMD_RESET_WTD: {
// log_misc("P4IOEMU_P4IO_CMD_RESET_WTD");
return 0;
@@ -188,20 +118,18 @@ static void p4ioemu_p4io_dump_buffer(const void *buffer, uint32_t len)
static HRESULT p4ioemu_p4io_bulk_read(void *resp, uint32_t nbytes)
{
struct p4ioemu_p4io_cmd_package *package;
void *payload;
struct p4io_cmd_package *package;
uint32_t max_payload_len;
uint32_t payload_len;
if (nbytes < sizeof(struct p4ioemu_p4io_cmd_package)) {
log_warning("Buffer for bulk read endpoint to short: %d", nbytes);
if (nbytes < sizeof(struct p4io_cmd_header)) {
log_warning("Buffer for bulk read endpoint too short: %d", nbytes);
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
package = (struct p4ioemu_p4io_cmd_package *) resp;
payload = resp + sizeof(struct p4ioemu_p4io_cmd_package);
max_payload_len = nbytes - sizeof(struct p4ioemu_p4io_cmd_package);
package = (struct p4io_cmd_package *) resp;
max_payload_len = nbytes - sizeof(struct p4io_cmd_header);
if (max_payload_len < p4ioemu_p4io_cmd_buffer_resp_len) {
log_warning(
@@ -213,46 +141,44 @@ static HRESULT p4ioemu_p4io_bulk_read(void *resp, uint32_t nbytes)
payload_len = p4ioemu_p4io_cmd_buffer_resp_len;
}
package->header_AA = 0xAA;
package->cmd = p4ioemu_p4io_last_cmd;
package->seq_num = p4ioemu_p4io_last_seq_num;
package->payload_len = payload_len;
package->header.sof = P4IO_SOF;
package->header.cmd = p4ioemu_p4io_last_cmd;
package->header.seq_num = p4ioemu_p4io_last_seq_num;
package->header.payload_len = payload_len;
memcpy(payload, p4ioemu_p4io_cmd_read_buffer, payload_len);
memcpy(package->payload, p4ioemu_p4io_cmd_read_buffer, payload_len);
return S_OK;
}
static HRESULT p4ioemu_p4io_bulk_write(const void *req, uint32_t nbytes)
{
const struct p4ioemu_p4io_cmd_package *package;
const void *payload;
const struct p4io_cmd_package *package;
if (nbytes < sizeof(struct p4ioemu_p4io_cmd_package)) {
log_warning("Command on bulk write endpoint to short: %d", nbytes);
if (nbytes < sizeof(struct p4io_cmd_header)) {
log_warning("Command on bulk write endpoint too short: %d", nbytes);
p4ioemu_p4io_dump_buffer(req, nbytes);
return E_INVALIDARG;
}
package = (struct p4ioemu_p4io_cmd_package *) req;
payload = req + sizeof(struct p4ioemu_p4io_cmd_package);
package = (struct p4io_cmd_package *) req;
if (package->header_AA != 0xAA) {
log_warning("Command on bulk endpoint to short: %d", nbytes);
if (package->header.sof != P4IO_SOF) {
log_warning("Command on bulk endpoint too short: %d", nbytes);
p4ioemu_p4io_dump_buffer(req, nbytes);
return E_INVALIDARG;
}
p4ioemu_p4io_last_cmd = package->cmd;
p4ioemu_p4io_last_seq_num = package->seq_num;
p4ioemu_p4io_last_cmd = package->header.cmd;
p4ioemu_p4io_last_seq_num = package->header.seq_num;
/* handle commands that are common p4io ones first */
p4ioemu_p4io_cmd_buffer_resp_len = p4ioemu_p4io_command_handle(
package->cmd,
payload,
package->payload_len,
package->header.cmd,
package->payload,
package->header.payload_len,
p4ioemu_p4io_cmd_read_buffer,
sizeof(p4ioemu_p4io_cmd_read_buffer));
@@ -261,16 +187,16 @@ static HRESULT p4ioemu_p4io_bulk_write(const void *req, uint32_t nbytes)
if (p4ioemu_device_msg_hook->command_handle) {
p4ioemu_p4io_cmd_buffer_resp_len =
p4ioemu_device_msg_hook->command_handle(
package->cmd,
payload,
package->payload_len,
package->header.cmd,
package->payload,
package->header.payload_len,
p4ioemu_p4io_cmd_read_buffer,
sizeof(p4ioemu_p4io_cmd_read_buffer));
}
}
if (p4ioemu_p4io_cmd_buffer_resp_len == 0xFFFFFFFF) {
log_warning("Unhandled cmd 0x%X", package->cmd);
log_warning("Unhandled cmd 0x%X", package->header.cmd);
return E_NOTIMPL;
}
@@ -413,7 +339,7 @@ static HRESULT p4ioemu_device_ioctl(struct irp *irp)
/* Cases are listed in order of first receipt */
switch (irp->ioctl) {
case IOCTL_P4IO_GET_DEVICE_NAME: {
case P4IO_IOCTL_GET_DEVICE_NAME: {
const char dev_name[] = "kactools p4ioemu";
if (irp->read.nbytes < strlen(dev_name)) {
@@ -427,7 +353,7 @@ static HRESULT p4ioemu_device_ioctl(struct irp *irp)
return S_OK;
}
case IOCTL_P4IO_READ_JAMMA_2: {
case P4IO_IOCTL_READ_JAMMA_2: {
p4ioemu_device_msg_hook->jamma2_read(
irp->read.bytes, irp->read.nbytes);
irp->read.pos = irp->read.nbytes;

View File

@@ -2,11 +2,10 @@
#include "p4ioemu/setupapi.h"
#include "p4io/guid.h"
const struct hook_setupapi_data p4ioemu_setupapi_data = {
.device_guid = {0x8B7250A5,
0x4F61,
0x46C9,
{0x84, 0x3A, 0xE6, 0x68, 0x06, 0x47, 0x6A, 0x20}},
.device_guid = p4io_guid,
.device_desc = NULL,
.device_path = "\\p4io",
};
};

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