Compare commits

...

98 Commits
5.34 ... 5.39

Author SHA1 Message Date
icex2
85a080e6b3 Update changelog for 5.39 release 2022-05-19 00:02:20 +02:00
95c6cd771e00602e3ec82fccba1b3741fdb7f7ca
28633ded37 jbhook2 and jbhook3 gfx updates
- Fix jbhook3 window mode
- Remove -f option for framed window, no value
- Add -s option to show mouse cursor on window
2022-05-13 19:26:00 +00:00
QCDLZCLW3K
721897d7b0 Separate key algorithm and core code for rp2 and rp3 2022-05-12 10:25:53 +09:00
QCDLZCLW3K
926bbf2e10 Small refactor for rp2 and rp3 + add new sign keys 2022-05-12 05:18:07 +09:00
Will Toohey
ce75e149f7 Sane default for vertical window (true) 2022-04-03 21:40:18 +10:00
Will Toohey
57d9d976ff jbhook2: get p3io sidcode from ea3-config, don't hardcode 2022-04-03 21:32:33 +10:00
Will Toohey
7e731916e2 Move p3io-specific jbhook-util funcs to their own static lib 2022-04-03 21:02:38 +10:00
icex2
dd9b8faafe Bump version to 5.39 for next development cycle 2022-04-02 11:16:58 +02:00
icex2
50ff026b85 Update changelog and docs for 5.38 release 2022-04-02 10:51:43 +02:00
Will Xyen
0ff6134b79 sdvxhook: address comments 2022-03-15 16:50:03 -07:00
Will Xyen
ae35b859d9 sdvxio-kfca: add volume overrides 2022-03-15 00:39:10 -07:00
Will Xyen
3cf3d44945 sdvxhook2: add nvapi and power hooks 2022-03-15 00:38:46 -07:00
icex2
2a80083af2 Update changelog for 5.37 2022-01-04 22:15:24 +01:00
icex2
66e0467ad3 Version bump in readme 2022-01-04 22:13:54 +01:00
icex2
c5f0116294 Add supported jubeat games to list of games 2022-01-04 22:13:39 +01:00
Will Toohey
ddfa814387 jbhook2: Move hooking further back where possible
This fixes a failure to boot (due to aciomgr hanging)
on jubeat knit append on my cab
2022-01-03 19:57:28 +10:00
Will Toohey
088d4bf338 jbhook2: fix broken windowed toggle 2022-01-03 19:56:10 +10:00
Will Toohey
f1a7621e2b jbhook1: also use ICCB 2022-01-03 18:32:31 +10:00
Will Toohey
4a3d5fa189 jbhook2: also use ICCB mode (fixes copious) 2022-01-03 17:03:44 +10:00
Will Toohey
0f2828da40 jbhook: make errors right-side-up as well 2022-01-03 16:48:12 +10:00
Will Toohey
ba2016b5bc jbhook: Fix security error when booting knit append 2022-01-03 16:46:56 +10:00
Will Toohey
b42c9aa93b jbhook: Finalise half-baked "rotate window" hooks 2022-01-03 14:57:43 +10:00
Will Toohey
8de259c639 jbhook: Add some better documentation 2022-01-03 14:30:20 +10:00
Will Toohey
0d54587787 jbhook: fix missing heap sizes in gamestart.bat 2022-01-03 14:13:33 +10:00
Will Toohey
4721ba2d3c p3ioemu: reorganise code for easy reading 2022-01-03 14:12:23 +10:00
Will Toohey
1105a2a130 jubeat: support p3io games 2021-12-31 20:23:31 +10:00
icex2
8ab92872ad Improve debugability for inline scripts in ci pipeline
Instead of a single big block of code which only shows up as a
single command executed, have each command on a separate "line"
so they show up on debug output. If one line fails, it's easier
to tell which one failed
2021-12-28 23:41:37 +01:00
icex2
a16dc82cef Bugfix gitlab-ci
Artifacts need to be yielded from build stage in order to have
these available in the following stages
2021-12-28 23:41:04 +01:00
icex2
729f5abcc0 Output to stderr instead of stdout in release message script
stdout is used for actual data output which is captured by
the ci pipeline. stderr shows up properly in debug output
2021-12-28 23:40:21 +01:00
Felix
6e0e5031ac avs: add additional avs_net_interface fields for newer AVS 2021-10-25 23:21:02 +00:00
Will Xyen
f17e8d6739 Bump version to 5.37 2021-10-11 14:01:45 -07:00
Will Xyen
ac02609948 dist: add IIDX28 support 2021-10-11 13:59:02 -07:00
icex2
c644db03ae doc/iidxhook3: Clarify usage of EAMID on iidx 14-17, network error
Add some additional symptoms and reasoning as this is different
for 14 to 17 compared to any other iidx version on how to use
the PCBID you get from server operators.
2021-09-27 21:50:16 +02:00
Will Xyen
7d5398b6af acio: minor fixes 2021-09-13 13:38:27 -07:00
Will Xyen
cac09f8f87 bio2: add definitions for 20th anniversary model 2021-09-13 02:51:19 +00:00
Will Xyen
85c9c444f1 aciotest: add RVOL test, and change to use product types instead of names 2021-09-13 02:51:19 +00:00
Will Xyen
8f2ce1f1b3 acio: add RVOL node definition 2021-09-13 02:51:19 +00:00
Will Xyen
d3bf381a4f aciodrv: add method to get product type of node
some devices share product codes (KFCA->RVOL), we really should be using type to differentiate them.
2021-09-13 02:51:19 +00:00
Will Xyen
3acbc7f251 acioemu: update name of AC_IO_ICCA_CMD_DEVICE_CONTROL 2021-09-13 02:51:19 +00:00
Will Xyen
839903ab48 acio: add MDXF node definition 2021-09-13 02:51:19 +00:00
Will Xyen
c929141e71 ddrhook: move common hooks to ddrhook-util 2021-09-13 02:51:19 +00:00
icex2
1477480836 Remove hardware docs, moved to arcade-docs project
These didn't really belong to this project to begin with but
didn't find a good home until recently. Already moved to
arcade-docs repository
2021-09-12 23:58:28 +02:00
icex2
bf4322e855 Add reference to arcade-docs project to documentation 2021-09-12 23:57:55 +02:00
icex2
3eed0a4ab3 Formatting 2021-09-12 23:56:45 +02:00
icex2
a9ade9d9d4 Refine CI/CD pipeline
Make use of GitLab features like the package registry to store dist
packages, GitLab releases and broadcast the release to different
channels.

Overall, this enables developers to be push out releases for frequently
since the amount of manual work is reduced.
2021-07-11 18:03:06 +00:00
Will Xyen
26336805d2 iidxhook: fix eamuse hook not using a sane port as the default when none are specified (#64) 2021-07-08 22:25:45 -07:00
Will Xyen
7d0e916b9f changelog: mention wavepass support in 5.35 2021-06-23 11:35:43 -07:00
Will Xyen
a03a5604ec Bump version to 5.36 2021-06-23 11:23:08 -07:00
Will Xyen
54e7d783ef Update changelog for 5.35 2021-06-23 11:17:29 -07:00
CrazyRedMachine
4ea1397af2 aciodrv: add PANB support (+ aciotest handler)
add aciodrv-proc module

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

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

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

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

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

View File

@@ -1,67 +1,136 @@
#
# This pipeline requires packages to be switched on under the repository settings. Otherwise, you will 403s when
# uploading to the package repo is triggered.
#
# Variables to setup in GitLab CI/CD settings of the project
#
# The variables with BASE64 postfixes need to contain the base64 encoded data. Otherwise, masking
# in GitLab won't work due to not matching their pre-defined regex
#
# CI_PIGSTALL_DATA_PREFIX_BASE64
# CI_PIGSTALL_LINK_BASE64
# CI_PIGSTALL_PHP_SESSION_ID
# CI_PIGSTALL_SESSION_BASE64
#
# CI_TOOLS_UPLOAD_KEY
# CI_TOOLS_UPLOAD_URL
# CI_TOOLS_URL
image: docker:stable image: docker:stable
variables: variables:
DOCKER_TLS_CERTDIR: "/certs" DOCKER_TLS_CERTDIR: "/certs"
DIST_PACKAGE_RELATIVE_PATH: "build/docker/bemanitools.zip"
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/bemanitools"
services: services:
- docker:19.03.8-dind - docker:19.03.8-dind
before_script:
- docker info
stages: stages:
- build - build
- create-release-package - upload
- releasetag - release
build: build:
stage: build stage: build
only:
refs:
- master
- tags
before_script: before_script:
- apk update && apk add make > /dev/null - apk update && apk add make > /dev/null
script: script:
- make build-docker - make build-docker
artifacts: artifacts:
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
paths: paths:
- build - build
expire_in: 1 week
upload-package-registry:
stage: upload
image: curlimages/curl:latest
only: only:
refs: refs:
- master - master
- tags
create-release-package:
stage: create-release-package
variables:
GIT_STRATEGY: none
dependencies: dependencies:
- build - 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: script:
- | - |
curl --silent --show-error \ if [ "${CI_COMMIT_TAG}" ]; then
--data "{\"tag_name\": \"${CI_COMMIT_TAG}\", \"name\": \"${CI_PROJECT_NAME}-${CI_COMMIT_TAG}\", \"description\": \"${CI_COMMIT_TAG_MESSAGE:-No release notes.}\"}" \ version="${CI_COMMIT_TAG}"
--header "Content-Type: application/json" \ else
--header "Private-Token: ${CI_PRIVATE_TOKEN}" \ version="${CI_COMMIT_SHORT_SHA}"
--request POST \ fi
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases" - |
curl \
--silent \
--fail \
--show-error \
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
--upload-file "${DIST_PACKAGE_RELATIVE_PATH}" \
$PACKAGE_REGISTRY_URL/${version}/bemanitools.zip
upload-tools-page:
stage: upload
image: curlimages/curl:latest
only: only:
- tags refs:
- tags
dependencies:
- build
script:
- |
curl \
--silent \
--fail \
--show-error \
--connect-timeout 5 \
--max-time 10 \
--retry 5 \
-F "key=${CI_TOOLS_UPLOAD_KEY}" \
-F "filename=${CI_PROJECT_NAME}-v${CI_COMMIT_TAG}.zip" \
-F "file=@${DIST_PACKAGE_RELATIVE_PATH}" \
${CI_TOOLS_UPLOAD_URL}
release-gitlab:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:v0.8.0
only:
refs:
- tags
script:
- version="$CI_COMMIT_TAG"
- release_message="$(scripts/ci/create-release-message.sh "${version}" < CHANGELOG.md)"
- |
release-cli create \
--name "bemanitools ${version}" \
--description="${release_message}" \
--tag-name ${version} \
--assets-link "{\"name\":\"Distribution binaries\",\"url\":\"${PACKAGE_REGISTRY_URL}/${version}/bemanitools.zip\"}"
release-pigstall:
stage: release
image: curlimages/curl:latest
only:
refs:
- tags
script:
- version="${CI_COMMIT_TAG}"
- changelog_excerpt="$(scripts/ci/create-release-message.sh "${version}" < CHANGELOG.md)"
- release_message="$(printf "bemanitools ${version} released\n${CI_TOOLS_URL}/bemanitools-v${version}.zip\n${changelog_excerpt}")"
- session="$(echo "$CI_PIGSTALL_SESSION_BASE64" | base64 -d)"
- data_prefix="$(echo "$CI_PIGSTALL_DATA_PREFIX_BASE64" | base64 -d)"
- link="$(echo "$CI_PIGSTALL_LINK_BASE64" | base64 -d)"
- |
curl \
--silent \
--fail \
--connect-timeout 5 \
--max-time 10 \
--retry 5 \
--show-error \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H "Cookie: PHPSESSID=$CI_PIGSTALL_PHP_SESSION_ID; session=${session}" \
--data-raw "${data_prefix}&body=${release_message}" \
"${link}"

View File

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

View File

@@ -1,4 +1,33 @@
# Release history # Release history
Note for CI/CD: Ensure the version formatting in the sections is kept identical to the versions
given in tags. The pipeline will pick this up and cuts out the relevant section for release notes.
## 5.39
* jbhook3: Fix window mode, remove window frame option, add show cursor on window option
* Code simplification and cleanup round plug modules
* Code structure improvements p3io jubeat
## 5.38
* sdvxhook2: Support sound voltex exceed gear
## 5.37
* jbhook1: Support jubeat (1) and ripples
* jbhook2: Support jubeat knit and copious
* jbhook3: Support jubeat saucer, prop, qubell, clan and festo
## 5.36
* iidxhook9: Support for IIDX28
* Various bugfixes
## 5.35
* Jubeat: Add jbio-p4io
* Nostalgia: Add nostio-panb
* Misc: Add wavepass support to aciodrv-icca (and eamio-icca)
* Misc: Refactor aciodrv to support multiple devices using the same port (with aciomgr)
* Misc: Fix d3d9ex windowed hook not behaving correctly (size/framed)
* Misc: Fix docs not being included with release
* Various bugfixes
## 5.34 ## 5.34
* IIDX: Support IO and card reader feature switches to disable emulation in iidxhook4-7 * IIDX: Support IO and card reader feature switches to disable emulation in iidxhook4-7
* Jubeat: jbio implementation for magicbox hardware * Jubeat: jbio implementation for magicbox hardware

View File

@@ -226,7 +226,7 @@ $$(dll_$1_$2_$3) $$(implib_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) \
$(V)echo ... $$(dll_$1_$2_$3) $(V)echo ... $$(dll_$1_$2_$3)
$(V)$$(toolchain_$1)gcc -shared \ $(V)$$(toolchain_$1)gcc -shared \
-o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \ -o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \
$$^ $$(ldflags_$3) -Wl,--start-group $$^ -Wl,--end-group $$(ldflags_$3)
$(V)$$(toolchain_$1)strip $$(dll_$1_$2_$3) $(V)$$(toolchain_$1)strip $$(dll_$1_$2_$3)
$(V)$$(toolchain_$1)ranlib $$(implib_$1_$2_$3) $(V)$$(toolchain_$1)ranlib $$(implib_$1_$2_$3)

103
Module.mk
View File

@@ -26,7 +26,8 @@
# 8: Patch 3: beatmania IIDX 16 Empress # 8: Patch 3: beatmania IIDX 16 Empress
# jubeat # jubeat
# #
# 10: Patch 4: DanceDanceRevolution X2 # 10: Patch 2: jubeat Knit
# Patch 4: DanceDanceRevolution X2
# #
# 11: Patch 1: beatmania IIDX 18 Resort Anthem # 11: Patch 1: beatmania IIDX 18 Resort Anthem
# pop'n music 19 Tune Street # pop'n music 19 Tune Street
@@ -71,13 +72,15 @@ cflags += \
# Each AVS-dependent project should consume the earliest AVS import definition # Each AVS-dependent project should consume the earliest AVS import definition
# that is still ABI-compatible with the real build its target links against. # that is still ABI-compatible with the real build its target links against.
avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 803 0 avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 1002 803 0
avsvers_64 := 1700 1603 1601 1508 avsvers_64 := 1700 1603 1601 1509 1508
imps += avs avs-ea3 imps += avs avs-ea3
include src/main/aciodrv/Module.mk include src/main/aciodrv/Module.mk
include src/main/aciodrv-proc/Module.mk
include src/main/acioemu/Module.mk include src/main/acioemu/Module.mk
include src/main/aciomgr/Module.mk
include src/main/aciotest/Module.mk include src/main/aciotest/Module.mk
include src/main/asio/Module.mk include src/main/asio/Module.mk
include src/main/bio2drv/Module.mk include src/main/bio2drv/Module.mk
@@ -89,6 +92,7 @@ include src/main/camhook/Module.mk
include src/main/cconfig/Module.mk include src/main/cconfig/Module.mk
include src/main/config/Module.mk include src/main/config/Module.mk
include src/main/d3d9exhook/Module.mk include src/main/d3d9exhook/Module.mk
include src/main/ddrhook-util/Module.mk
include src/main/ddrhook/Module.mk include src/main/ddrhook/Module.mk
include src/main/ddrio-mm/Module.mk include src/main/ddrio-mm/Module.mk
include src/main/ddrio-smx/Module.mk include src/main/ddrio-smx/Module.mk
@@ -133,16 +137,21 @@ include src/main/iidxio-ezusb2/Module.mk
include src/main/iidxio/Module.mk include src/main/iidxio/Module.mk
include src/main/iidxiotest/Module.mk include src/main/iidxiotest/Module.mk
include src/main/inject/Module.mk include src/main/inject/Module.mk
include src/main/jbhook/Module.mk
include src/main/jbhook1/Module.mk
include src/main/jbio-magicbox/Module.mk include src/main/jbio-magicbox/Module.mk
include src/main/jbio-p4io/Module.mk
include src/main/jbio/Module.mk include src/main/jbio/Module.mk
include src/main/jbiotest/Module.mk include src/main/jbiotest/Module.mk
include src/main/jbhook-util/Module.mk
include src/main/jbhook-util-p3io/Module.mk
include src/main/jbhook1/Module.mk
include src/main/jbhook2/Module.mk
include src/main/jbhook3/Module.mk
include src/main/launcher/Module.mk include src/main/launcher/Module.mk
include src/main/mempatch-hook/Module.mk include src/main/mempatch-hook/Module.mk
include src/main/mm/Module.mk include src/main/mm/Module.mk
include src/main/p3io/Module.mk include src/main/p3io/Module.mk
include src/main/p3ioemu/Module.mk include src/main/p3ioemu/Module.mk
include src/main/p4iodrv/Module.mk
include src/main/p4ioemu/Module.mk include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk include src/main/sdvxhook/Module.mk
@@ -361,7 +370,7 @@ $(zipdir)/iidx-25-to-26.zip: \
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/iidx-27.zip: \ $(zipdir)/iidx-27-to-28.zip: \
build/bin/avs2_1700-64/iidxhook9.dll \ build/bin/avs2_1700-64/iidxhook9.dll \
build/bin/avs2_1700-64/launcher.exe \ build/bin/avs2_1700-64/launcher.exe \
build/bin/indep-64/config.exe \ build/bin/indep-64/config.exe \
@@ -371,13 +380,16 @@ $(zipdir)/iidx-27.zip: \
build/bin/indep-64/vefxio.dll \ build/bin/indep-64/vefxio.dll \
dist/iidx/config.bat \ dist/iidx/config.bat \
dist/iidx/gamestart-27.bat \ dist/iidx/gamestart-27.bat \
dist/iidx/gamestart-28.bat \
dist/iidx/iidxhook-27.conf \ dist/iidx/iidxhook-27.conf \
dist/iidx/iidxhook-28.conf \
dist/iidx/vefx.txt \ dist/iidx/vefx.txt \
| $(zipdir)/ | $(zipdir)/
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x86.zip: \ $(zipdir)/iidx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \ build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/iidxio-bio2.dll \ build/bin/indep-32/iidxio-bio2.dll \
build/bin/indep-32/iidxio-ezusb.dll \ build/bin/indep-32/iidxio-ezusb.dll \
@@ -390,6 +402,7 @@ $(zipdir)/iidx-hwio-x86.zip: \
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x64.zip: \ $(zipdir)/iidx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \ build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/iidxio-bio2.dll \ build/bin/indep-64/iidxio-bio2.dll \
build/bin/indep-64/iidxio-ezusb.dll \ build/bin/indep-64/iidxio-ezusb.dll \
@@ -415,28 +428,79 @@ $(zipdir)/jb-01.zip: \
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/jb-02.zip: \
build/bin/avs2_1002-32/jbhook1.dll \
build/bin/indep-32/inject.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/jbio.dll \
dist/jb/config.bat \
dist/jb/gamestart-02.bat \
dist/jb/jbhook-02.conf \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-03.zip: \
build/bin/avs2_1101-32/jbhook2.dll \
build/bin/avs2_1101-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/jbio.dll \
dist/jb/config.bat \
dist/jb/gamestart-03.bat \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-04.zip: \
build/bin/avs2_1304-32/jbhook2.dll \
build/bin/avs2_1304-32/launcher.exe \
build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/jbio.dll \
dist/jb/config.bat \
dist/jb/gamestart-03.bat \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-05-to-07.zip: \ $(zipdir)/jb-05-to-07.zip: \
build/bin/avs2_1508-32/jbhook.dll \ build/bin/avs2_1508-32/jbhook3.dll \
build/bin/avs2_1508-32/launcher.exe \ build/bin/avs2_1508-32/launcher.exe \
build/bin/indep-32/config.exe \ build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \ build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \ build/bin/indep-32/geninput.dll \
build/bin/indep-32/jbio.dll \ build/bin/indep-32/jbio.dll \
dist/jb/config.bat \ dist/jb/config.bat \
dist/jb/gamestart.bat \ dist/jb/gamestart-04.bat \
| $(zipdir)/ | $(zipdir)/
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/jb-08.zip: \ $(zipdir)/jb-08.zip: \
build/bin/avs2_1700-32/jbhook.dll \ build/bin/avs2_1700-32/jbhook3.dll \
build/bin/avs2_1700-32/launcher.exe \ build/bin/avs2_1700-32/launcher.exe \
build/bin/indep-32/config.exe \ build/bin/indep-32/config.exe \
build/bin/indep-32/eamio.dll \ build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \ build/bin/indep-32/geninput.dll \
build/bin/indep-32/jbio.dll \ build/bin/indep-32/jbio.dll \
dist/jb/config.bat \ dist/jb/config.bat \
dist/jb/gamestart.bat \ dist/jb/gamestart-04.bat \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/jb-hwio.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/jbio-magicbox.dll \
build/bin/indep-32/jbio-p4io.dll \
dist/jb/jbio-h44b.conf \
dist/jb/eamio-icc.conf \
| $(zipdir)/ | $(zipdir)/
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
@@ -454,7 +518,7 @@ $(zipdir)/sdvx-01-to-04.zip: \
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/sdvx-05.zip: \ $(zipdir)/sdvx-05-to-06.zip: \
build/bin/avs2_1700-64/launcher.exe \ build/bin/avs2_1700-64/launcher.exe \
build/bin/avs2_1700-64/sdvxhook2.dll \ build/bin/avs2_1700-64/sdvxhook2.dll \
build/bin/indep-64/config.exe \ build/bin/indep-64/config.exe \
@@ -483,6 +547,8 @@ $(zipdir)/sdvx-05-cn.zip: \
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x86.zip: \ $(zipdir)/sdvx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/sdvxio-kfca.dll \ build/bin/indep-32/sdvxio-kfca.dll \
build/bin/indep-32/sdvxio-bio2.dll \ build/bin/indep-32/sdvxio-bio2.dll \
build/bin/indep-32/vigem-sdvxio.exe \ build/bin/indep-32/vigem-sdvxio.exe \
@@ -491,6 +557,8 @@ $(zipdir)/sdvx-hwio-x86.zip: \
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x64.zip: \ $(zipdir)/sdvx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/sdvxio-kfca.dll \ build/bin/indep-64/sdvxio-kfca.dll \
build/bin/indep-64/sdvxio-bio2.dll \ build/bin/indep-64/sdvxio-bio2.dll \
build/bin/indep-64/vigem-sdvxio.exe \ build/bin/indep-64/vigem-sdvxio.exe \
@@ -549,10 +617,7 @@ $(zipdir)/bst.zip: \
$(V)zip -j $@ $^ $(V)zip -j $@ $^
$(zipdir)/doc.zip: \ $(zipdir)/doc.zip: \
doc/iidxhook \ doc/ \
doc/sdvxhook \
doc/jbhook \
doc/tools \
| $(zipdir)/ | $(zipdir)/
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -r $@ $^ $(V)zip -r $@ $^
@@ -596,14 +661,18 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/iidx-20.zip \ $(zipdir)/iidx-20.zip \
$(zipdir)/iidx-21-to-24.zip \ $(zipdir)/iidx-21-to-24.zip \
$(zipdir)/iidx-25-to-26.zip \ $(zipdir)/iidx-25-to-26.zip \
$(zipdir)/iidx-27.zip \ $(zipdir)/iidx-27-to-28.zip \
$(zipdir)/iidx-hwio-x86.zip \ $(zipdir)/iidx-hwio-x86.zip \
$(zipdir)/iidx-hwio-x64.zip \ $(zipdir)/iidx-hwio-x64.zip \
$(zipdir)/jb-01.zip \ $(zipdir)/jb-01.zip \
$(zipdir)/jb-02.zip \
$(zipdir)/jb-03.zip \
$(zipdir)/jb-04.zip \
$(zipdir)/jb-05-to-07.zip \ $(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \ $(zipdir)/jb-08.zip \
$(zipdir)/jb-hwio.zip \
$(zipdir)/sdvx-01-to-04.zip \ $(zipdir)/sdvx-01-to-04.zip \
$(zipdir)/sdvx-05.zip \ $(zipdir)/sdvx-05-to-06.zip \
$(zipdir)/sdvx-05-cn.zip \ $(zipdir)/sdvx-05-cn.zip \
$(zipdir)/sdvx-hwio-x86.zip \ $(zipdir)/sdvx-hwio-x86.zip \
$(zipdir)/sdvx-hwio-x64.zip \ $(zipdir)/sdvx-hwio-x64.zip \

View File

@@ -1,7 +1,7 @@
# Bemanitools 5 # Bemanitools 5
[![pipeline status](https://dev.s-ul.eu/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.eu/djhackers/bemanitools/commits/master) [![pipeline status](https://dev.s-ul.net/djhackers/bemanitools/badges/master/pipeline.svg)](https://dev.s-ul.net/djhackers/bemanitools/commits/master)
Version: 5.34 Version: 5.39
[Release history](CHANGELOG.md) [Release history](CHANGELOG.md)
@@ -55,25 +55,31 @@ The tl;dr version and golden rules of the sections in the document:
* Beatmania IIDX 24 SINOBUZ (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 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) * Beatmania IIDX 26 Rootage (iidx-25-to-26.zip) using [iidxhook8](doc/iidxhook/iidxhook8.md)
* Beatmania IIDX 27 Heroic Verse (iidx-27.zip) using [iidxhook9](doc/iidxhook/iidxhook9.md) * Beatmania IIDX 27 Heroic Verse (iidx-27-to-28.zip) using [iidxhook9](doc/iidxhook/iidxhook9.md)
* Beatmania IIDX 28 BISTROVER (iidx-27-to-28.zip) using [iidxhook9](doc/iidxhook/iidxhook9.md)
* jubeat * jubeat
* jubeat (experimental/buggy) (jb-01.zip) using [jbhook1](doc/jbhook1/jbhook1.md) * jubeat (jb-01.zip) using [jbhook1](doc/jbhook/jbhook1.md)
* jubeat saucer (fulfill) (jb-05-to-07.zip) using jbhook * jubeat ripples (jb-02.zip) using [jbhook1](doc/jbhook/jbhook1.md)
* jubeat prop (jb-05-to-07.zip) using jbhook * jubeat knit (jb-03.zip) using [jbhook2](doc/jbhook/jbhook2.md)
* jubeat Qubell (jb-05-to-07.zip) using jbhook * jubeat copious (jb-04.zip) using [jbhook2](doc/jbhook/jbhook2.md)
* jubeat clan (jb-08.zip) using jbhook * jubeat saucer (fulfill) (jb-05-to-07.zip) using [jbhook3](doc/jbhook/jbhook3.md)
* jubeat prop (jb-05-to-07.zip) using [jbhook3](doc/jbhook/jbhook3.md)
* jubeat qubell (jb-05-to-07.zip) using [jbhook3](doc/jbhook/jbhook3.md)
* jubeat clan (jb-08.zip) using [jbhook3](doc/jbhook/jbhook3.md)
* jubeat festo (jb-08.zip) using [jbhook3](doc/jbhook/jbhook3.md)
* SOUND VOLTEX * SOUND VOLTEX
* SOUND VOLTEX BOOTH (sdvx-01-to-04.zip) using sdvxhook * SOUND VOLTEX BOOTH (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX II -infinite infection- (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 III GRAVITY WARS (sdvx-01-to-04.zip) using sdvxhook
* SOUND VOLTEX IV HEAVENLY HAVEN (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 * SOUND VOLTEX Vivid Wave (sdvx-05-to-06) using sdvxhook2
* SOUND VOLTEX EXCEED GEAR (sdvx-05-to-06) using sdvxhook2
## ViGEm clients: Expose BT5 APIs as XBOX game controllers ## ViGEm clients: Expose BT5 APIs as XBOX game controllers
Play your favorite non-bemani arcade games with any hardware, e.g. real cabinet hardware, that Play your favorite non-bemani arcade games with any hardware, e.g. real cabinet hardware, that
implements BT5 APIs. implements BT5 APIs.
See the dedicated [readme](docs/vigem/README.md) for details. See the dedicated [readme](doc/vigem/README.md) for details.
## Supported platforms ## Supported platforms
Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware
@@ -110,6 +116,34 @@ important aspects you should know before you get started with development.
### API ### API
Please refer to the [API documentation](doc/api.md). Please refer to the [API documentation](doc/api.md).
## Release process
Steps for the release process:
1. Update the corresponding section in the [changelog](CHANGELOG.md) with bullet points reflecting
major features merged into master since the previous release
1. Make sure you have the latest `master` state pulled to your local copy
1. Tag the release with the next release number which also be found at the
[top of the readme](#bemanitools-5) as it always reflects the current version beinged worked on
on the `master` branch , e.g. 5.35: `git tag 5.35`
1. Push the tag to upstream: `git push origin 5.35`
1. The [build pipeline](https://dev.s-ul.net/djhackers/bemanitools/-/pipelines) should start
automatically once the tag is pushed including the steps `build` and `upload-release`
1. Once completed successfully, the release is uploaded
1. Take the changelog of the published version and notify the pigs in the stall about it:
1. New post in thread
```
<insert version here> released: <direct link to published version>
Changelog:
<paste changelog here>
```
1. Update the OP title by bumping the version number in it
1. Update the OP post by extending it accordingly (see previous entries)
1. Bump the version number at the [top of this readme](#bemanitools-5) and add a new empty section
in the [changelog](CHANGELOG.md) with the new version number as title. Commit changes and push to
`master` branch
1. Continue developing and merging MRs until you decide its time for another release
## License ## License
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the 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. [LICENSE file](LICENSE) included with the source code.

16
dist/iidx/gamestart-28.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 -B iidxhook9.dll bm2dx.dll --config iidxhook-28.conf %*

View File

@@ -46,8 +46,5 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time # Disable operator clock setting system clock time
misc.disable_clock_set=false misc.disable_clock_set=false
# Security boot version (e.g. GEC02).
sec.boot_version=GQGLDJAA
# Security black plug mcode id string (e.g. GQC02JAA). # Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQGLDJA sec.black_plug_mcode=GQGLDJAA

View File

@@ -46,8 +46,5 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time # Disable operator clock setting system clock time
misc.disable_clock_set=false misc.disable_clock_set=false
# Security boot version (e.g. GEC02).
sec.boot_version=GQHDDJAA
# Security black plug mcode id string (e.g. GQC02JAA). # Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQHDDJA sec.black_plug_mcode=GQHDDJAA

View File

@@ -49,8 +49,5 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time # Disable operator clock setting system clock time
misc.disable_clock_set=false misc.disable_clock_set=false
# Security boot version (e.g. GEC02).
sec.boot_version=GQI00JAA
# Security black plug mcode id string (e.g. GQC02JAA). # Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GQI00JA sec.black_plug_mcode=GQI00JAA

View File

@@ -49,8 +49,5 @@ gfx.device_adapter=-1
# Disable operator clock setting system clock time # Disable operator clock setting system clock time
misc.disable_clock_set=false misc.disable_clock_set=false
# Security boot version (e.g. GEC02).
sec.boot_version=GCJDJJAA
# Security black plug mcode id string (e.g. GQC02JAA). # Security black plug mcode id string (e.g. GQC02JAA).
sec.black_plug_mcode=GCJDJJA sec.black_plug_mcode=GCJDJJAA

View File

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

78
dist/iidx/iidxhook-28.conf vendored Normal file
View File

@@ -0,0 +1,78 @@
# 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
# Lightning cab mode (requires additional IO emulation)
io.lightning_mode=false
# Disable camera connection
io.disable_cams=true
# Disables the built in file hooks, requiring manual file creation
io.disable_file_hooks=false
# Turntable sensitivity multiplier (1.0 is default)
io.tt_multiplier=1.0
# Disables the camera emulation
cam.disable_emu=true
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id1=
# Override camera device ID detection (copy from device manager, do not escape)
cam.device_id2=
# Run the game in a framed window (requires windowed option)
gfx.framed=true
# Run the game windowed
gfx.windowed=false
# Confine mouse cursor to window
gfx.confined=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed X, -1 for default X position
gfx.window_x=-1
# Windowed Y, -1 for default Y position
gfx.window_y=-1
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
gfx.forced_refresh_rate=-1
# 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
# Force a screen resolution (width), -1 to disable. Use this if the game does not auto detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.
gfx.force_screen_res.width=-1
# Force a screen resolution (height), -1 to disable. Use this if the game does not auto detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.
gfx.force_screen_res.height=-1
# IP of adapter to force override with
adapter.override_ip=
# Force ASIO audio mode/device (if applicable / TDJ default)
asio.force_asio=false
# Force WASAPI audio mode (if applicable / LDJ default)
asio.force_wasapi=true
# The ASIO device name to use
asio.device_name=XONAR SOUND CARD(64)

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

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

5
dist/jb/gamestart-02.bat vendored Normal file
View File

@@ -0,0 +1,5 @@
@echo off
cd /d %~dp0
inject jbhook1.dll jubeat.exe --config jbhook-02.conf %*

10
dist/jb/gamestart-03.bat vendored Normal file
View File

@@ -0,0 +1,10 @@
@echo off
cd /d %~dp0
if not exist dev\nvram mkdir dev\nvram
if not exist dev\nvram\coin.xml copy prop\defaults\coin.xml dev\nvram\coin.xml
if not exist dev\nvram\eacoin.xml copy prop\defaults\eacoin.xml dev\nvram\eacoin.xml
if not exist dev\raw mkdir dev\raw
launcher -H 33554432 -K jbhook2.dll jubeat.dll -v

View File

@@ -7,4 +7,4 @@ if not exist dev\nvram\coin.xml copy prop\defaults\coin.xml dev\nvram\coin.xml
if not exist dev\nvram\eacoin.xml copy prop\defaults\eacoin.xml dev\nvram\eacoin.xml if not exist dev\nvram\eacoin.xml copy prop\defaults\eacoin.xml dev\nvram\eacoin.xml
if not exist dev\raw mkdir dev\raw if not exist dev\raw mkdir dev\raw
launcher -H 33554432 -K jbhook.dll jubeat.dll launcher -H 33554432 -K jbhook3.dll jubeat.dll

View File

@@ -1,6 +1,9 @@
# Run the game windowed # Run the game windowed
gfx.windowed=false gfx.windowed=false
# rotate the normally-horizontal game window to be vertical
gfx.vertical=true
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80. # URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
eamuse.server=localhost:80 eamuse.server=localhost:80

18
dist/jb/jbhook-02.conf vendored Normal file
View File

@@ -0,0 +1,18 @@
# Run the game windowed
gfx.windowed=false
# rotate the normally-horizontal game window to be vertical
gfx.vertical=true
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
eamuse.server=localhost:80
# PCBID
eamuse.pcbid=0101020304050607086F
# EAMID
eamuse.eamid=0101020304050607086F
# Mcode of the game to run.
security.mcode=GCI44JAA

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

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

View File

@@ -13,13 +13,22 @@ io.force_headphones=false
# Disables the built in file hooks, requiring manual file creation (/dev/raw/j.dest) # Disables the built in file hooks, requiring manual file creation (/dev/raw/j.dest)
io.disable_file_hooks=false io.disable_file_hooks=false
# Disables the built in power control hooks, allowing game to modify system power settings
io.disable_power_hooks=false
# Disables the built in NVAPI control hooks, allowing game to modify system monitor settings
io.disable_nvapi_hooks=false
# Emulates the card reader on COM1 instead of COM2
io.com1_card_reader=false
# Run the game in a framed window (requires windowed option) # Run the game in a framed window (requires windowed option)
gfx.framed=true gfx.framed=true
# Run the game windowed # Run the game windowed
gfx.windowed=false gfx.windowed=false
# Confine mouse coursor to window # Confine mouse cursor to window
gfx.confined=false gfx.confined=false
# Windowed width, -1 for default size # Windowed width, -1 for default size
@@ -28,6 +37,12 @@ gfx.window_width=1080
# Windowed height, -1 for default size # Windowed height, -1 for default size
gfx.window_height=1920 gfx.window_height=1920
# Windowed X, -1 for default X position
gfx.window_x=-1
# Windowed Y, -1 for default Y position
gfx.window_y=-1
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors) # 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 gfx.forced_refresh_rate=-1
@@ -37,6 +52,12 @@ gfx.device_adapter=-1
# Orientation to force monitor into, -1 to use default, 0, 1, 2, 3 to do 0, 90, 180, 270 degrees # Orientation to force monitor into, -1 to use default, 0, 1, 2, 3 to do 0, 90, 180, 270 degrees
gfx.force_orientation=-1 gfx.force_orientation=-1
# Force a screen resolution (width), -1 to disable. Use this if the game does not auto detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.
gfx.force_screen_res.width=-1
# Force a screen resolution (height), -1 to disable. Use this if the game does not auto detect your monitor's resolution properly, e.g. 1368x768 instead of 1280x720.
gfx.force_screen_res.height=-1
# Disables the camera emulation # Disables the camera emulation
cam.disable_emu=false cam.disable_emu=false

View File

@@ -1,21 +1,29 @@
# Bemanitools 5 documentation # Bemanitools 5 documentation
This folder contains various types of documentation. This folder contains various types of documentation.
Table of contents: Table of contents:
* Key tools * Key tools
* [Inject](inject.md): Readme for one of BT5's key applications, `inject.exe` * [Inject](inject.md): Readme for one of BT5's key applications, `inject.exe`
* [Launcher](launcher.md): Readme for another one of BT5's key applications, `launcher.exe` * [Launcher](launcher.md): Readme for another one of BT5's key applications, `launcher.exe`
* [Tools](tools/README.md): Documentation for additional user and development tooling * [Tools](tools/README.md): Documentation for additional user and development tooling
* Game hooks * Game hooks
* [ddrhook](ddrhook/README.md): Documentation relevant to `ddrhook` implementations * [ddrhook](ddrhook/README.md): Documentation relevant to `ddrhook` implementations
* [iidxhook](iidxhook/README.md): Documentation relevant to `iidxhook` implementations * [iidxhook](iidxhook/README.md): Documentation relevant to `iidxhook` implementations
* [jbhook](jbhook/README.md): Documentation relevant to `jbhook` implementations * [jbhook](jbhook/README.md): Documentation relevant to `jbhook` implementations
* [sdvxhook](sdvxhook/README.md): Documentation relevant to `sdvxhook` implementations * [sdvxhook](sdvxhook/README.md): Documentation relevant to `sdvxhook` implementations
* Development * Development
* [API](api.md): Available APIs for BT5 and instructions how to use them * [API](api.md): Available APIs for BT5 and instructions how to use them
* [Architecture](architecture.md): Outline of BT5's architecture, how things are designed and why * [Architecture](architecture.md): Outline of BT5's architecture, how things are designed and why
* [Development](development.md): Development environment, building, releasing, etc. * [Development](development.md): Development environment, building, releasing, etc.
* [Developer documentation](dev/README.md): Various lose documentation/notes by developers * [Developer documentation](dev/README.md): Various lose documentation/notes by developers
* [Tools](tools/README.md): Documentation for additional user and development tooling * [Tools](tools/README.md): Documentation for additional user and development tooling
* Hardware
* [Hardware](hardware/README.md): Anything related to hardware, e.g. IO boards ## Further external documentation
A list of external documentation that can be useful when dealing with bemanitools,
supported data and hardware.
* [arcade-docs](https://github.com/Shizmob/arcade-docs): An open (to read and contribute) repository
of arcade hardware and software documentation

View File

@@ -1,54 +0,0 @@
# BIO2 sub IO turntable bypass cable
If you upgraded a C02/IO2 wired cabinet, the turntables are connected to the
sub IO via a serial line that goes to another sub IO behind the front panel
next to the 16seg display. This introduces additional latency as the input
data needs to pass through multiple systems/PCBs until it reaches the game.
This can be reduced by using a so-called "bypass" cable, that connects the
turntables directly to the BIO2 sub IO board reducing latency significantly.
This cable could be ordered with any IIDX upgrade kit including the BIO sub IO
board but can also be easily created from scratch.
## Parts
* Some wires
* [JST HL](https://jst.de/file/download/219/pitch-3-96-mm-wtw-hl2-pdf) 2x4 pin female connector
* [JST HVQ](https://jst.de/file/download/637/hvq) 8 pin female connector
* Matching terminals for the connectors
## Pinout
```text
JST HL 2x4 pin front view connector
notch at top
___
|---------|
| 1 2 3 4 |
| 5 6 7 8 |
|---------|
```
```
JST HVQ 8 pin front view connector
Numbering on connector matches
notch at top
___________________
-------------------
|-----------------|
| 1 2 3 4 5 6 7 8 |
|-----------------|
```
Pins of the two connectors need to be connected like this:
| JST HL 2x4 pin | JST 8 pin |
|----------------|-----------|
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 2 |
| 5 | 5 |
| 6 | 4 |
| 7 | 8 |
| 8 | 8 |

View File

@@ -1,51 +0,0 @@
# Ezusb 1/2 RJ45 to DIN8 connector pinout
This was created from using the BIO2 sub IO board to connect pre IIDX 25 cabinet hardware to the
BIO2 IO board. The two connector types from different generation IO boards, RJ45 on the ezusb FX
(C02) board and a round DIN8 connector on the ezusb FX2 (IO2) board are just different connectors to
the same hardware on the PCB.
Therefore, any C02 wired cabinet can be easily upgraded to IO2 wiring and vice versa by building
a simple RJ45 -> DIN8 or DIN8 -> RJ45 adapter.
The following connection information was traced on a original Konami BIO2 sub IO board.
RJ45 (female) connector, top view:
```text
plug insert
|
|
v
|-----------|
| Top view |
| |
| Pins |
| 7 5 3 1 |
| 8 6 4 2 |
|-----------|
```
DIN8 (female) connector, top view:
```text
plug insert
|
|
v
|-----------|
| Top view |
| Pins |
| 3 1 2 6 |
| 7 4 5 8 9 |
|-----------|
```
The two connectors are interconnected on the PCB like this:
| RJ45 pins | DIN8 pins |
|-----------|-----------|
| 1 | 1 |
| 2 | 7 |
| 3 | 4 |
| 4 | 6 |
| 5 | 5 |
| 6 | 3 |
| 7 | 2 |
| 8 | 1 |

View File

@@ -23,14 +23,14 @@ games:
* [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage * [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage
* [iidxhook8](iidxhook9.md): Heroic Verse * [iidxhook8](iidxhook9.md): Heroic Verse
When building kactools, independent packages are created for each set of games When building bemanitools, independent packages are created for each set of games
which are ready to be dropped on top of vanilla AC data dumps. We recommend which are ready to be dropped on top of vanilla AC data dumps. We recommend
using prestine dumps to avoid any conflicts with other hardcoded hacks or using pristine dumps to avoid any conflicts with other hardcoded hacks or
binary patches. binary patches.
## How to run ## How to run
To run your game with iidxhook, you have to use the inject tool to inject the To run your game with iidxhook, you have to use the inject tool to inject the
DLL to the game process. *dist/iidx* contains bat scripts with all the DLL to the game process. `dist/iidx` contains bat scripts with all the
important parameters configured. Further parameters can be added but might not important parameters configured. Further parameters can be added but might not
be required to run the game with default settings. be required to run the game with default settings.
Further information on how to setup the data for each specific version are Further information on how to setup the data for each specific version are
@@ -47,4 +47,4 @@ IO hardware you want to use:
game controllers game controllers
* [iidxio-bio2](iidxhook/iidxio-bio2.md): Support BIO2 hardware * [iidxio-bio2](iidxhook/iidxio-bio2.md): Support BIO2 hardware
* [iidxio-ezusb](iidxhook/iidxio-ezusb.md): Support C02 ezusb FX hardware * [iidxio-ezusb](iidxhook/iidxio-ezusb.md): Support C02 ezusb FX hardware
* [iidxio-ezusb2](iidxhook/iidxio-ezusb2.md): Support IO2 ezusb FX2 hardware * [iidxio-ezusb2](iidxhook/iidxio-ezusb2.md): Support IO2 ezusb FX2 hardware

View File

@@ -57,6 +57,12 @@ If you want to run the games online, you have to set a valid PCBID and EAMID
argument. You also have to set the url of the eamuse server you want to argument. You also have to set the url of the eamuse server you want to
connect to. connect to.
Additional note regarding EAMID: This is new compared to the prior games and
is provided as the identifier of the "eamuse license" to the server. Depending
on the implementation of the server, this can lead to authentication failure
resulting in
[a network error on boot or warning during gameplay](#network-warning-instead-of-network-ok).
Run the game with the gamestart-XX.bat file and enable network on the operator Run the game with the gamestart-XX.bat file and enable network on the operator
menu. When enabled, the game seems to hang and expects you to power menu. When enabled, the game seems to hang and expects you to power
cycle the machine (i.e. quit the game and restart it). cycle the machine (i.e. quit the game and restart it).
@@ -134,7 +140,7 @@ value to cut down start-up times.
## "NETWORK WARNING" instead of "NETWORK OK" ## "NETWORK WARNING" instead of "NETWORK OK"
This can be caused by: This can be caused by:
* Invalid PCBID * Invalid PCBID/EAMID: Ensure both are [set to the same ID](#eamuse-network-setup)
* Firewall blocking connections * Firewall blocking connections
* Invalid eamuse url or port specified * Invalid eamuse url or port specified
* Game is not run using the Administrator account * Game is not run using the Administrator account

View File

@@ -2,6 +2,7 @@
The following games are compatible with this version of iidxhook: The following games are compatible with this version of iidxhook:
* Heroic Verse * Heroic Verse
* BISTROVER
The games must be bootstrapped using [launcher](../launcher.md). The games must be bootstrapped using [launcher](../launcher.md).

77
doc/jbhook/README.md Normal file
View File

@@ -0,0 +1,77 @@
# jbhook
jbhook is a collection of hook libraries for jubeat 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 jbhook version
(see below).
# Versions
jbhook comes in a few different flavors. The game and its engine changed over
the years. Some game versions might require patches/parameters enabled which
others don't need or have different AVS versions. Here is the list of supported
games:
* [jbhook1](jbhook1.md): jubeat, ripples
* [jbhook2](jbhook2.md): knit, copious
* [jbhook3](jbhook3.md): saucer, prop, qubell, clan, festo
I sure have trouble remembering which jubeat version is which, here's a handy
guide:
* 01 - jubeat
* 02 - ripples
* 03 - knit
* 04 - copious
* 05 - saucer
* 06 - prop
* 07 - qubell
* 08 - clan
* 09 - festo
When building bemanitools, independent packages are created for each set of games
which are ready to be dropped on top of vanilla AC data dumps. We recommend
using pristine dumps to avoid any conflicts with other hardcoded hacks or
binary patches.
# How to run
To run your game with jbhook, you have to use the inject tool to inject the
DLL to the game process. `dist/jb` contains bat scripts with all the
important parameters configured. Further parameters can be added but might not
be required to run the game with default settings.
Further information on how to setup the data for each specific version are
elaborated in their dedicated readme files.
# Data setup and running the game
Ensure your folder with your unpacked data looks like this:
- `data`
- `prop`
- Various dll files including `jubeat.dll` **OR** `jubeat.exe`
Unpack the package containing jbhook into the folder containing the jubeat
binary file.
Run the `gamestart-XX.bat` file where `XX` denotes the version of the game you want to run.
# Eamuse network setup
Running jubeat or ripples? Modify jbhook-01.conf or jbhook-02.conf.
Running anything newer?
* Open the `prop/ea3-config.xml`
* Replace the `ea3/network/services` URL with network service URL of your
choice (for example http://my.eamuse.com)
* Edit the `ea3/id/pcbid`
# Real hardware support
Run the launcher without the hook dll: `launcher jubeat.dll`
# Command line options
Add the argument *-h* when running inject with jbhook to print help/usage
information with a list of parameters you can apply to tweak various things.

View File

@@ -1,31 +0,0 @@
# Game list
The following games are compatible with this version of jbhook:
* saucer
* prop
* qubell
# Data setup and running the game
Ensure your folder with your unpacked data looks like this:
- data
- prop
- Various dll files including jubeat.dll
Unpack the package containing jbhook into the folder containing the jubeat.dll
file.
Run the gamestart.bat file.
# Eamuse network setup
* Open the prop/ea3-config.xml
* Replace the *ea3/network/services* URL with network service URL of your
choice (for example http://my.eamuse.com)
* Edit the *ea3/id/pcbid*
# Real hardware support
Run the launcher without the hook dll: *launcher jubeat.dll*
# Troubleshooting and FAQ

42
doc/jbhook/jbhook1.md Normal file
View File

@@ -0,0 +1,42 @@
# Game list
The following games are compatible with this version of jbhook:
* jubeat
* jubeat ripples
The games must be bootstrapped using [inject](../inject.md).
# Data setup and running the game
Unpack the package containing jbhook1 into the revision folder of your choice.
Most likely, you want to target the latest revision you have to run the latest
binary of the game with any bugfixes by developers.
The DLLs in this package should be in the same location as the game DLLs and
executable - i.e. all these files should be in the same folder:
- `inject.exe`
- `jubeat.exe`
- `jbhook-01.conf`
- `eamio.dll`
- `libavs-win32.dll`
- etc
Run the `gamestart-01.bat` file as admin.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID in the
configuration file. You also have to set the url of the eamuse server you want
to connect to.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID and EAMID
(use the PCBID as the EAMID) in the configuration file or as a command line
argument. You also have to set the url of the eamuse server you want to
connect to.
Additional note regarding EAMID: This is provided as the identifier of the
"eamuse license" to the server. Depending on the implementation of the server,
this can lead to authentication failure resulting in a network error on boot or
warning during gameplay.

42
doc/jbhook/jbhook2.md Normal file
View File

@@ -0,0 +1,42 @@
# Game list
The following games are compatible with this version of jbhook:
* jubeat knit
* jubeat copious
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
Unpack the package containing jbhook2 into the revision folder of your choice.
Most likely, you want to target the latest revision you have to run the latest
binary of the game with any bugfixes by developers.
The DLLs in this package should be in the same location as the game DLLs and
executable - i.e. all these files should be in the same folder:
- `launcher.exe`
- `jubeat.dll`
- `eamio.dll`
- `jbhook2.dll`
- `libavs-win32.dll`
- etc
Run the `gamestart-02.bat` file as admin.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID in the
configuration file. You also have to set the url of the eamuse server you want
to connect to.
# Eamuse network setup
If you want to run the games online, you have to set a valid PCBID and EAMID
(use the PCBID as the EAMID) in the configuration file or as a command line
argument. You also have to set the url of the eamuse server you want to
connect to.
Additional note regarding EAMID: This is provided as the identifier of the
"eamuse license" to the server. Depending on the implementation of the server,
this can lead to authentication failure resulting in a network error on boot or
warning during gameplay.

18
doc/jbhook/jbhook3.md Normal file
View File

@@ -0,0 +1,18 @@
# Game list
The following games are compatible with this version of jbhook:
* jubeat saucer
* jubeat prop
* jubeat qubell
* jubeat clan
* jubeat festo
The games must be bootstrapped using [launcher](../launcher.md).
# Data setup and running the game
Unpack the package containing jbhook3 into the revision folder of your choice.
Most likely, you want to target the latest revision you have to run the latest
binary of the game with any bugfixes by developers.
Run the `gamestart-03.bat` file as admin.

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

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

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
#!/bin/sh
VERSION="$1"
section_active=""
changelog_excerpt=""
while IFS= read -r line; do
if [ "$section_active" ]; then
if [[ "$(echo "$line" | grep '^#')" ]]; then
section_active=""
else
changelog_excerpt="$(printf "%s\n%s" "$changelog_excerpt" "$line")"
fi
else
if [ "$line" = "## $VERSION" ]; then
section_active="1"
fi
fi
done
if [ "$changelog_excerpt" ]; then
printf "%s" "$changelog_excerpt"
exit 0
else
>&2 echo "Could not find version in changelog: $VERSION"
exit 1
fi

View File

@@ -46,6 +46,12 @@ struct property_node;
struct avs_net_interface { struct avs_net_interface {
uint8_t mac_addr[6]; uint8_t mac_addr[6];
uint8_t unknown[30]; uint8_t unknown[30];
#if AVS_VERSION >= 1603
uint8_t unknown2[6];
#endif
#if AVS_VERSION >= 1700
uint8_t unknown3[6];
#endif
}; };
enum psmap_type { enum psmap_type {

10
src/imports/glhelper.h Normal file
View File

@@ -0,0 +1,10 @@
#include <GL/gl.h>
void glFramebufferTexture2DEXT(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level);
void glGenFramebuffersEXT(GLsizei n,
GLuint *ids);

View File

@@ -0,0 +1,5 @@
LIBRARY libavs-win32-ea3
EXPORTS
ea3_boot
ea3_shutdown

View File

@@ -0,0 +1,37 @@
LIBRARY libavs-win32
EXPORTS
avs_boot
avs_net_ctrl
avs_shutdown
avs_thread_create
avs_thread_destroy
avs_thread_exit
avs_thread_join
log_body_fatal
log_body_info
log_body_misc
log_body_warning
log_boot
log_change_level
property_create
property_desc_to_buffer
property_destroy
property_file_write
property_insert_read
property_mem_write
property_read_query_memsize
property_search
property_set_flag
property_node_clone
property_node_create
property_node_datasize
property_node_name
property_node_refer
property_node_remove
property_node_type
property_node_traversal
property_node_refdata
std_getenv
std_setenv

View File

@@ -0,0 +1,6 @@
LIBRARY glhelper
EXPORTS
glBindFramebufferEXT
glFramebufferTexture2DEXT
glGenFramebuffersEXT

View File

@@ -0,0 +1,6 @@
LIBRARY glhelper
EXPORTS
glBindFramebufferEXT
glFramebufferTexture2DEXT
glGenFramebuffersEXT

View File

@@ -0,0 +1,6 @@
LIBRARY glhelper
EXPORTS
glBindFramebufferEXT
glFramebufferTexture2DEXT
glGenFramebuffersEXT

View File

@@ -0,0 +1,6 @@
LIBRARY glhelper
EXPORTS
glBindFramebufferEXT
glFramebufferTexture2DEXT
glGenFramebuffersEXT

View File

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

View File

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

View File

@@ -5,9 +5,13 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "acio/h44b.h"
#include "acio/hdxs.h" #include "acio/hdxs.h"
#include "acio/icca.h" #include "acio/icca.h"
#include "acio/kfca.h" #include "acio/kfca.h"
#include "acio/mdxf.h"
#include "acio/panb.h"
#include "acio/rvol.h"
#define AC_IO_SOF 0xAA #define AC_IO_SOF 0xAA
#define AC_IO_ESCAPE 0xFF #define AC_IO_ESCAPE 0xFF
@@ -35,8 +39,11 @@ enum ac_io_node_type {
AC_IO_NODE_TYPE_LED_STRIP = 0x04020000, AC_IO_NODE_TYPE_LED_STRIP = 0x04020000,
AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000, AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000,
AC_IO_NODE_TYPE_KFCA = 0x09060000, AC_IO_NODE_TYPE_KFCA = 0x09060000,
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
AC_IO_NODE_TYPE_RVOL = 0x09060001, AC_IO_NODE_TYPE_RVOL = 0x09060001,
AC_IO_NODE_TYPE_MDXF = 0x09070000,
AC_IO_NODE_TYPE_PANB = 0x090E0000,
AC_IO_NODE_TYPE_BMPU = 0x0B000000,
AC_IO_NODE_TYPE_BI2A = 0x0D060000,
}; };
#pragma pack(push, 1) #pragma pack(push, 1)
@@ -69,13 +76,24 @@ struct ac_io_message {
uint8_t param; uint8_t param;
struct ac_io_version version; struct ac_io_version version;
struct ac_io_h44b_output h44b_output;
struct ac_io_icca_misc icca_misc; struct ac_io_icca_misc icca_misc;
struct ac_io_icca_state icca_state; struct ac_io_icca_state icca_state;
struct ac_io_kfca_poll_in kfca_poll_in; struct ac_io_kfca_poll_in kfca_poll_in;
struct ac_io_kfca_poll_out kfca_poll_out; struct ac_io_kfca_poll_out kfca_poll_out;
struct ac_io_panb_poll_in panb_poll_in;
struct ac_io_panb_poll_out panb_poll_out;
struct ac_io_hdxs_output hdxs_output; struct ac_io_hdxs_output hdxs_output;
struct ac_io_rvol_poll_in rvol_poll_in;
struct ac_io_rvol_poll_out rvol_poll_out;
struct ac_io_mdxf_poll_in mdxf_poll_in;
struct ac_io_mdxf_light_out mdxf_light_out;
}; };
} cmd; } cmd;

View File

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

View File

@@ -4,13 +4,15 @@
#include <stdint.h> #include <stdint.h>
enum ac_io_icca_cmd { enum ac_io_icca_cmd {
/* found on jubeat, sent right after queue loop start */
AC_IO_ICCA_CMD_UNKN_0116 = 0x0116,
/* Yet unknown command encountered first on jubeat (1) */ /* 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_QUEUE_LOOP_START = 0x0130,
AC_IO_ICCA_CMD_ENGAGE = 0x0131, AC_IO_ICCA_CMD_ENGAGE = 0x0131,
AC_IO_ICCA_CMD_POLL = 0x0134, AC_IO_ICCA_CMD_POLL = 0x0134,
AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135, AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135,
AC_IO_ICCA_CMD_BEGIN_KEYPAD = 0x013A, AC_IO_ICCA_CMD_DEVICE_CONTROL = 0x013A,
AC_IO_ICCA_CMD_POLL_FELICA = 0x0161, AC_IO_ICCA_CMD_POLL_FELICA = 0x0161,
AC_IO_ICCA_CMD_KEY_EXCHANGE = 0x0160, AC_IO_ICCA_CMD_KEY_EXCHANGE = 0x0160,
AC_IO_ICCA_CMD_POLL_ENCRYPTED = 0x0164, AC_IO_ICCA_CMD_POLL_ENCRYPTED = 0x0164,
@@ -29,6 +31,14 @@ enum ac_io_icca_sensor_state {
AC_IO_ICCA_SENSOR_MASK_BACK_ON = (1 << 5) AC_IO_ICCA_SENSOR_MASK_BACK_ON = (1 << 5)
}; };
enum ac_io_icca_status_code {
AC_IO_ICCA_STATUS_FAULT = 0x00,
AC_IO_ICCA_STATUS_IDLE = 0x01,
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04,
AC_IO_ICCA_STATUS_BUSY_NEW = 0x01,
};
enum ac_io_icca_keypad_mask { enum ac_io_icca_keypad_mask {
AC_IO_ICCA_KEYPAD_MASK_EMPTY = (1 << 0), AC_IO_ICCA_KEYPAD_MASK_EMPTY = (1 << 0),
AC_IO_ICCA_KEYPAD_MASK_3 = (1 << 1), AC_IO_ICCA_KEYPAD_MASK_3 = (1 << 1),

View File

@@ -1,48 +0,0 @@
#ifndef AC_IO_ICCB_H
#define AC_IO_ICCB_H
#include <stdint.h>
enum ac_io_iccb_cmd {
/* found on jubeat prop, sent after acio init req, maybe fw update? */
AC_IO_ICCB_CMD_UNK_0100 = 0x0100,
/* found on jubeat prop, sent right after queue loop start */
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_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
};
enum ac_io_iccb_sensor_state {
AC_IO_ICCB_SENSOR_CARD = 0x02,
AC_IO_ICCB_SENSOR_NO_CARD = 0x04
};
enum ac_io_iccb_card_type {
AC_IO_ICCB_CARD_TYPE_ISO15696 = 0x0,
AC_IO_ICCB_CARD_TYPE_FELICA = 0x1,
};
#pragma pack(push, 1)
struct ac_io_iccb_misc {
uint8_t unknown;
uint8_t subcmd;
};
struct ac_io_iccb_state {
uint8_t sensor_state;
uint8_t card_type;
uint8_t uid[8];
uint8_t unk2;
uint8_t unk3;
uint8_t unk4[4];
};
#pragma pack(pop)
#endif

49
src/main/acio/mdxf.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef AC_IO_MDXF_H
#define AC_IO_MDXF_H
#include <stdint.h>
#define AC_IO_CMD_MDXF_POLL 0x0110
#define AC_IO_CMD_MDXF_AUTO_GET_START 0x0116
#define AC_IO_CMD_MDXF_LIGHT 0x0113
#pragma pack(push, 1)
union mdxf_panel_sensors_individual {
struct {
uint8_t right : 1;
uint8_t left : 1;
uint8_t down : 1;
uint8_t up : 1;
uint8_t unused : 4;
};
uint8_t raw;
};
struct mdxf_panel_sensors {
uint8_t down : 4;
uint8_t up : 4;
uint8_t right : 4;
uint8_t left : 4;
};
struct ac_io_mdxf_poll_in {
struct mdxf_panel_sensors panel;
uint8_t unk;
};
struct mdxf_lights {
uint8_t up_right;
uint8_t down_left;
uint8_t up_left;
uint8_t down_right;
uint8_t unk;
};
struct ac_io_mdxf_light_out {
struct mdxf_lights side[2];
};
#pragma pack(pop)
#endif

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

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

74
src/main/acio/rvol.h Normal file
View File

@@ -0,0 +1,74 @@
#ifndef AC_IO_RVOL_H
#define AC_IO_RVOL_H
#include <stdint.h>
// technically RVOL also can poll with CMD 0x0113
// but museca never uses this (it's controlled by if the watchdog is on/off)
#define AC_IO_CMD_RVOL_POLL 0x0112
#define AC_IO_CMD_RVOL_SET_EXPAND_MODE 0x0114
#define AC_IO_CMD_RVOL_AMP_CONTROL 0x0128
#pragma pack(push, 1)
struct ac_io_rvol_buttons_1 {
uint8_t unk0 : 1;
uint8_t unk1 : 1;
uint8_t spinner_4 : 1;
uint8_t pedal : 1;
uint8_t spinner_5 : 1;
uint8_t unk5 : 1;
uint8_t unk6 : 1;
uint8_t unk7 : 1;
};
struct ac_io_rvol_buttons_2 {
uint8_t spinner_2 : 1;
uint8_t unk1 : 1;
uint8_t unk2 : 1;
uint8_t spinner_1 : 1;
uint8_t unk4 : 1;
uint8_t unk5 : 1;
uint8_t unk6 : 1;
uint8_t unk7 : 1;
};
struct ac_io_rvol_buttons_3 {
uint8_t unk0 : 1;
uint8_t unk1 : 1;
uint8_t unk2 : 1;
uint8_t spinner_3 : 1;
uint8_t unk4 : 1;
uint8_t unk5 : 1;
uint8_t unk6 : 1;
uint8_t unk7 : 1;
};
struct ac_io_rvol_poll_in {
uint8_t unk_0;
struct ac_io_rvol_buttons_1 buttons_1;
uint8_t unk_2_8[7];
struct ac_io_rvol_buttons_2 buttons_2;
uint8_t unk_10;
struct ac_io_rvol_buttons_3 buttons_3;
uint8_t unk_12_15[4];
uint8_t spinners[5];
uint8_t unk_21_22[2];
};
struct light_rgb {
uint8_t r;
uint8_t g;
uint8_t b;
};
struct ac_io_rvol_poll_out {
uint8_t unk0_3[4];
struct light_rgb spinner[5];
struct light_rgb title;
uint8_t unk22_31[10];
};
#pragma pack(pop)
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

View File

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

View File

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

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

@@ -0,0 +1,80 @@
#define LOG_MODULE "aciodrv-rvol"
#include <stdio.h>
#include <string.h>
#include "aciodrv/device.h"
#include "util/log.h"
static bool aciodrv_rvol_change_expand_mode(
struct aciodrv_device_ctx *device,
uint8_t node_id,
uint8_t mode)
{
struct ac_io_message msg;
log_assert(device);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_RVOL_SET_EXPAND_MODE);
msg.cmd.nbytes = 1;
msg.cmd.raw[0] = (mode | (2 * mode)) << 6;
if (!aciodrv_send_and_recv(
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("RVOL change expand mode failed %d", node_id);
return false;
}
log_info("I/O expand mode set %d, mode: %d",
node_id, mode);
return true;
}
bool aciodrv_rvol_init(
struct aciodrv_device_ctx *device,
uint8_t node_id)
{
log_assert(device);
if (!aciodrv_rvol_change_expand_mode(device, node_id, 1)) {
return false;
}
return true;
}
bool aciodrv_rvol_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_rvol_poll_out *pout,
struct ac_io_rvol_poll_in *pin)
{
struct ac_io_message msg;
log_assert(device);
log_assert(pout);
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_RVOL_POLL);
msg.cmd.nbytes = sizeof(*pout);
/* buffer size of data we expect */
msg.cmd.rvol_poll_out = *pout;
if (!aciodrv_send_and_recv(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
if (pin != NULL) {
memcpy(pin, &msg.cmd.rvol_poll_in, sizeof(*pin));
}
return true;
}

36
src/main/aciodrv/rvol.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef ACIODRV_RVOL_H
#define ACIODRV_RVOL_H
#include "acio/rvol.h"
/**
* Initialize a Revolte (KFCA 1.5) IO board
*
* @param device Context of opened device
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_rvol_init(struct aciodrv_device_ctx *device, uint8_t node_id);
/**
* Poll a Revolte (KFCA 1.5) IO board
*
* @param device Context of opened device
* @param node_id Id of the node to query (0 based).
* @param pout Pointer to a state struct to write to device
* @param pin Pointer to a state struct to return the current state to
* @return True on success, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_rvol_poll(
struct aciodrv_device_ctx *device,
uint8_t node_id,
const struct ac_io_rvol_poll_out *pout,
struct ac_io_rvol_poll_in *pin);
#endif

View File

@@ -6,6 +6,5 @@ src_acioemu := \
h44b.c \ h44b.c \
hdxs.c \ hdxs.c \
icca.c \ icca.c \
iccb.c \
pipe.c \ pipe.c \

View File

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

View File

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

View File

@@ -29,13 +29,6 @@ enum ac_io_icca_flag {
AC_IO_ICCA_FLAG_SOLENOID = 0x40 AC_IO_ICCA_FLAG_SOLENOID = 0x40
}; };
enum ac_io_icca_status_code {
AC_IO_ICCA_STATUS_FAULT = 0x00,
AC_IO_ICCA_STATUS_IDLE = 0x01,
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04
};
static void ac_io_emu_icca_cmd_send_version( 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);
@@ -70,6 +63,8 @@ void ac_io_emu_icca_init(
// default to 1.6.0 // default to 1.6.0
icca->version = v160; icca->version = v160;
// default, most common code
ac_io_emu_icca_set_product_code(icca, AC_IO_EMU_PROD_CODE_ICCA);
} }
void ac_io_emu_icca_set_version( void ac_io_emu_icca_set_version(
@@ -78,6 +73,12 @@ void ac_io_emu_icca_set_version(
icca->version = version; icca->version = version;
} }
void ac_io_emu_icca_set_product_code(
struct ac_io_emu_icca *icca, const char product_code[4])
{
memcpy(icca->product_code, product_code, sizeof(icca->product_code));
}
void ac_io_emu_icca_dispatch_request( 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)
{ {
@@ -126,14 +127,15 @@ void ac_io_emu_icca_dispatch_request(
break; break;
case AC_IO_ICCA_CMD_UNKN_0116:
case AC_IO_ICCA_CMD_UNKN_0120: case AC_IO_ICCA_CMD_UNKN_0120:
log_misc("AC_IO_ICCA_CMD_UNKN_0120(%d)", req->addr); log_misc("AC_IO_ICCA_CMD_UNK_%04X(%d)", cmd_code, req->addr);
ac_io_emu_icca_send_status(icca, req, 0x00); ac_io_emu_icca_send_status(icca, req, 0x00);
break; break;
case AC_IO_ICCA_CMD_BEGIN_KEYPAD: case AC_IO_ICCA_CMD_DEVICE_CONTROL:
log_misc("AC_IO_ICCA_CMD_BEGIN_KEYPAD(%d)", req->addr); log_misc("AC_IO_ICCA_CMD_DEVICE_CONTROL(%d)", req->addr);
ac_io_emu_icca_send_status(icca, req, 0x00); ac_io_emu_icca_send_status(icca, req, 0x00);
icca->keypad_started = true; icca->keypad_started = true;
@@ -145,48 +147,52 @@ void ac_io_emu_icca_dispatch_request(
break; break;
case AC_IO_ICCA_CMD_SET_SLOT_STATE: { case AC_IO_ICCA_CMD_SET_SLOT_STATE: {
struct ac_io_icca_misc *misc = if(icca->version == v150) {
(struct ac_io_icca_misc *) &req->cmd.raw; ac_io_emu_icca_send_state(icca, req, 0, false);
uint8_t cmd; } else {
struct ac_io_icca_misc *misc =
(struct ac_io_icca_misc *) &req->cmd.raw;
uint8_t cmd;
switch (misc->subcmd) { switch (misc->subcmd) {
case AC_IO_ICCA_SUBCMD_CARD_SLOT_CLOSE: case AC_IO_ICCA_SUBCMD_CARD_SLOT_CLOSE:
cmd = EAM_IO_CARD_SLOT_CMD_CLOSE; cmd = EAM_IO_CARD_SLOT_CMD_CLOSE;
break; break;
case AC_IO_ICCA_SUBCMD_CARD_SLOT_OPEN: case AC_IO_ICCA_SUBCMD_CARD_SLOT_OPEN:
cmd = EAM_IO_CARD_SLOT_CMD_OPEN; cmd = EAM_IO_CARD_SLOT_CMD_OPEN;
break; break;
case AC_IO_ICCA_SUBCMD_CARD_SLOT_EJECT: case AC_IO_ICCA_SUBCMD_CARD_SLOT_EJECT:
cmd = EAM_IO_CARD_SLOT_CMD_EJECT; cmd = EAM_IO_CARD_SLOT_CMD_EJECT;
icca->engaged = false; icca->engaged = false;
break; break;
case 3: case 3:
cmd = EAM_IO_CARD_SLOT_CMD_READ; cmd = EAM_IO_CARD_SLOT_CMD_READ;
break; break;
default: default:
cmd = 0xFF; cmd = 0xFF;
log_warning( log_warning(
"Unhandled slot command %X, node %d", "Unhandled slot command %X, node %d",
misc->subcmd, misc->subcmd,
icca->unit_no); icca->unit_no);
break; 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);
} }
}
/* response with current slot state */ if (cmd != 0xFF) {
ac_io_emu_icca_send_status(icca, req, misc->subcmd); 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);
}
}
/* response with current slot state */
ac_io_emu_icca_send_status(icca, req, misc->subcmd);
}
break; break;
} }
@@ -209,12 +215,14 @@ void ac_io_emu_icca_dispatch_request(
break; break;
case AC_IO_ICCA_CMD_POLL_FELICA: case AC_IO_ICCA_CMD_POLL_FELICA:
icca->detected_new_reader = true; if (icca->version == v150) {
ac_io_emu_icca_send_state(icca, req, 0, false);
if (icca->version == v170) { } else if (icca->version == v170) {
ac_io_emu_icca_send_empty(icca, req); ac_io_emu_icca_send_empty(icca, req);
icca->detected_new_reader = true;
} else { } else {
ac_io_emu_icca_send_status(icca, req, 0x01); ac_io_emu_icca_send_status(icca, req, 0x01);
icca->detected_new_reader = true;
} }
break; break;
@@ -251,8 +259,6 @@ static void ac_io_emu_icca_cmd_send_version(
resp.cmd.version.major = 0x01; resp.cmd.version.major = 0x01;
if (icca->version == v150) { if (icca->version == v150) {
log_warning(
"ICCA v1.5.0 emulation requested, please remove this log once implemented");
resp.cmd.version.minor = 0x05; resp.cmd.version.minor = 0x05;
} else if (icca->version == v160) { } else if (icca->version == v160) {
resp.cmd.version.minor = 0x06; resp.cmd.version.minor = 0x06;
@@ -269,7 +275,7 @@ static void ac_io_emu_icca_cmd_send_version(
memcpy( memcpy(
resp.cmd.version.product_code, resp.cmd.version.product_code,
"ICCA", icca->product_code,
sizeof(resp.cmd.version.product_code)); sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date)); strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time)); strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));

View File

@@ -12,6 +12,11 @@ enum ac_io_emu_icca_version {
v170 = 0x7, v170 = 0x7,
}; };
// ICC product types for ac_io_emu_icca_set_product_code
#define AC_IO_EMU_PROD_CODE_ICCA "ICCA"
#define AC_IO_EMU_PROD_CODE_ICCB "ICCB"
#define AC_IO_EMU_PROD_CODE_ICCC "ICCC"
struct ac_io_emu_icca { struct ac_io_emu_icca {
struct ac_io_emu *emu; struct ac_io_emu *emu;
uint8_t unit_no; uint8_t unit_no;
@@ -28,6 +33,7 @@ struct ac_io_emu_icca {
uint64_t time_counter_last_poll; uint64_t time_counter_last_poll;
enum ac_io_emu_icca_version version; enum ac_io_emu_icca_version version;
char product_code[4];
bool cipher_started; bool cipher_started;
uint32_t cipher_keys[4]; uint32_t cipher_keys[4];
}; };
@@ -39,6 +45,12 @@ void ac_io_emu_icca_init(
void ac_io_emu_icca_set_version( void ac_io_emu_icca_set_version(
struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version); struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version);
// optional, call after init to override default "ICCA" product code.
// Some games may refuse to boot or expect a different packet format when using
// one of the alternative codes such as ICCB or ICCC
void ac_io_emu_icca_set_product_code(
struct ac_io_emu_icca *icca, const char product_code[4]);
void ac_io_emu_icca_dispatch_request( 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);

View File

@@ -1,219 +0,0 @@
#define LOG_MODULE "acioemu-iccb"
#include "acioemu/iccb.h"
#include <windows.h> /* for _BitScanForward */
#include <stdint.h>
#include <string.h>
#include "acio/iccb.h"
#include "acioemu/emu.h"
#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);
static void ac_io_emu_iccb_send_state(
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);
static void ac_io_emu_iccb_send_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)
{
memset(iccb, 0, sizeof(*iccb));
iccb->emu = emu;
iccb->unit_no = unit_no;
}
void ac_io_emu_iccb_dispatch_request(
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
uint16_t cmd_code;
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_iccb_cmd_send_version(iccb, req);
break;
case AC_IO_CMD_START_UP:
log_misc("AC_IO_CMD_START_UP(%d)", req->addr);
ac_io_emu_iccb_send_status(iccb, req, 0x00);
break;
case AC_IO_CMD_KEEPALIVE:
ac_io_emu_iccb_send_empty(iccb, req);
break;
case AC_IO_ICCB_CMD_QUEUE_LOOP_START:
log_misc("AC_IO_CMD_QUEUE_LOOP_START(%d)", req->addr);
ac_io_emu_iccb_send_status(iccb, req, 0x00);
break;
case AC_IO_ICCB_CMD_UNK_0100:
case AC_IO_ICCB_CMD_UNK_0116:
case AC_IO_ICCB_CMD_UNK_0120:
log_misc("AC_IO_ICCB_CMD_UNK_%04X(%d)", cmd_code, req->addr);
ac_io_emu_iccb_send_status(iccb, req, 0x00);
break;
case AC_IO_ICCB_CMD_SLEEP:
ac_io_emu_iccb_send_status(iccb, req, 0x00);
break;
case AC_IO_ICCB_CMD_UNK_135:
/* log_misc("AC_IO_ICCB_CMD_UNK_135"); */
ac_io_emu_iccb_send_state(iccb, req);
break;
case AC_IO_ICCB_CMD_POLL:
/* log_misc("AC_IO_ICCB_CMD_POLL"); */
ac_io_emu_iccb_send_state(iccb, req);
break;
case AC_IO_ICCB_CMD_READ_CARD:
/* log_misc("AC_IO_ICCB_CMD_READ_CARD"); */
ac_io_emu_iccb_send_state(iccb, req);
break;
default:
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_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 = sizeof(resp.cmd.version);
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_ICCB);
resp.cmd.version.flag = 0x00;
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));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
ac_io_emu_response_push(iccb->emu, &resp, 0);
}
static void ac_io_emu_iccb_send_empty(
struct ac_io_emu_iccb *iccb, 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 = 0;
ac_io_emu_response_push(iccb->emu, &resp, 0);
}
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_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 = sizeof(resp.cmd.status);
resp.cmd.status = status;
ac_io_emu_response_push(iccb->emu, &resp, 0);
}
static void ac_io_emu_iccb_send_state(
struct ac_io_emu_iccb *iccb, const struct ac_io_message *req)
{
struct ac_io_message resp;
struct ac_io_iccb_state *body;
bool sensor;
/* state update */
sensor = eam_io_get_sensor_state(iccb->unit_no);
if (sensor != iccb->last_sensor) {
if (sensor) {
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);
} else {
iccb->fault = false;
}
}
iccb->last_sensor = sensor;
if (iccb->fault) {
memset(iccb->uid, 0, sizeof(iccb->uid));
}
/* create response */
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 = sizeof(struct ac_io_iccb_state);
body = (struct ac_io_iccb_state *) &resp.cmd.raw;
if (sensor) {
body->sensor_state = AC_IO_ICCB_SENSOR_CARD;
} else {
body->sensor_state = AC_IO_ICCB_SENSOR_NO_CARD;
}
if (!iccb->fault) {
memcpy(body->uid, iccb->uid, sizeof(body->uid));
}
body->card_type = 0x30 | (iccb->card_result - 1);
body->unk2 = 0;
// 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
body->unk3 = 0x03;
memset(body->unk4, 0, sizeof(body->unk4));
ac_io_emu_response_push(iccb->emu, &resp, 0);
}

View File

@@ -1,24 +0,0 @@
#ifndef AC_IO_EMU_ICCB_H
#define AC_IO_EMU_ICCB_H
#include <stdbool.h>
#include <stdint.h>
#include "acioemu/emu.h"
struct ac_io_emu_iccb {
struct ac_io_emu *emu;
uint8_t unit_no;
bool fault;
bool last_sensor;
uint8_t uid[8];
uint8_t card_result;
};
void ac_io_emu_iccb_init(
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);
#endif

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,8 @@
#include "aciotest/handler.h" #include "aciotest/handler.h"
#include "aciotest/icca.h" #include "aciotest/icca.h"
#include "aciotest/kfca.h" #include "aciotest/kfca.h"
#include "aciotest/panb.h"
#include "aciotest/rvol.h"
#include "util/log.h" #include "util/log.h"
@@ -20,24 +22,37 @@ static uint8_t bi2a_mode = 0;
* Enumerate supported ACIO nodes based on their product id. * Enumerate supported ACIO nodes based on their product id.
*/ */
static bool aciotest_assign_handler( static bool aciotest_assign_handler(
char product[4], struct aciotest_handler_node_handler *handler) uint32_t product_type, struct aciotest_handler_node_handler *handler)
{ {
if (!memcmp(product, "ICCA", 4) || !memcmp(product, "ICCB", 4) || if (product_type == AC_IO_NODE_TYPE_ICCA) {
!memcmp(product, "ICCC", 4)) {
handler->init = aciotest_icca_handler_init; handler->init = aciotest_icca_handler_init;
handler->update = aciotest_icca_handler_update; handler->update = aciotest_icca_handler_update;
return true; return true;
} }
if (!memcmp(product, "KFCA", 4)) { if (product_type == AC_IO_NODE_TYPE_KFCA) {
handler->init = aciotest_kfca_handler_init; handler->init = aciotest_kfca_handler_init;
handler->update = aciotest_kfca_handler_update; handler->update = aciotest_kfca_handler_update;
return true; return true;
} }
if (!memcmp(product, "BI2A", 4)) { if (product_type == AC_IO_NODE_TYPE_PANB) {
handler->init = aciotest_panb_handler_init;
handler->update = aciotest_panb_handler_update;
return true;
}
if (product_type == AC_IO_NODE_TYPE_RVOL) {
handler->init = aciotest_rvol_handler_init;
handler->update = aciotest_rvol_handler_update;
return true;
}
if (product_type == AC_IO_NODE_TYPE_BI2A) {
if (bi2a_mode == 0) { if (bi2a_mode == 0) {
handler->init = aciotest_bi2a_sdvx_handler_init; handler->init = aciotest_bi2a_sdvx_handler_init;
handler->update = aciotest_bi2a_sdvx_handler_update; handler->update = aciotest_bi2a_sdvx_handler_update;
@@ -70,14 +85,17 @@ int main(int argc, char **argv)
log_to_writer(log_writer_stdout, NULL); log_to_writer(log_writer_stdout, NULL);
if (!aciodrv_device_open(argv[1], atoi(argv[2]))) {
struct aciodrv_device_ctx *device = aciodrv_device_open_path(argv[1], atoi(argv[2]));
if (!device) {
printf("Opening acio device failed\n"); printf("Opening acio device failed\n");
return -1; return -1;
} }
printf("Opening acio device successful\n"); printf("Opening acio device successful\n");
uint8_t node_count = aciodrv_device_get_node_count(); uint8_t node_count = aciodrv_device_get_node_count(device);
printf("Enumerated %d nodes\n", node_count); printf("Enumerated %d nodes\n", node_count);
struct aciotest_handler_node_handler handler[aciotest_handler_max]; struct aciotest_handler_node_handler handler[aciotest_handler_max];
@@ -88,29 +106,29 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < node_count; i++) { for (uint8_t i = 0; i < node_count; i++) {
char product[4]; char product[4];
aciodrv_device_get_node_product_ident(i, product); uint32_t product_type = aciodrv_device_get_node_product_type(device, i);
aciodrv_device_get_node_product_ident(device, i, product);
printf( printf(
"> %d: %c%c%c%c\n", "> %d: %c%c%c%c (%08x)\n",
i + 1, i + 1,
product[0], product[0],
product[1], product[1],
product[2], product[2],
product[3]); product[3],
product_type);
if (!aciotest_assign_handler(product, &handler[i])) { if (!aciotest_assign_handler(product_type, &handler[i])) {
printf( printf(
"ERROR: Unsupported acio node product %c%c%c%c on node %d\n", "ERROR: Unsupported acio node product %08x on node %d\n",
product[0], product_type,
product[1],
product[2],
product[3],
i); i);
} }
} }
for (uint8_t i = 0; i < aciotest_handler_max; i++) { for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].init != NULL) { if (handler[i].init != NULL) {
if (!handler[i].init(i, &handler[i].ctx)) { if (!handler[i].init(device, i, &handler[i].ctx)) {
printf("ERROR: Initializing node %d failed\n", i); printf("ERROR: Initializing node %d failed\n", i);
handler[i].update = NULL; handler[i].update = NULL;
} }
@@ -129,7 +147,7 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < aciotest_handler_max; i++) { for (uint8_t i = 0; i < aciotest_handler_max; i++) {
if (handler[i].update != NULL) { if (handler[i].update != NULL) {
if (!handler[i].update(i, handler[i].ctx)) { if (!handler[i].update(device, i, handler[i].ctx)) {
printf("ERROR: Updating node %d, removed from loop\n", i); printf("ERROR: Updating node %d, removed from loop\n", i);
handler[i].update = NULL; handler[i].update = NULL;
Sleep(5000); Sleep(5000);

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

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

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

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

73
src/main/aciotest/rvol.c Normal file
View File

@@ -0,0 +1,73 @@
#include "aciotest/rvol.h"
#include "acio/acio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aciodrv/rvol.h"
static struct ac_io_rvol_poll_out pout;
bool aciotest_rvol_handler_init(
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
{
memset(&pout, 0, sizeof(pout));
return aciodrv_rvol_init(device, node_id);
}
bool aciotest_rvol_handler_update(
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
{
struct ac_io_rvol_poll_in pin;
if (!aciodrv_rvol_poll(device, node_id, &pout, &pin)) {
return false;
}
uint8_t selected_light = pin.spinners[0] / 43;
printf(
">>> RVOL %d\n"
"Press: %3d %3d %3d\n"
" %3d %3d\n"
"\n"
"Spin: %3d %3d %3d\n"
" %3d %3d\n"
"\n"
"Pedal: %3d\n"
"\n"
"Editing light #%d R: %d G: %d B: %d\n"
"(Change light with Spinner 1, values with 3-5)\n",
node_id,
pin.buttons_2.spinner_1,
pin.buttons_3.spinner_3,
pin.buttons_1.spinner_5,
pin.buttons_2.spinner_2,
pin.buttons_1.spinner_4,
pin.spinners[0],
pin.spinners[2],
pin.spinners[4],
pin.spinners[1],
pin.spinners[3],
!pin.buttons_1.pedal,
selected_light,
pin.spinners[2] / 2,
pin.spinners[3] / 2,
pin.spinners[4] / 2
);
memset(&pout, 0, sizeof(pout));
if (selected_light == 5) {
pout.title.r = pin.spinners[2] / 2;
pout.title.g = pin.spinners[3] / 2;
pout.title.b = pin.spinners[4] / 2;
} else {
pout.spinner[selected_light].r = pin.spinners[2] / 2;
pout.spinner[selected_light].g = pin.spinners[3] / 2;
pout.spinner[selected_light].b = pin.spinners[4] / 2;
}
return true;
}

14
src/main/aciotest/rvol.h Normal file
View File

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

View File

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

56
src/main/bio2/bi2a-ddr.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef BIO2_BI2A_DDR
#define BIO2_BI2A_DDR
#include "bio2/bio2.h"
#pragma pack(push, 1)
struct bi2a_ddr_system_panel {
uint8_t b_unk1 : 1;
uint8_t b_coin : 1;
uint8_t b_service : 1;
uint8_t b_test : 1;
uint8_t b_un2 : 4;
};
struct bi2a_ddr_player_1_panel {
uint8_t b_unk : 3;
uint8_t b_right : 1;
uint8_t b_left : 1;
uint8_t b_down : 1;
uint8_t b_up : 1;
uint8_t b_start : 1;
};
struct bi2a_ddr_player_2_panel {
uint8_t b_unk1 : 1;
uint8_t b_right : 1;
uint8_t b_left : 1;
uint8_t b_down : 1;
uint8_t b_up : 1;
uint8_t b_start : 1;
uint8_t b_unk2 : 2;
};
struct bi2a_ddr_state_in {
uint8_t unk1;
struct bi2a_ddr_system_panel system;
uint8_t unk2[7];
struct bi2a_ddr_player_1_panel player_1;
struct bi2a_ddr_player_2_panel player_2;
uint8_t unk3[5];
};
struct bi2a_ddr_state_out {
uint8_t unk1[40];
};
_Static_assert(
sizeof(struct bi2a_ddr_state_in) == 16,
"bi2a_ddr_state_in is the wrong size");
_Static_assert(
sizeof(struct bi2a_ddr_state_out) == 40,
"bi2a_ddr_state_out is the wrong size");
#pragma pack(pop)
#endif

View File

@@ -11,6 +11,11 @@ enum bio2_bi2a_cmd {
BIO2_BI2A_CMD_INIT = 0x0100, BIO2_BI2A_CMD_INIT = 0x0100,
BIO2_BI2A_CMD_WATCHDOG = 0x0120, BIO2_BI2A_CMD_WATCHDOG = 0x0120,
BIO2_BI2A_CMD_POLL = 0x0152, // For IIDX BIO2_BI2A_CMD_POLL = 0x0152, // For IIDX
// For games using libacio for BIO2 communication
BIO2_BI2A_CMD_ACIO_POLL_NOWD = 0x0112,
BIO2_BI2A_CMD_ACIO_POLL_WD = 0x0113,
BIO2_BI2A_CMD_TAPELED_INIT = 0x0140,
BIO2_BI2A_CMD_TAPELED_SEND = 0x0141,
}; };
#endif #endif

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