Compare commits

..

95 Commits
v5.27 ... 5.32

Author SHA1 Message Date
icex2
e0cfc8c948 Bump to version 5.32 and update changelog 2020-08-13 13:14:54 +02:00
icex2
93cfb591b7 iidxio-ezusb: Update documentation 2020-08-12 18:01:22 +00:00
icex2
3396c09fbf ezusb-iidx: Add macro to enable D01 board emulation
Used for dumping firmware, only. C02 and D01 boards only differ
in the FPGA firmware written to the board on boot up. This doesn't
matter for emulation, but when using a real IO board with
iidxio-ezusb.dll, a different FPGA firmware is required to be
flashed in order to get working turntables, top unit lights etc
2020-08-12 18:01:22 +00:00
icex2
bd8dc18b30 iidxio-ezusb: Support coin mech input 2020-08-11 22:05:46 +02:00
Will Xyen
8e9abf9906 launcher: Set soft_id_code before calling init as some games use it then 2020-07-24 08:47:25 -07:00
Will Xyen
62bb717582 hdxs: Is really an HDXB 1.0.1 apparently
Also update enum hdxs_rgb_light_idx to start from 0 since that's what the function does
2020-07-10 11:06:13 -07:00
Will Xyen
4816fb809d launcher: Use more descriptive error message for ERROR_MOD_NOT_FOUND 2020-07-06 18:03:25 +00:00
Tau
2a2c77f255 Add ddrhook "COM4" passthrough mode 2020-07-01 21:03:47 +02:00
icex2
55513bac41 Update changelog for 5.31 release 2020-07-01 20:33:35 +02:00
Will Xyen
9c37ef71ba ddrio: add some more comments 2020-06-29 11:23:01 -07:00
Will Xyen
a0a1dea397 ddrhook: Add HDXS acio device + emu 2020-06-29 06:52:07 -07:00
Will Xyen
3c26a3f315 ddrio: Add hdxs output functions
Also fixes IDS_DDR_P1_BOTTOM_LIGHT schema being incorrectly mapped (on SD)
2020-06-29 06:51:25 -07:00
Will Xyen
b408cd9687 config: fix number of lights being loaded wrong if config is outdated 2020-06-29 06:49:22 -07:00
Will Xyen
be4df516fd ddrio: Fix p3io and extio lighting output being swapped with one another
the header, mm and smx modules had it right

also fixes p3io responses being the wrong size in 2 cases
2020-06-29 06:47:31 -07:00
Will Xyen
d1080905e5 ddrhook: Adds 64 bit ddr build and related dependencies 2020-06-29 06:43:29 -07:00
Tau
f87a51bbe4 Silence cabinet type spam under DDR A 2020-06-28 22:10:27 -07:00
635e512cccf1256559f0c600d8185deae60a6840
2a4d3e2865 Moved location of ddrio-smx.md to doc/ddrhook/ddrio-smx.md, fixed some formatting, clarified joystick config. 2020-06-28 15:37:29 -04:00
635e512cccf1256559f0c600d8185deae60a6840
6697ff7df1 Included SMX md file with step-by-step instructions and additional info. 2020-06-28 14:47:51 -04:00
Will Xyen
682fe8aa1b crc: forgot an include 2020-06-24 19:25:46 -07:00
Will Xyen
7d533f60cb acioemu: add support for 1.7.0 and encrypted polls 2020-06-25 00:57:59 +00:00
233596621999a3accb78d883a9ab4d1f3460d772
e5331fbc7c jbhook: add adapter hook 2020-06-14 02:22:07 +02:00
10f2d26b708e9205de6ce889920e36b5596f4908
77527e346b popn hid lights 2020-06-08 11:17:22 +02:00
Will Xyen
1d0a96fa20 aciodrv: Make init more consistent by reading until we actually get a 0xAA
(reboots / command interruptions will cause incorrect state on device side)
2020-05-27 08:51:16 -07:00
icex2
63e19aaaf6 Remove src.zip from distribution package
No need to include the source code with the repository being public.
2020-05-11 00:27:11 +02:00
icex2
4c59f16d46 Update gitlab-ci, build project with Dockerfile 2020-05-11 00:27:09 +02:00
icex2
7157fdedb7 Update readme/development doc about docker building 2020-05-11 00:24:21 +02:00
icex2
13d29cb62e Add Dockerfile for building bemanitools with docker 2020-05-11 00:23:53 +02:00
icex2
bf48715466 test: Fix compiler warning 2020-05-11 00:23:29 +02:00
icex2
24b490e36b Bump version to 5.31 2020-04-27 22:00:50 +02:00
icex2
ff2a4b9a2c Changelog 5.30 update 2020-04-27 21:59:33 +02:00
Will Xyen
10bddd4905 d3d9ex: add cursor confining (ported from sdvxhook1) 2020-04-27 12:52:07 -07:00
Will Xyen
ad5fbc1f5b sdvxhook2: Add option to force headphone detection on 2020-04-27 10:19:29 -07:00
Will Xyen
25413bcba8 dinput/asio: drop hook suffix 2020-04-05 02:18:24 -07:00
Will Xyen
937290f93d asiohook: add config 2020-04-05 01:44:42 -07:00
Will Xyen
d04598a570 dinputhook: Adds dinput stub hook for later use
Thanks to felix for the original di8_stub_device.
2020-04-05 01:44:42 -07:00
Will Xyen
bd382e5509 asiohook: Adds asio reghook for later use 2020-04-05 01:44:41 -07:00
Will Xyen
0d3fa54316 launcher: Add before-hook support
Required to hook certain things that happen on module load / avs boot:
 - network adapter hooking for avs
 - envvar setting

Note: the logging facilities are NOT setup yet at this point
so these hooks cannot use avs for logging
2020-04-05 01:42:08 -07:00
6d16ce71d2cb7fb29ef6c9b6fd0f0943018cd3d0
e8943edff6 Add light support for SMX gen 4 pads
The old set lights API doesn't support gen 4 pads. Replace the call to SMX_SetLights with SMX_SetLights2 which adds support for gen 4 pads while maintaining backwards compatibility.
2020-03-22 21:18:38 +01:00
Will Xyen
61f3eb44d2 hooklib: fix warning in adapter.c 2020-02-05 01:26:41 -05:00
icex2
5aa1e27a31 Bump version to 5.30 2020-02-01 11:15:51 +01:00
icex2
596b962cfe Update changelog for 5.29 release 2020-02-01 11:07:18 +01:00
Will Xyen
5969573dc9 d3d9exhook: actually rotate the right monitor 2020-01-29 00:29:46 -05:00
Will Xyen
5da6997805 address MR comments. 2020-01-29 00:09:26 -05:00
Will Xyen
dc98103419 formatting update 2020-01-28 04:25:25 -05:00
Will Xyen
2d07bd6f5a d3d9exhook/sdvxhook2: add option to force monitor orientation
also adds adapter hook into sdvxhook2
2020-01-28 04:23:19 -05:00
Will Xyen
a21e37c894 hooklib: add adapter_hook_override to allow specifying network adapter id 2020-01-28 04:15:47 -05:00
Will Xyen
fbb7731681 dist: Update sdvxhook2.conf provided to have new d3d9exhook options 2020-01-21 06:13:36 -05:00
Will Xyen
3659494c18 misc: touchup some comments 2020-01-13 21:21:43 -05:00
Will Xyen
6d638ff1ae sdvxhook2-cn: sdvx5 cn support 2020-01-13 16:16:12 -05:00
Will Xyen
214a31b24d iidxhook/d3d9exhook: Use -1 to specify default adapter instead of 0 because the indexing starts at 0
Originally thought the default monitor showed up again later, it does not
2020-01-10 17:36:34 -05:00
Will Xyen
66d1131664 clang-format pass 2020-01-10 17:24:47 -05:00
Will Xyen
3450686cf5 iidxhook: allow forcing adapter and refresh rate in d3d9 based IIDX games 2020-01-10 10:44:21 -05:00
Will Xyen
3b8f6ac1d9 launcher: make app_config.xml optional 2019-12-23 20:40:51 -05:00
Will Xyen
8ae06f6f4b d3d9exhook: Add option to specify the display adapter to open 2019-12-23 20:14:26 -05:00
Will Xyen
b1fd175318 dist/docs: --config not --options 2019-12-18 21:48:47 -05:00
Will Xyen
b1329d10bf camhook: Fix cameras not being auto-detected sometimes on older machines
MFStartup needs to be called before any MF functions are used (such as for auto detect)
2019-12-10 15:24:46 -05:00
icex2
bf3d543893 Add some general notes about data setup for OS to README 2019-12-09 15:17:09 +01:00
icex2
f1f26dece3 Update development doc with some useful dev tools 2019-12-09 15:08:14 +01:00
icex2
fe0996ec3b Update MR templates, add checklist for guidance 2019-12-09 15:01:16 +01:00
icex2
d551930ea0 Version bump to 5.29 2019-12-06 23:25:21 +01:00
icex2
daad6a09c5 Fix versioning for sdvx distribution packages
sdvx.zip -> sdvx-01-to-04.zip
sdvx5.zip -> sdvx-05.zip
2019-12-06 23:23:12 +01:00
icex2
27fdabe17a Add instructions how to create releases 2019-12-06 23:19:27 +01:00
icex2
d29d9415b2 Create changelog for 5.28 release 2019-12-06 23:08:28 +01:00
icex2
3212981cc9 Readme update supported games list, add SDVX Vivid Wave 2019-12-06 23:08:09 +01:00
Will Xyen
7ea12a8517 cconfig: add some documentation to init functions 2019-12-01 15:14:04 -05:00
Will Xyen
82ac30e49f sdvxio-kfca: use cconfig instead of envvar 2019-12-01 15:01:44 -05:00
Will Xyen
d177f23476 cconfig: add ability to load configs from default path and specify alternate flag names 2019-12-01 15:00:45 -05:00
Will Xyen
13050b05e5 sdvxio-kfca: add some docs and address some comments 2019-12-01 13:32:09 -05:00
Will Xyen
673881bc47 sdvxio-kfca: node detection and allow setting port through envvar 2019-12-01 12:56:18 -05:00
Will Xyen
74ddd96d32 sdvxhook2: fix usage info naming wrong port 2019-12-01 12:38:22 -05:00
Will Xyen
48622f6a58 cconfig: allow crlf line endings 2019-12-01 11:41:09 -05:00
Will Xyen
0ca353b250 sdvxhook2: add some minor documentation to config-gfx.h 2019-11-30 21:46:25 -05:00
Will Xyen
ddd7853810 d3d9exhook: refactor d3d9ex hook from sdvxhook2 to shared library 2019-11-30 10:05:14 -05:00
Will Xyen
51a697659b sdvxhook: remove pci override for gfx hooks and general cleanup 2019-11-30 09:12:08 -05:00
Will Xyen
412ece18fc sdvxhoook2: typo in gamestart 2019-11-26 16:04:14 -05:00
Will Xyen
1d247d44d5 sdvxhook2: Add sdvxhook2 2019-11-26 15:59:57 -05:00
Will Xyen
2011bfafd6 camhook: fixup some minor formatting and enable iidxhook8-config-cam-test 2019-11-26 00:32:12 -05:00
Will Xyen
b434d7975d camhook: move camera hook facilities to their own module
makes the number of cameras configurable (up to 2), as SDVX only needs 1
2019-11-24 00:47:35 -05:00
5ee40b3373b0ab4600315554ea660a00c47813da
2d8017dbda Stop SDVX hanging on thankyou for playing
Makes the following changes to the card poll response message when
emulating new card readers:
 - change the idle status code to 0x04 instead of 0x01
 - always set keypad_started field to 0x03
2019-11-13 00:24:10 +00:00
icex2
6da3732968 makefile: Add -Werror flag for release builds, only.
Keep normal/dev builds (e.g. just run make) without this flag
to allow keeping warnings around and not being forced to clean
them up during development.
2019-11-09 20:14:24 +01:00
icex2
f3ead543ab Update README.md with pipeline status 2019-11-08 21:41:18 +00:00
icex2
ad3995eeae Update .gitlab-ci.yml, missing releasetag stage. 2019-11-08 21:30:18 +00:00
icex2
78a7fd418a Update .gitlab-ci.yml. Create release on git tag. 2019-11-08 21:27:54 +00:00
icex2
518f65b8c0 Add gitlab-ci.yml for CI. 2019-11-08 20:01:11 +00:00
Will Xyen
041d6935ff imports: add avs_fs_addfs to list of imports for 1700 2019-10-24 20:37:43 -04:00
Will Xyen
69ee95c79a dist: Speify config.exe instead of just config in config.bat (#35) 2019-10-24 20:32:47 -04:00
icex2
b6e588116d Various import fixes caused by clang-format
Added format protection block to avoid re-ordering of header files
according to formatting rules.
2019-10-22 21:04:45 +02:00
icex2
c3bc8782f4 Apply clang-format code style to all source files 2019-10-20 00:50:40 +02:00
icex2
c600e1a423 Some clang-format tweaks to optimize code style 2019-10-20 00:50:37 +02:00
icex2
6741a1f2fd Add code formatting and testing to build pipeline. #3
This adds a few new make targets for formatting, testing and
release building.
2019-10-19 23:12:31 +02:00
icex2
ce61a246a6 doc: Try to highlight the usage of d3d8to9 wrapper in iidxhook1/2 2019-10-19 21:39:48 +02:00
icex2
e96a280bde Add documentation: inject, launcher and iidxhooks using them 2019-10-19 21:33:49 +02:00
icex2
5aa9ad1e02 iidxhook8: Add missing dist files for iidx 26
I know this is slightly redundant but we should stick to this
pattern as we have multiple old games that do not use identical
conf and gamestart files.
2019-10-18 20:24:08 +02:00
Will Xyen
d60a1e0c0f iidxhook8: Fixup some missed renaming from struct cleanup 2019-10-13 11:50:56 -04:00
icex2
03a9beae41 Bump version to 5.28 2019-10-12 20:50:14 +02:00
528 changed files with 19582 additions and 12146 deletions

View File

@@ -9,23 +9,23 @@ AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakAfterDefinitionReturnType: All
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: 'false'
AlwaysBreakBeforeMultilineStrings: 'true'
BinPackArguments: 'false'
BinPackParameters: 'false'
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Linux
BreakBeforeTernaryOperators: 'false'
BreakStringLiterals: 'true'
ColumnLimit: '120'
ContinuationIndentWidth: '8'
ColumnLimit: '80'
ContinuationIndentWidth: '4'
IncludeBlocks: Preserve
IndentCaseLabels: 'false'
IndentCaseLabels: 'true'
IndentPPDirectives: None
IndentWidth: '4'
IndentWrappedFunctionNames: 'false'
KeepEmptyLinesAtTheStartOfBlocks: 'false'
KeepEmptyLinesAtTheStartOfBlocks: 'true'
Language: Cpp
MaxEmptyLinesToKeep: '1'
PointerAlignment: Right

67
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,67 @@
image: docker:stable
variables:
DOCKER_TLS_CERTDIR: "/certs"
services:
- docker:19.03.8-dind
before_script:
- docker info
stages:
- build
- create-release-package
- releasetag
build:
stage: build
before_script:
- apk update && apk add make > /dev/null
script:
- make build-docker
artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths:
- build
only:
refs:
- master
create-release-package:
stage: create-release-package
variables:
GIT_STRATEGY: none
dependencies:
- build
before_script:
- apk update && apk add zip > /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
artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths:
- ./*
only:
refs:
- master
releasetag:
stage: releasetag
dependencies: []
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"
only:
- tags

View File

@@ -13,4 +13,15 @@
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
<!--- see how your change affects other areas of the code, etc. -->
## Checklist
<!-- Make sure you covered all items, which apply, of the checklist below. -->
<!-- Strikethrough items that do not apply and provide a brief description why. -->
* [ ] Implemented (unit) test(s) which prove that the introduced changes are working as expected.
* Tested with the following games:
* [ ] ... <!-- insert game name 1-->
* [ ] ... <!-- insert game name 2--->
* [ ] Followed the developer (style) guidelines.
* [ ] Updated existing doc of or add new doc to README file(s).
* [ ] Updated development documentation.

View File

@@ -13,4 +13,15 @@
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
<!--- see how your change affects other areas of the code, etc. -->
## Checklist
<!-- Make sure you covered all items, which apply, of the checklist below. -->
<!-- Strikethrough items that do not apply and provide a brief description why. -->
* [ ] Implemented (unit) test(s) which prove that the introduced changes are working as expected.
* Tested with the following games:
* [ ] ... <!-- insert game name 1-->
* [ ] ... <!-- insert game name 2--->
* [ ] Followed the developer (style) guidelines.
* [ ] Updated existing doc of or add new doc to README file(s).
* [ ] Updated development documentation.

View File

@@ -1,4 +1,35 @@
# Release history
## 5.32
* Various bugfixes
## 5.31
* DDR: Fix p3io and extio lights not working / being swapped when using geninput
* DDR: Add HDXS light support
* DDR: Add 64 bit support
* DDR: Add option to use COM4 as the p3io rs232 port instead of emulating (for use with acrealio etc.)
* Jubeat: Add network adapter hook
* Misc: Fix aciodrv sometimes hanging on boot (eamio-icca and sdvxio-kfca)
## 5.30
* SDVX: sdvxhook2 headphone force and cursor confining config options
* DDR: Add light support for SMX gen 4 pads
## 5.29
* SDVX: Add option for monitor rotation
* SDVX: Add option to allow overriding network adapter IP
* IIDX: Add force display adapter and refresh rate configuration
* SDVX: Allow specifying display adapter to open for d3d9ex hook
* IIDX/SDVX camerahooks bugfix: Camera sometimes not detected on some older machines
## 5.28
* Improve documentation in various places
* Automatic code formatting in build pipeline
* Bugfix: Recursive config.bat script
* Enable automatic building on pushes to master
* Bugfix: Stop SDVX hanging on thankyou for playing
* sdvx2: Support for Vivid Wave using sdvxhook2
* sdvxio-kfca: Driver for real sdvx cabinet IO hardware
## 5.27
* Various documentation updates regarding development and how to contribute
* KFCA emulation accuracy fixes

32
Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM fedora:31
LABEL description="Build environment for bemanitools"
RUN yum -y install \
git \
make \
zip \
clang \
mingw64-gcc.x86_64 \
mingw32-gcc.x86_64 \
wine.x86_64
RUN mkdir /bemanitools
WORKDIR /bemanitools
# Order optimized for docker layer caching
COPY run-tests-wine.sh run-tests-wine.sh
COPY CHANGELOG.md CHANGELOG.md
COPY CONTRIBUTING.md CONTRIBUTING.md
COPY LICENSE LICENSE
COPY GNUmakefile GNUmakefile
COPY Module.mk Module.mk
COPY README.md README.md
COPY doc doc
COPY dist dist
COPY src src
# .git folder required or building fails when version is generated
COPY .git .git
# Building
RUN make

View File

@@ -11,34 +11,84 @@ BUILDDIR ?= build
# Internal variables
#
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
bindir := $(BUILDDIR)/bin
builddir_docker := $(BUILDDIR)/docker
toolchain_32 := i686-w64-mingw32-
toolchain_64 := x86_64-w64-mingw32-
docker_container_name := "bemanitools-build"
docker_image_name := "bemanitools:build"
gitrev := $(shell git rev-parse HEAD)
cppflags := -I src -I src/main -I src/test -DGITREV=$(gitrev)
cflags := -O2 -pipe -ffunction-sections -fdata-sections \
-Wall -std=c99
ldflags := -Wl,--gc-sections -static-libgcc
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
bindir := $(BUILDDIR)/bin
toolchain_32 := i686-w64-mingw32-
toolchain_64 := x86_64-w64-mingw32-
gitrev := $(shell git rev-parse HEAD)
cppflags := -I src -I src/main -I src/test -DGITREV=$(gitrev)
cflags := -O2 -pipe -ffunction-sections -fdata-sections \
-Wall -std=c99
cflags_release := -Werror
ldflags := -Wl,--gc-sections -static-libgcc
#
# The first target that GNU Make encounters becomes the default target.
# Define our ultimate target (`all') here, and also some helpers
#
all:
all: build
.PHONY: \
build-docker \
clean \
code-format \
print-building \
print-release \
run-tests \
version
release: \
print-release \
clean \
code-format \
all \
run-tests
build: \
print-building \
version
print-building:
@echo "Build gitrev "$(gitrev)"..."
print-release:
@echo "Starting release build..."
clean:
@echo "Cleaning up..."
$(V)rm -rf $(BUILDDIR)
code-format:
@echo "Applying clang-format..."
# -style=file enables reading .clang-format
@find src/ -iname *.h -o -iname *.c | xargs clang-format -i -style=file
run-tests:
@echo "Running tests..."
@./run-tests-wine.sh
# Generate a version file to identify the build
version:
@echo "$(gitrev)" > version
.PHONY: clean
clean:
$(V)rm -rf $(BUILDDIR)
build-docker:
$(V)docker rm -f $(docker_container_name) 2> /dev/null || true
$(V)docker build -t $(docker_image_name) -f Dockerfile .
$(V)docker create --name $(docker_container_name) $(docker_image_name)
$(V)rm -rf $(builddir_docker)
$(V)mkdir -p $(builddir_docker)
$(V)docker cp $(docker_container_name):/bemanitools/build $(builddir_docker)
$(V)mv $(builddir_docker)/build/* $(builddir_docker)
$(V)rm -r $(builddir_docker)/build
#
# Pull in module definitions
@@ -71,6 +121,7 @@ define t_moddefs
cppflags_$3 += $(cppflags) -DBUILD_MODULE=$3
cflags_$3 += $(cflags)
release: cflags_$3 += $(cflags_release)
ldflags_$3 += $(ldflags)
srcdir_$3 ?= src/main/$3

View File

@@ -77,15 +77,19 @@ imps += avs avs-ea3
include src/main/aciodrv/Module.mk
include src/main/acioemu/Module.mk
include src/main/aciotest/Module.mk
include src/main/asio/Module.mk
include src/main/bio2emu/Module.mk
include src/main/bsthook/Module.mk
include src/main/bstio/Module.mk
include src/main/camhook/Module.mk
include src/main/cconfig/Module.mk
include src/main/config/Module.mk
include src/main/d3d9exhook/Module.mk
include src/main/ddrhook/Module.mk
include src/main/ddrio/Module.mk
include src/main/ddrio-smx/Module.mk
include src/main/ddrio-mm/Module.mk
include src/main/dinput/Module.mk
include src/main/eamio/Module.mk
include src/main/eamio-icca/Module.mk
include src/main/eamiotest/Module.mk
@@ -133,6 +137,8 @@ include src/main/p3ioemu/Module.mk
include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk
include src/main/sdvxhook2/Module.mk
include src/main/sdvxhook2-cn/Module.mk
include src/main/sdvxio/Module.mk
include src/main/sdvxio-kfca/Module.mk
include src/main/security/Module.mk
@@ -146,6 +152,7 @@ include src/test/iidxhook-util/Module.mk
include src/test/security/Module.mk
include src/test/test/Module.mk
include src/test/util/Module.mk
include src/test/iidxhook8/Module.mk
#
# Distribution build rules
@@ -176,6 +183,7 @@ $(zipdir)/tools.zip: \
$(V)zip -j $@ $^
$(zipdir)/tools-x64.zip: \
build/bin/indep-64/aciotest.exe \
build/bin/indep-64/eamiotest.exe \
build/bin/indep-64/iidxiotest.exe \
build/bin/indep-64/iidx-ezusb-exit-hook.dll \
@@ -184,10 +192,6 @@ $(zipdir)/tools-x64.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/src.zip: .git/HEAD $(zipdir)/
$(V)echo ... $@
$(V)git archive -o $@ HEAD
$(zipdir)/iidx-09-to-12.zip: \
build/bin/indep-32/iidxhook1.dll \
build/bin/indep-32/config.exe \
@@ -355,7 +359,9 @@ $(zipdir)/iidx-25-to-26.zip: \
build/bin/indep-64/vefxio.dll \
dist/iidx/config.bat \
dist/iidx/gamestart-25.bat \
dist/iidx/gamestart-26.bat \
dist/iidx/iidxhook-25.conf \
dist/iidx/iidxhook-26.conf \
dist/iidx/vefx.txt \
| $(zipdir)/
$(V)echo ... $@
@@ -401,7 +407,7 @@ $(zipdir)/jb-08.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx.zip: \
$(zipdir)/sdvx-01-to-04.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/sdvxhook.dll \
build/bin/indep-32/config.exe \
@@ -415,6 +421,35 @@ $(zipdir)/sdvx.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-05.zip: \
build/bin/avs2_1700-64/launcher.exe \
build/bin/avs2_1700-64/sdvxhook2.dll \
build/bin/indep-64/config.exe \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/sdvxio.dll \
build/bin/indep-64/sdvxio-kfca.dll \
dist/sdvx5/config.bat \
dist/sdvx5/gamestart.bat \
dist/sdvx5/sdvxhook2.conf \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx-05-cn.zip: \
build/bin/avs2_1700-64/launcher.exe \
build/bin/avs2_1700-64/sdvxhook2-cn.dll \
build/bin/indep-64/config.exe \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/sdvxio.dll \
dist/sdvx5/config.bat \
dist/sdvx5/gamestart-cn.bat \
dist/sdvx5/sdvxhook2-cn.conf \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/ddr-12-to-16.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/ddrhook.dll \
@@ -435,6 +470,22 @@ $(zipdir)/ddr-12-to-16.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/ddr-16-x64.zip: \
build/bin/avs2_1603-64/launcher.exe \
build/bin/avs2_1603-64/ddrhook.dll \
build/bin/avs2_1603-64/unicorntail.dll \
build/bin/indep-64/config.exe \
build/bin/indep-64/ddrio.dll \
build/bin/indep-64/ddrio-mm.dll \
build/bin/indep-64/ddrio-smx.dll \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
dist/ddr/config.bat \
dist/ddr/gamestart-16.bat \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/bst.zip: \
build/bin/avs2_1603-64/bsthook.dll \
build/bin/avs2_1603-64/launcher.exe \
@@ -451,6 +502,7 @@ $(zipdir)/bst.zip: \
$(zipdir)/doc.zip: \
doc/iidxhook \
doc/sdvxhook \
doc/jbhook \
doc/tools \
| $(zipdir)/
@@ -477,6 +529,7 @@ $(BUILDDIR)/tests.zip: \
build/bin/indep-32/security-rp3-test.exe \
build/bin/indep-32/security-util-test.exe \
build/bin/indep-32/util-net-test.exe \
build/bin/indep-64/iidxhook8-config-cam-test.exe \
dist/test/run-tests.sh \
| $(zipdir)/
$(V)echo ... $@
@@ -485,6 +538,7 @@ $(BUILDDIR)/tests.zip: \
$(BUILDDIR)/bemanitools.zip: \
$(zipdir)/bst.zip \
$(zipdir)/ddr-12-to-16.zip \
$(zipdir)/ddr-16-x64.zip \
$(zipdir)/doc.zip \
$(zipdir)/iidx-09-to-12.zip \
$(zipdir)/iidx-13.zip \
@@ -497,8 +551,9 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/jb-01.zip \
$(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \
$(zipdir)/src.zip \
$(zipdir)/sdvx.zip \
$(zipdir)/sdvx-01-to-04.zip \
$(zipdir)/sdvx-05.zip \
$(zipdir)/sdvx-05-cn.zip \
$(zipdir)/tools.zip \
$(zipdir)/tools-x64.zip \
CHANGELOG.md \

View File

@@ -1,5 +1,7 @@
# Bemanitools 5
Version: 5.27</br>
[![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master)
Version: 5.32</br>
[Release history](CHANGELOG.md)
A collection of tools to run [various Bemani arcade games](#list-of-supported-games).
@@ -11,44 +13,45 @@ authentic gameplay experience, and easier support for a broader range of release
# List of supported games
* BeatStream
* BeatStream (bst.zip)
* BeatStream アニムトライヴ (bst.zip)
* BeatStream (bst.zip) using bsthook
* BeatStream アニムトライヴ (bst.zip) using bsthook
* Dance Dance Revolution
* Dance Dance Revolution X2 (ddr-12-to-16.zip)
* Dance Dance Revolution X3 vs. 2ndMIX (ddr-12-to-16.zip)
* Dance Dance Revolution 2013 (ddr-12-to-16.zip)
* Dance Dance Revolution 2014 (ddr-12-to-16.zip)
* Dance Dance Revolution A (ddr-12-to-16.zip)
* Dance Dance Revolution X2 (ddr-12-to-16.zip) using ddrhook
* Dance Dance Revolution X3 vs. 2ndMIX (ddr-12-to-16.zip) using ddrhook
* Dance Dance Revolution 2013 (ddr-12-to-16.zip) using ddrhook
* Dance Dance Revolution 2014 (ddr-12-to-16.zip) using ddrhook
* Dance Dance Revolution A (ddr-12-to-16.zip) using ddrhook
* Beatmania IIDX
* Beatmania IIDX 9th Style (iidx-09-to-12.zip)
* Beatmania IIDX 10th Style (iidx-09-to-12.zip)
* Beatmania IIDX 11 IIDX RED (iidx-09-to-12.zip)
* Beatmania IIDX 12 HAPPY SKY (iidx-09-to-12.zip)
* Beatmania IIDX 13 DistorteD (iidx-13.zip)
* Beatmania IIDX 14 GOLD (iidx-14-to-17.zip)
* Beatmania IIDX 15 DJ TROOPERS (iidx-14-to-17.zip)
* Beatmania IIDX 16 EMPRESS (iidx-14-to-17.zip)
* Beatmania IIDX 17 SIRIUS (iidx-14-to-17.zip)
* Beatmania IIDX 18 Resort Anthem (iidx-18.zip)
* Beatmania IIDX 19 Lincle (iidx-19.zip)
* Beatmania IIDX 20 Tricoro (iidx-20.zip)
* Beatmania IIDX 21 SPADA (iidx-21-to-24.zip)
* Beatmania IIDX 22 PENDUAL (iidx-21-to-24.zip)
* Beatmania IIDX 23 copula (iidx-21-to-24.zip)
* Beatmania IIDX 24 SINOBUZ (iidx-21-to-24.zip)
* Beatmania IIDX 25 CANNON BALLERS (iidx-25-to-26.zip)
* Beatmania IIDX 26 Rootage (iidx-25-to-26.zip)
* Beatmania IIDX 9th Style (iidx-09-to-12.zip) using [iidxhook1](doc/iidxhook/iidxhook1.md)
* Beatmania IIDX 10th Style (iidx-09-to-12.zip) using [iidxhook1](doc/iidxhook/iidxhook1.md)
* Beatmania IIDX 11 IIDX RED (iidx-09-to-12.zip) using [iidxhook1](doc/iidxhook/iidxhook1.md)
* Beatmania IIDX 12 HAPPY SKY (iidx-09-to-12.zip) using [iidxhook1](doc/iidxhook/iidxhook1.md)
* Beatmania IIDX 13 DistorteD (iidx-13.zip) using [iidxhook2](doc/iidxhook/iidxhook2.md)
* Beatmania IIDX 14 GOLD (iidx-14-to-17.zip) using [iidxhook3](doc/iidxhook/iidxhook3.md)
* Beatmania IIDX 15 DJ TROOPERS (iidx-14-to-17.zip) using [iidxhook3](doc/iidxhook/iidxhook3.md)
* Beatmania IIDX 16 EMPRESS (iidx-14-to-17.zip) using [iidxhook3](doc/iidxhook/iidxhook3.md)
* Beatmania IIDX 17 SIRIUS (iidx-14-to-17.zip) using [iidxhook3](doc/iidxhook/iidxhook3.md)
* Beatmania IIDX 18 Resort Anthem (iidx-18.zip) using [iidxhook4](doc/iidxhook/iidxhook4.md)
* Beatmania IIDX 19 Lincle (iidx-19.zip) using [iidxhook5](doc/iidxhook/iidxhook5.md)
* Beatmania IIDX 20 Tricoro (iidx-20.zip) using [iidxhook6](doc/iidxhook/iidxhook6.md)
* Beatmania IIDX 21 SPADA (iidx-21-to-24.zip) using [iidxhook7](doc/iidxhook/iidxhook7.md)
* Beatmania IIDX 22 PENDUAL (iidx-21-to-24.zip) using [iidxhook7](doc/iidxhook/iidxhook7.md)
* Beatmania IIDX 23 copula (iidx-21-to-24.zip) using [iidxhook7](doc/iidxhook/iidxhook7.md)
* Beatmania IIDX 24 SINOBUZ (iidx-21-to-24.zip) using [iidxhook7](doc/iidxhook/iidxhook7.md)
* Beatmania IIDX 25 CANNON BALLERS (iidx-25-to-26.zip) using [iidxhook8](doc/iidxhook/iidxhook8.md)
* Beatmania IIDX 26 Rootage (iidx-25-to-26.zip) using [iidxhook8](doc/iidxhook/iidxhook8.md)
* jubeat
* jubeat (experimental/buggy) (jb-01.zip)
* jubeat saucer (fulfill) (jb-05-to-07.zip)
* jubeat prop (jb-05-to-07.zip)
* jubeat Qubell (jb-05-to-07.zip)
* jubeat clan (jb-08.zip)
* jubeat (experimental/buggy) (jb-01.zip) using [jbhook1](doc/jbhook1/jbhook1.md)
* jubeat saucer (fulfill) (jb-05-to-07.zip) using jbhook
* jubeat prop (jb-05-to-07.zip) using jbhook
* jubeat Qubell (jb-05-to-07.zip) using jbhook
* jubeat clan (jb-08.zip) using jbhook
* SOUND VOLTEX
* SOUND VOLTEX BOOTH (sdvx.zip)
* SOUND VOLTEX II -infinite infection- (sdvx.zip)
* SOUND VOLTEX III GRAVITY WARS (sdvx.zip)
* SOUND VOLTEX IV HEAVENLY HAVEN (sdvx.zip)
* SOUND VOLTEX BOOTH (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX II -infinite infection- (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX III GRAVITY WARS (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX IV HEAVENLY HAVEN (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX Vivid Wave (sdvx-05.zip) using sdvxhook2
# Supported platforms
Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware
@@ -64,10 +67,23 @@ You will find *.md files in various sub-packages that give you further instructi
or FAQ. We advice you to read them as your questions and concerns might already be answered by them. If not, let us
know if there is any information that you consider helpful or important to know and should be added.
# Setup and dependencies
Most (older generation) games were developed for Windows XP Embedded but should run fine on any
consumer version of Windows XP. Newer versions of Windows, e.g. Windows 7, 8 and 10, should be fine
as well. Some hooks also include fixes required to run the games on a more recent version.
Depending on the game, you also need the following dependencies installed:
* DirectX 9 runtime
* Microsoft Visual C++ Redistributables 2010 **and** 2013: Depends on the game and age but both
should cover most if not all of the games so far
# Contributions
Please refer to the [dedicated documentation](CONTRIBUTING.md).
# Development
## Building
See the [development document](doc/development).
## Architecture
A dedicate [architecture document](doc/architecture.md) outlines the architecture of Bemanitools and points out the most
important aspects you should know before you get started with development.
@@ -75,10 +91,6 @@ important aspects you should know before you get started with development.
## API
Please refer to the [API documentation](doc/api.md).
## Source Code
The source code is included with this distribution package (src.zip). Please refer to the
[development document](doc/development.md) for further details.
# 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.

2
dist/bst/config.bat vendored
View File

@@ -1 +1 @@
@start config bst
@start config.exe bst

2
dist/ddr/config.bat vendored
View File

@@ -1 +1 @@
@start config ddr
@start config.exe ddr

View File

@@ -1 +1 @@
@start config iidx
@start config.exe iidx

16
dist/iidx/gamestart-26.bat vendored Normal file
View File

@@ -0,0 +1,16 @@
@echo off
cd /d %~dp0
if not exist dev mkdir dev
if not exist dev\e mkdir dev\e
if not exist dev\g mkdir dev\g
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
if not exist dev\raw\log mkdir dev\raw\log
if not exist dev\raw\fscache mkdir dev\raw\fscache
for /R prop\defaults %%D in (*.*) do (
if not exist dev\nvram\%%~nxD copy /y prop\defaults\%%~nxD dev\nvram
)
launcher -H 134217728 -K iidxhook8.dll bm2dx.dll --config iidxhook-26.conf %*

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Fix broken 3D background on Happy Sky's music select (if appearing completely white)
misc.happy_sky_ms_bg_fix=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Fix broken 3D background on DistorteD's music select (if appearing completely black)
misc.distorted_ms_bg_fix=false

View File

@@ -37,6 +37,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -37,6 +37,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -40,6 +40,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -30,3 +30,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -27,3 +27,9 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1

View File

@@ -28,6 +28,12 @@ gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disables the camera emulation
cam.disable_emu=false

53
dist/iidx/iidxhook-26.conf vendored Normal file
View File

@@ -0,0 +1,53 @@
# Fix stretched BG videos on newer GPUs. Might appear on Red and newer
gfx.bgvideo_uv_fix=false
# Run the game in a framed window (requires windowed option)
gfx.framed=false
# Software limit the frame rate of the rendering loop in hz, e.g. 60 or 59.95 (0.0 = no software limit)
gfx.frame_rate_limit=0.0
# Patch the GPU device ID detection (leave empty to disable), format XXXX:YYYY, two 4 digit hex numbers (vid:pid). Examples: 1002:7146 (RV515, Radeon X1300), 1002:95C5 (RV620 LE, Radeon HD3450)
gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
# Up-/downscale the back buffer's height. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding width parameter.
gfx.scale_back_buffer_height=0
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
gfx.scale_back_buffer_filter=none
# 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
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Disables the camera emulation
cam.disable_emu=false
# Override camera device ID 1 detection (copy from device manager, do not escape)
cam.device_id1=
# Override camera device ID 2 detection (copy from device manager, do not escape)
cam.device_id2=
# Disable card reader emulation and enable usage of real card reader hardware on COM0 (for games supporting slotted readers)
io.disable_card_reader_emu=false
# Disable BIO2 emulation and enable usage of real BIO2 hardware
io.disable_bio2_emu=false
# Disables the poll limiter, warning very high CPU usage may arise
io.disable_poll_limiter=false

2
dist/jb/config.bat vendored
View File

@@ -1 +1 @@
@start config jb
@start config.exe jb

View File

@@ -1 +1 @@
@start config dm
@start config.exe dm

View File

@@ -1 +1 @@
@start config gf
@start config.exe gf

View File

@@ -1 +1 @@
@start config pnm
@start config.exe pnm

View File

@@ -1 +1 @@
@start config sdvx
@start config.exe sdvx

View File

@@ -1 +1 @@
@start config sdvx
@start config.exe sdvx

1
dist/sdvx5/config.bat vendored Normal file
View File

@@ -0,0 +1 @@
@start config.exe sdvx

17
dist/sdvx5/gamestart-cn.bat vendored Normal file
View File

@@ -0,0 +1,17 @@
@echo off
cd /d %~dp0
if not exist dev mkdir dev
if not exist dev\e mkdir dev\e
if not exist dev\g mkdir dev\g
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
if not exist dev\raw\c.dest echo $null >> dev\raw\c.dest
if not exist dev\raw\log mkdir dev\raw\log
if not exist dev\raw\fscache mkdir dev\raw\fscache
for /R prop\defaults %%D in (*.*) do (
if not exist dev\nvram\%%~nxD copy /y prop\defaults\%%~nxD dev\nvram
)
launcher -H 268435456 -K sdvxhook2-cn.dll soundvoltex.dll --config sdvxhook2-cn.conf %*

16
dist/sdvx5/gamestart.bat vendored Normal file
View File

@@ -0,0 +1,16 @@
@echo off
cd /d %~dp0
if not exist dev mkdir dev
if not exist dev\e mkdir dev\e
if not exist dev\g mkdir dev\g
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
if not exist dev\raw\log mkdir dev\raw\log
if not exist dev\raw\fscache mkdir dev\raw\fscache
for /R prop\defaults %%D in (*.*) do (
if not exist dev\nvram\%%~nxD copy /y prop\defaults\%%~nxD dev\nvram
)
launcher -H 268435456 -K sdvxhook2.dll soundvoltex.dll --config sdvxhook2.conf %*

24
dist/sdvx5/sdvxhook2-cn.conf vendored Normal file
View File

@@ -0,0 +1,24 @@
# Disable IO emulation and enable usage of real KFCA hardware
io.disable_io_emu=false
# Path to unis version file under the prop.s folder
cn.unis_path=prop/unis.xml
# Run the game in a framed window (requires windowed option)
gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=720
# Windowed height, -1 for default size
gfx.window_height=1280
# Disables the camera emulation
cam.disable_emu=false
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id1=

45
dist/sdvx5/sdvxhook2.conf vendored Normal file
View File

@@ -0,0 +1,45 @@
# Disable card reader emulation and enable usage of real card reader hardware on COM2
io.disable_card_reader_emu=false
# Disable BIO2 emulation and enable usage of real BIO2 hardware
io.disable_bio2_emu=false
# Disables the poll limiter, warning very high CPU usage may arise
io.disable_poll_limiter=false
# Forces game to think headphones are attached
io.force_headphones=false
# Run the game in a framed window (requires windowed option)
gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse coursor to window
gfx.confined=false
# Windowed width, -1 for default size
gfx.window_width=1080
# Windowed height, -1 for default size
gfx.window_height=1920
# 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
# D3D9ex device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
gfx.device_adapter=-1
# Orientation to force monitor into, -1 to use default, 0, 1, 2, 3 to do 0, 90, 180, 270 degrees
gfx.force_orientation=-1
# Disables the camera emulation
cam.disable_emu=false
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id1=
# IP of adapter to force override with
adapter.override_ip=

14
doc/ddrhook/ddrio-smx.md Normal file
View File

@@ -0,0 +1,14 @@
# Using SMX pads with BemaniTools (DDR Ace and higher)
If you are looking to use StepManiaX pads with DDR, these are supported **natively** for Gen 1 through Gen 5.(And theoretically beyond!) Steps and info below
## Step-by-Step
1. Ensure that you have the latest `SMX.dll` copied to your contents folder. The easiest way to get this is to download and install the latest SMX Config program on [StepManiaX.com](https://data.stepmaniax.com/docs/SMXConfigInstaller-2020-04-03-01.exe). `SMX.dll`'s default install location is `C:\Program Files (x86)\SMXConfig`
2. After bemanitools has been copied to your contents folder, rename the regular `ddrio.dll` to something like `ddrio-orig.dll`.
3. Rename `ddrio-smx.dll` to `ddrio.dll`.
4. Use the config tool to set up the usual stuff.(cards, network, etc.) Be sure to map menu, test, service, and start buttons to your keyboard or other controllers. You **cannot** map SMX panels as joystick inputs.
5. Start the game. If everything works properly, the game will boot and your panels will light up when stepped on during gameplay and song selection.
## Important Things
* Pad panel inputs (UDLR on P1 and P2) are mapped automatically. If you've purchased a single pad from StepManiaX, this jumper is installed and will set your pad to P2 by default. If you want to change to P1, you'll need to open up your pads and remove this jumper in the [MCU box](https://data.stepmaniax.com/docs/Stage%20-%20Gen%205%20Manual%20Rev1.pdf).
* Panel colors set in the SMX config tool are not used. Colors are set internally by Bemanitools.
* If you get a warning about setlights2 when starting the game, your `SMX.dll` is likely out of date. Make sure you've downloaded the latest version of the StepManiaX config tool from stepmaniax.com and have copied the `SMX.dll` to your contents folder.

View File

@@ -36,6 +36,13 @@ development environment which we run on a Linux distribution of our choice:
* C++ Intellisense
* Clang-Format
### Further tools for testing and debugging
* Debugger: Can be part of your reverse engineering IDE of your choice or stand-along like
[OllyDbg](http://www.ollydbg.de/).
* [apitrace](https://apitrace.github.io/): Trace render calls to graphics APIs like D3D and OpenGL.
This tool allows you to record and re-play render calls of an application with frame-by-frame
debugging. Very useful to analyze the render pipeline or debug graphicial glitches.
## Building
Simply run make in the root folder:
```
@@ -44,10 +51,75 @@ make
All output is located in the *build* folder including the final *bemanitools.zip* package.
### Release building
A release build is a clean build including code formatting and testing. This can be executed by running the following
command:
```
make release
```
## Building with docker
You can also build bemanitools using docker which avoids having to setup a full development
environment if you are just interested in building binaries for the latest changes. Naturally, this
requires you to have the docker daemon installed. Then, run the following command from the root
folder of the project:
```bash
make build-docker
```
Once completed successfully, the build output is located in the `build/docker` sub-folder.
## Creating releases
For developers to create official releases with major and minor versioning:
1. Ensure that all everything you want to have for this release is merged into master.
1. Create a [changelog](CHANGELOG.md) based on aggregating and summerizing commit messages of
whatever got added starting from the tag of the current version to the current head of master.
Commit that changelog and push to master.
1. Create a tag with the next version number, e.g. for 5.28:
```bash
git tag v5.28
```
1. Push the tag upstream:
```bash
git push origin v5.28
```
1. Wait for the CI pipeline to finish building the release and check if everything's ok.
1. On GitLab, go to "Tags" in the repository, click on the commit ID below the tag in the list you
just created.
1. Click on the "Pipelines" tab and click on the download button on the right and on "Download
release artifacts".
1. Rename the downloaded zip to "bemanitools-v5.28.zip" and the replace v5.28 with the version
you want to release.
1. Upload the release.
1. For publishing the release, create a post with the following contents:
```
v5.28
<insert link to uploaded zip here>
<additional comments or things to point out for this release>
Changelog copy-paste:
<insert copy-pasted changelog you created previously here>
```
## Code formatting
To apply our code style using clang-format, simply run the following command:
```
make code-format
```
Please also refer to the [section about](###Additional-code-style-guidelines) which cannot be covered using
clang-format.
## Testing
This still needs to be improved/implemented properly to run the unit-tests easily. Currently, you have to be on either
a Linux/MacOSX system to run *run-test-wine.sh* from the root folder. This executes all currently available unit-tests
and reports to the terminal any errors. This requires wine to be installed.
a Linux/MacOSX system and run
```
make run-tests
```
This executes all currently available unit-tests and reports to the terminal any errors. This requires wine to be
installed.
## Project structure
Now that your setup is ready to go, here is brief big picture of what you find in this project.
@@ -140,6 +212,26 @@ if (var == 2) {
printf("%d\n", var);
```
#### Empty line at the start of blocks
There are situations when you want to have an empty line at the start of the block to enhance readability, for example:
```
if (a &&
b &&
c) {
d = 5;
}
```
Here the assignment aligns with the conditions of the if-black making it hard to read. Better:
```
if (a &&
b &&
c) {
d = 5;
}
```
#### Includes
* Always keep all includes at the top of a header and source file. Exception: Documentation before include guards on
header file.
@@ -291,6 +383,20 @@ Upper-case with underscore as spacing, proper namespacing to namespace and modul
#define EZUSB_DEVICE_VID 0xFFFF
```
#### Multiple variable declarations
Only one declaration per line which also avoids various errors, for example:
```
// Nope
char a, b, b;
```
```
// Ok
char a;
char b;
char c;
```
### Testing
We advice you to write unit tests for all modules that allow proper unit testing. This applies to modules that are not
part of the actual hooking process and do not rely on external devices to be available. Add these tests to the

View File

@@ -4,6 +4,11 @@ iidxhook is a collection of hook libraries for BeatmaniaIIDX providing
emulation and various patches to run these games on non BemaniPC hardware and
newer Windows versions.
The hook libraries must be bootstrapped either using [inject](../inject.md) or
[launcher](../launcher.md) depending on the version you want to run. Further
instructions are given in dedicated readme files for each iidxhook version
(see below).
# Versions
iidxhook comes in a few different flavors. The game and its engine changed over

View File

@@ -6,6 +6,8 @@ The following games are compatible with this version of iidxhook:
* RED
* HAPPY SKY
The games must be bootstrapped using [inject](../inject.md).
# Data setup and running the game
Ensure your folder with your unpacked data looks like this:
@@ -24,12 +26,6 @@ integrated sound chip, you have to replace RtEffect.dll with a stubbed/patched
version (RtEffect_patched.dll). Otherwise, the game might crash instantly when
trying to start it.
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you have to use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
Run the appropriate gamestart-XX.bat file as admin, where XX is either
09, 10, 11, 12.
@@ -58,6 +54,14 @@ to have a pre-ceeding "-p" for every parameter added.
However, if a parameter is specifed in the configuration file and as a command
line argument, the command line argument overrides the config file's value.
# Use d3d8to9 wrapper
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you **must** use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID in the
@@ -122,6 +126,10 @@ happens, run the game again.
# Troubleshooting and FAQ
## Window mode or any other gfx related options do not work when changing them in the config file or using cmd args
See [this](#Use-d3d8to9-wrapper) section.
## The game does not run "well" (frame drops, drifting offsync etc)
This can be related to various issues:
* Make sure to run the game as (true) Administrator especially on Windows 7 and

View File

@@ -3,6 +3,8 @@
The following games are compatible with this version of iidxhook:
* DistorteD
The games must be bootstrapped using [inject](../inject.md).
# Data setup and running the game
Ensure your folder with your unpacked data looks like this:
@@ -21,12 +23,6 @@ integrated sound chip, you have to replace RtEffect.dll with a stubbed/patched
version (RtEffect_patched.dll). Otherwise, the game might crash instantly when
trying to start it.
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you have to use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
Run the gamestart-13.bat file as admin.
# Configuring iidxhook
@@ -54,6 +50,14 @@ to have a pre-ceeding "-p" for every parameter added.
However, if a parameter is specifed in the configuration file and as a command
line argument, the command line argument overrides the config file's value.
# Use d3d8to9 wrapper
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you **must** use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID in the
@@ -98,6 +102,10 @@ happens, run the game again.
# Troubleshooting and FAQ
## Window mode or any other gfx related options do not work when changing them in the config file or using cmd args
See [this](#Use-d3d8to9-wrapper) section.
## The game does not run "well" (frame drops, drifting offsync etc)
This can be related to various issues:
* Make sure to run the game as (true) Administrator especially on Windows 7 and

View File

@@ -6,6 +6,8 @@ The following games are compatible with this version of iidxhook:
* EMPRESS
* SIRIUS
The games must be bootstrapped using [inject](../inject.md).
# Data setup and running the game
Ensure your folder with your unpacked data looks like this:

View File

@@ -3,6 +3,8 @@
The following games are compatible with this version of iidxhook:
* Resort Anthem
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
We assume that you are using a clean/vanilla data dump. Ensure your ("concents")

View File

@@ -3,6 +3,8 @@
The following games are compatible with this version of iidxhook:
* Lincle
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
We assume that you are using a clean/vanilla data dump. Ensure your ("concents")

View File

@@ -3,6 +3,8 @@
The following games are compatible with this version of iidxhook:
* Tricoro
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
We assume that you are using a clean/vanilla data dump. Ensure your ("concents")

View File

@@ -6,6 +6,8 @@ The following games are compatible with this version of iidxhook:
* copula
* SINOBUZ
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
We assume that you are using a clean/vanilla data dump. Ensure your ("concents")

View File

@@ -3,6 +3,8 @@
The following games are compatible with this version of iidxhook:
* CANNON BALLERS
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
## Supported versions of Windows

View File

@@ -1,4 +1,4 @@
This library drives a "legacy" ezusb IO board, also known as C02 IO, and
This library drives a "legacy" ezusb IO board, also known as C02/D01 IO, and
implements the iidxio API of BT5. Thus, it allows you to use this IO board with
*any* version of IIDX that is supported by BT5.
@@ -24,5 +24,7 @@ the status LEDs on the side of the board should show a blinking pattern.
dump to the FPGA.
* There is a script called ezusb-boot.bat which combines the two steps above
and can be integrated into the startup process of a dedicated setup.
* If you are using a D01 IO board, use the `fpga-d01.bin` file instead of the
`fpga.bin` file.
* If you ignore these steps, you will either run into errors or parts of the
IO board won't work (e.g. lights).

18
doc/inject.md Normal file
View File

@@ -0,0 +1,18 @@
# Inject
Inject is a tool that creates a process for a specified application executable
file and injects a specified list of library/dll files into the process before
it is kicked off.
Typically, the tool is run when you use one of the bat script files to start
any of the games that require its usage, e.g. older IIDX games.
It comes with further option switches for development, e.g. Halting until
a debugger is attached, outputting debug output to a logfile etc.
Just run the application without any parameters to get a usage message:
```
inject.exe
```
How inject.exe is used can be taken from the bat script files of various
(typically older) games.

15
doc/launcher.md Normal file
View File

@@ -0,0 +1,15 @@
# Launcher
Launcher is a tool which is required to run the more recent titles. It sets up
the AVS environment for the target game to boot before it runs the it.
Typically, the tool is run when you use one of the bat script files to start
any of the games that require its usage, e.g. newer IIDX games.
It comes with option switches to configure the AVS environment and for
development, e.g. Halting until a debugger is attached, outputting debug
output to a logfile etc.
Just run the application without any parameters to get a usage message:
```
launcher.exe
```

View File

@@ -0,0 +1,16 @@
This library talks to a KFCA node through ACIO and implements the sdvxio API of BT5.
Thus, it allows you to use a KFCA device board with *any* version of SDVX that is supported by BT5.
# Setup
* Rename sdvxio-kfca.dll to sdvxio.dll.
* Ensure that your gamestart.bat actually injects the appropriate sdvxhook dll
for example:
```
launcher -K sdvxhook2.dll soundvoltex.dll ...*
```
or that the application otherwise uses sdvxio.dll
* sdvxio-kfca expects a KFCA device on COM3 by default
* You can change the port and baudrate by editing the sdvxio-kfca.conf that should be created by default
* If there is also an ICCA device on the same ACIO bus, it cannot be used with eamio-icca at this time
* Please connect any additional acio devices to their own port (ex: SDVX5 expects an ICCA by itself on COM2)

View File

@@ -14,12 +14,12 @@ it to the list of libraries to inject:
Example when using *inject.exe*:
```
inject iidxhook3.dll mempatch-hook.dll bm2dx.exe --options iidxhook-16.conf --mempatch myPatch.mph %*
inject iidxhook3.dll mempatch-hook.dll bm2dx.exe --config iidxhook-16.conf --mempatch myPatch.mph %*
```
When using *launcher.exe*:
```
launcher -K iidxhook4.dll -K mempatch-hook.dll bm2dx.dll --options iidxhook.conf --mempatch myPatch.mph %*
launcher -K iidxhook4.dll -K mempatch-hook.dll bm2dx.dll --config iidxhook.conf --mempatch myPatch.mph %*
```
To load a patch script, add the *--mempatch <path to patch script>* argument (as

View File

@@ -25,27 +25,33 @@ enum SensorTestMode;
enum SMXUpdateCallbackReason;
struct SMXSensorTestModeData;
// All functions are nonblocking. Getters will return the most recent state. Setters will
// return immediately and do their work in the background. No functions return errors, and
// setting data on a pad which isn't connected will have no effect.
// All functions are nonblocking. Getters will return the most recent state.
// Setters will return immediately and do their work in the background. No
// functions return errors, and setting data on a pad which isn't connected will
// have no effect.
// Initialize, and start searching for devices.
//
// UpdateCallback will be called when something happens: connection or disconnection, inputs
// changed, configuration updated, test data updated, etc. It doesn't specify what's changed,
// and the user should check all state that it's interested in.
// UpdateCallback will be called when something happens: connection or
// disconnection, inputs changed, configuration updated, test data updated, etc.
// It doesn't specify what's changed, and the user should check all state that
// it's interested in.
//
// This is called asynchronously from a helper thread, so the receiver must be thread-safe.
typedef void SMXUpdateCallback(int pad, enum SMXUpdateCallbackReason reason, void *pUser);
SMX_EXTERN_C SMX_API void SMX_Start(SMXUpdateCallback UpdateCallback, void *pUser);
// This is called asynchronously from a helper thread, so the receiver must be
// thread-safe.
typedef void
SMXUpdateCallback(int pad, enum SMXUpdateCallbackReason reason, void *pUser);
SMX_EXTERN_C SMX_API void
SMX_Start(SMXUpdateCallback UpdateCallback, void *pUser);
// Shut down and disconnect from all devices. This will wait for any user callbacks to complete,
// and no user callbacks will be called after this returns. This must not be called from within
// the update callback.
// Shut down and disconnect from all devices. This will wait for any user
// callbacks to complete, and no user callbacks will be called after this
// returns. This must not be called from within the update callback.
SMX_EXTERN_C SMX_API void SMX_Stop();
// Set a function to receive diagnostic logs. By default, logs are written to stdout.
// This can be called before SMX_Start, so it affects any logs sent during initialization.
// Set a function to receive diagnostic logs. By default, logs are written to
// stdout. This can be called before SMX_Start, so it affects any logs sent
// during initialization.
typedef void SMXLogCallback(const char *log);
SMX_EXTERN_C SMX_API void SMX_SetLogCallback(SMXLogCallback callback);
@@ -55,13 +61,24 @@ SMX_EXTERN_C SMX_API void SMX_GetInfo(int pad, struct SMXInfo *info);
// Get a mask of the currently pressed panels.
SMX_EXTERN_C SMX_API uint16_t SMX_GetInputState(int pad);
// Update the lights. Both pads are always updated together. lightsData is a list of 8-bit RGB
// colors, one for each LED. Each panel has lights in the following order:
// (deprecated) Equivalent to SMX_SetLights2(lightsData, 864).
SMX_API void SMX_SetLights(const char lightData[864]);
// Update the lights. Both pads are always updated together. lightData is a list of 8-bit RGB
// colors, one for each LED.
//
// 0123
// 4567
// 89AB
// CDEF
// lightDataSize is the number of bytes in lightsData. This should be 1350 (2 pads * 9 panels *
// 25 lights * 3 RGB colors). For backwards-compatibility, this can also be 864.
//
// Each panel has lights in the following order:
//
// 00 01 02 03
// 16 17 18
// 04 05 06 07
// 19 20 21
// 08 09 10 11
// 22 23 24
// 12 13 14 15
//
// Panels are in the following order:
//
@@ -69,61 +86,70 @@ SMX_EXTERN_C SMX_API uint16_t SMX_GetInputState(int pad);
// 345 CDE
// 678 F01
//
// With 18 panels, 16 LEDs per panel and 3 bytes per LED, each light update has 864 bytes of data.
// With 18 panels, 25 LEDs per panel and 3 bytes per LED, each light update has 1350 bytes of data.
//
// Lights will update at up to 30 FPS. If lights data is sent more quickly, a best effort will be
// made to send the most recent lights data available, but the panels won't update more quickly.
//
// The panels will return to automatic lighting if no lights are received for a while, so applications
// controlling lights should send light updates continually, even if the lights aren't changing.
SMX_EXTERN_C SMX_API void SMX_SetLights(const char lightsData[864]);
// By default, the panels light automatically when stepped on. If a lights command is sent by
// the application, this stops happening to allow the application to fully control lighting.
// If no lights update is received for a few seconds, automatic lighting is reenabled by the
// panels.
//
// SMX_ReenableAutoLights can be called to immediately reenable auto-lighting, without waiting
// for the timeout period to elapse. Games don't need to call this, since the panels will return
// to auto-lighting mode automatically after a brief period of no updates.
// For backwards compatibility, if lightDataSize is 864, the old 4x4-only order is used,
// which simply omits lights 16-24.
SMX_API void SMX_SetLights2(const char *lightData, int lightDataSize);
// By default, the panels light automatically when stepped on. If a lights
// command is sent by the application, this stops happening to allow the
// application to fully control lighting. If no lights update is received for a
// few seconds, automatic lighting is reenabled by the panels.
//
// SMX_ReenableAutoLights can be called to immediately reenable auto-lighting,
// without waiting for the timeout period to elapse. Games don't need to call
// this, since the panels will return to auto-lighting mode automatically after
// a brief period of no updates.
SMX_EXTERN_C SMX_API void SMX_ReenableAutoLights();
// Get the current controller's configuration.
//
// Return true if a configuration is available. If false is returned, no panel is connected
// and no data will be set.
// Return true if a configuration is available. If false is returned, no panel
// is connected and no data will be set.
SMX_EXTERN_C SMX_API bool SMX_GetConfig(int pad, struct SMXConfig *config);
// Update the current controller's configuration. This doesn't block, and the new configuration will
// be sent in the background. SMX_GetConfig will return the new configuration as soon as this call
// returns, without waiting for it to actually be sent to the controller.
SMX_EXTERN_C SMX_API void SMX_SetConfig(int pad, const struct SMXConfig *config);
// Update the current controller's configuration. This doesn't block, and the
// new configuration will be sent in the background. SMX_GetConfig will return
// the new configuration as soon as this call returns, without waiting for it to
// actually be sent to the controller.
SMX_EXTERN_C SMX_API void
SMX_SetConfig(int pad, const struct SMXConfig *config);
// Reset a pad to its original configuration.
SMX_EXTERN_C SMX_API void SMX_FactoryReset(int pad);
// Request an immediate panel recalibration. This is normally not necessary, but can be helpful
// for diagnostics.
// Request an immediate panel recalibration. This is normally not necessary,
// but can be helpful for diagnostics.
SMX_EXTERN_C SMX_API void SMX_ForceRecalibration(int pad);
// Set a panel test mode and request test data. This is used by the configuration tool.
// Set a panel test mode and request test data. This is used by the
// configuration tool.
SMX_EXTERN_C SMX_API void SMX_SetTestMode(int pad, enum SensorTestMode mode);
SMX_EXTERN_C SMX_API bool SMX_GetTestData(int pad, struct SMXSensorTestModeData *data);
SMX_EXTERN_C SMX_API bool
SMX_GetTestData(int pad, struct SMXSensorTestModeData *data);
// Return the build version of the DLL, which is based on the git tag at build time. This
// is only intended for diagnostic logging, and it's also the version we show in SMXConfig.
// Return the build version of the DLL, which is based on the git tag at build
// time. This is only intended for diagnostic logging, and it's also the
// version we show in SMXConfig.
SMX_EXTERN_C SMX_API const char *SMX_Version();
// General info about a connected controller. This can be retrieved with SMX_GetInfo.
struct SMXInfo
{
// True if we're fully connected to this controller. If this is false, the other
// fields won't be set.
// General info about a connected controller. This can be retrieved with
// SMX_GetInfo.
struct SMXInfo {
// True if we're fully connected to this controller. If this is false, the
// other fields won't be set.
bool m_bConnected;
// This device's serial number. This can be used to distinguish devices from each
// other if more than one is connected. This is a null-terminated string instead
// of a C++ string for C# marshalling.
// This device's serial number. This can be used to distinguish devices
// from each other if more than one is connected. This is a null-terminated
// string instead of a C++ string for C# marshalling.
char m_Serial[33];
// This device's firmware version.
@@ -131,22 +157,24 @@ struct SMXInfo
};
enum SMXUpdateCallbackReason {
// This is called when a generic state change happens: connection or disconnection, inputs changed,
// test data updated, etc. It doesn't specify what's changed. We simply check the whole state.
// This is called when a generic state change happens: connection or
// disconnection, inputs changed,
// test data updated, etc. It doesn't specify what's changed. We simply
// check the whole state.
SMXUpdateCallback_Updated,
// This is called when SMX_FactoryReset completes, indicating that SMX_GetConfig will now return
// This is called when SMX_FactoryReset completes, indicating that
// SMX_GetConfig will now return
// the reset configuration.
SMXUpdateCallback_FactoryResetCommandComplete
};
// The configuration for a connected controller. This can be retrieved with SMX_GetConfig
// and modified with SMX_SetConfig.
// The configuration for a connected controller. This can be retrieved with
// SMX_GetConfig and modified with SMX_SetConfig.
//
// The order and packing of this struct corresponds to the configuration packet sent to
// the master controller, so it must not be changed.
struct SMXConfig
{
// The order and packing of this struct corresponds to the configuration packet
// sent to the master controller, so it must not be changed.
struct SMXConfig {
#if 0
// These fields are unused and must be left at their existing values.
uint8_t unused1 = 0xFF, unused2 = 0xFF;
@@ -228,9 +256,10 @@ struct SMXConfig
uint8_t panelThreshold8Low, panelThreshold8High;
#endif
};
//static_assert(sizeof(SMXConfig) == 84, "Expected 84 bytes");
// static_assert(sizeof(SMXConfig) == 84, "Expected 84 bytes");
// The values (except for Off) correspond with the protocol and must not be changed.
// The values (except for Off) correspond with the protocol and must not be
// changed.
enum SensorTestMode {
SensorTestMode_Off = 0,
// Return the raw, uncalibrated value of each sensor.
@@ -246,10 +275,11 @@ enum SensorTestMode {
SensorTestMode_Tare = '3',
};
// Data for the current SensorTestMode. The interpretation of sensorLevel depends on the mode.
struct SMXSensorTestModeData
{
// If false, sensorLevel[n][*] is zero because we didn't receive a response from that panel.
// Data for the current SensorTestMode. The interpretation of sensorLevel
// depends on the mode.
struct SMXSensorTestModeData {
// If false, sensorLevel[n][*] is zero because we didn't receive a response
// from that panel.
bool bHaveDataFromPanel[9];
int16_t sensorLevel[9][4];

View File

@@ -1,6 +1,8 @@
#ifndef IMPORTS_AVS_EA3_H
#define IMPORTS_AVS_EA3_H
#include "imports/avs.h"
void ea3_boot(struct property_node *conf);
void ea3_shutdown(void);

View File

@@ -74,45 +74,44 @@ struct property_psmap {
intptr_t xdefault;
};
#define PSMAP_BEGIN(name) \
struct property_psmap name[] = {
#define PSMAP_BEGIN(name) struct property_psmap name[] = {
#define PSMAP_REQUIRED(type, xstruct, field, path) \
{ \
type, \
0, \
offsetof(xstruct, field), \
sizeof( ((xstruct *) 0)->field ), \
path, \
0, \
}, \
{ \
type, \
0, \
offsetof(xstruct, field), \
sizeof(((xstruct *) 0)->field), \
path, \
0, \
},
#define PSMAP_OPTIONAL(type, xstruct, field, path, xdefault) \
{ \
type, \
PSMAP_FLAG_HAVE_DEFAULT, \
offsetof(xstruct, field), \
sizeof( ((xstruct *) 0)->field ), \
path, \
(intptr_t) xdefault, \
}, \
{ \
type, \
PSMAP_FLAG_HAVE_DEFAULT, \
offsetof(xstruct, field), \
sizeof(((xstruct *) 0)->field), \
path, \
(intptr_t) xdefault, \
},
#define PSMAP_END \
{ 0xFF, 0, 0, 0, NULL, 0 } \
};
#define PSMAP_END \
{ \
0xFF, 0, 0, 0, NULL, 0 \
} \
} \
;
#if AVS_VERSION >= 1500
# define AVS_LOG_WRITER(name, chars, nchars, ctx) \
void name(const char * chars , uint32_t nchars , void * ctx )
#define AVS_LOG_WRITER(name, chars, nchars, ctx) \
void name(const char *chars, uint32_t nchars, void *ctx)
typedef void (*avs_log_writer_t)(const char *chars, uint32_t nchars,
void *ctx);
typedef void (*avs_log_writer_t)(const char *chars, uint32_t nchars, void *ctx);
#else
# define AVS_LOG_WRITER(name, chars, nchars, ctx) \
void name(void * ctx , const char * chars , uint32_t nchars )
#define AVS_LOG_WRITER(name, chars, nchars, ctx) \
void name(void *ctx, const char *chars, uint32_t nchars)
typedef void (*avs_log_writer_t)(void *ctx, const char *chars,
uint32_t nchars);
typedef void (*avs_log_writer_t)(void *ctx, const char *chars, uint32_t nchars);
#endif
typedef int (*avs_reader_t)(uint32_t context, void *bytes, size_t nbytes);
@@ -120,22 +119,38 @@ typedef int (*avs_reader_t)(uint32_t context, void *bytes, size_t nbytes);
#if AVS_VERSION >= 1600
/* "avs" and "std" heaps have been unified */
typedef void (*avs_boot_t)(
struct property_node *config, void *com_heap, size_t sz_com_heap,
void *reserved, avs_log_writer_t log_writer, void *log_context);
struct property_node *config,
void *com_heap,
size_t sz_com_heap,
void *reserved,
avs_log_writer_t log_writer,
void *log_context);
void avs_boot(
struct property_node *config, void *com_heap, size_t sz_com_heap,
void *reserved, avs_log_writer_t log_writer, void *log_context);
struct property_node *config,
void *com_heap,
size_t sz_com_heap,
void *reserved,
avs_log_writer_t log_writer,
void *log_context);
#else
typedef void (*avs_boot_t)(
struct property_node *config, void *std_heap, size_t sz_std_heap,
void *avs_heap, size_t sz_avs_heap, avs_log_writer_t log_writer,
void* log_context);
struct property_node *config,
void *std_heap,
size_t sz_std_heap,
void *avs_heap,
size_t sz_avs_heap,
avs_log_writer_t log_writer,
void *log_context);
void avs_boot(
struct property_node *config, void *std_heap, size_t sz_std_heap,
void *avs_heap, size_t sz_avs_heap, avs_log_writer_t log_writer,
void *log_context);
struct property_node *config,
void *std_heap,
size_t sz_std_heap,
void *avs_heap,
size_t sz_avs_heap,
avs_log_writer_t log_writer,
void *log_context);
#endif
void avs_shutdown(void);
@@ -149,54 +164,70 @@ void log_change_level(int level);
int avs_net_ctrl(int ioctl, void *bytes, uint32_t nbytes);
int avs_thread_create(int (*proc)(void *), void *ctx, uint32_t sz_stack,
unsigned int priority);
int avs_thread_create(
int (*proc)(void *), void *ctx, uint32_t sz_stack, unsigned int priority);
void avs_thread_destroy(int thread_id);
void avs_thread_exit(int result);
void avs_thread_join(int thread_id, int *result);
uint32_t property_read_query_memsize(
avs_reader_t reader, uint32_t context, int unk0, int unk1);
struct property *property_create(
int flags, void *buffer, uint32_t buffer_size);
avs_reader_t reader, uint32_t context, int unk0, int unk1);
struct property *property_create(int flags, void *buffer, uint32_t buffer_size);
struct property_node *property_search(
struct property *prop, struct property_node *root, const char *path);
struct property *prop, struct property_node *root, const char *path);
int property_insert_read(
struct property *prop, struct property_node *root, avs_reader_t reader,
uint32_t context);
struct property *prop,
struct property_node *root,
avs_reader_t reader,
uint32_t context);
int property_mem_write(struct property *prop, void *bytes, int nbytes);
void *property_desc_to_buffer(struct property *prop);
void property_file_write(struct property *prop, const char *path);
int property_set_flag(struct property *prop, int flags, int mask);
void property_destroy(struct property *prop);
int property_psmap_import(struct property *prop, struct property_node *root,
void *dest, const struct property_psmap *psmap);
int property_psmap_export(struct property *prop, struct property_node *root,
const void *src, const struct property_psmap *psmap);
int property_psmap_import(
struct property *prop,
struct property_node *root,
void *dest,
const struct property_psmap *psmap);
int property_psmap_export(
struct property *prop,
struct property_node *root,
const void *src,
const struct property_psmap *psmap);
struct property_node *property_node_clone(
struct property *new_parent, int unk0,
struct property_node *src, bool deep);
struct property *new_parent,
int unk0,
struct property_node *src,
bool deep);
struct property_node *property_node_create(
struct property *prop, struct property_node *parent, int type,
const char *key, ...);
void property_node_name(
struct property_node *node, char *chars, int nchars);
struct property *prop,
struct property_node *parent,
int type,
const char *key,
...);
void property_node_name(struct property_node *node, char *chars, int nchars);
const char *property_node_refdata(struct property_node *node);
int property_node_refer(struct property *prop,
struct property_node *node, const char *name,
enum property_type type, void *bytes, uint32_t nbytes);
int property_node_refer(
struct property *prop,
struct property_node *node,
const char *name,
enum property_type type,
void *bytes,
uint32_t nbytes);
void property_node_remove(struct property_node *node);
enum property_type property_node_type(
struct property_node *node);
enum property_type property_node_type(struct property_node *node);
struct property_node *property_node_traversal(
struct property_node *node, enum property_node_traversal direction);
void property_node_datasize(struct property_node* node);
struct property_node *node, enum property_node_traversal direction);
void property_node_datasize(struct property_node *node);
bool std_getenv(const char *key, char *val, uint32_t nbytes);
void std_setenv(const char *key, const char *val);
void *avs_fs_mount (char* mountpoint, char* fsroot, void* fstype, int flags);
int avs_fs_addfs(void *filesys_struct);
int avs_fs_mount(
const char *mountpoint, const char *fsroot, const char *fstype, void *data);
#endif

View File

@@ -5,6 +5,7 @@ EXPORTS
avs_thread_destroy @7 NONAME
avs_thread_exit @11 NONAME
avs_thread_join @12 NONAME
avs_fs_addfs @73 NONAME
avs_fs_mount @76 NONAME
avs_net_ctrl @119 NONAME
property_create @145 NONAME

View File

@@ -7,6 +7,7 @@ EXPORTS
SMX_GetInfo
SMX_GetInputState
SMX_SetLights
SMX_SetLights2
SMX_ReenableAutoLights
SMX_GetConfig
SMX_SetConfig

View File

@@ -5,6 +5,7 @@ EXPORTS
avs_thread_destroy @7 NONAME
avs_thread_exit @11 NONAME
avs_thread_join @12 NONAME
avs_fs_addfs @73 NONAME
avs_fs_mount @76 NONAME
avs_net_ctrl @119 NONAME
property_create @145 NONAME

View File

@@ -0,0 +1,18 @@
LIBRARY SMX
EXPORTS
SMX_Start
SMX_Stop
SMX_SetLogCallback
SMX_GetInfo
SMX_GetInputState
SMX_SetLights
SMX_SetLights2
SMX_ReenableAutoLights
SMX_GetConfig
SMX_SetConfig
SMX_FactoryReset
SMX_ForceRecalibration
SMX_SetTestMode
SMX_GetTestData
SMX_Version

View File

@@ -5,36 +5,37 @@
#include <stdint.h>
#include <stdlib.h>
#include "acio/hdxs.h"
#include "acio/icca.h"
#include "acio/kfca.h"
#define AC_IO_SOF 0xAA
#define AC_IO_ESCAPE 0xFF
#define AC_IO_RESPONSE_FLAG 0x80
#define AC_IO_BROADCAST 0x70
#define AC_IO_SOF 0xAA
#define AC_IO_ESCAPE 0xFF
#define AC_IO_RESPONSE_FLAG 0x80
#define AC_IO_BROADCAST 0x70
#define ac_io_u16(x) _byteswap_ushort(x)
#define ac_io_u32(x) _byteswap_ulong(x)
#define ac_io_u16(x) _byteswap_ushort(x)
#define ac_io_u32(x) _byteswap_ulong(x)
enum ac_io_cmd {
AC_IO_CMD_ASSIGN_ADDRS = 0x0001,
AC_IO_CMD_GET_VERSION = 0x0002,
AC_IO_CMD_START_UP = 0x0003,
AC_IO_CMD_KEEPALIVE = 0x0080,
AC_IO_CMD_ASSIGN_ADDRS = 0x0001,
AC_IO_CMD_GET_VERSION = 0x0002,
AC_IO_CMD_START_UP = 0x0003,
AC_IO_CMD_KEEPALIVE = 0x0080,
/* Yet unknown command encountered first on jubeat (1) */
AC_IO_CMD_UNKN_00FF = 0x00FF,
AC_IO_CMD_CLEAR = 0x0100,
AC_IO_CMD_UNKN_00FF = 0x00FF,
AC_IO_CMD_CLEAR = 0x0100,
};
enum ac_io_node_type {
AC_IO_NODE_TYPE_H44B = 0x04010000,
AC_IO_NODE_TYPE_ICCA = 0x03000000,
AC_IO_NODE_TYPE_H44B = 0x04010000,
AC_IO_NODE_TYPE_ICCA = 0x03000000,
/* same as ICCA */
AC_IO_NODE_TYPE_ICCB = 0x03000000,
AC_IO_NODE_TYPE_LED_STRIP = 0x04020000,
AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000,
AC_IO_NODE_TYPE_KFCA = 0x09060000,
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
AC_IO_NODE_TYPE_ICCB = 0x03000000,
AC_IO_NODE_TYPE_LED_STRIP = 0x04020000,
AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000,
AC_IO_NODE_TYPE_KFCA = 0x09060000,
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
};
#pragma pack(push, 1)
@@ -52,7 +53,7 @@ struct ac_io_version {
};
struct ac_io_message {
uint8_t addr; /* High bit: clear = req, set = resp */
uint8_t addr; /* High bit: clear = req, set = resp */
union {
struct {
@@ -71,12 +72,14 @@ struct ac_io_message {
struct ac_io_kfca_poll_in kfca_poll_in;
struct ac_io_kfca_poll_out kfca_poll_out;
struct ac_io_hdxs_output hdxs_output;
};
} cmd;
struct {
uint8_t nbytes;
uint8_t raw[0xFF]; /* 0xFFucked if I know */
uint8_t raw[0xFF]; /* 0xFFucked if I know */
} bcast;
};
};

48
src/main/acio/hdxs.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef ACIO_HDXS_H
#define ACIO_HDXS_H
#include <stdint.h>
enum ac_io_hdxs_cmd {
AC_IO_HDXS_CMD_SET_OUTPUTS = 0x0112,
};
#pragma pack(push, 1)
struct ac_io_hdxs_light {
uint8_t analog : 7; // rgb component
uint8_t bit : 1; // buttons
};
struct ac_io_hdxs_output {
uint8_t empty;
struct ac_io_hdxs_light lights[12];
};
enum ac_io_hdxs_front_panel_lights {
AC_IO_HDXS_OUT_P1_START = 0,
AC_IO_HDXS_OUT_P1_UP_DOWN = 1,
AC_IO_HDXS_OUT_P1_LEFT_RIGHT = 2,
AC_IO_HDXS_OUT_P2_START = 3,
AC_IO_HDXS_OUT_P2_UP_DOWN = 4,
AC_IO_HDXS_OUT_P2_LEFT_RIGHT = 5,
};
enum ac_io_hdxs_grb_layout {
AC_IO_HDXS_GREEN = 0,
AC_IO_HDXS_RED = 1,
AC_IO_HDXS_BLUE = 2,
};
enum ac_io_hdxs_speaker_lights {
AC_IO_HDXS_OUT_P1_SPEAKER_F = 0,
AC_IO_HDXS_OUT_P2_SPEAKER_F = 1,
AC_IO_HDXS_OUT_P1_SPEAKER_W = 2,
AC_IO_HDXS_OUT_P2_SPEAKER_W = 3,
};
_Static_assert(
sizeof(struct ac_io_hdxs_output) == 13,
"ac_io_hdxs_output is the wrong size");
#pragma pack(pop)
#endif

View File

@@ -5,13 +5,15 @@
enum ac_io_icca_cmd {
/* Yet unknown command encountered first on jubeat (1) */
AC_IO_ICCA_CMD_UNKN_0120 = 0x0120,
AC_IO_ICCA_CMD_UNKN_0120 = 0x0120,
AC_IO_ICCA_CMD_QUEUE_LOOP_START = 0x0130,
AC_IO_ICCA_CMD_ENGAGE = 0x0131,
AC_IO_ICCA_CMD_POLL = 0x0134,
AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135,
AC_IO_ICCA_CMD_BEGIN_KEYPAD = 0x013A,
AC_IO_ICCA_CMD_POLL_FELICA = 0x0161,
AC_IO_ICCA_CMD_ENGAGE = 0x0131,
AC_IO_ICCA_CMD_POLL = 0x0134,
AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135,
AC_IO_ICCA_CMD_BEGIN_KEYPAD = 0x013A,
AC_IO_ICCA_CMD_POLL_FELICA = 0x0161,
AC_IO_ICCA_CMD_KEY_EXCHANGE = 0x0160,
AC_IO_ICCA_CMD_POLL_ENCRYPTED = 0x0164,
};
enum ac_io_icca_slot_state {

View File

@@ -5,16 +5,16 @@
enum ac_io_iccb_cmd {
/* found on jubeat prop, sent after acio init req, maybe fw update? */
AC_IO_ICCB_CMD_UNK_0100 = 0x0100,
AC_IO_ICCB_CMD_UNK_0100 = 0x0100,
/* found on jubeat prop, sent right after queue loop start */
AC_IO_ICCB_CMD_UNK_0116 = 0x0116,
AC_IO_ICCB_CMD_UNK_0116 = 0x0116,
/* found on jubeat prop, sent after 0100 req */
AC_IO_ICCB_CMD_UNK_0120 = 0x0120,
AC_IO_ICCB_CMD_UNK_0120 = 0x0120,
AC_IO_ICCB_CMD_QUEUE_LOOP_START = 0x0130,
AC_IO_ICCB_CMD_POLL = 0x0134,
AC_IO_ICCB_CMD_UNK_135 = 0x0135,
AC_IO_ICCB_CMD_SLEEP = 0x013A,
AC_IO_ICCB_CMD_READ_CARD = 0x0161
AC_IO_ICCB_CMD_POLL = 0x0134,
AC_IO_ICCB_CMD_UNK_135 = 0x0135,
AC_IO_ICCB_CMD_SLEEP = 0x013A,
AC_IO_ICCB_CMD_READ_CARD = 0x0161
};
enum ac_io_iccb_sensor_state {

View File

@@ -1,25 +1,25 @@
#ifndef AC_IO_KFCA_H
#define AC_IO_KFCA_H
#define AC_IO_CMD_KFCA_POLL 0x0113
#define AC_IO_CMD_KFCA_WATCHDOG 0x0120
#define AC_IO_CMD_KFCA_AMP_CONTROL 0x0128
#define AC_IO_CMD_KFCA_POLL 0x0113
#define AC_IO_CMD_KFCA_WATCHDOG 0x0120
#define AC_IO_CMD_KFCA_AMP_CONTROL 0x0128
#define AC_IO_KFCA_IN_GPIO_SYS_COIN 0x04
#define AC_IO_KFCA_IN_GPIO_SYS_COIN 0x04
/* ... AC_IO_KFCA_IN_GPIO_SYS_COIN2 0x08 (maybe?) */
#define AC_IO_KFCA_IN_GPIO_SYS_TEST 0x10
#define AC_IO_KFCA_IN_GPIO_SYS_SERVICE 0x20
#define AC_IO_KFCA_IN_GPIO_SYS_TEST 0x10
#define AC_IO_KFCA_IN_GPIO_SYS_SERVICE 0x20
#define AC_IO_KFCA_IN_GPIO_0_C 0x0001
#define AC_IO_KFCA_IN_GPIO_0_B 0x0002
#define AC_IO_KFCA_IN_GPIO_0_A 0x0004
#define AC_IO_KFCA_IN_GPIO_0_START 0x0008
#define AC_IO_KFCA_IN_GPIO_0_RECORDER 0x0010
#define AC_IO_KFCA_IN_GPIO_0_HEADPHONE 0x0020
#define AC_IO_KFCA_IN_GPIO_0_C 0x0001
#define AC_IO_KFCA_IN_GPIO_0_B 0x0002
#define AC_IO_KFCA_IN_GPIO_0_A 0x0004
#define AC_IO_KFCA_IN_GPIO_0_START 0x0008
#define AC_IO_KFCA_IN_GPIO_0_RECORDER 0x0010
#define AC_IO_KFCA_IN_GPIO_0_HEADPHONE 0x0020
#define AC_IO_KFCA_IN_GPIO_1_FX_R 0x0008
#define AC_IO_KFCA_IN_GPIO_1_FX_L 0x0010
#define AC_IO_KFCA_IN_GPIO_1_D 0x0020
#define AC_IO_KFCA_IN_GPIO_1_FX_R 0x0008
#define AC_IO_KFCA_IN_GPIO_1_FX_L 0x0010
#define AC_IO_KFCA_IN_GPIO_1_D 0x0020
#pragma pack(push, 1)

View File

@@ -19,6 +19,7 @@ static char aviodrv_device_node_products[16][4];
static bool aciodrv_device_init(void)
{
uint8_t init_seq[1] = {AC_IO_SOF};
uint8_t read_buff[1] = {0x00};
/* init/reset the device by sending 0xAA until 0xAA is returned */
int read = 0;
@@ -27,33 +28,36 @@ static bool aciodrv_device_init(void)
return false;
}
read = aciodrv_port_read(init_seq, sizeof(init_seq));
} while (read == 0);
read = aciodrv_port_read(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");
/* empty buffer by reading all data */
while (read > 0) {
read = aciodrv_port_read(init_seq, sizeof(init_seq));
}
log_warning("Cleared buffer, init done");
return read == 0;
} else {
log_warning("Read failure when trying to clear device state");
return false;
}
}
#ifdef AC_IO_MSG_LOG
static void aciodrv_device_log_buffer(const char* msg, const uint8_t* buffer,
int length)
static void
aciodrv_device_log_buffer(const char *msg, const uint8_t *buffer, int length)
{
char str[4096];
hex_encode_uc((const void*) buffer, length, str, sizeof(str));
hex_encode_uc((const void *) buffer, length, str, sizeof(str));
log_misc("%s, length %d: %s", msg, length, str);
}
#endif
static bool aciodrv_device_send(const uint8_t* buffer, int length)
static bool aciodrv_device_send(const uint8_t *buffer, int length)
{
uint8_t send_buf[512];
int send_buf_pos = 0;
@@ -102,7 +106,7 @@ static bool aciodrv_device_send(const uint8_t* buffer, int length)
return true;
}
static int aciodrv_device_receive(uint8_t* buffer, int size)
static int aciodrv_device_receive(uint8_t *buffer, int size)
{
uint8_t recv_buf[512];
int recv_size = 0;
@@ -142,8 +146,7 @@ static int aciodrv_device_receive(uint8_t* buffer, int size)
/* check for escape byte. these don't count towards the
size we expect! */
if (recv_buf[recv_size] == AC_IO_ESCAPE)
{
if (recv_buf[recv_size] == AC_IO_ESCAPE) {
/* next byte is our real data
overwrite escape byte */
do {
@@ -162,7 +165,7 @@ static int aciodrv_device_receive(uint8_t* buffer, int size)
}
#ifdef AC_IO_MSG_LOG
aciodrv_device_log_buffer("Recv (1)", recv_buf, recv_size);
aciodrv_device_log_buffer("Recv (1)", recv_buf, recv_size);
#endif
/* recv_size - 1: omit checksum for checksum calc */
@@ -174,12 +177,14 @@ 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("Recv (2)", buffer, result_size);
#endif
if (checksum != recv_buf[recv_size - 1]) {
log_warning("Invalid message checksum: %02X != %02X",
checksum, recv_buf[recv_size - 1]);
log_warning(
"Invalid message checksum: %02X != %02X",
checksum,
recv_buf[recv_size - 1]);
return -1;
}
@@ -198,7 +203,8 @@ static uint8_t aciodrv_device_enum_nodes(void)
msg.cmd.nbytes = 1;
msg.cmd.count = 0;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Enumerating nodes failed");
return 0;
}
@@ -216,13 +222,16 @@ static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
msg.cmd.code = ac_io_u16(AC_IO_CMD_GET_VERSION);
msg.cmd.nbytes = 0;
if ( !aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) +
sizeof(struct ac_io_version))) {
if (!aciodrv_send_and_recv(
&msg,
offsetof(struct ac_io_message, cmd.raw) +
sizeof(struct ac_io_version))) {
log_warning("Get version of node %d failed", node_id);
return false;
}
log_info("Node %d: type %d, flag %d, version %d.%d.%d, product %c%c%c%c, "
log_info(
"Node %d: type %d, flag %d, version %d.%d.%d, product %c%c%c%c, "
"build date: %s %s",
node_id,
msg.cmd.version.type,
@@ -250,7 +259,8 @@ static bool aciodrv_device_start_node(uint8_t node_id)
msg.cmd.code = ac_io_u16(AC_IO_CMD_START_UP);
msg.cmd.nbytes = 0;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting node %d failed", node_id);
return false;
}
@@ -259,7 +269,7 @@ static bool aciodrv_device_start_node(uint8_t node_id)
return true;
}
bool aciodrv_device_open(const char* port, int baud)
bool aciodrv_device_open(const char *port, int baud)
{
if (!aciodrv_port_open(port, baud)) {
return false;
@@ -275,7 +285,8 @@ bool aciodrv_device_open(const char* port, int baud)
}
for (uint8_t i = 0; i < aciodrv_device_node_count; i++) {
if (!aciodrv_device_get_version(i + 1, aviodrv_device_node_products[i])) {
if (!aciodrv_device_get_version(
i + 1, aviodrv_device_node_products[i])) {
return false;
}
}
@@ -304,25 +315,32 @@ bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4])
return true;
}
bool aciodrv_send_and_recv(struct ac_io_message* msg, int resp_size)
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
{
msg->cmd.seq_no = aciodrv_device_msg_counter++;
int send_size = offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes;
if (aciodrv_device_send((uint8_t*) msg,
offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes) <= 0) {
#ifdef AC_IO_MSG_LOG
log_info("Beginning send on %d: %04x (%d b)", msg->addr, msg->cmd.code, send_size);
#endif
if (aciodrv_device_send((uint8_t *) msg, send_size) <= 0) {
return false;
}
uint16_t req_code = msg->cmd.code;
if (aciodrv_device_receive((uint8_t*) msg,
resp_size) <= 0) {
#ifdef AC_IO_MSG_LOG
log_info("Beginning recv: (%d b)", resp_size);
#endif
if (aciodrv_device_receive((uint8_t *) msg, resp_size) <= 0) {
return false;
}
if (req_code != msg->cmd.code) {
log_warning("Received invalid response %04X for request %04X",
msg->cmd.code, req_code);
log_warning(
"Received invalid response %04X for request %04X",
msg->cmd.code,
req_code);
return false;
}

View File

@@ -13,7 +13,7 @@
* @return True if opening the port and resetting the device was successful,
* false on error.
*/
bool aciodrv_device_open(const char* port, int baud);
bool aciodrv_device_open(const char *port, int baud);
/**
* Get the node count on the opened device.
@@ -27,8 +27,8 @@ uint8_t aciodrv_device_get_node_count(void);
*
* @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.
* @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]);
@@ -42,7 +42,7 @@ bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4]);
* @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 ac_io_message *msg, int resp_size);
/**
* Close the previously opened ACIO device.

View File

@@ -15,13 +15,14 @@ static bool aciodrv_icca_queue_loop_start(uint8_t node_id)
msg.cmd.nbytes = 1;
msg.cmd.status = 0;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Starting queue loop failed");
return false;
}
log_info("Started queue loop of node %d, status: %d",
node_id, msg.cmd.status);
log_info(
"Started queue loop of node %d, status: %d", node_id, msg.cmd.status);
return true;
}
@@ -35,8 +36,8 @@ bool aciodrv_icca_init(uint8_t node_id)
return true;
}
bool aciodrv_icca_set_state(uint8_t node_id, int slot_state,
struct ac_io_icca_state* state)
bool aciodrv_icca_set_state(
uint8_t node_id, int slot_state, struct ac_io_icca_state *state)
{
struct ac_io_message msg;
@@ -47,8 +48,8 @@ bool aciodrv_icca_set_state(uint8_t node_id, int slot_state,
msg.cmd.raw[0] = sizeof(struct ac_io_icca_state);
msg.cmd.raw[1] = slot_state;
if ( !aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) +
msg.cmd.raw[0])) {
if (!aciodrv_send_and_recv(
&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;
}
@@ -60,7 +61,7 @@ bool aciodrv_icca_set_state(uint8_t node_id, int slot_state,
return true;
}
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state* state)
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
{
struct ac_io_message msg;
@@ -70,8 +71,8 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state* state)
/* buffer size of data we expect */
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)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
log_warning("Getting state of node %d failed", node_id + 1);
return false;
}
@@ -83,7 +84,7 @@ 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(uint8_t node_id, struct ac_io_icca_state *state)
{
struct ac_io_message msg;
@@ -93,8 +94,8 @@ bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state* state)
/* buffer size of data we expect */
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)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
log_warning("Reading card of node %d failed", node_id + 1);
return false;
}

View File

@@ -26,7 +26,8 @@ bool aciodrv_icca_init(uint8_t node_id);
* device driver foundation.
* @see driver.h
*/
bool aciodrv_icca_set_state(uint8_t node_id, int slot_state, struct ac_io_icca_state* state);
bool aciodrv_icca_set_state(
uint8_t node_id, int slot_state, struct ac_io_icca_state *state);
/**
* Get the current state of an ICCA node.
@@ -39,7 +40,7 @@ bool aciodrv_icca_set_state(uint8_t node_id, int slot_state, struct ac_io_icca_s
* 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(uint8_t node_id, struct ac_io_icca_state *state);
/**
* Trigger a card read action on the ICCA reader. Make sure to call this
@@ -55,6 +56,6 @@ 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(uint8_t node_id, struct ac_io_icca_state *state);
#endif

View File

@@ -1,7 +1,7 @@
#define LOG_MODULE "aciodrv-kfca"
#include <string.h>
#include <stdio.h>
#include <string.h>
#include "aciodrv/device.h"
@@ -9,10 +9,9 @@
static bool aciodrv_kfca_watchdog_start(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)
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
return true;
/*
@@ -27,9 +26,8 @@ static bool aciodrv_kfca_watchdog_start(uint8_t node_id)
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(&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",
@@ -54,7 +52,8 @@ static bool aciodrv_kfca_amp(uint8_t node_id)
msg.cmd.raw[2] = 0;
msg.cmd.raw[3] = 0;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
@@ -77,17 +76,21 @@ bool aciodrv_kfca_init(uint8_t node_id)
return true;
}
bool aciodrv_kfca_poll(uint8_t node_id, const struct ac_io_kfca_poll_out* pout, struct ac_io_kfca_poll_in* pin)
bool aciodrv_kfca_poll(
uint8_t node_id,
const struct ac_io_kfca_poll_out *pout,
struct ac_io_kfca_poll_in *pin)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
/* buffer size of data we expect */
msg.cmd.kfca_poll_out = *pout;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@@ -25,6 +25,9 @@ bool aciodrv_kfca_init(uint8_t node_id);
* device driver foundation.
* @see driver.h
*/
bool aciodrv_kfca_poll(uint8_t node_id, const struct ac_io_kfca_poll_out* pout, struct ac_io_kfca_poll_in* pin);
bool aciodrv_kfca_poll(
uint8_t node_id,
const struct ac_io_kfca_poll_out *pout,
struct ac_io_kfca_poll_in *pin);
#endif

View File

@@ -9,15 +9,21 @@
static HANDLE aciodrv_port_fd;
bool aciodrv_port_open(const char* port, int baud)
bool aciodrv_port_open(const char *port, int baud)
{
COMMTIMEOUTS ct;
DCB dcb;
log_info("Opening ACIO on %s at %d baud", port, baud);
aciodrv_port_fd = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL, NULL);
aciodrv_port_fd = CreateFile(
port,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL,
NULL);
if (aciodrv_port_fd == INVALID_HANDLE_VALUE) {
log_warning("Failed to open %s", port);
@@ -37,9 +43,9 @@ bool aciodrv_port_open(const char* port, int baud)
goto fail;
}
if (!PurgeComm(aciodrv_port_fd,
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
if (!PurgeComm(
aciodrv_port_fd,
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
log_warning("PurgeComm failed");
goto fail;
@@ -143,7 +149,7 @@ int aciodrv_port_write(const void *bytes, int nbytes)
log_warning("WriteFile failed: err = %lu", GetLastError());
return -1;
}
}
return nwrit;
}
@@ -154,4 +160,3 @@ void aciodrv_port_close(void)
CloseHandle(aciodrv_port_fd);
}
}

View File

@@ -1,8 +1,8 @@
#ifndef ACIODRV_PORT_H
#define ACIODRV_PORT_H
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
/**
* Open a serial port for communication with a ACIO device.
@@ -12,7 +12,7 @@
* @return True if opening the com port was successful, false on error.
* @note This will open and setup the com port, only.
*/
bool aciodrv_port_open(const char* port, int baud);
bool aciodrv_port_open(const char *port, int baud);
/**
* Read data from the opened com port.

View File

@@ -8,9 +8,7 @@
#include "util/log.h"
void ac_io_emu_cmd_assign_addrs(
struct ac_io_emu *emu,
const struct ac_io_message *req,
uint8_t node_count)
struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t node_count)
{
struct ac_io_message resp;
uint16_t cmd;
@@ -21,9 +19,7 @@ void ac_io_emu_cmd_assign_addrs(
cmd = ac_io_u16(req->cmd.code);
if (cmd != AC_IO_CMD_ASSIGN_ADDRS) {
log_warning(
"Address 0 expects address assignment cmd, got %04x",
cmd);
log_warning("Address 0 expects address assignment cmd, got %04x", cmd);
return;
}

View File

@@ -8,8 +8,6 @@
#include <stdint.h>
void ac_io_emu_cmd_assign_addrs(
struct ac_io_emu *emu,
const struct ac_io_message *req,
uint8_t node_count);
struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t node_count);
#endif

View File

@@ -1,8 +1,11 @@
#include <windows.h> /* Usermode API */
#include <windows.h> /* Usermode API */
#include <ntdef.h> /* Kernel-mode API for ioctls */
// clang-format off
// Don't format because the order is important here
#include <ntdef.h>
#include <devioctl.h>
#include <ntddser.h>
// clang-format on
#include <stdbool.h>
#include <stdint.h>
@@ -61,18 +64,26 @@ bool ac_io_emu_match_irp(const struct ac_io_emu *emu, const struct irp *irp)
}
}
HRESULT ac_io_emu_dispatch_irp(struct ac_io_emu *emu, struct irp *irp)
HRESULT
ac_io_emu_dispatch_irp(struct ac_io_emu *emu, struct irp *irp)
{
log_assert(irp != NULL);
switch (irp->op) {
case IRP_OP_OPEN: return ac_io_emu_open(emu, irp);
case IRP_OP_CLOSE: return ac_io_emu_close(emu, irp);
case IRP_OP_READ: return ac_io_emu_read(emu, irp);
case IRP_OP_WRITE: return ac_io_emu_write(emu, irp);
case IRP_OP_IOCTL: return ac_io_emu_ioctl(emu, irp);
case IRP_OP_FSYNC: return S_FALSE;
default: return E_NOTIMPL;
case IRP_OP_OPEN:
return ac_io_emu_open(emu, irp);
case IRP_OP_CLOSE:
return ac_io_emu_close(emu, irp);
case IRP_OP_READ:
return ac_io_emu_read(emu, irp);
case IRP_OP_WRITE:
return ac_io_emu_write(emu, irp);
case IRP_OP_IOCTL:
return ac_io_emu_ioctl(emu, irp);
case IRP_OP_FSYNC:
return S_FALSE;
default:
return E_NOTIMPL;
}
}
@@ -129,29 +140,30 @@ static HRESULT ac_io_emu_ioctl(struct ac_io_emu *emu, struct irp *irp)
log_assert(irp != NULL);
switch (irp->ioctl) {
case IOCTL_SERIAL_GET_COMMSTATUS:
if (irp->read.bytes == NULL) {
log_warning("IOCTL_SERIAL_GET_COMMSTATUS: Output buffer is NULL");
case IOCTL_SERIAL_GET_COMMSTATUS:
if (irp->read.bytes == NULL) {
log_warning(
"IOCTL_SERIAL_GET_COMMSTATUS: Output buffer is NULL");
return E_INVALIDARG;
}
return E_INVALIDARG;
}
if (irp->read.nbytes < sizeof(*status)) {
log_warning("IOCTL_SERIAL_GET_COMMSTATUS: Buffer is too small");
if (irp->read.nbytes < sizeof(*status)) {
log_warning("IOCTL_SERIAL_GET_COMMSTATUS: Buffer is too small");
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
status = (SERIAL_STATUS *) irp->read.bytes;
status->Errors = 0;
status->AmountInInQueue = ac_io_in_is_msg_pending(&emu->in);
status = (SERIAL_STATUS *) irp->read.bytes;
status->Errors = 0;
status->AmountInInQueue = ac_io_in_is_msg_pending(&emu->in);
irp->read.pos = sizeof(*status);
irp->read.pos = sizeof(*status);
return S_FALSE;
return S_FALSE;
default:
return S_FALSE;
default:
return S_FALSE;
}
}
@@ -170,9 +182,7 @@ void ac_io_emu_request_pop(struct ac_io_emu *emu)
}
void ac_io_emu_response_push(
struct ac_io_emu *emu,
const struct ac_io_message *resp,
uint64_t delay_us)
struct ac_io_emu *emu, const struct ac_io_message *resp, uint64_t delay_us)
{
log_assert(emu != NULL);
log_assert(resp != NULL);
@@ -181,14 +191,10 @@ void ac_io_emu_response_push(
}
void ac_io_emu_response_push_thunk(
struct ac_io_emu *emu,
ac_io_in_thunk_t thunk,
void *ctx,
uint64_t delay_us)
struct ac_io_emu *emu, ac_io_in_thunk_t thunk, void *ctx, uint64_t delay_us)
{
log_assert(emu != NULL);
log_assert(thunk != NULL);
ac_io_in_supply_thunk(&emu->in, thunk, ctx, delay_us);
}

View File

@@ -27,13 +27,11 @@ HRESULT ac_io_emu_dispatch_irp(struct ac_io_emu *emu, struct irp *irp);
const struct ac_io_message *ac_io_emu_request_peek(const struct ac_io_emu *emu);
void ac_io_emu_request_pop(struct ac_io_emu *emu);
void ac_io_emu_response_push(
struct ac_io_emu *emu,
const struct ac_io_message *resp,
uint64_t delay_ms);
struct ac_io_emu *emu, const struct ac_io_message *resp, uint64_t delay_ms);
void ac_io_emu_response_push_thunk(
struct ac_io_emu *emu,
ac_io_in_thunk_t thunk,
void *ctx,
uint64_t delay_ms);
struct ac_io_emu *emu,
ac_io_in_thunk_t thunk,
void *ctx,
uint64_t delay_ms);
#endif

View File

@@ -16,18 +16,15 @@
#include "util/hex.h"
static void ac_io_emu_h44b_cmd_send_version(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req);
struct ac_io_emu_h44b *h44b, const struct ac_io_message *req);
static void ac_io_emu_h44b_send_status(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req,
uint8_t status);
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req,
uint8_t status);
void ac_io_emu_h44b_init(
struct ac_io_emu_h44b *h44b,
struct ac_io_emu *emu,
uint8_t unit_no)
struct ac_io_emu_h44b *h44b, struct ac_io_emu *emu, uint8_t unit_no)
{
memset(h44b, 0, sizeof(*h44b));
h44b->emu = emu;
@@ -35,8 +32,7 @@ void ac_io_emu_h44b_init(
}
void ac_io_emu_h44b_dispatch_request(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req)
struct ac_io_emu_h44b *h44b, const struct ac_io_message *req)
{
uint16_t cmd_code;
@@ -58,7 +54,8 @@ void ac_io_emu_h44b_dispatch_request(
case AC_IO_H44B_CMD_SET_OUTPUTS:
/* Not using the struct ac_io_h44b_output here */
for (int i = 0; i < 6; i++) {
jb_io_set_rgb_led((enum jb_io_rgb_led) i,
jb_io_set_rgb_led(
(enum jb_io_rgb_led) i,
req->cmd.raw[i * 3],
req->cmd.raw[i * 3 + 1],
req->cmd.raw[i * 3 + 2]);
@@ -71,16 +68,17 @@ void ac_io_emu_h44b_dispatch_request(
break;
default:
log_warning("Unknown ACIO message %04x on h44b node, addr=%d",
cmd_code, req->addr);
log_warning(
"Unknown ACIO message %04x on h44b node, addr=%d",
cmd_code,
req->addr);
break;
}
}
static void ac_io_emu_h44b_cmd_send_version(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req)
struct ac_io_emu_h44b *h44b, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -93,8 +91,10 @@ static void ac_io_emu_h44b_cmd_send_version(
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x00;
resp.cmd.version.revision = 0x02;
memcpy(resp.cmd.version.product_code, "H44B",
sizeof(resp.cmd.version.product_code));
memcpy(
resp.cmd.version.product_code,
"H44B",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
@@ -102,9 +102,9 @@ static void ac_io_emu_h44b_cmd_send_version(
}
static void ac_io_emu_h44b_send_status(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req,
uint8_t status)
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req,
uint8_t status)
{
struct ac_io_message resp;

View File

@@ -15,12 +15,9 @@ struct ac_io_emu_h44b {
void acioemu_h44b_init(void);
void ac_io_emu_h44b_init(
struct ac_io_emu_h44b *h44b,
struct ac_io_emu *emu,
uint8_t unit_no);
struct ac_io_emu_h44b *h44b, struct ac_io_emu *emu, uint8_t unit_no);
void ac_io_emu_h44b_dispatch_request(
struct ac_io_emu_h44b *h44b,
const struct ac_io_message *req);
struct ac_io_emu_h44b *h44b, const struct ac_io_message *req);
#endif

View File

@@ -1,5 +1,6 @@
#define LOG_MODULE "acioemu-hdxs"
#include "acio/hdxs.h"
#include "acio/acio.h"
#include "acioemu/emu.h"
@@ -8,31 +9,34 @@
#include "util/log.h"
static void ac_io_emu_hdxs_cmd_send_version(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req);
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req);
static void ac_io_emu_hdxs_send_empty(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req);
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req);
static void ac_io_emu_hdxs_send_status(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req,
uint8_t status);
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req,
uint8_t status);
void ac_io_emu_hdxs_init(
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu)
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu,
acio_hdxs_dispatcher lights_dispatcher)
{
log_assert(hdxs != NULL);
log_assert(emu != NULL);
if (lights_dispatcher == NULL) {
log_warning("NULL lights_dispatcher, HDXS light output won't work");
}
hdxs->emu = emu;
hdxs->lights_dispatcher = lights_dispatcher;
}
void ac_io_emu_hdxs_dispatch_request(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req)
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req)
{
uint16_t cmd_code;
@@ -42,46 +46,55 @@ void ac_io_emu_hdxs_dispatch_request(
cmd_code = ac_io_u16(req->cmd.code);
switch (cmd_code) {
case AC_IO_CMD_GET_VERSION:
log_misc("AC_IO_CMD_GET_VERSION(%d)", req->addr);
ac_io_emu_hdxs_cmd_send_version(hdxs, req);
case AC_IO_CMD_GET_VERSION:
log_misc("AC_IO_CMD_GET_VERSION(%d)", req->addr);
ac_io_emu_hdxs_cmd_send_version(hdxs, req);
break;
break;
case AC_IO_CMD_START_UP:
log_misc("AC_IO_CMD_START_UP(%d)", req->addr);
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
case AC_IO_CMD_START_UP:
log_misc("AC_IO_CMD_START_UP(%d)", req->addr);
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
break;
break;
case AC_IO_CMD_CLEAR:
log_misc("AC_IO_CMD_CLEAR(%d)", req->addr);
case AC_IO_CMD_CLEAR:
log_misc("AC_IO_CMD_CLEAR(%d)", req->addr);
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
case 0x110:
case 0x112:
case 0x128:
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
break;
break;
case AC_IO_HDXS_CMD_SET_OUTPUTS:
if (hdxs->lights_dispatcher != NULL) {
hdxs->lights_dispatcher(hdxs, req);
}
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
case AC_IO_CMD_KEEPALIVE:
ac_io_emu_hdxs_send_empty(hdxs, req);
break;
break;
case 0x110:
case 0x128:
ac_io_emu_hdxs_send_status(hdxs, req, 0x00);
default:
log_warning(
break;
case AC_IO_CMD_KEEPALIVE:
ac_io_emu_hdxs_send_empty(hdxs, req);
break;
default:
log_warning(
"Unknown ACIO message %04x on HDXS node, addr=%d",
cmd_code,
req->addr);
break;
break;
}
}
static void ac_io_emu_hdxs_cmd_send_version(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req)
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -92,10 +105,12 @@ static void ac_io_emu_hdxs_cmd_send_version(
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_LED_STRIP);
resp.cmd.version.flag = 0x00;
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x06;
resp.cmd.version.revision = 0x00;
memcpy(resp.cmd.version.product_code, "HDXS",
sizeof(resp.cmd.version.product_code));
resp.cmd.version.minor = 0x00;
resp.cmd.version.revision = 0x01;
memcpy(
resp.cmd.version.product_code,
"HDXB",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
@@ -103,8 +118,7 @@ static void ac_io_emu_hdxs_cmd_send_version(
}
static void ac_io_emu_hdxs_send_empty(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req)
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -117,9 +131,9 @@ static void ac_io_emu_hdxs_send_empty(
}
static void ac_io_emu_hdxs_send_status(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req,
uint8_t status)
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req,
uint8_t status)
{
struct ac_io_message resp;

View File

@@ -5,17 +5,23 @@
#include "acioemu/emu.h"
struct ac_io_emu_hdxs;
struct ac_io_message;
typedef void (*acio_hdxs_dispatcher)(
struct ac_io_emu_hdxs *emu, const struct ac_io_message *req);
struct ac_io_emu_hdxs {
struct ac_io_emu *emu;
// TODO ops vtbl
acio_hdxs_dispatcher lights_dispatcher;
};
void ac_io_emu_hdxs_init(
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu);
struct ac_io_emu_hdxs *hdxs,
struct ac_io_emu *emu,
acio_hdxs_dispatcher lights_dispatcher);
void ac_io_emu_hdxs_dispatch_request(
struct ac_io_emu_hdxs *hdxs,
const struct ac_io_message *req);
struct ac_io_emu_hdxs *hdxs, const struct ac_io_message *req);
#endif

View File

@@ -14,6 +14,7 @@
#include "bemanitools/eamio.h"
#include "util/crc.h"
#include "util/time.h"
enum ac_io_icca_subcmd {
@@ -23,50 +24,62 @@ enum ac_io_icca_subcmd {
};
enum ac_io_icca_flag {
AC_IO_ICCA_FLAG_FRONT_SENSOR = 0x10,
AC_IO_ICCA_FLAG_REAR_SENSOR = 0x20,
AC_IO_ICCA_FLAG_SOLENOID = 0x40
AC_IO_ICCA_FLAG_FRONT_SENSOR = 0x10,
AC_IO_ICCA_FLAG_REAR_SENSOR = 0x20,
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_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);
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
static void ac_io_emu_icca_send_state(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us);
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us,
bool encrypted);
static void ac_io_emu_icca_send_empty(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req);
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
static void ac_io_emu_icca_send_status(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint8_t status);
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint8_t status);
static void ac_io_emu_icca_cipher(
struct ac_io_emu_icca *icca, uint8_t *data, size_t length);
static void ac_io_emu_icca_cipher_set_key(
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
void ac_io_emu_icca_init(
struct ac_io_emu_icca *icca,
struct ac_io_emu *emu,
uint8_t unit_no)
struct ac_io_emu_icca *icca, struct ac_io_emu *emu, uint8_t unit_no)
{
memset(icca, 0, sizeof(*icca));
icca->emu = emu;
icca->unit_no = unit_no;
// queue must be started
icca->fault = true;
// default to 1.6.0
icca->version = v160;
}
void ac_io_emu_icca_set_version(
struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version)
{
icca->version = version;
}
void ac_io_emu_icca_dispatch_request(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req)
struct ac_io_emu_icca *icca, const struct ac_io_message *req)
{
uint16_t cmd_code;
uint64_t delay_us;
@@ -127,14 +140,13 @@ void ac_io_emu_icca_dispatch_request(
break;
case AC_IO_ICCA_CMD_ENGAGE:
ac_io_emu_icca_send_state(icca, req, 0);
ac_io_emu_icca_send_state(icca, req, 0, false);
break;
case AC_IO_ICCA_CMD_SET_SLOT_STATE:
{
struct ac_io_icca_misc* misc =
(struct ac_io_icca_misc*) &req->cmd.raw;
case AC_IO_ICCA_CMD_SET_SLOT_STATE: {
struct ac_io_icca_misc *misc =
(struct ac_io_icca_misc *) &req->cmd.raw;
uint8_t cmd;
switch (misc->subcmd) {
@@ -157,15 +169,19 @@ void ac_io_emu_icca_dispatch_request(
default:
cmd = 0xFF;
log_warning("Unhandled slot command %X, node %d",
misc->subcmd, icca->unit_no);
log_warning(
"Unhandled slot command %X, node %d",
misc->subcmd,
icca->unit_no);
break;
}
if (cmd != 0xFF) {
if (!eam_io_card_slot_cmd(icca->unit_no, cmd)) {
log_warning("Eamio failed to handle slot cmd %d for node %d",
cmd, icca->unit_no);
log_warning(
"Eamio failed to handle slot cmd %d for node %d",
cmd,
icca->unit_no);
}
}
@@ -175,36 +191,53 @@ void ac_io_emu_icca_dispatch_request(
break;
}
case AC_IO_ICCA_CMD_POLL_ENCRYPTED:
case AC_IO_ICCA_CMD_POLL:
delay_us = time_get_elapsed_us(time_get_counter() - icca->time_counter_last_poll);
delay_us = time_get_elapsed_us(
time_get_counter() - icca->time_counter_last_poll);
/* emulating delay implemented by hardware. do not delay messages that exceed a certain threshold. */
/* emulating delay implemented by hardware. do not delay messages
* that exceed a certain threshold. */
if (delay_us > 16000) {
delay_us = 0;
}
icca->time_counter_last_poll = time_get_counter();
ac_io_emu_icca_send_state(icca, req, delay_us);
bool encrypted = cmd_code == AC_IO_ICCA_CMD_POLL_ENCRYPTED;
ac_io_emu_icca_send_state(icca, req, delay_us, encrypted);
break;
case AC_IO_ICCA_CMD_POLL_FELICA:
icca->detected_new_reader = true;
ac_io_emu_icca_send_status(icca, req, 0x01);
if (icca->version == v170) {
ac_io_emu_icca_send_empty(icca, req);
} else {
ac_io_emu_icca_send_status(icca, req, 0x01);
}
break;
case AC_IO_ICCA_CMD_KEY_EXCHANGE:
icca->detected_new_reader = true;
log_misc("AC_IO_ICCA_CMD_KEY_EXCHANGE(%d)", req->addr);
ac_io_emu_icca_cipher_set_key(icca, req);
break;
default:
log_warning("Unknown ACIO message %04x on ICCA node, addr=%d",
cmd_code, req->addr);
log_warning(
"Unknown ACIO message %04x on ICCA node, addr=%d",
cmd_code,
req->addr);
break;
}
}
static void ac_io_emu_icca_cmd_send_version(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req)
struct ac_io_emu_icca *icca, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -213,12 +246,31 @@ static void ac_io_emu_icca_cmd_send_version(
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(resp.cmd.version);
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_ICCA);
resp.cmd.version.flag = 0x00;
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x06;
if (icca->version == v150) {
log_warning(
"ICCA v1.5.0 emulation requested, please remove this log once implemented");
resp.cmd.version.minor = 0x05;
} else if (icca->version == v160) {
resp.cmd.version.minor = 0x06;
} else if (icca->version == v170) {
resp.cmd.version.minor = 0x07;
} else {
// probably log invalid version here
log_warning(
"Unknown ICCA version: %d emulation requested",
icca->version);
}
resp.cmd.version.revision = 0x00;
memcpy(resp.cmd.version.product_code, "ICCA",
sizeof(resp.cmd.version.product_code));
memcpy(
resp.cmd.version.product_code,
"ICCA",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
@@ -226,8 +278,7 @@ static void ac_io_emu_icca_cmd_send_version(
}
static void ac_io_emu_icca_send_empty(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req)
struct ac_io_emu_icca *icca, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -240,9 +291,9 @@ static void ac_io_emu_icca_send_empty(
}
static void ac_io_emu_icca_send_status(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint8_t status)
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint8_t status)
{
struct ac_io_message resp;
@@ -256,9 +307,10 @@ static void ac_io_emu_icca_send_status(
}
static void ac_io_emu_icca_send_state(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us)
struct ac_io_emu_icca *icca,
const struct ac_io_message *req,
uint64_t delay_us,
bool encrypted)
{
struct ac_io_message resp;
struct ac_io_icca_state *body;
@@ -277,25 +329,22 @@ static void ac_io_emu_icca_send_state(
keypad = eam_io_get_keypad_state(icca->unit_no);
sensor_state = eam_io_get_sensor_state(icca->unit_no);
keypad_rise = keypad & (icca->last_keypad ^ keypad);
card_full_insert = sensor_state & (1 << EAM_IO_SENSOR_FRONT) &&
sensor_state & (1 << EAM_IO_SENSOR_BACK);
if (sensor_state != icca->last_sensor) {
if (card_full_insert) {
if (!eam_io_card_slot_cmd(icca->unit_no,
EAM_IO_CARD_SLOT_CMD_READ)) {
log_warning("EAM_IO_CARD_SLOT_CMD_READ to unit %d failed",
if (!eam_io_card_slot_cmd(
icca->unit_no, EAM_IO_CARD_SLOT_CMD_READ)) {
log_warning(
"EAM_IO_CARD_SLOT_CMD_READ to unit %d failed",
icca->unit_no);
}
icca->card_result = eam_io_read_card(
icca->unit_no,
icca->uid,
sizeof(icca->uid));
icca->card_result =
eam_io_read_card(icca->unit_no, icca->uid, sizeof(icca->uid));
// fault if sensor says to read but we got no card
icca->fault = (icca->card_result == EAM_IO_CARD_NONE);
@@ -319,7 +368,14 @@ static void ac_io_emu_icca_send_state(
} else if (card_full_insert) {
body->status_code = AC_IO_ICCA_STATUS_GOT_UID;
} else {
body->status_code = AC_IO_ICCA_STATUS_IDLE;
if (icca->detected_new_reader && icca->version == v170) {
// else we get a power failure?
body->status_code = 0;
} else if (icca->detected_new_reader) {
body->status_code = AC_IO_ICCA_STATUS_IDLE_NEW;
} else {
body->status_code = AC_IO_ICCA_STATUS_IDLE;
}
}
body->sensor_state = 0;
@@ -338,8 +394,8 @@ static void ac_io_emu_icca_send_state(
memcpy(body->uid, icca->uid, sizeof(body->uid));
body->card_type = 0;
if (body->status_code == AC_IO_ICCA_STATUS_GOT_UID){
if (icca->detected_new_reader){
if (body->status_code == AC_IO_ICCA_STATUS_GOT_UID) {
if (icca->detected_new_reader) {
// sensor_state actually refers to cardtype for wavepass readers
// EAM_IO_CARD_ISO15696 = 1 -> 0
// EAM_IO_CARD_FELICA = 2 -> 1
@@ -349,7 +405,6 @@ static void ac_io_emu_icca_send_state(
}
if (keypad_rise) {
if (icca->key_events[0]) {
event = (icca->key_events[0] + 0x10) & 0xF0;
} else {
@@ -365,7 +420,8 @@ static void ac_io_emu_icca_send_state(
// this doesn't seem to be an error code. If this is not set to 0x03
// on slotted readers (only?), the game throws an unknown status error
if (icca->keypad_started) {
// and on SDVX4 it hangs on the thank you screen
if (icca->keypad_started || icca->detected_new_reader) {
body->keypad_started = 0x03;
} else {
body->keypad_started = 0x00;
@@ -380,6 +436,88 @@ static void ac_io_emu_icca_send_state(
body->status_code = AC_IO_ICCA_STATUS_FAULT;
}
if (encrypted) {
size_t base_state_sz = sizeof(struct ac_io_icca_state);
resp.cmd.nbytes = base_state_sz + 2;
if (!icca->cipher_started) {
log_warning("No crypto keys set for unit %d", icca->unit_no);
} else {
uint16_t crc = crc16_msb(resp.cmd.raw, base_state_sz, 0);
resp.cmd.raw[base_state_sz + 0] = (crc >> 8) & 0xFF;
resp.cmd.raw[base_state_sz + 1] = crc & 0xFF;
ac_io_emu_icca_cipher(icca, resp.cmd.raw, 18);
}
}
ac_io_emu_response_push(icca->emu, &resp, delay_us);
}
static void ac_io_emu_icca_cipher_shift_keys(struct ac_io_emu_icca *icca)
{
uint32_t key4_old = icca->cipher_keys[3];
uint32_t key_new = (key4_old << 11) ^ key4_old;
uint32_t key1_old = icca->cipher_keys[0];
// shift keys up
icca->cipher_keys[3] = icca->cipher_keys[2];
icca->cipher_keys[2] = icca->cipher_keys[1];
icca->cipher_keys[1] = icca->cipher_keys[0];
icca->cipher_keys[0] =
((((key1_old >> 11) ^ key_new) >> 8) ^ key_new ^ key1_old);
}
static void
ac_io_emu_icca_cipher(struct ac_io_emu_icca *icca, uint8_t *data, size_t length)
{
for (size_t i = 0; i < length; i++) {
uint8_t count4 = i % 4;
// shift keys every 4 bytes
if (count4 == 0) {
ac_io_emu_icca_cipher_shift_keys(icca);
}
// process data
data[i] =
(uint8_t)(icca->cipher_keys[0] >> (((3 - count4) << 3)) ^ data[i]);
}
}
static void ac_io_emu_icca_cipher_set_key(
struct ac_io_emu_icca *icca, const struct ac_io_message *req)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = 4; // 4 bytes, uint32_t
uint32_t host_key = 0x00000000;
host_key |= req->cmd.raw[0] << 24;
host_key |= req->cmd.raw[1] << 16;
host_key |= req->cmd.raw[2] << 8;
host_key |= req->cmd.raw[3];
// TODO: should probably RNG this
uint32_t reader_key = 0x14243444;
resp.cmd.raw[0] = (reader_key >> 24) & 0xFF;
resp.cmd.raw[1] = (reader_key >> 16) & 0xFF;
resp.cmd.raw[2] = (reader_key >> 8) & 0xFF;
resp.cmd.raw[3] = (reader_key) & 0xFF;
// so I looked these constants up, this isn't actually a secure key
// generator it's actually Marsaglia's "KISS" algorithm with different
// initial states
icca->cipher_keys[0] = reader_key ^ 0x5491333;
icca->cipher_keys[1] = host_key ^ 0x1F123BB5;
icca->cipher_keys[2] = reader_key ^ 0x159A55E5;
icca->cipher_keys[3] = host_key ^ 0x75BCD15;
log_misc("keys set to: H: %08x R: %08x", host_key, reader_key);
ac_io_emu_response_push(icca->emu, &resp, 0);
icca->cipher_started = true;
}

View File

@@ -6,6 +6,12 @@
#include "acioemu/emu.h"
enum ac_io_emu_icca_version {
v150 = 0x5,
v160 = 0x6,
v170 = 0x7,
};
struct ac_io_emu_icca {
struct ac_io_emu *emu;
uint8_t unit_no;
@@ -20,15 +26,20 @@ struct ac_io_emu_icca {
bool keypad_started;
bool polling_started;
uint64_t time_counter_last_poll;
enum ac_io_emu_icca_version version;
bool cipher_started;
uint32_t cipher_keys[4];
};
void ac_io_emu_icca_init(
struct ac_io_emu_icca *icca,
struct ac_io_emu *emu,
uint8_t unit_no);
struct ac_io_emu_icca *icca, struct ac_io_emu *emu, uint8_t unit_no);
// optional, call after init to override default version
void ac_io_emu_icca_set_version(
struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version);
void ac_io_emu_icca_dispatch_request(
struct ac_io_emu_icca *icca,
const struct ac_io_message *req);
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
#endif

View File

@@ -14,26 +14,21 @@
#include "bemanitools/eamio.h"
static void ac_io_emu_iccb_cmd_send_version(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req);
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req);
static void ac_io_emu_iccb_send_state(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req);
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req);
static void ac_io_emu_iccb_send_empty(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req);
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req);
static void ac_io_emu_iccb_send_status(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req,
uint8_t status);
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req,
uint8_t status);
void ac_io_emu_iccb_init(
struct ac_io_emu_iccb *iccb,
struct ac_io_emu *emu,
uint8_t unit_no)
struct ac_io_emu_iccb *iccb, struct ac_io_emu *emu, uint8_t unit_no)
{
memset(iccb, 0, sizeof(*iccb));
iccb->emu = emu;
@@ -41,8 +36,7 @@ void ac_io_emu_iccb_init(
}
void ac_io_emu_iccb_dispatch_request(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req)
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
uint16_t cmd_code;
@@ -104,16 +98,17 @@ void ac_io_emu_iccb_dispatch_request(
break;
default:
log_warning("Unknown ACIO message %04x on ICCB node, addr=%d",
cmd_code, req->addr);
log_warning(
"Unknown ACIO message %04x on ICCB node, addr=%d",
cmd_code,
req->addr);
break;
}
}
static void ac_io_emu_iccb_cmd_send_version(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req)
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -126,8 +121,10 @@ static void ac_io_emu_iccb_cmd_send_version(
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x05;
resp.cmd.version.revision = 0x01;
memcpy(resp.cmd.version.product_code, "ICCB",
sizeof(resp.cmd.version.product_code));
memcpy(
resp.cmd.version.product_code,
"ICCB",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
@@ -135,8 +132,7 @@ static void ac_io_emu_iccb_cmd_send_version(
}
static void ac_io_emu_iccb_send_empty(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req)
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -149,9 +145,9 @@ static void ac_io_emu_iccb_send_empty(
}
static void ac_io_emu_iccb_send_status(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req,
uint8_t status)
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req,
uint8_t status)
{
struct ac_io_message resp;
@@ -165,8 +161,7 @@ static void ac_io_emu_iccb_send_status(
}
static void ac_io_emu_iccb_send_state(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req)
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
struct ac_io_message resp;
struct ac_io_iccb_state *body;
@@ -178,10 +173,8 @@ static void ac_io_emu_iccb_send_state(
if (sensor != iccb->last_sensor) {
if (sensor) {
iccb->card_result = eam_io_read_card(
iccb->unit_no,
iccb->uid,
sizeof(iccb->uid));
iccb->card_result =
eam_io_read_card(iccb->unit_no, iccb->uid, sizeof(iccb->uid));
// fault if sensor says to read but we got no card
iccb->fault = (iccb->card_result == EAM_IO_CARD_NONE);
@@ -224,4 +217,3 @@ static void ac_io_emu_iccb_send_state(
ac_io_emu_response_push(iccb->emu, &resp, 0);
}

View File

@@ -16,12 +16,9 @@ struct ac_io_emu_iccb {
};
void ac_io_emu_iccb_init(
struct ac_io_emu_iccb *iccb,
struct ac_io_emu *emu,
uint8_t unit_no);
struct ac_io_emu_iccb *iccb, struct ac_io_emu *emu, uint8_t unit_no);
void ac_io_emu_iccb_dispatch_request(
struct ac_io_emu_iccb *iccb,
const struct ac_io_message *req);
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req);
#endif

View File

@@ -13,11 +13,10 @@
#include "util/mem.h"
#include "util/time.h"
static struct ac_io_in_queued *ac_io_in_queued_alloc(struct ac_io_in *in,
uint64_t delay_us);
static struct ac_io_in_queued *
ac_io_in_queued_alloc(struct ac_io_in *in, uint64_t delay_us);
static void ac_io_in_queued_populate(
struct ac_io_in_queued *iq,
const struct ac_io_message *msg);
struct ac_io_in_queued *iq, const struct ac_io_message *msg);
static void ac_io_in_queued_putc(struct ac_io_in_queued *iq, uint8_t b);
static bool ac_io_out_supply_byte(struct ac_io_out *out, uint8_t b);
@@ -30,8 +29,8 @@ static bool ac_io_out_reject_message(struct ac_io_out *out);
static bool ac_io_enable_legacy_mode = false;
static struct ac_io_in_queued *ac_io_in_queued_alloc(struct ac_io_in *in,
uint64_t delay_us)
static struct ac_io_in_queued *
ac_io_in_queued_alloc(struct ac_io_in *in, uint64_t delay_us)
{
struct ac_io_in_queued *iq;
@@ -51,8 +50,7 @@ static struct ac_io_in_queued *ac_io_in_queued_alloc(struct ac_io_in *in,
}
static void ac_io_in_queued_populate(
struct ac_io_in_queued *iq,
const struct ac_io_message *msg)
struct ac_io_in_queued *iq, const struct ac_io_message *msg)
{
uint8_t checksum;
const uint8_t *src;
@@ -68,7 +66,7 @@ static void ac_io_in_queued_populate(
src = (const uint8_t *) msg;
checksum = 0;
for (i = 0 ; i < nbytes ; i++) {
for (i = 0; i < nbytes; i++) {
ac_io_in_queued_putc(iq, src[i]);
checksum += src[i];
}
@@ -97,8 +95,8 @@ void ac_io_in_init(struct ac_io_in *in)
list_init(&in->queue);
}
void ac_io_in_supply(struct ac_io_in *in, const struct ac_io_message *msg,
uint64_t delay_us)
void ac_io_in_supply(
struct ac_io_in *in, const struct ac_io_message *msg, uint64_t delay_us)
{
struct ac_io_in_queued *dest;
@@ -113,10 +111,7 @@ void ac_io_in_supply(struct ac_io_in *in, const struct ac_io_message *msg,
}
void ac_io_in_supply_thunk(
struct ac_io_in *in,
ac_io_in_thunk_t thunk,
void *ctx,
uint64_t delay_us)
struct ac_io_in *in, ac_io_in_thunk_t thunk, void *ctx, uint64_t delay_us)
{
struct ac_io_in_queued *dest;
@@ -177,7 +172,7 @@ void ac_io_in_drain(struct ac_io_in *in, struct iobuf *dest)
if (ac_io_enable_legacy_mode) {
break;
}
} while (nmoved > 0);
} while (nmoved > 0);
}
bool ac_io_in_is_msg_pending(const struct ac_io_in *in)
@@ -209,7 +204,6 @@ static bool ac_io_out_supply_byte(struct ac_io_out *out, uint8_t b)
if (out->in_frame) {
return ac_io_out_supply_frame_byte(out, b);
} else {
if (b == AC_IO_SOF) {
out->in_frame = true;
} else if (b == AC_IO_ESCAPE) {
@@ -235,7 +229,6 @@ static bool ac_io_out_supply_frame_byte(struct ac_io_out *out, uint8_t b)
return true;
} else if (b == AC_IO_SOF) {
if (out->pos == 0) {
/* Got autobaud/empty message */
out->have_message = true;
@@ -247,7 +240,6 @@ static bool ac_io_out_supply_frame_byte(struct ac_io_out *out, uint8_t b)
return true;
}
}
/* Payload byte */
@@ -257,13 +249,11 @@ static bool ac_io_out_supply_frame_byte(struct ac_io_out *out, uint8_t b)
/* Handle contextually-implied end-of-packet events */
if (out->pos > offsetof(struct ac_io_message, addr)) {
if (out->msg.addr == AC_IO_BROADCAST) {
return ac_io_out_detect_broadcast_eof(out);
} else {
return ac_io_out_detect_command_eof(out);
}
}
return true;
@@ -274,9 +264,8 @@ static bool ac_io_out_detect_broadcast_eof(struct ac_io_out *out)
size_t end;
if (out->pos > offsetof(struct ac_io_message, bcast.nbytes)) {
end = offsetof(struct ac_io_message,bcast.raw)
+ out->msg.bcast.nbytes
+ 1;
end = offsetof(struct ac_io_message, bcast.raw) +
out->msg.bcast.nbytes + 1;
if (out->pos == end) {
return ac_io_out_check_sum(out);
@@ -291,9 +280,7 @@ static bool ac_io_out_detect_command_eof(struct ac_io_out *out)
size_t end;
if (out->pos > offsetof(struct ac_io_message, cmd.nbytes)) {
end = offsetof(struct ac_io_message, cmd.raw)
+ out->msg.cmd.nbytes
+ 1;
end = offsetof(struct ac_io_message, cmd.raw) + out->msg.cmd.nbytes + 1;
if (out->pos == end) {
return ac_io_out_check_sum(out);
@@ -310,15 +297,17 @@ static bool ac_io_out_check_sum(struct ac_io_out *out)
checksum = 0;
for (i = 0 ; i < out->pos - 1 ; i++) {
for (i = 0; i < out->pos - 1; i++) {
checksum += out->bytes[i];
}
if (checksum == out->bytes[out->pos - 1]) {
return ac_io_out_accept_message(out);
} else {
log_warning("Checksum bad: expected %02x got %02x",
checksum, out->bytes[out->pos - 1]);
log_warning(
"Checksum bad: expected %02x got %02x",
checksum,
out->bytes[out->pos - 1]);
return ac_io_out_reject_message(out);
}
@@ -363,4 +352,3 @@ void ac_io_out_consume_message(struct ac_io_out *out)
out->have_message = false;
out->escape = false;
}

View File

@@ -47,13 +47,10 @@ struct ac_io_out {
void ac_io_legacy_mode(void);
void ac_io_in_init(struct ac_io_in *in);
void ac_io_in_supply(struct ac_io_in *in, const struct ac_io_message *msg,
uint64_t delay);
void ac_io_in_supply(
struct ac_io_in *in, const struct ac_io_message *msg, uint64_t delay);
void ac_io_in_supply_thunk(
struct ac_io_in *in,
ac_io_in_thunk_t thunk,
void *ctx,
uint64_t delay);
struct ac_io_in *in, ac_io_in_thunk_t thunk, void *ctx, uint64_t delay);
void ac_io_in_drain(struct ac_io_in *in, struct iobuf *dest);
bool ac_io_in_is_msg_pending(const struct ac_io_in *in);

View File

@@ -6,11 +6,10 @@ static const uint8_t aciotest_handler_max = 16;
/**
* Handler interface for an ACIO device.
*/
struct aciotest_handler_node_handler
{
void* ctx;
bool (*init)(uint8_t node_id, void** ctx);
bool (*update)(uint8_t node_id, void* ctx);
struct aciotest_handler_node_handler {
void *ctx;
bool (*init)(uint8_t node_id, void **ctx);
bool (*update)(uint8_t node_id, void *ctx);
};
#endif

View File

@@ -1,28 +1,28 @@
#include "aciotest/icca.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include "aciodrv/icca.h"
bool aciotest_icca_handler_init(uint8_t node_id, void** ctx)
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t*) *ctx) = 0;
*((uint32_t *) *ctx) = 0;
return aciodrv_icca_init(node_id);
}
bool aciotest_icca_handler_update(uint8_t node_id, void* ctx)
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx)
{
if (*((uint32_t*) ctx) == 0) {
*((uint32_t*) ctx) = 1;
if (*((uint32_t *) ctx) == 0) {
*((uint32_t *) ctx) = 1;
/* eject cards that were left in the reader */
if (!aciodrv_icca_set_state(node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
if (!aciodrv_icca_set_state(
node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
return false;
}
}
struct ac_io_icca_state state;
@@ -31,7 +31,8 @@ bool aciotest_icca_handler_update(uint8_t node_id, void* ctx)
return false;
}
printf(">>> ICCA %d:\n"
printf(
">>> ICCA %d:\n"
"status_code: %d\n"
"sensor_state: %d\n"
"keypad_started: %d\n"
@@ -40,43 +41,51 @@ bool aciotest_icca_handler_update(uint8_t node_id, void* ctx)
"key_state: %04X\n"
"key_events[0]: %02X\n"
"key_events[1]: %02X\n",
node_id, state.status_code, state.sensor_state, state.keypad_started,
state.card_type,
state.uid[0], state.uid[1], state.uid[2], state.uid[3],
state.uid[4], state.uid[5], state.uid[6], state.uid[7],
state.key_state, state.key_events[0], state.key_events[1]);
node_id,
state.status_code,
state.sensor_state,
state.keypad_started,
state.card_type,
state.uid[0],
state.uid[1],
state.uid[2],
state.uid[3],
state.uid[4],
state.uid[5],
state.uid[6],
state.uid[7],
state.key_state,
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)) {
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)) {
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)) {
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 (!aciodrv_icca_read_card(node_id, NULL)) {
return false;
}
}
return true;

View File

@@ -1,10 +1,10 @@
#ifndef ACIOTEST_ICCA_H
#define ACIOTEST_ICCA_H
#include <stdint.h>
#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);
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx);
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx);
#endif

View File

@@ -1,22 +1,22 @@
#include "aciotest/kfca.h"
#include "aciotest/kfca.h"
#include "acio/acio.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aciodrv/kfca.h"
bool aciotest_kfca_handler_init(uint8_t node_id, void** ctx)
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t*) *ctx) = 0;
*((uint32_t *) *ctx) = 0;
return aciodrv_kfca_init(node_id);
}
bool aciotest_kfca_handler_update(uint8_t node_id, void* ctx)
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx)
{
struct ac_io_kfca_poll_in pin;
struct ac_io_kfca_poll_out pout;
@@ -38,28 +38,29 @@ bool aciotest_kfca_handler_update(uint8_t node_id, void* ctx)
pin.gpio[0] = ac_io_u16(pin.gpio[0]);
pin.gpio[1] = ac_io_u16(pin.gpio[1]);
printf(">>> KFCA %d: GPIO ON %d\n"
printf(
">>> KFCA %d: GPIO ON %d\n"
"BTN A B C D: %d %d %d %d\n"
"FX-L R: %d %d\n"
"VOL L: %d\n"
"VOL R: %d\n"
"START COIN TEST SERV REC HP: %d %d %d %d %d %d\n",
node_id, gpio_test_pin,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_A,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_B,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_C,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_D,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_L,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_R,
(pin.adc[0] >> 6) & 0x3FF,
(pin.adc[1] >> 6) & 0x3FF,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_START,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_COIN,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_TEST,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_SERVICE,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_RECORDER,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_HEADPHONE
);
node_id,
gpio_test_pin,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_A,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_B,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_C,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_D,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_L,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_R,
(pin.adc[0] >> 6) & 0x3FF,
(pin.adc[1] >> 6) & 0x3FF,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_START,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_COIN,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_TEST,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_SERVICE,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_RECORDER,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_HEADPHONE);
++gpio_test_counter;
if (gpio_test_counter >= 4) {

View File

@@ -1,10 +1,10 @@
#ifndef ACIOTEST_KFCA_H
#define ACIOTEST_KFCA_H
#include <stdint.h>
#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);
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx);
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx);
#endif

View File

@@ -1,6 +1,6 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <windows.h>
@@ -17,20 +17,18 @@ static uint8_t aciotest_cnt = 0;
/**
* Enumerate supported ACIO nodes based on their product id.
*/
static bool aciotest_assign_handler(char product[4],
struct aciotest_handler_node_handler* handler)
static bool aciotest_assign_handler(
char product[4], struct aciotest_handler_node_handler *handler)
{
if (!memcmp(product, "ICCA", 4)
|| !memcmp(product, "ICCB", 4)
|| !memcmp(product, "ICCC", 4)
){
if (!memcmp(product, "ICCA", 4) || !memcmp(product, "ICCB", 4) ||
!memcmp(product, "ICCC", 4)) {
handler->init = aciotest_icca_handler_init;
handler->update = aciotest_icca_handler_update;
return true;
}
if (!memcmp(product, "KFCA", 4)){
if (!memcmp(product, "KFCA", 4)) {
handler->init = aciotest_kfca_handler_init;
handler->update = aciotest_kfca_handler_update;
@@ -43,14 +41,17 @@ static bool aciotest_assign_handler(char product[4],
/**
* Tool to test real ACIO hardware.
*/
int main(int argc, char** argv)
int main(int argc, char **argv)
{
if (argc < 3) {
printf(
"aciotest, build "__DATE__ " " __TIME__ "\n"
"aciotest, build "__DATE__
" " __TIME__
"\n"
"Usage: %s <com port str> <baud rate>\n"
"Example for two slotted readers: %s COM1 57600\n",
argv[0], argv[0]);
argv[0],
argv[0]);
return -1;
}
@@ -67,33 +68,40 @@ int main(int argc, char** argv)
printf("Enumerated %d nodes\n", node_count);
struct aciotest_handler_node_handler handler[aciotest_handler_max];
memset(&handler, 0,
memset(
&handler,
0,
sizeof(struct aciotest_handler_node_handler) * aciotest_handler_max);
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciodrv_device_get_node_product_ident(i, product);
printf("> %d: %c%c%c%c\n", i + 1,
product[0], product[1], product[2], product[3]);
printf(
"> %d: %c%c%c%c\n",
i + 1,
product[0],
product[1],
product[2],
product[3]);
if (!aciotest_assign_handler(product, &handler[i])) {
printf("ERROR: Unsupported acio node product %c%c%c%c on node %d\n",
product[0], product[1], product[2], product[3], i);
printf(
"ERROR: Unsupported acio node product %c%c%c%c on node %d\n",
product[0],
product[1],
product[2],
product[3],
i);
}
}
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].init != NULL) {
if (!handler[i].init(i, &handler[i].ctx)) {
printf("ERROR: Initializing node %d failed\n", i);
handler[i].update = NULL;
}
}
}
printf(">>> Initializing done, press enter to start update loop <<<\n");
@@ -107,17 +115,13 @@ int main(int argc, char** argv)
printf("%d\n", aciotest_cnt++);
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].update != NULL) {
if (!handler[i].update(i, handler[i].ctx)) {
printf("ERROR: Updating node %d, removed from loop\n", i);
handler[i].update = NULL;
Sleep(5000);
}
}
}
/* avoid cpu banging */

10
src/main/asio/Module.mk Normal file
View File

@@ -0,0 +1,10 @@
libs += asio
libs_asio := \
hook \
hooklib \
util \
src_asio := \
asio-reghook.c \
config-asio.c \

View File

@@ -0,0 +1,199 @@
#define LOG_MODULE "asio-reghook"
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <initguid.h>
// clang-format on
#include <winreg.h>
#include <stdio.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "asio/asio-reghook.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
// MAXDRVNAMELEN
#define ASIO_NAME_STRING_SIZE 128
static char asio_expected_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)";
static char asio_target_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)";
static HKEY asio_root_key;
static HKEY asio_sub_key;
LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName);
LSTATUS my_RegOpenKeyExA(
HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
LSTATUS my_RegCloseKey(HKEY hKey);
LSTATUS (*real_RegOpenKeyA)(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
LSTATUS (*real_RegEnumKeyA)
(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName);
LSTATUS (*real_RegOpenKeyExA)
(HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
LSTATUS (*real_RegQueryValueExA)
(HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
LSTATUS (*real_RegCloseKey)(HKEY hKey);
static const struct hook_symbol asio_reghook_advapi32_syms[] = {
{.name = "RegOpenKeyA",
.patch = my_RegOpenKeyA,
.link = (void **) &real_RegOpenKeyA},
{.name = "RegEnumKeyA",
.patch = my_RegEnumKeyA,
.link = (void **) &real_RegEnumKeyA},
{.name = "RegOpenKeyExA",
.patch = my_RegOpenKeyExA,
.link = (void **) &real_RegOpenKeyExA},
{.name = "RegQueryValueExA",
.patch = my_RegQueryValueExA,
.link = (void **) &real_RegQueryValueExA},
{.name = "RegCloseKey",
.patch = my_RegCloseKey,
.link = (void **) &real_RegCloseKey},
};
LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
{
LSTATUS result = real_RegOpenKeyA(hKey, lpSubKey, phkResult);
if (!strcmp("software\\asio", lpSubKey)) {
log_info("ASIO root key found");
asio_root_key = *phkResult;
}
return result;
}
LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName)
{
LSTATUS result = real_RegEnumKeyA(hKey, dwIndex, lpName, cchName);
if (hKey == asio_root_key) {
if (!strcmp(asio_target_name, lpName)) {
log_info(
"Replacing key [%s] with [%s]",
asio_target_name,
asio_expected_name);
strncpy(lpName, asio_expected_name, cchName);
}
}
return result;
}
LSTATUS my_RegOpenKeyExA(
HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult)
{
if (hKey == asio_root_key) {
if (!strcmp(asio_expected_name, lpSubKey)) {
// swap to the real one so the call succeeds
LSTATUS result = real_RegOpenKeyExA(
hKey, asio_target_name, ulOptions, samDesired, phkResult);
asio_sub_key = *phkResult;
log_info("ASIO device key found");
return result;
}
}
return real_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
DWORD lpcbData_orig = *lpcbData;
LSTATUS result = real_RegQueryValueExA(
hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
if (result == ERROR_SUCCESS) {
if (hKey == asio_sub_key) {
if (!strcmp("description", lpValueName)) {
log_info(
"Replacing description [%s] with [%s]",
lpData,
asio_expected_name);
strncpy((char *) lpData, asio_expected_name, lpcbData_orig);
}
}
}
return result;
}
LSTATUS my_RegCloseKey(HKEY hKey)
{
if (hKey == asio_root_key) {
asio_root_key = NULL;
}
if (hKey == asio_sub_key) {
asio_sub_key = NULL;
}
return real_RegCloseKey(hKey);
}
void asio_reghook_init(const char *expected_name, const char *target_name)
{
strncpy(asio_expected_name, expected_name, ASIO_NAME_STRING_SIZE - 1);
strncpy(asio_target_name, target_name, ASIO_NAME_STRING_SIZE - 1);
asio_expected_name[ASIO_NAME_STRING_SIZE - 1] = '\0';
asio_target_name[ASIO_NAME_STRING_SIZE - 1] = '\0';
hook_table_apply(
NULL,
"Advapi32.dll",
asio_reghook_advapi32_syms,
lengthof(asio_reghook_advapi32_syms));
log_info("Inserted reg hooks for ASIO override");
}

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