mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-09-15 11:55:10 -05:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac02609948 | ||
|
|
c644db03ae | ||
|
|
7d5398b6af | ||
|
|
cac09f8f87 | ||
|
|
85c9c444f1 | ||
|
|
8f2ce1f1b3 | ||
|
|
d3bf381a4f | ||
|
|
3acbc7f251 | ||
|
|
839903ab48 | ||
|
|
c929141e71 | ||
|
|
1477480836 | ||
|
|
bf4322e855 | ||
|
|
3eed0a4ab3 | ||
|
|
a9ade9d9d4 | ||
|
|
26336805d2 | ||
|
|
7d0e916b9f | ||
|
|
a03a5604ec | ||
|
|
54e7d783ef | ||
|
|
4ea1397af2 | ||
|
|
fb593df4a1 | ||
|
|
f0c33663e9 | ||
|
|
87ee37d059 | ||
|
|
5688fb7319 | ||
|
|
d529ee484f | ||
|
|
7c43fb7163 | ||
|
|
652d2ef633 | ||
|
|
78884aebad | ||
|
|
549f00bfb3 | ||
|
|
aab45f145f | ||
|
|
6171f0dc60 | ||
|
|
2f05760f4e | ||
|
|
7b5e4772ea | ||
|
|
e266aed1f9 | ||
|
|
0b0e7faef0 | ||
|
|
53866130cb | ||
|
|
dbb8c45a9f | ||
|
|
8ed7d6db71 | ||
|
|
4c746df6a8 | ||
|
|
7d485e7c7e | ||
|
|
deb6e5cf77 | ||
|
|
2a03690772 | ||
|
|
6ce4cce500 | ||
|
|
c6e59bae9b | ||
|
|
31e15ec5ea | ||
|
|
9cef7c03d0 | ||
|
|
f9b37c7a72 | ||
|
|
609c19b0ca | ||
|
|
75b27d5992 | ||
|
|
965df98093 | ||
|
|
0c06d224cc | ||
|
|
fb3d2ea312 | ||
|
|
089253a537 | ||
|
|
a4436747de | ||
|
|
43b11c8778 | ||
|
|
dd7fd860b5 | ||
|
|
18842a1dd3 | ||
|
|
18f6d9ef70 | ||
|
|
592967e191 | ||
|
|
6614cc801e | ||
|
|
8e1151ac02 | ||
|
|
4b60cb6c6c | ||
|
|
770bae4169 | ||
|
|
49d0bc638b | ||
|
|
837affc66c | ||
|
|
ec76ba075f | ||
|
|
f438f04f2a | ||
|
|
865980991e |
156
.gitlab-ci.yml
156
.gitlab-ci.yml
@@ -1,67 +1,139 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
variables:
|
||||
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:
|
||||
- docker:19.03.8-dind
|
||||
|
||||
before_script:
|
||||
- docker info
|
||||
|
||||
stages:
|
||||
- build
|
||||
- create-release-package
|
||||
- releasetag
|
||||
- upload
|
||||
- release
|
||||
|
||||
build:
|
||||
stage: build
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- tags
|
||||
before_script:
|
||||
- apk update && apk add make > /dev/null
|
||||
script:
|
||||
- make build-docker
|
||||
artifacts:
|
||||
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
|
||||
paths:
|
||||
- build
|
||||
|
||||
upload-package-registry:
|
||||
stage: upload
|
||||
image: curlimages/curl:latest
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
|
||||
create-release-package:
|
||||
stage: create-release-package
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
- tags
|
||||
dependencies:
|
||||
- build
|
||||
before_script:
|
||||
- apk update && apk add zip > /dev/null
|
||||
script:
|
||||
- mv build/docker/bemanitools.zip ./bemanitools.zip
|
||||
- rm -r build
|
||||
- find . -mindepth 1 ! -regex '^./bemanitools.zip' -delete
|
||||
- unzip bemanitools.zip
|
||||
- rm bemanitools.zip
|
||||
artifacts:
|
||||
name: "$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME"
|
||||
paths:
|
||||
- ./*
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
|
||||
releasetag:
|
||||
stage: releasetag
|
||||
dependencies: []
|
||||
before_script:
|
||||
- apk update && apk add curl > /dev/null
|
||||
script:
|
||||
- |
|
||||
curl --silent --show-error \
|
||||
--data "{\"tag_name\": \"${CI_COMMIT_TAG}\", \"name\": \"${CI_PROJECT_NAME}-${CI_COMMIT_TAG}\", \"description\": \"${CI_COMMIT_TAG_MESSAGE:-No release notes.}\"}" \
|
||||
--header "Content-Type: application/json" \
|
||||
--header "Private-Token: ${CI_PRIVATE_TOKEN}" \
|
||||
--request POST \
|
||||
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases"
|
||||
if [ "${CI_COMMIT_TAG}" ]; then
|
||||
version="${CI_COMMIT_TAG}"
|
||||
else
|
||||
version="${CI_COMMIT_SHORT_SHA}"
|
||||
fi
|
||||
|
||||
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:
|
||||
- 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}"
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
necessary -->
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- Try running the game with a default configuration as well. If that also causes issues, please point that out here in the report. This might speed up the debugging process.-->
|
||||
|
||||
<!--- Provide a detailed step by step description how to reproduce this issue -->
|
||||
1.
|
||||
2.
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,4 +1,20 @@
|
||||
# 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.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
|
||||
* IIDX: Support IO and card reader feature switches to disable emulation in iidxhook4-7
|
||||
* Jubeat: jbio implementation for magicbox hardware
|
||||
|
||||
36
Module.mk
36
Module.mk
@@ -72,12 +72,14 @@ cflags += \
|
||||
# that is still ABI-compatible with the real build its target links against.
|
||||
|
||||
avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 803 0
|
||||
avsvers_64 := 1700 1603 1601 1508
|
||||
avsvers_64 := 1700 1603 1601 1509 1508
|
||||
|
||||
imps += avs avs-ea3
|
||||
|
||||
include src/main/aciodrv/Module.mk
|
||||
include src/main/aciodrv-proc/Module.mk
|
||||
include src/main/acioemu/Module.mk
|
||||
include src/main/aciomgr/Module.mk
|
||||
include src/main/aciotest/Module.mk
|
||||
include src/main/asio/Module.mk
|
||||
include src/main/bio2drv/Module.mk
|
||||
@@ -89,6 +91,7 @@ include src/main/camhook/Module.mk
|
||||
include src/main/cconfig/Module.mk
|
||||
include src/main/config/Module.mk
|
||||
include src/main/d3d9exhook/Module.mk
|
||||
include src/main/ddrhook-util/Module.mk
|
||||
include src/main/ddrhook/Module.mk
|
||||
include src/main/ddrio-mm/Module.mk
|
||||
include src/main/ddrio-smx/Module.mk
|
||||
@@ -136,6 +139,7 @@ include src/main/inject/Module.mk
|
||||
include src/main/jbhook/Module.mk
|
||||
include src/main/jbhook1/Module.mk
|
||||
include src/main/jbio-magicbox/Module.mk
|
||||
include src/main/jbio-p4io/Module.mk
|
||||
include src/main/jbio/Module.mk
|
||||
include src/main/jbiotest/Module.mk
|
||||
include src/main/launcher/Module.mk
|
||||
@@ -143,6 +147,7 @@ include src/main/mempatch-hook/Module.mk
|
||||
include src/main/mm/Module.mk
|
||||
include src/main/p3io/Module.mk
|
||||
include src/main/p3ioemu/Module.mk
|
||||
include src/main/p4iodrv/Module.mk
|
||||
include src/main/p4ioemu/Module.mk
|
||||
include src/main/pcbidgen/Module.mk
|
||||
include src/main/sdvxhook/Module.mk
|
||||
@@ -361,7 +366,7 @@ $(zipdir)/iidx-25-to-26.zip: \
|
||||
$(V)echo ... $@
|
||||
$(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/launcher.exe \
|
||||
build/bin/indep-64/config.exe \
|
||||
@@ -371,13 +376,16 @@ $(zipdir)/iidx-27.zip: \
|
||||
build/bin/indep-64/vefxio.dll \
|
||||
dist/iidx/config.bat \
|
||||
dist/iidx/gamestart-27.bat \
|
||||
dist/iidx/gamestart-28.bat \
|
||||
dist/iidx/iidxhook-27.conf \
|
||||
dist/iidx/iidxhook-28.conf \
|
||||
dist/iidx/vefx.txt \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/iidx-hwio-x86.zip: \
|
||||
build/bin/indep-32/aciomgr.dll \
|
||||
build/bin/indep-32/eamio-icca.dll \
|
||||
build/bin/indep-32/iidxio-bio2.dll \
|
||||
build/bin/indep-32/iidxio-ezusb.dll \
|
||||
@@ -390,6 +398,7 @@ $(zipdir)/iidx-hwio-x86.zip: \
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/iidx-hwio-x64.zip: \
|
||||
build/bin/indep-64/aciomgr.dll \
|
||||
build/bin/indep-64/eamio-icca.dll \
|
||||
build/bin/indep-64/iidxio-bio2.dll \
|
||||
build/bin/indep-64/iidxio-ezusb.dll \
|
||||
@@ -441,6 +450,17 @@ $(zipdir)/jb-08.zip: \
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/jb-hwio.zip: \
|
||||
build/bin/indep-32/aciomgr.dll \
|
||||
build/bin/indep-32/eamio-icca.dll \
|
||||
build/bin/indep-32/jbio-magicbox.dll \
|
||||
build/bin/indep-32/jbio-p4io.dll \
|
||||
dist/jb/jbio-h44b.conf \
|
||||
dist/jb/eamio-icc.conf \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/sdvx-01-to-04.zip: \
|
||||
build/bin/avs2_1508-32/launcher.exe \
|
||||
build/bin/avs2_1508-32/sdvxhook.dll \
|
||||
@@ -483,6 +503,8 @@ $(zipdir)/sdvx-05-cn.zip: \
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/sdvx-hwio-x86.zip: \
|
||||
build/bin/indep-32/aciomgr.dll \
|
||||
build/bin/indep-32/eamio-icca.dll \
|
||||
build/bin/indep-32/sdvxio-kfca.dll \
|
||||
build/bin/indep-32/sdvxio-bio2.dll \
|
||||
build/bin/indep-32/vigem-sdvxio.exe \
|
||||
@@ -491,6 +513,8 @@ $(zipdir)/sdvx-hwio-x86.zip: \
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/sdvx-hwio-x64.zip: \
|
||||
build/bin/indep-64/aciomgr.dll \
|
||||
build/bin/indep-64/eamio-icca.dll \
|
||||
build/bin/indep-64/sdvxio-kfca.dll \
|
||||
build/bin/indep-64/sdvxio-bio2.dll \
|
||||
build/bin/indep-64/vigem-sdvxio.exe \
|
||||
@@ -549,10 +573,7 @@ $(zipdir)/bst.zip: \
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/doc.zip: \
|
||||
doc/iidxhook \
|
||||
doc/sdvxhook \
|
||||
doc/jbhook \
|
||||
doc/tools \
|
||||
doc/ \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -r $@ $^
|
||||
@@ -596,12 +617,13 @@ $(BUILDDIR)/bemanitools.zip: \
|
||||
$(zipdir)/iidx-20.zip \
|
||||
$(zipdir)/iidx-21-to-24.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-x64.zip \
|
||||
$(zipdir)/jb-01.zip \
|
||||
$(zipdir)/jb-05-to-07.zip \
|
||||
$(zipdir)/jb-08.zip \
|
||||
$(zipdir)/jb-hwio.zip \
|
||||
$(zipdir)/sdvx-01-to-04.zip \
|
||||
$(zipdir)/sdvx-05.zip \
|
||||
$(zipdir)/sdvx-05-cn.zip \
|
||||
|
||||
37
README.md
37
README.md
@@ -1,7 +1,7 @@
|
||||
# Bemanitools 5
|
||||
[](https://dev.s-ul.eu/djhackers/bemanitools/commits/master)
|
||||
[](https://dev.s-ul.net/djhackers/bemanitools/commits/master)
|
||||
|
||||
Version: 5.34
|
||||
Version: 5.36
|
||||
|
||||
[Release history](CHANGELOG.md)
|
||||
|
||||
@@ -55,7 +55,8 @@ 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 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 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 (experimental/buggy) (jb-01.zip) using [jbhook1](doc/jbhook1/jbhook1.md)
|
||||
* jubeat saucer (fulfill) (jb-05-to-07.zip) using jbhook
|
||||
@@ -73,7 +74,7 @@ The tl;dr version and golden rules of the sections in the document:
|
||||
Play your favorite non-bemani arcade games with any hardware, e.g. real cabinet hardware, that
|
||||
implements BT5 APIs.
|
||||
|
||||
See the dedicated [readme](docs/vigem/README.md) for details.
|
||||
See the dedicated [readme](doc/vigem/README.md) for details.
|
||||
|
||||
## Supported platforms
|
||||
Our main platforms are currently Windows XP and Windows 7 which are also the target platforms on the original hardware
|
||||
@@ -110,6 +111,34 @@ important aspects you should know before you get started with development.
|
||||
### API
|
||||
Please refer to the [API documentation](doc/api.md).
|
||||
|
||||
## Release process
|
||||
Steps for the release process:
|
||||
1. Update the corresponding section in the [changelog](CHANGELOG.md) with bullet points reflecting
|
||||
major features merged into master since the previous release
|
||||
1. Make sure you have the latest `master` state pulled to your local copy
|
||||
1. Tag the release with the next release number which also be found at the
|
||||
[top of the readme](#bemanitools-5) as it always reflects the current version beinged worked on
|
||||
on the `master` branch , e.g. 5.35: `git tag 5.35`
|
||||
1. Push the tag to upstream: `git push origin 5.35`
|
||||
1. The [build pipeline](https://dev.s-ul.net/djhackers/bemanitools/-/pipelines) should start
|
||||
automatically once the tag is pushed including the steps `build` and `upload-release`
|
||||
1. Once completed successfully, the release is uploaded
|
||||
1. Take the changelog of the published version and notify the pigs in the stall about it:
|
||||
1. New post in thread
|
||||
```
|
||||
<insert version here> released: <direct link to published version>
|
||||
|
||||
Changelog:
|
||||
<paste changelog here>
|
||||
```
|
||||
1. Update the OP title by bumping the version number in it
|
||||
1. Update the OP post by extending it accordingly (see previous entries)
|
||||
|
||||
1. Bump the version number at the [top of this readme](#bemanitools-5) and add a new empty section
|
||||
in the [changelog](CHANGELOG.md) with the new version number as title. Commit changes and push to
|
||||
`master` branch
|
||||
1. Continue developing and merging MRs until you decide its time for another release
|
||||
|
||||
## License
|
||||
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the
|
||||
[LICENSE file](LICENSE) included with the source code.
|
||||
|
||||
16
dist/iidx/gamestart-28.bat
vendored
Normal file
16
dist/iidx/gamestart-28.bat
vendored
Normal 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 %*
|
||||
8
dist/iidx/iidxhook-27.conf
vendored
8
dist/iidx/iidxhook-27.conf
vendored
@@ -34,7 +34,7 @@ gfx.framed=true
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Confine mouse coursor to window
|
||||
# Confine mouse cursor to window
|
||||
gfx.confined=false
|
||||
|
||||
# Windowed width, -1 for default size
|
||||
@@ -43,6 +43,12 @@ gfx.window_width=-1
|
||||
# Windowed height, -1 for default size
|
||||
gfx.window_height=-1
|
||||
|
||||
# Windowed X, -1 for default X position
|
||||
gfx.window_x=-1
|
||||
|
||||
# Windowed Y, -1 for default Y position
|
||||
gfx.window_y=-1
|
||||
|
||||
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
|
||||
gfx.forced_refresh_rate=-1
|
||||
|
||||
|
||||
78
dist/iidx/iidxhook-28.conf
vendored
Normal file
78
dist/iidx/iidxhook-28.conf
vendored
Normal 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
5
dist/jb/eamio-icc.conf
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# ICCA serial port
|
||||
icc.port=COM2
|
||||
|
||||
# ICCA bus baudrate (real devices expect 57600)
|
||||
icc.baud=57600
|
||||
5
dist/jb/jbio-h44b.conf
vendored
Normal file
5
dist/jb/jbio-h44b.conf
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# H44B serial port
|
||||
h44b.port=COM2
|
||||
|
||||
# H44B bus baudrate (real devices expect 57600)
|
||||
h44b.baud=57600
|
||||
8
dist/sdvx5/sdvxhook2.conf
vendored
8
dist/sdvx5/sdvxhook2.conf
vendored
@@ -19,7 +19,7 @@ gfx.framed=true
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Confine mouse coursor to window
|
||||
# Confine mouse cursor to window
|
||||
gfx.confined=false
|
||||
|
||||
# Windowed width, -1 for default size
|
||||
@@ -28,6 +28,12 @@ gfx.window_width=1080
|
||||
# Windowed height, -1 for default size
|
||||
gfx.window_height=1920
|
||||
|
||||
# Windowed X, -1 for default X position
|
||||
gfx.window_x=-1
|
||||
|
||||
# Windowed Y, -1 for default Y position
|
||||
gfx.window_y=-1
|
||||
|
||||
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
|
||||
gfx.forced_refresh_rate=-1
|
||||
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
# Bemanitools 5 documentation
|
||||
|
||||
This folder contains various types of documentation.
|
||||
|
||||
Table of contents:
|
||||
|
||||
* Key tools
|
||||
* [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`
|
||||
* [Tools](tools/README.md): Documentation for additional user and development tooling
|
||||
* [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`
|
||||
* [Tools](tools/README.md): Documentation for additional user and development tooling
|
||||
* Game hooks
|
||||
* [ddrhook](ddrhook/README.md): Documentation relevant to `ddrhook` implementations
|
||||
* [iidxhook](iidxhook/README.md): Documentation relevant to `iidxhook` implementations
|
||||
* [jbhook](jbhook/README.md): Documentation relevant to `jbhook` implementations
|
||||
* [sdvxhook](sdvxhook/README.md): Documentation relevant to `sdvxhook` implementations
|
||||
* [ddrhook](ddrhook/README.md): Documentation relevant to `ddrhook` implementations
|
||||
* [iidxhook](iidxhook/README.md): Documentation relevant to `iidxhook` implementations
|
||||
* [jbhook](jbhook/README.md): Documentation relevant to `jbhook` implementations
|
||||
* [sdvxhook](sdvxhook/README.md): Documentation relevant to `sdvxhook` implementations
|
||||
* Development
|
||||
* [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
|
||||
* [Development](development.md): Development environment, building, releasing, etc.
|
||||
* [Developer documentation](dev/README.md): Various lose documentation/notes by developers
|
||||
* [Tools](tools/README.md): Documentation for additional user and development tooling
|
||||
* Hardware
|
||||
* [Hardware](hardware/README.md): Anything related to hardware, e.g. IO boards
|
||||
* [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
|
||||
* [Development](development.md): Development environment, building, releasing, etc.
|
||||
* [Developer documentation](dev/README.md): Various lose documentation/notes by developers
|
||||
* [Tools](tools/README.md): Documentation for additional user and development tooling
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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 |
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
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
|
||||
menu. When enabled, the game seems to hang and expects you to power
|
||||
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"
|
||||
This can be caused by:
|
||||
* Invalid PCBID
|
||||
* Invalid PCBID/EAMID: Ensure both are [set to the same ID](#eamuse-network-setup)
|
||||
* Firewall blocking connections
|
||||
* Invalid eamuse url or port specified
|
||||
* Game is not run using the Administrator account
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
The following games are compatible with this version of iidxhook:
|
||||
* Heroic Verse
|
||||
* BISTROVER
|
||||
|
||||
The games must be bootstrapped using [launcher](../launcher.md).
|
||||
|
||||
|
||||
18
doc/jbhook/jbio-p4io.md
Normal file
18
doc/jbhook/jbio-p4io.md
Normal 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
|
||||
@@ -58,5 +58,5 @@ Turntables are either in absolute or relative mode depending on how it's defined
|
||||
* Make sure that you follow the instructions exactly from the release page
|
||||
([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
|
||||
* If you get an error while trying to install KB3033929, re-enable windows update
|
||||
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be
|
||||
done once)
|
||||
* If you can't find some of these files, see bemanitools-supplements
|
||||
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once)
|
||||
|
||||
@@ -19,6 +19,8 @@ Thus, it allows you to use a real cab with *any* game that supports xinput.
|
||||
* VOL LR are mapped to L thumbstick X/Y (either in absolute or relative mode depending on the config)
|
||||
|
||||
# Additional Notes For Cabinets (Running on embedded Windows 7):
|
||||
* Make sure that you follow the instructions exactly from the release page ([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
|
||||
* Make sure that you follow the instructions exactly from the release page
|
||||
([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7))
|
||||
* If you get an error while trying to install KB3033929, re-enable windows update
|
||||
* If you can't find some of these files, see bemanitools-supplements
|
||||
* Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once)
|
||||
|
||||
28
scripts/ci/create-release-message.sh
Executable file
28
scripts/ci/create-release-message.sh
Executable 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
|
||||
echo "Could not find version in changelog: $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
7
src/imports/import_64_1509_avs-ea3.def
Normal file
7
src/imports/import_64_1509_avs-ea3.def
Normal 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
|
||||
32
src/imports/import_64_1509_avs.def
Normal file
32
src/imports/import_64_1509_avs.def
Normal 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
|
||||
@@ -5,9 +5,13 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "acio/h44b.h"
|
||||
#include "acio/hdxs.h"
|
||||
#include "acio/icca.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_ESCAPE 0xFF
|
||||
@@ -35,8 +39,11 @@ enum ac_io_node_type {
|
||||
AC_IO_NODE_TYPE_LED_STRIP = 0x04020000,
|
||||
AC_IO_NODE_TYPE_LED_SPIKE = 0x05010000,
|
||||
AC_IO_NODE_TYPE_KFCA = 0x09060000,
|
||||
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
|
||||
AC_IO_NODE_TYPE_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)
|
||||
@@ -69,13 +76,24 @@ struct ac_io_message {
|
||||
uint8_t param;
|
||||
struct ac_io_version version;
|
||||
|
||||
struct ac_io_h44b_output h44b_output;
|
||||
|
||||
struct ac_io_icca_misc icca_misc;
|
||||
struct ac_io_icca_state icca_state;
|
||||
|
||||
struct ac_io_kfca_poll_in kfca_poll_in;
|
||||
struct ac_io_kfca_poll_out kfca_poll_out;
|
||||
|
||||
struct ac_io_panb_poll_in panb_poll_in;
|
||||
struct ac_io_panb_poll_out panb_poll_out;
|
||||
|
||||
struct ac_io_hdxs_output hdxs_output;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ struct ac_io_h44b_output {
|
||||
uint8_t right_rgb[3];
|
||||
uint8_t title_rgb[3];
|
||||
uint8_t woofer_rgb[3];
|
||||
};
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@ enum ac_io_icca_cmd {
|
||||
AC_IO_ICCA_CMD_ENGAGE = 0x0131,
|
||||
AC_IO_ICCA_CMD_POLL = 0x0134,
|
||||
AC_IO_ICCA_CMD_SET_SLOT_STATE = 0x0135,
|
||||
AC_IO_ICCA_CMD_BEGIN_KEYPAD = 0x013A,
|
||||
AC_IO_ICCA_CMD_DEVICE_CONTROL = 0x013A,
|
||||
AC_IO_ICCA_CMD_POLL_FELICA = 0x0161,
|
||||
AC_IO_ICCA_CMD_KEY_EXCHANGE = 0x0160,
|
||||
AC_IO_ICCA_CMD_POLL_ENCRYPTED = 0x0164,
|
||||
@@ -29,6 +29,14 @@ enum ac_io_icca_sensor_state {
|
||||
AC_IO_ICCA_SENSOR_MASK_BACK_ON = (1 << 5)
|
||||
};
|
||||
|
||||
enum ac_io_icca_status_code {
|
||||
AC_IO_ICCA_STATUS_FAULT = 0x00,
|
||||
AC_IO_ICCA_STATUS_IDLE = 0x01,
|
||||
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
|
||||
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04,
|
||||
AC_IO_ICCA_STATUS_BUSY_NEW = 0x01,
|
||||
};
|
||||
|
||||
enum ac_io_icca_keypad_mask {
|
||||
AC_IO_ICCA_KEYPAD_MASK_EMPTY = (1 << 0),
|
||||
AC_IO_ICCA_KEYPAD_MASK_3 = (1 << 1),
|
||||
|
||||
49
src/main/acio/mdxf.h
Normal file
49
src/main/acio/mdxf.h
Normal 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
42
src/main/acio/panb.h
Normal 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
74
src/main/acio/rvol.h
Normal 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
|
||||
7
src/main/aciodrv-proc/Module.mk
Normal file
7
src/main/aciodrv-proc/Module.mk
Normal file
@@ -0,0 +1,7 @@
|
||||
libs += aciodrv-proc
|
||||
|
||||
libs_aciodrv-proc := \
|
||||
|
||||
src_aciodrv-proc := \
|
||||
panb.c \
|
||||
|
||||
90
src/main/aciodrv-proc/panb.c
Normal file
90
src/main/aciodrv-proc/panb.c
Normal 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);
|
||||
}
|
||||
32
src/main/aciodrv-proc/panb.h
Normal file
32
src/main/aciodrv-proc/panb.h
Normal 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
|
||||
@@ -1,10 +1,13 @@
|
||||
libs += aciodrv
|
||||
|
||||
libs_aciodrv := \
|
||||
|
||||
|
||||
src_aciodrv := \
|
||||
device.c \
|
||||
h44b.c \
|
||||
icca.c \
|
||||
kfca.c \
|
||||
panb.c \
|
||||
rvol.c \
|
||||
port.c \
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#define LOG_MODULE "aciodrv-device"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aciodrv/device.h"
|
||||
@@ -8,34 +9,64 @@
|
||||
|
||||
#include "util/hex.h"
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
/* Enable to dump all data to the logger */
|
||||
//#define AC_IO_MSG_LOG
|
||||
|
||||
static uint8_t aciodrv_device_msg_counter = 1;
|
||||
static uint8_t aciodrv_device_node_count;
|
||||
static char aviodrv_device_node_products[16][4];
|
||||
#define ACIO_MAX_NODES_PER_PORT 16
|
||||
|
||||
static bool aciodrv_device_init(void)
|
||||
struct aciodrv_device_ctx {
|
||||
HANDLE fd;
|
||||
struct aciodrv_device_node_version node_versions[ACIO_MAX_NODES_PER_PORT];
|
||||
uint8_t msg_counter;
|
||||
uint8_t node_count;
|
||||
};
|
||||
|
||||
bool aciodrv_device_reset(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
uint8_t reset_seq[525] = {0};
|
||||
|
||||
/* init/reset the device by sending 525 NULL bytes */
|
||||
log_info("Resetting device");
|
||||
if (aciodrv_port_write(device->fd, reset_seq, sizeof(reset_seq)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* signal to device for a reset */
|
||||
EscapeCommFunction(device->fd, SETBREAK);
|
||||
Sleep(1450);
|
||||
EscapeCommFunction(device->fd, CLRBREAK);
|
||||
Sleep(1200);
|
||||
|
||||
/* ignore the next 100 reads (of whatever length) */
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
aciodrv_port_read(device->fd, reset_seq, sizeof(reset_seq));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool aciodrv_device_sof_flush(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
uint8_t init_seq[1] = {AC_IO_SOF};
|
||||
uint8_t read_buff[1] = {0x00};
|
||||
uint8_t read_buff[1] = {0};
|
||||
|
||||
/* init/reset the device by sending 0xAA until 0xAA is returned */
|
||||
/* wait for reset to finish */
|
||||
int read = 0;
|
||||
do {
|
||||
if (aciodrv_port_write(init_seq, sizeof(init_seq)) <= 0) {
|
||||
if (aciodrv_port_write(device->fd, init_seq, sizeof(init_seq)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
read = aciodrv_port_read(read_buff, sizeof(read_buff));
|
||||
read = aciodrv_port_read(device->fd, read_buff, sizeof(read_buff));
|
||||
} while ((read <= 0) || (read_buff[0] != init_seq[0]));
|
||||
|
||||
if (read > 0) {
|
||||
log_warning("Obtained SOF, clearing out buffer now");
|
||||
log_info("Obtained SOF, clearing out buffer now");
|
||||
/* empty buffer by reading all data */
|
||||
while (read > 0) {
|
||||
read = aciodrv_port_read(init_seq, sizeof(init_seq));
|
||||
read = aciodrv_port_read(device->fd, init_seq, sizeof(init_seq));
|
||||
}
|
||||
log_warning("Cleared buffer, init done");
|
||||
|
||||
@@ -46,30 +77,39 @@ static bool aciodrv_device_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
static bool aciodrv_device_init(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
if (!aciodrv_device_reset(device)) {
|
||||
log_warning("Reset failed");
|
||||
return false;
|
||||
}
|
||||
return aciodrv_device_sof_flush(device);
|
||||
}
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
static void
|
||||
aciodrv_device_log_buffer(const char *msg, const uint8_t *buffer, int length)
|
||||
aciodrv_device_log_buffer(struct aciodrv_device_ctx *device, const char *msg, const uint8_t *buffer, int length)
|
||||
{
|
||||
char str[4096];
|
||||
|
||||
hex_encode_uc((const void *) buffer, length, str, sizeof(str));
|
||||
log_misc("%s, length %d: %s", msg, length, str);
|
||||
log_misc("[%p] %s, length %d: %s", device->fd, msg, length, str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool aciodrv_device_send(const uint8_t *buffer, int length)
|
||||
static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t *buffer, int length)
|
||||
{
|
||||
uint8_t send_buf[512];
|
||||
int send_buf_pos = 0;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
if (length > sizeof(send_buf)) {
|
||||
log_warning("Send buffer overflow");
|
||||
log_warning("[%p] Send buffer overflow", device->fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
aciodrv_device_log_buffer("Send (1)", buffer, length);
|
||||
aciodrv_device_log_buffer(device, "Send (1)", buffer, length);
|
||||
#endif
|
||||
|
||||
send_buf[send_buf_pos++] = AC_IO_SOF;
|
||||
@@ -95,18 +135,18 @@ static bool aciodrv_device_send(const uint8_t *buffer, int length)
|
||||
}
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
aciodrv_device_log_buffer("Send (2)", send_buf, send_buf_pos);
|
||||
aciodrv_device_log_buffer(device, "Send (2)", send_buf, send_buf_pos);
|
||||
#endif
|
||||
|
||||
if (aciodrv_port_write(send_buf, send_buf_pos) != send_buf_pos) {
|
||||
log_warning("Sending data with length %d failed", send_buf_pos);
|
||||
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) != send_buf_pos) {
|
||||
log_warning("[%p] Sending data with length %d failed", device->fd, send_buf_pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *buffer, int max_resp_size)
|
||||
{
|
||||
uint8_t recv_buf[512];
|
||||
int recv_size = 0;
|
||||
@@ -118,16 +158,14 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
of 0xAAs before we get a valid message. */
|
||||
recv_buf[0] = AC_IO_SOF;
|
||||
do {
|
||||
read = aciodrv_port_read(recv_buf, 1);
|
||||
read = aciodrv_port_read(device->fd, recv_buf, 1);
|
||||
} while (recv_buf[0] == AC_IO_SOF);
|
||||
|
||||
if (read > 0) {
|
||||
size += 1;
|
||||
|
||||
if (read > 0) {
|
||||
/* recv_buf[0] is already the first byte of the message.
|
||||
now read until nothing's left */
|
||||
recv_size++;
|
||||
size--;
|
||||
|
||||
/* important: we have to know how much data we expect
|
||||
and have to read until we reach the requested amount.
|
||||
@@ -135,9 +173,10 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
need to handle escaping (which relies on an up to
|
||||
date recv_buf[recv_size]) we loop until we get a
|
||||
non-zero read. */
|
||||
while (size > 0) {
|
||||
size_t expected_size = offsetof(struct ac_io_message, cmd.nbytes) + 1;
|
||||
while (recv_size < expected_size) {
|
||||
do {
|
||||
read = aciodrv_port_read(recv_buf + recv_size, 1);
|
||||
read = aciodrv_port_read(device->fd, recv_buf + recv_size, 1);
|
||||
} while (read == 0);
|
||||
|
||||
if (read < 0) {
|
||||
@@ -150,7 +189,8 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
/* next byte is our real data
|
||||
overwrite escape byte */
|
||||
do {
|
||||
read = aciodrv_port_read(recv_buf + recv_size, 1);
|
||||
read = aciodrv_port_read(
|
||||
device->fd, recv_buf + recv_size, 1);
|
||||
} while (read == 0);
|
||||
|
||||
if (read < 0) {
|
||||
@@ -161,15 +201,23 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
}
|
||||
|
||||
recv_size += read;
|
||||
size -= read;
|
||||
|
||||
if (recv_size > offsetof(struct ac_io_message, cmd.nbytes)) {
|
||||
// header + data + checksum
|
||||
expected_size = offsetof(struct ac_io_message, cmd.raw) + ((struct ac_io_message*)recv_buf)->cmd.nbytes + 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
aciodrv_device_log_buffer("Recv (1)", recv_buf, recv_size);
|
||||
log_warning("Expected %d got %d", recv_buf[4], recv_size - 6);
|
||||
aciodrv_device_log_buffer(device, "Recv (1)", recv_buf, recv_size);
|
||||
log_warning("Expected %d got %d", max_resp_size - 6, recv_buf[4]);
|
||||
#endif
|
||||
|
||||
/* recv_size - 1: omit checksum for checksum calc */
|
||||
if ((recv_size - 1) > max_resp_size) {
|
||||
log_warning("[%p] Expected %d got %d", device->fd, max_resp_size - 6, recv_buf[4]);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < recv_size - 1; i++) {
|
||||
checksum += recv_buf[i];
|
||||
buffer[i] = recv_buf[i];
|
||||
@@ -178,12 +226,13 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
result_size = recv_size - 1;
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
aciodrv_device_log_buffer("Recv (2)", buffer, result_size);
|
||||
aciodrv_device_log_buffer(device, "Recv (2)", buffer, result_size);
|
||||
#endif
|
||||
|
||||
if (checksum != recv_buf[recv_size - 1]) {
|
||||
log_warning(
|
||||
"Invalid message checksum: %02X != %02X",
|
||||
"[%p] Invalid message checksum: %02X != %02X",
|
||||
device->fd,
|
||||
checksum,
|
||||
recv_buf[recv_size - 1]);
|
||||
return -1;
|
||||
@@ -195,7 +244,7 @@ static int aciodrv_device_receive(uint8_t *buffer, int size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint8_t aciodrv_device_enum_nodes(void)
|
||||
static uint8_t aciodrv_device_enum_nodes(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
@@ -205,7 +254,9 @@ static uint8_t aciodrv_device_enum_nodes(void)
|
||||
msg.cmd.count = 0;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Enumerating nodes failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -215,7 +266,7 @@ static uint8_t aciodrv_device_enum_nodes(void)
|
||||
return msg.cmd.count;
|
||||
}
|
||||
|
||||
static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
|
||||
static bool aciodrv_device_get_version(struct aciodrv_device_ctx *device, uint8_t node_id, struct aciodrv_device_node_version *version)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
@@ -224,6 +275,7 @@ static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
|
||||
msg.cmd.nbytes = 0;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) +
|
||||
sizeof(struct ac_io_version))) {
|
||||
@@ -247,12 +299,16 @@ static bool aciodrv_device_get_version(uint8_t node_id, char product[4])
|
||||
msg.cmd.version.date,
|
||||
msg.cmd.version.time);
|
||||
|
||||
memcpy(product, msg.cmd.version.product_code, 4);
|
||||
memcpy(version->product, msg.cmd.version.product_code, ACIO_NODE_PRODUCT_CODE_LEN);
|
||||
version->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;
|
||||
}
|
||||
|
||||
static bool aciodrv_device_start_node(uint8_t node_id)
|
||||
static bool aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
@@ -261,7 +317,9 @@ static bool aciodrv_device_start_node(uint8_t node_id)
|
||||
msg.cmd.nbytes = 0;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Starting node %d failed", node_id);
|
||||
return false;
|
||||
}
|
||||
@@ -270,80 +328,135 @@ static bool aciodrv_device_start_node(uint8_t node_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_device_open(const char *port, int baud)
|
||||
// deprecated name
|
||||
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
|
||||
{
|
||||
if (!aciodrv_port_open(port, baud)) {
|
||||
return aciodrv_device_open_path(port_path, baud);
|
||||
}
|
||||
|
||||
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud)
|
||||
{
|
||||
HANDLE port = aciodrv_port_open(port_path, baud);
|
||||
|
||||
if (!port) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct aciodrv_device_ctx *device = xmalloc(sizeof(struct aciodrv_device_ctx));
|
||||
|
||||
memset(device, 0, sizeof(struct aciodrv_device_ctx));
|
||||
device->fd = port;
|
||||
device->msg_counter = 1;
|
||||
|
||||
if (!aciodrv_device_init(device)) {
|
||||
aciodrv_device_close(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->node_count = aciodrv_device_enum_nodes(device);
|
||||
|
||||
if (device->node_count == 0) {
|
||||
aciodrv_device_close(device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aciodrv_device_init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aciodrv_device_node_count = aciodrv_device_enum_nodes();
|
||||
if (aciodrv_device_node_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < aciodrv_device_node_count; i++) {
|
||||
for (uint8_t i = 0; i < device->node_count; i++) {
|
||||
if (!aciodrv_device_get_version(
|
||||
i + 1, aviodrv_device_node_products[i])) {
|
||||
return false;
|
||||
device, i + 1, &device->node_versions[i])) {
|
||||
aciodrv_device_close(device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < aciodrv_device_node_count; i++) {
|
||||
if (!aciodrv_device_start_node(i + 1)) {
|
||||
return false;
|
||||
for (uint8_t i = 0; i < device->node_count; i++) {
|
||||
if (!aciodrv_device_start_node(device, i + 1)) {
|
||||
aciodrv_device_close(device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
log_info("Opening ACIO device on [%p]", device->fd);
|
||||
return device;
|
||||
}
|
||||
|
||||
uint8_t aciodrv_device_get_node_count(void)
|
||||
uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
return aciodrv_device_node_count;
|
||||
return device->node_count;
|
||||
}
|
||||
|
||||
bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4])
|
||||
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN])
|
||||
{
|
||||
if (aciodrv_device_node_count == 0 || node_id > aciodrv_device_node_count) {
|
||||
if (device->node_count == 0 || node_id > device->node_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(product, aviodrv_device_node_products[node_id], 4);
|
||||
memcpy(product, device->node_versions[node_id].product, ACIO_NODE_PRODUCT_CODE_LEN);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
|
||||
uint32_t aciodrv_device_get_node_product_type(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
msg->cmd.seq_no = aciodrv_device_msg_counter++;
|
||||
if (device->node_count == 0 || node_id > device->node_count) {
|
||||
return 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;
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
log_info(
|
||||
"Beginning send on %d: %04x (%d b)",
|
||||
"[%p] Beginning send on %d: %04x (%d b)",
|
||||
device->fd,
|
||||
msg->addr,
|
||||
msg->cmd.code,
|
||||
send_size);
|
||||
#endif
|
||||
if (aciodrv_device_send((uint8_t *) msg, send_size) <= 0) {
|
||||
if (aciodrv_device_send(device, (uint8_t *) msg, send_size) <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
|
||||
{
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
log_info("[%p] Beginning recv: (%d b)", device->fd, max_resp_size);
|
||||
#endif
|
||||
if (aciodrv_device_receive(device, (uint8_t *) msg, max_resp_size) <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
|
||||
{
|
||||
if (!aciodrv_send(device, msg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t req_code = msg->cmd.code;
|
||||
|
||||
#ifdef AC_IO_MSG_LOG
|
||||
log_info("Beginning recv: (%d b)", resp_size);
|
||||
#endif
|
||||
if (aciodrv_device_receive((uint8_t *) msg, resp_size) <= 0) {
|
||||
if (!aciodrv_recv(device, msg, max_resp_size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (req_code != msg->cmd.code) {
|
||||
log_warning(
|
||||
"Received invalid response %04X for request %04X",
|
||||
"[%p] Received invalid response %04X for request %04X",
|
||||
device->fd,
|
||||
msg->cmd.code,
|
||||
req_code);
|
||||
return false;
|
||||
@@ -352,7 +465,13 @@ bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
void aciodrv_device_close(void)
|
||||
void aciodrv_device_close(struct aciodrv_device_ctx *device)
|
||||
{
|
||||
aciodrv_port_close();
|
||||
log_assert(device);
|
||||
|
||||
log_info("Closing ACIO on [%p]", device->fd);
|
||||
|
||||
aciodrv_port_close(device->fd);
|
||||
|
||||
free(device);
|
||||
}
|
||||
|
||||
@@ -5,48 +5,119 @@
|
||||
|
||||
#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.
|
||||
*
|
||||
* @param port Port the device is connected to (e.g. "COM1")
|
||||
* @param baud Baud rate for communication (e.g. 57600 for ICCA)
|
||||
* @return True if opening the port and resetting the device was successful,
|
||||
* false on error.
|
||||
* @return opened device context, NULL on error
|
||||
*/
|
||||
bool aciodrv_device_open(const char *port, int baud);
|
||||
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((deprecated("Use aciomgr instead if device is shareable, else aciodrv_device_open_path")))
|
||||
#endif
|
||||
;
|
||||
|
||||
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud);
|
||||
|
||||
/**
|
||||
* Get the node count on the opened device.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @return Total num of nodes enumerated on the ACIO device.
|
||||
*/
|
||||
uint8_t aciodrv_device_get_node_count(void);
|
||||
uint8_t aciodrv_device_get_node_count(struct aciodrv_device_ctx *device);
|
||||
|
||||
/**
|
||||
* Get the product identifier of an enumerated node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node. Needs to be in range of the total node count.
|
||||
* @param product Buffer to return the product id to.
|
||||
* @return True on success, false on error. If True the variable product
|
||||
* contains the identifier of the queried node.
|
||||
*/
|
||||
bool aciodrv_device_get_node_product_ident(uint8_t node_id, char product[4]);
|
||||
bool aciodrv_device_get_node_product_ident(struct aciodrv_device_ctx *device, uint8_t node_id, char product[ACIO_NODE_PRODUCT_CODE_LEN]);
|
||||
|
||||
/**
|
||||
* Get the product 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.
|
||||
* Use this to implement the protocol for each type of device that can be
|
||||
* part of the bus.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param msg Msg to send to the bus. Make sure that the buffer backing
|
||||
* this message is big enough to receive the response as well.
|
||||
* @param resp_size Size of the expecting response.
|
||||
* @return True on success, false on error.
|
||||
*/
|
||||
bool aciodrv_send_and_recv(struct ac_io_message *msg, int resp_size);
|
||||
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
|
||||
|
||||
/**
|
||||
* Send a message to the ACIO bus.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param msg Msg to send to the bus.
|
||||
* @return True on success, false on error.
|
||||
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for commands which don't trigger a reply.
|
||||
*/
|
||||
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg);
|
||||
|
||||
/**
|
||||
* Read a message from the ACIO bus.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param msg Msg to send to the bus. Make sure that the buffer
|
||||
* is big enough to receive the response.
|
||||
* @return True on success, false on error.
|
||||
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for unsollicited incoming messages.
|
||||
*/
|
||||
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
|
||||
|
||||
/**
|
||||
* Reset an opened device.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @return Total num of nodes enumerated on the ACIO device.
|
||||
*/
|
||||
bool aciodrv_device_reset(struct aciodrv_device_ctx *device);
|
||||
|
||||
/**
|
||||
* Close the previously opened ACIO device.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
*/
|
||||
void aciodrv_device_close(void);
|
||||
void aciodrv_device_close(struct aciodrv_device_ctx *device);
|
||||
|
||||
#endif
|
||||
45
src/main/aciodrv/h44b.c
Normal file
45
src/main/aciodrv/h44b.c
Normal 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
32
src/main/aciodrv/h44b.h
Normal 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
|
||||
@@ -3,20 +3,27 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "aciodrv/device.h"
|
||||
#include "aciodrv/icca.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static bool aciodrv_icca_queue_loop_start(uint8_t node_id)
|
||||
static bool aciodrv_icca_queue_loop_start(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_QUEUE_LOOP_START);
|
||||
msg.cmd.nbytes = 1;
|
||||
msg.cmd.status = 0;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Starting queue loop failed");
|
||||
return false;
|
||||
}
|
||||
@@ -27,9 +34,11 @@ static bool aciodrv_icca_queue_loop_start(uint8_t node_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_icca_init(uint8_t node_id)
|
||||
bool aciodrv_icca_init(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
if (!aciodrv_icca_queue_loop_start(node_id + 1)) {
|
||||
log_assert(device);
|
||||
|
||||
if (!aciodrv_icca_queue_loop_start(device, node_id + 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,10 +46,15 @@ bool aciodrv_icca_init(uint8_t node_id)
|
||||
}
|
||||
|
||||
bool aciodrv_icca_set_state(
|
||||
uint8_t node_id, int slot_state, struct ac_io_icca_state *state)
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
int slot_state,
|
||||
struct ac_io_icca_state *state)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_SET_SLOT_STATE);
|
||||
msg.cmd.nbytes = 2;
|
||||
@@ -49,7 +63,9 @@ bool aciodrv_icca_set_state(
|
||||
msg.cmd.raw[1] = slot_state;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.raw[0])) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.raw[0])) {
|
||||
log_warning("Setting state of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
@@ -61,10 +77,15 @@ bool aciodrv_icca_set_state(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
bool aciodrv_icca_get_state(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
struct ac_io_icca_state *state)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_POLL);
|
||||
msg.cmd.nbytes = 1;
|
||||
@@ -72,7 +93,9 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
msg.cmd.count = sizeof(struct ac_io_icca_state);
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
|
||||
log_warning("Getting state of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
@@ -84,10 +107,15 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
bool aciodrv_icca_read_card(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
struct ac_io_icca_state *state)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_ENGAGE);
|
||||
msg.cmd.nbytes = 1;
|
||||
@@ -95,7 +123,9 @@ bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
msg.cmd.count = sizeof(struct ac_io_icca_state);
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
|
||||
log_warning("Reading card of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
@@ -105,4 +135,53 @@ bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool aciodrv_icca_is_slotted(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
const struct aciodrv_device_node_version *version;
|
||||
version = aciodrv_device_get_node_product_version(device, node_id);
|
||||
|
||||
// current heuristic is to check if version >= 1.5
|
||||
if (version) {
|
||||
if (version->major == 1) {
|
||||
if (version->minor >= 5) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_icca_poll_felica(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_ICCA_CMD_POLL_FELICA);
|
||||
msg.cmd.nbytes = 4;
|
||||
/* buffer size of data we expect */
|
||||
msg.cmd.count = 1;
|
||||
|
||||
// additional data, not sure
|
||||
msg.cmd.raw[1] = 0x03;
|
||||
msg.cmd.raw[2] = 0xFF;
|
||||
msg.cmd.raw[3] = 0xFF;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + msg.cmd.count)) {
|
||||
log_warning("Reading card of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,17 +6,19 @@
|
||||
/**
|
||||
* Initialize an ICCA node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to initialize (0 based).
|
||||
* @return True if successful, false on error.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_init(uint8_t node_id);
|
||||
bool aciodrv_icca_init(struct aciodrv_device_ctx *device, uint8_t node_id);
|
||||
|
||||
/**
|
||||
* Set the state of on ICCA node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to set the state for (0 based).
|
||||
* @param slot_state State of the slot (refer to corresponding enum).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
@@ -27,11 +29,15 @@ bool aciodrv_icca_init(uint8_t node_id);
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_set_state(
|
||||
uint8_t node_id, int slot_state, struct ac_io_icca_state *state);
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
int slot_state,
|
||||
struct ac_io_icca_state *state);
|
||||
|
||||
/**
|
||||
* Get the current state of an ICCA node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
* (optional, NULL for none).
|
||||
@@ -40,7 +46,10 @@ bool aciodrv_icca_set_state(
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
|
||||
bool aciodrv_icca_get_state(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
struct ac_io_icca_state *state);
|
||||
|
||||
/**
|
||||
* Trigger a card read action on the ICCA reader. Make sure to call this
|
||||
@@ -48,6 +57,7 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
|
||||
* to get the most recent card data. Make sure to re-get the state after
|
||||
* a read call. The state returned here might not be up to date for some reason.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
* (optional, NULL for none).
|
||||
@@ -56,6 +66,46 @@ bool aciodrv_icca_get_state(uint8_t node_id, struct ac_io_icca_state *state);
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_read_card(uint8_t node_id, struct ac_io_icca_state *state);
|
||||
bool aciodrv_icca_read_card(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
struct ac_io_icca_state *state);
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Uses some heruistics based on the product ident to determine if the detected
|
||||
* device is a slotted (true) or wavepass reader (false).
|
||||
*
|
||||
* This function will also return false if the provided node_id is invalid.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @return True on slotted, false on wavepass.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_is_slotted(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id);
|
||||
|
||||
/**
|
||||
* Polls the felica chip on wavepass readers. This will cause the state of the
|
||||
* reader to be AC_IO_ICCA_STATUS_BUSY_NEW for a few polls, before returning
|
||||
* either: AC_IO_ICCA_STATUS_IDLE_NEW or AC_IO_ICCA_STATUS_GOT_UID.
|
||||
*
|
||||
* The user should take care to call this every so often to actually get new
|
||||
* felica UIDs, instead of just old NFC idents. The game seems to do it every
|
||||
* 5 or so polls after the last AC_IO_ICCA_STATUS_BUSY_NEW poll.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @return True on success, false on error.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_icca_poll_felica(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,37 +7,35 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static bool aciodrv_kfca_watchdog_start(uint8_t node_id)
|
||||
static bool aciodrv_kfca_watchdog_start(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
// exit early and don't actually call watchdog
|
||||
// the watchdog call actually returns different sized packets depending on
|
||||
// the state this results in an issue during packet processing (see: #68)
|
||||
return true;
|
||||
|
||||
/*
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
|
||||
msg.cmd.nbytes = 2;
|
||||
msg.cmd.nbytes = 2;
|
||||
|
||||
// uint16_t: 6000
|
||||
msg.cmd.raw[0] = 23;
|
||||
msg.cmd.raw[1] = 112;
|
||||
|
||||
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) +
|
||||
2)) { log_warning("Starting watchdog failed"); return false;
|
||||
if (!aciodrv_send_and_recv(
|
||||
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2)) {
|
||||
log_warning("Starting watchdog failed"); return false;
|
||||
}
|
||||
|
||||
log_warning("Started watchdog of node %d, status: %d",
|
||||
node_id, msg.cmd.status);
|
||||
log_warning("Started watchdog of node %d, sz: %d, status: %d",
|
||||
node_id, msg.cmd.nbytes, msg.cmd.status);
|
||||
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
bool aciodrv_kfca_amp(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
uint8_t primary,
|
||||
uint8_t headphone,
|
||||
@@ -46,6 +44,8 @@ bool aciodrv_kfca_amp(
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
|
||||
msg.cmd.nbytes = 4;
|
||||
@@ -56,7 +56,9 @@ bool aciodrv_kfca_amp(
|
||||
msg.cmd.raw[3] = subwoofer;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Setting AMP failed");
|
||||
return false;
|
||||
}
|
||||
@@ -66,13 +68,17 @@ bool aciodrv_kfca_amp(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aciodrv_kfca_init(uint8_t node_id)
|
||||
bool aciodrv_kfca_init(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
if (!aciodrv_kfca_watchdog_start(node_id)) {
|
||||
log_assert(device);
|
||||
|
||||
if (!aciodrv_kfca_watchdog_start(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aciodrv_kfca_amp(node_id, 0, 0, 0, 0)) {
|
||||
if (!aciodrv_kfca_amp(device, node_id, 0, 0, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,12 +86,15 @@ bool aciodrv_kfca_init(uint8_t node_id)
|
||||
}
|
||||
|
||||
bool aciodrv_kfca_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct ac_io_kfca_poll_out *pout,
|
||||
struct ac_io_kfca_poll_in *pin)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
|
||||
msg.cmd.nbytes = sizeof(*pout);
|
||||
@@ -93,7 +102,9 @@ bool aciodrv_kfca_poll(
|
||||
msg.cmd.kfca_poll_out = *pout;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
log_warning("Polling of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,17 +6,19 @@
|
||||
/**
|
||||
* Initialize an KFCA node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to initialize (0 based).
|
||||
* @return True if successful, false on error.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_kfca_init(uint8_t node_id);
|
||||
bool aciodrv_kfca_init(struct aciodrv_device_ctx *device, uint8_t node_id);
|
||||
|
||||
/**
|
||||
* Poll the KFCA io board
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
* (optional, NULL for none).
|
||||
@@ -26,6 +28,7 @@ bool aciodrv_kfca_init(uint8_t node_id);
|
||||
* @see driver.h
|
||||
*/
|
||||
bool aciodrv_kfca_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct ac_io_kfca_poll_out *pout,
|
||||
struct ac_io_kfca_poll_in *pin);
|
||||
@@ -33,6 +36,7 @@ bool aciodrv_kfca_poll(
|
||||
/**
|
||||
* Set the KFCA digital amp level
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param primary primary volume (96-0)
|
||||
* @param headphone headphone volume (96-0)
|
||||
@@ -42,6 +46,7 @@ bool aciodrv_kfca_poll(
|
||||
* @note Note 96 (or 100?) is lowest volume level, 0 is highest
|
||||
*/
|
||||
bool aciodrv_kfca_amp(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
uint8_t primary,
|
||||
uint8_t headphone,
|
||||
|
||||
80
src/main/aciodrv/panb.c
Normal file
80
src/main/aciodrv/panb.c
Normal 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
56
src/main/aciodrv/panb.h
Normal 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
|
||||
@@ -1,5 +1,6 @@
|
||||
#define LOG_MODULE "aciodrv-port"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -7,17 +8,15 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static HANDLE aciodrv_port_fd;
|
||||
|
||||
bool aciodrv_port_open(const char *port, int baud)
|
||||
HANDLE aciodrv_port_open(const char *port_path, int baud)
|
||||
{
|
||||
COMMTIMEOUTS ct;
|
||||
DCB dcb;
|
||||
|
||||
log_info("Opening ACIO on %s at %d baud", port, baud);
|
||||
log_info("Opening ACIO on %s at %d baud", port_path, baud);
|
||||
|
||||
aciodrv_port_fd = CreateFile(
|
||||
port,
|
||||
HANDLE port_fd = CreateFile(
|
||||
port_path,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
@@ -25,26 +24,26 @@ bool aciodrv_port_open(const char *port, int baud)
|
||||
FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (aciodrv_port_fd == INVALID_HANDLE_VALUE) {
|
||||
log_warning("Failed to open %s", port);
|
||||
if (port_fd == INVALID_HANDLE_VALUE) {
|
||||
log_warning("Failed to open %s", port_path);
|
||||
|
||||
goto early_fail;
|
||||
}
|
||||
|
||||
if (!SetCommMask(aciodrv_port_fd, EV_RXCHAR)) {
|
||||
if (!SetCommMask(port_fd, EV_RXCHAR)) {
|
||||
log_warning("SetCommMask failed");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!SetupComm(aciodrv_port_fd, 0x1000, 0x1000)) {
|
||||
if (!SetupComm(port_fd, 0x1000, 0x1000)) {
|
||||
log_warning("SetupComm failed");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!PurgeComm(
|
||||
aciodrv_port_fd,
|
||||
port_fd,
|
||||
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
|
||||
log_warning("PurgeComm failed");
|
||||
|
||||
@@ -57,7 +56,7 @@ bool aciodrv_port_open(const char *port, int baud)
|
||||
ct.ReadTotalTimeoutMultiplier = 0;
|
||||
ct.WriteTotalTimeoutMultiplier = 0;
|
||||
|
||||
if (!SetCommTimeouts(aciodrv_port_fd, &ct)) {
|
||||
if (!SetCommTimeouts(port_fd, &ct)) {
|
||||
log_warning("SetCommTimeouts failed");
|
||||
|
||||
goto fail;
|
||||
@@ -65,7 +64,7 @@ bool aciodrv_port_open(const char *port, int baud)
|
||||
|
||||
dcb.DCBlength = sizeof(dcb);
|
||||
|
||||
if (!GetCommState(aciodrv_port_fd, &dcb)) {
|
||||
if (!GetCommState(port_fd, &dcb)) {
|
||||
log_warning("GetCommState failed");
|
||||
|
||||
goto fail;
|
||||
@@ -90,46 +89,47 @@ bool aciodrv_port_open(const char *port, int baud)
|
||||
dcb.XonLim = 100;
|
||||
dcb.XoffLim = 100;
|
||||
|
||||
if (!SetCommState(aciodrv_port_fd, &dcb)) {
|
||||
if (!SetCommState(port_fd, &dcb)) {
|
||||
log_warning("SetCommState failed");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!EscapeCommFunction(aciodrv_port_fd, SETDTR)) {
|
||||
if (!EscapeCommFunction(port_fd, SETDTR)) {
|
||||
log_warning("SETDTR failed: err = %lu", GetLastError());
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
log_info("Opened ACIO device on %s", port);
|
||||
log_info("[%p] Opened ACIO device on %s", port_fd, port_path);
|
||||
|
||||
return true;
|
||||
return port_fd;
|
||||
|
||||
fail:
|
||||
CloseHandle(aciodrv_port_fd);
|
||||
CloseHandle(port_fd);
|
||||
|
||||
early_fail:
|
||||
aciodrv_port_fd = NULL;
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int aciodrv_port_read(void *bytes, int nbytes)
|
||||
int aciodrv_port_read(HANDLE port_fd, void *bytes, int nbytes)
|
||||
{
|
||||
DWORD nread;
|
||||
|
||||
if (aciodrv_port_fd == NULL) {
|
||||
log_assert(bytes);
|
||||
|
||||
if (port_fd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ClearCommError(aciodrv_port_fd, NULL, NULL)) {
|
||||
log_warning("ClearCommError failed");
|
||||
if (!ClearCommError(port_fd, NULL, NULL)) {
|
||||
log_warning("[%p] ClearCommError failed", port_fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ReadFile(aciodrv_port_fd, bytes, nbytes, &nread, NULL)) {
|
||||
log_warning("ReadFile failed: err = %lu", GetLastError());
|
||||
if (!ReadFile(port_fd, bytes, nbytes, &nread, NULL)) {
|
||||
log_warning("[%p] ReadFile failed: err = %lu", port_fd, GetLastError());
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -137,16 +137,18 @@ int aciodrv_port_read(void *bytes, int nbytes)
|
||||
return nread;
|
||||
}
|
||||
|
||||
int aciodrv_port_write(const void *bytes, int nbytes)
|
||||
int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes)
|
||||
{
|
||||
DWORD nwrit;
|
||||
|
||||
if (aciodrv_port_fd == NULL) {
|
||||
log_assert(bytes);
|
||||
|
||||
if (port_fd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!WriteFile(aciodrv_port_fd, bytes, nbytes, &nwrit, NULL)) {
|
||||
log_warning("WriteFile failed: err = %lu", GetLastError());
|
||||
if (!WriteFile(port_fd, bytes, nbytes, &nwrit, NULL)) {
|
||||
log_warning("[%p] WriteFile failed: err = %lu", port_fd, GetLastError());
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -154,9 +156,9 @@ int aciodrv_port_write(const void *bytes, int nbytes)
|
||||
return nwrit;
|
||||
}
|
||||
|
||||
void aciodrv_port_close(void)
|
||||
void aciodrv_port_close(HANDLE port_fd)
|
||||
{
|
||||
if (aciodrv_port_fd != NULL) {
|
||||
CloseHandle(aciodrv_port_fd);
|
||||
if (port_fd != NULL) {
|
||||
CloseHandle(port_fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,39 +4,45 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
* Open a serial port for communication with a ACIO device.
|
||||
*
|
||||
* @param port Port the device is connected to (e.g. "COM1")
|
||||
* @param baud Baud rate for communication (e.g. 57600 for ICCA)
|
||||
* @return True if opening the com port was successful, false on error.
|
||||
* @return HANDLE of the port, NULL on error
|
||||
* @note This will open and setup the com port, only.
|
||||
*/
|
||||
bool aciodrv_port_open(const char *port, int baud);
|
||||
HANDLE aciodrv_port_open(const char *port_path, int baud);
|
||||
|
||||
/**
|
||||
* Read data from the opened com port.
|
||||
*
|
||||
* @param port_fd HANDLE of opened serial port
|
||||
* @param bytes Pointer to an allocated buffer to read the data into.
|
||||
* @param nbytes Number of bytes to read. Has to be less or equal the allocated
|
||||
* buffer size.
|
||||
* @return Number of bytes read on success or -1 on error.
|
||||
*/
|
||||
int aciodrv_port_read(void *bytes, int nbytes);
|
||||
int aciodrv_port_read(HANDLE port_fd, void *bytes, int nbytes);
|
||||
|
||||
/**
|
||||
* Write data to the opened com port.
|
||||
*
|
||||
* @param port_fd HANDLE of opened serial port
|
||||
* @param bytes Pointer to an allocated buffer with data to write.
|
||||
* @param nbytes Number of bytes to write. Has to be equal or less the size
|
||||
* of the allocated buffer.
|
||||
* @return Number of bytes written on success or -1 on error.
|
||||
*/
|
||||
int aciodrv_port_write(const void *bytes, int nbytes);
|
||||
int aciodrv_port_write(HANDLE port_fd, const void *bytes, int nbytes);
|
||||
|
||||
/**
|
||||
* Close the previously opened com port.
|
||||
*
|
||||
* @param port_fd HANDLE of opened serial port
|
||||
*/
|
||||
void aciodrv_port_close(void);
|
||||
void aciodrv_port_close(HANDLE port_fd);
|
||||
|
||||
#endif
|
||||
80
src/main/aciodrv/rvol.c
Normal file
80
src/main/aciodrv/rvol.c
Normal 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
36
src/main/aciodrv/rvol.h
Normal 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
|
||||
@@ -134,6 +134,7 @@ static HRESULT ac_io_emu_write(struct ac_io_emu *emu, struct irp *irp)
|
||||
break;
|
||||
}
|
||||
|
||||
// this supplies a single SOF byte per byte read
|
||||
ac_io_in_supply(&emu->in, NULL, 0);
|
||||
ac_io_out_consume_message(&emu->out);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ void ac_io_emu_h44b_dispatch_request(
|
||||
req->cmd.raw[i * 3 + 2]);
|
||||
}
|
||||
|
||||
jb_io_write_outputs();
|
||||
jb_io_write_lights();
|
||||
|
||||
ac_io_emu_h44b_send_status(h44b, req, 0x00);
|
||||
|
||||
|
||||
@@ -29,13 +29,6 @@ enum ac_io_icca_flag {
|
||||
AC_IO_ICCA_FLAG_SOLENOID = 0x40
|
||||
};
|
||||
|
||||
enum ac_io_icca_status_code {
|
||||
AC_IO_ICCA_STATUS_FAULT = 0x00,
|
||||
AC_IO_ICCA_STATUS_IDLE = 0x01,
|
||||
AC_IO_ICCA_STATUS_GOT_UID = 0x02,
|
||||
AC_IO_ICCA_STATUS_IDLE_NEW = 0x04
|
||||
};
|
||||
|
||||
static void ac_io_emu_icca_cmd_send_version(
|
||||
struct ac_io_emu_icca *icca, const struct ac_io_message *req);
|
||||
|
||||
@@ -132,8 +125,8 @@ void ac_io_emu_icca_dispatch_request(
|
||||
|
||||
break;
|
||||
|
||||
case AC_IO_ICCA_CMD_BEGIN_KEYPAD:
|
||||
log_misc("AC_IO_ICCA_CMD_BEGIN_KEYPAD(%d)", req->addr);
|
||||
case AC_IO_ICCA_CMD_DEVICE_CONTROL:
|
||||
log_misc("AC_IO_ICCA_CMD_DEVICE_CONTROL(%d)", req->addr);
|
||||
ac_io_emu_icca_send_status(icca, req, 0x00);
|
||||
icca->keypad_started = true;
|
||||
|
||||
|
||||
@@ -169,6 +169,10 @@ static void ac_io_emu_iccb_send_state(
|
||||
|
||||
/* state update */
|
||||
|
||||
if (!eam_io_poll(iccb->unit_no)) {
|
||||
log_warning("Polling eamio failed");
|
||||
}
|
||||
|
||||
sensor = eam_io_get_sensor_state(iccb->unit_no);
|
||||
|
||||
if (sensor != iccb->last_sensor) {
|
||||
|
||||
9
src/main/aciomgr/Module.mk
Normal file
9
src/main/aciomgr/Module.mk
Normal file
@@ -0,0 +1,9 @@
|
||||
dlls += aciomgr
|
||||
|
||||
libs_aciomgr := \
|
||||
aciodrv \
|
||||
util \
|
||||
|
||||
src_aciomgr := \
|
||||
dllmain.c \
|
||||
manager.c \
|
||||
12
src/main/aciomgr/aciomgr.def
Normal file
12
src/main/aciomgr/aciomgr.def
Normal 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
|
||||
16
src/main/aciomgr/dllmain.c
Normal file
16
src/main/aciomgr/dllmain.c
Normal 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;
|
||||
}
|
||||
8
src/main/aciomgr/manager-init.h
Normal file
8
src/main/aciomgr/manager-init.h
Normal 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
210
src/main/aciomgr/manager.c
Normal 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);
|
||||
}
|
||||
}
|
||||
86
src/main/aciomgr/manager.h
Normal file
86
src/main/aciomgr/manager.h
Normal 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
|
||||
@@ -3,10 +3,13 @@ exes += aciotest
|
||||
libs_aciotest := \
|
||||
bio2drv \
|
||||
aciodrv \
|
||||
aciodrv-proc \
|
||||
util \
|
||||
|
||||
src_aciotest := \
|
||||
icca.c \
|
||||
kfca.c \
|
||||
panb.c \
|
||||
rvol.c \
|
||||
bi2a-sdvx.c \
|
||||
main.c \
|
||||
|
||||
@@ -8,22 +8,24 @@
|
||||
|
||||
#include "bio2drv/bi2a-sdvx.h"
|
||||
|
||||
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx)
|
||||
bool aciotest_bi2a_sdvx_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
|
||||
{
|
||||
*ctx = malloc(sizeof(uint32_t));
|
||||
*((uint32_t *) *ctx) = 0;
|
||||
|
||||
return bio2drv_bi2a_sdvx_init(node_id);
|
||||
return bio2drv_bi2a_sdvx_init(device, node_id);
|
||||
}
|
||||
|
||||
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx)
|
||||
bool aciotest_bi2a_sdvx_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
|
||||
{
|
||||
struct bi2a_sdvx_state_in pin;
|
||||
struct bi2a_sdvx_state_out pout;
|
||||
|
||||
memset(&pout, 0, sizeof(pout));
|
||||
|
||||
if (!bio2drv_bi2a_sdvx_poll(node_id, &pout, &pin)) {
|
||||
if (!bio2drv_bi2a_sdvx_poll(device, node_id, &pout, &pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx);
|
||||
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx);
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
bool aciotest_bi2a_sdvx_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
|
||||
bool aciotest_bi2a_sdvx_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ACIOTEST_HANDLER_H
|
||||
#define ACIOTEST_HANDLER_H
|
||||
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
static const uint8_t aciotest_handler_max = 16;
|
||||
|
||||
/**
|
||||
@@ -8,8 +10,10 @@ static const uint8_t aciotest_handler_max = 16;
|
||||
*/
|
||||
struct aciotest_handler_node_handler {
|
||||
void *ctx;
|
||||
bool (*init)(uint8_t node_id, void **ctx);
|
||||
bool (*update)(uint8_t node_id, void *ctx);
|
||||
bool (*init)(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
|
||||
bool (*update)(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,29 +5,52 @@
|
||||
|
||||
#include "aciodrv/icca.h"
|
||||
|
||||
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx)
|
||||
{
|
||||
*ctx = malloc(sizeof(uint32_t));
|
||||
*((uint32_t *) *ctx) = 0;
|
||||
|
||||
return aciodrv_icca_init(node_id);
|
||||
#define IDLE_RESPONSES_BETWEEN_FELICA_POLLS 5
|
||||
|
||||
struct icca_handler_ctx {
|
||||
bool init;
|
||||
bool slotted_reader;
|
||||
uint8_t last_poll;
|
||||
};
|
||||
|
||||
bool aciotest_icca_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
|
||||
{
|
||||
*ctx = malloc(sizeof(struct icca_handler_ctx));
|
||||
|
||||
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)*ctx;
|
||||
icca_ctx->init = false;
|
||||
|
||||
icca_ctx->slotted_reader = true;
|
||||
|
||||
icca_ctx->last_poll = 0;
|
||||
|
||||
icca_ctx->slotted_reader = aciodrv_icca_is_slotted(device, node_id);
|
||||
|
||||
return aciodrv_icca_init(device, node_id);
|
||||
}
|
||||
|
||||
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx)
|
||||
bool aciotest_icca_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
|
||||
{
|
||||
if (*((uint32_t *) ctx) == 0) {
|
||||
*((uint32_t *) ctx) = 1;
|
||||
struct icca_handler_ctx *icca_ctx = (struct icca_handler_ctx*)ctx;
|
||||
|
||||
/* eject cards that were left in the reader */
|
||||
if (!aciodrv_icca_set_state(
|
||||
node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
|
||||
return false;
|
||||
if (icca_ctx->init == false) {
|
||||
icca_ctx->init = true;
|
||||
|
||||
if (icca_ctx->slotted_reader) {
|
||||
/* eject cards that were left in the reader */
|
||||
if (!aciodrv_icca_set_state(
|
||||
device, node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ac_io_icca_state state;
|
||||
|
||||
if (!aciodrv_icca_get_state(node_id, &state)) {
|
||||
if (!aciodrv_icca_get_state(device, node_id, &state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,33 +81,48 @@ bool aciotest_icca_handler_update(uint8_t node_id, void *ctx)
|
||||
state.key_events[0],
|
||||
state.key_events[1]);
|
||||
|
||||
/* eject card with "empty" key */
|
||||
if (state.key_state & AC_IO_ICCA_KEYPAD_MASK_EMPTY) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* allow new card to be inserted when slot is clear */
|
||||
if (!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
|
||||
!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
node_id, AC_IO_ICCA_SLOT_STATE_OPEN, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* lock the card when fully inserted */
|
||||
if ((state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
|
||||
(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
node_id, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL)) {
|
||||
return false;
|
||||
if (icca_ctx->slotted_reader) {
|
||||
/* eject card with "empty" key */
|
||||
if (state.key_state & AC_IO_ICCA_KEYPAD_MASK_EMPTY) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
device, node_id, AC_IO_ICCA_SLOT_STATE_EJECT, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aciodrv_icca_read_card(node_id, NULL)) {
|
||||
return false;
|
||||
/* allow new card to be inserted when slot is clear */
|
||||
if (!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
|
||||
!(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
device, node_id, AC_IO_ICCA_SLOT_STATE_OPEN, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* lock the card when fully inserted */
|
||||
if ((state.sensor_state & AC_IO_ICCA_SENSOR_MASK_BACK_ON) &&
|
||||
(state.sensor_state & AC_IO_ICCA_SENSOR_MASK_FRONT_ON)) {
|
||||
if (!aciodrv_icca_set_state(
|
||||
device, node_id, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aciodrv_icca_read_card(device, node_id, NULL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// wavepass reader, see eamio-icca for why this is done this way
|
||||
if (state.status_code != AC_IO_ICCA_STATUS_BUSY_NEW) {
|
||||
++icca_ctx->last_poll;
|
||||
}
|
||||
|
||||
if (icca_ctx->last_poll >= IDLE_RESPONSES_BETWEEN_FELICA_POLLS) {
|
||||
if (!aciodrv_icca_poll_felica(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
icca_ctx->last_poll = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool aciotest_icca_handler_init(uint8_t node_id, void **ctx);
|
||||
bool aciotest_icca_handler_update(uint8_t node_id, void *ctx);
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
bool aciotest_icca_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
|
||||
bool aciotest_icca_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
|
||||
|
||||
#endif
|
||||
@@ -8,15 +8,17 @@
|
||||
|
||||
#include "aciodrv/kfca.h"
|
||||
|
||||
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx)
|
||||
bool aciotest_kfca_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
|
||||
{
|
||||
*ctx = malloc(sizeof(uint32_t));
|
||||
*((uint32_t *) *ctx) = 0;
|
||||
|
||||
return aciodrv_kfca_init(node_id);
|
||||
return aciodrv_kfca_init(device, node_id);
|
||||
}
|
||||
|
||||
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx)
|
||||
bool aciotest_kfca_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
|
||||
{
|
||||
struct ac_io_kfca_poll_in pin;
|
||||
struct ac_io_kfca_poll_out pout;
|
||||
@@ -28,7 +30,7 @@ bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx)
|
||||
pout.gpio |= 1 << gpio_test_pin;
|
||||
pout.gpio = ac_io_u32(pout.gpio);
|
||||
|
||||
if (!aciodrv_kfca_poll(node_id, &pout, &pin)) {
|
||||
if (!aciodrv_kfca_poll(device, node_id, &pout, &pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool aciotest_kfca_handler_init(uint8_t node_id, void **ctx);
|
||||
bool aciotest_kfca_handler_update(uint8_t node_id, void *ctx);
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
bool aciotest_kfca_handler_init(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
|
||||
bool aciotest_kfca_handler_update(
|
||||
struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "aciotest/handler.h"
|
||||
#include "aciotest/icca.h"
|
||||
#include "aciotest/kfca.h"
|
||||
#include "aciotest/panb.h"
|
||||
#include "aciotest/rvol.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
@@ -20,24 +22,37 @@ static uint8_t bi2a_mode = 0;
|
||||
* Enumerate supported ACIO nodes based on their product id.
|
||||
*/
|
||||
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) ||
|
||||
!memcmp(product, "ICCC", 4)) {
|
||||
if (product_type == AC_IO_NODE_TYPE_ICCA) {
|
||||
handler->init = aciotest_icca_handler_init;
|
||||
handler->update = aciotest_icca_handler_update;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!memcmp(product, "KFCA", 4)) {
|
||||
if (product_type == AC_IO_NODE_TYPE_KFCA) {
|
||||
handler->init = aciotest_kfca_handler_init;
|
||||
handler->update = aciotest_kfca_handler_update;
|
||||
|
||||
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) {
|
||||
handler->init = aciotest_bi2a_sdvx_handler_init;
|
||||
handler->update = aciotest_bi2a_sdvx_handler_update;
|
||||
@@ -70,14 +85,17 @@ int main(int argc, char **argv)
|
||||
|
||||
log_to_writer(log_writer_stdout, NULL);
|
||||
|
||||
if (!aciodrv_device_open(argv[1], atoi(argv[2]))) {
|
||||
|
||||
struct aciodrv_device_ctx *device = aciodrv_device_open_path(argv[1], atoi(argv[2]));
|
||||
|
||||
if (!device) {
|
||||
printf("Opening acio device failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Opening acio device successful\n");
|
||||
|
||||
uint8_t node_count = aciodrv_device_get_node_count();
|
||||
uint8_t node_count = aciodrv_device_get_node_count(device);
|
||||
printf("Enumerated %d nodes\n", node_count);
|
||||
|
||||
struct aciotest_handler_node_handler handler[aciotest_handler_max];
|
||||
@@ -88,29 +106,29 @@ int main(int argc, char **argv)
|
||||
|
||||
for (uint8_t i = 0; i < node_count; i++) {
|
||||
char product[4];
|
||||
aciodrv_device_get_node_product_ident(i, product);
|
||||
uint32_t product_type = aciodrv_device_get_node_product_type(device, i);
|
||||
aciodrv_device_get_node_product_ident(device, i, product);
|
||||
|
||||
printf(
|
||||
"> %d: %c%c%c%c\n",
|
||||
"> %d: %c%c%c%c (%08x)\n",
|
||||
i + 1,
|
||||
product[0],
|
||||
product[1],
|
||||
product[2],
|
||||
product[3]);
|
||||
product[3],
|
||||
product_type);
|
||||
|
||||
if (!aciotest_assign_handler(product, &handler[i])) {
|
||||
if (!aciotest_assign_handler(product_type, &handler[i])) {
|
||||
printf(
|
||||
"ERROR: Unsupported acio node product %c%c%c%c on node %d\n",
|
||||
product[0],
|
||||
product[1],
|
||||
product[2],
|
||||
product[3],
|
||||
"ERROR: Unsupported acio node product %08x on node %d\n",
|
||||
product_type,
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
|
||||
if (handler[i].init != NULL) {
|
||||
if (!handler[i].init(i, &handler[i].ctx)) {
|
||||
if (!handler[i].init(device, i, &handler[i].ctx)) {
|
||||
printf("ERROR: Initializing node %d failed\n", i);
|
||||
handler[i].update = NULL;
|
||||
}
|
||||
@@ -129,7 +147,7 @@ int main(int argc, char **argv)
|
||||
|
||||
for (uint8_t i = 0; i < aciotest_handler_max; i++) {
|
||||
if (handler[i].update != NULL) {
|
||||
if (!handler[i].update(i, handler[i].ctx)) {
|
||||
if (!handler[i].update(device, i, handler[i].ctx)) {
|
||||
printf("ERROR: Updating node %d, removed from loop\n", i);
|
||||
handler[i].update = NULL;
|
||||
Sleep(5000);
|
||||
|
||||
76
src/main/aciotest/panb.c
Normal file
76
src/main/aciotest/panb.c
Normal 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
12
src/main/aciotest/panb.h
Normal 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
73
src/main/aciotest/rvol.c
Normal 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
14
src/main/aciotest/rvol.h
Normal 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
|
||||
@@ -29,6 +29,17 @@ enum jb_io_panel_bit {
|
||||
JB_IO_PANEL_16 = 0x0F,
|
||||
};
|
||||
|
||||
/* input "single button mode" mappings. Allows you to check each corner of each
|
||||
button to determine any flaky inputs
|
||||
*/
|
||||
enum jb_io_panel_mode {
|
||||
JB_IO_PANEL_MODE_ALL = 0, // any of the four corners will trigger a panel
|
||||
JB_IO_PANEL_MODE_TOP_LEFT = 1,
|
||||
JB_IO_PANEL_MODE_TOP_RIGHT = 2,
|
||||
JB_IO_PANEL_MODE_BOTTOM_RIGHT = 3,
|
||||
JB_IO_PANEL_MODE_BOTTOM_LEFT = 4,
|
||||
};
|
||||
|
||||
/* Bit mappings for "system" inputs */
|
||||
enum jb_io_sys_bit {
|
||||
JB_IO_SYS_TEST = 0x00,
|
||||
@@ -73,17 +84,36 @@ bool jb_io_init(
|
||||
|
||||
void jb_io_fini(void);
|
||||
|
||||
/* TODO doc */
|
||||
/* Read input state */
|
||||
|
||||
bool jb_io_read_inputs(void);
|
||||
|
||||
bool jb_io_write_outputs(void);
|
||||
/* Get state of coin, test, service inputs */
|
||||
|
||||
uint8_t jb_io_get_sys_inputs(void);
|
||||
|
||||
/* Get panel button state. Will return either any button being pressed, or a
|
||||
particular panel corner depending on previous call to jb_io_set_panel_mode */
|
||||
|
||||
uint16_t jb_io_get_panel_inputs(void);
|
||||
|
||||
/* Set state of a PWM (dimmable) light */
|
||||
|
||||
void jb_io_set_rgb_led(
|
||||
enum jb_io_rgb_led unit, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
/* Transmit the light state to the IOPCB */
|
||||
|
||||
bool jb_io_write_lights(void);
|
||||
|
||||
/* Select operating mode for the panel. Should be immediately sent to the IOPCB */
|
||||
|
||||
bool jb_io_set_panel_mode(enum jb_io_panel_mode mode);
|
||||
|
||||
/* Open or close the coin chute - true will redirect all coins to the return
|
||||
slot. Required for jb_io_set_panel_mode to operate correctly on p4io.
|
||||
Should be immediately sent to the IOPCB */
|
||||
|
||||
bool jb_io_set_coin_blocker(bool blocked);
|
||||
|
||||
#endif
|
||||
|
||||
56
src/main/bio2/bi2a-ddr.h
Normal file
56
src/main/bio2/bi2a-ddr.h
Normal 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
|
||||
@@ -11,6 +11,11 @@ enum bio2_bi2a_cmd {
|
||||
BIO2_BI2A_CMD_INIT = 0x0100,
|
||||
BIO2_BI2A_CMD_WATCHDOG = 0x0120,
|
||||
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
|
||||
@@ -14,17 +14,23 @@
|
||||
// in all inputs and outputs (over sub IO) other than 14 keys to not work.
|
||||
static const uint8_t _BIO2DR_BI2A_IIDX_INIT_DATA = 0x2D;
|
||||
|
||||
static bool bio2drv_bi2a_iidx_init_io(uint8_t node_id)
|
||||
static bool bio2drv_bi2a_iidx_init_io(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_INIT);
|
||||
msg.cmd.nbytes = 1;
|
||||
msg.cmd.param = _BIO2DR_BI2A_IIDX_INIT_DATA;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Init node failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -34,8 +40,12 @@ static bool bio2drv_bi2a_iidx_init_io(uint8_t node_id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
|
||||
static bool bio2drv_bi2a_iidx_watchdog_start(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id)
|
||||
{
|
||||
log_assert(device);
|
||||
|
||||
// exit early and don't actually call watchdog
|
||||
// the watchdog call actually returns different sized packets depending on
|
||||
// the state this results in an issue during packet processing (see: #68)
|
||||
@@ -47,14 +57,13 @@ static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
|
||||
msg.cmd.nbytes = 2;
|
||||
msg.cmd.nbytes = 2;
|
||||
|
||||
// uint16_t: 6000
|
||||
msg.cmd.raw[0] = 23;
|
||||
msg.cmd.raw[1] = 112;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
|
||||
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2
|
||||
)) {
|
||||
log_warning("Starting watchdog failed"); return false;
|
||||
}
|
||||
@@ -66,13 +75,15 @@ static bool bio2drv_bi2a_iidx_watchdog_start(uint8_t node_id)
|
||||
*/
|
||||
}
|
||||
|
||||
bool bio2drv_bi2a_iidx_init(uint8_t node_id)
|
||||
bool bio2drv_bi2a_iidx_init(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
if (!bio2drv_bi2a_iidx_init_io(node_id)) {
|
||||
log_assert(device);
|
||||
|
||||
if (!bio2drv_bi2a_iidx_init_io(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bio2drv_bi2a_iidx_watchdog_start(node_id)) {
|
||||
if (!bio2drv_bi2a_iidx_watchdog_start(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,12 +91,15 @@ bool bio2drv_bi2a_iidx_init(uint8_t node_id)
|
||||
}
|
||||
|
||||
bool bio2drv_bi2a_iidx_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct bi2a_iidx_state_out *pout,
|
||||
struct bi2a_iidx_state_in *pin)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
// log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_POLL);
|
||||
msg.cmd.nbytes = sizeof(*pout);
|
||||
@@ -93,7 +107,9 @@ bool bio2drv_bi2a_iidx_poll(
|
||||
*(struct bi2a_iidx_state_out *) msg.cmd.raw = *pout;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
log_warning("Polling of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
#ifndef BIO2DRV_BI2A_IIDX_H
|
||||
#define BIO2DRV_BI2A_IIDX_H
|
||||
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
#include "bio2/bi2a-iidx.h"
|
||||
|
||||
/**
|
||||
* Initialize a BI2A node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to initialize (0 based).
|
||||
* @return True if successful, false on error.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool bio2drv_bi2a_iidx_init(uint8_t node_id);
|
||||
bool bio2drv_bi2a_iidx_init(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id);
|
||||
|
||||
/**
|
||||
* Poll the BI2A board
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
* (optional, NULL for none).
|
||||
@@ -26,6 +32,7 @@ bool bio2drv_bi2a_iidx_init(uint8_t node_id);
|
||||
* @see driver.h
|
||||
*/
|
||||
bool bio2drv_bi2a_iidx_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct bi2a_iidx_state_out *pout,
|
||||
struct bi2a_iidx_state_in *pin);
|
||||
|
||||
@@ -12,17 +12,21 @@
|
||||
static const uint8_t _BIO2DR_BI2A_SDVX_INIT_DATA = 0x3B;
|
||||
|
||||
// this is probably InitIO
|
||||
static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
|
||||
static bool bio2drv_bi2a_sdvx_init_io(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(BIO2_BI2A_CMD_INIT);
|
||||
msg.cmd.nbytes = 1;
|
||||
msg.cmd.param = _BIO2DR_BI2A_SDVX_INIT_DATA;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Init node failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -32,8 +36,10 @@ static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
|
||||
static bool bio2drv_bi2a_sdvx_watchdog_start(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
log_assert(device);
|
||||
|
||||
// exit early and don't actually call watchdog
|
||||
// the watchdog call actually returns different sized packets depending on
|
||||
// the state this results in an issue during packet processing (see: #68)
|
||||
@@ -52,7 +58,7 @@ static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
|
||||
msg.cmd.raw[1] = 112;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
|
||||
device, &msg, offsetof(struct ac_io_message, cmd.raw) + 2
|
||||
)) {
|
||||
log_warning("Starting watchdog failed"); return false;
|
||||
}
|
||||
@@ -65,6 +71,7 @@ static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
|
||||
}
|
||||
|
||||
bool bio2drv_bi2a_sdvx_amp(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
uint8_t unused_1,
|
||||
uint8_t unused_2,
|
||||
@@ -73,6 +80,8 @@ bool bio2drv_bi2a_sdvx_amp(
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
|
||||
msg.cmd.nbytes = 4;
|
||||
@@ -86,7 +95,9 @@ bool bio2drv_bi2a_sdvx_amp(
|
||||
msg.cmd.raw[3] = right;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + 1)) {
|
||||
log_warning("Setting AMP failed");
|
||||
return false;
|
||||
}
|
||||
@@ -96,17 +107,19 @@ bool bio2drv_bi2a_sdvx_amp(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
|
||||
bool bio2drv_bi2a_sdvx_init(struct aciodrv_device_ctx *device, uint8_t node_id)
|
||||
{
|
||||
if (!bio2drv_bi2a_sdvx_init_io(node_id)) {
|
||||
log_assert(device);
|
||||
|
||||
if (!bio2drv_bi2a_sdvx_init_io(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bio2drv_bi2a_sdvx_watchdog_start(node_id)) {
|
||||
if (!bio2drv_bi2a_sdvx_watchdog_start(device, node_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bio2drv_bi2a_sdvx_amp(node_id, 0, 0, 0, 0)) {
|
||||
if (!bio2drv_bi2a_sdvx_amp(device, node_id, 0, 0, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -114,12 +127,15 @@ bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
|
||||
}
|
||||
|
||||
bool bio2drv_bi2a_sdvx_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct bi2a_sdvx_state_out *pout,
|
||||
struct bi2a_sdvx_state_in *pin)
|
||||
{
|
||||
struct ac_io_message msg;
|
||||
|
||||
// log_assert(device);
|
||||
|
||||
msg.addr = node_id + 1;
|
||||
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
|
||||
msg.cmd.nbytes = sizeof(*pout);
|
||||
@@ -127,7 +143,9 @@ bool bio2drv_bi2a_sdvx_poll(
|
||||
*(struct bi2a_sdvx_state_out *) msg.cmd.raw = *pout;
|
||||
|
||||
if (!aciodrv_send_and_recv(
|
||||
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
device,
|
||||
&msg,
|
||||
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
|
||||
log_warning("Polling of node %d failed", node_id + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
#ifndef BIO2DRV_BI2A_H
|
||||
#define BIO2DRV_BI2A_H
|
||||
#ifndef BIO2DRV_BI2A_SDVX_H
|
||||
#define BIO2DRV_BI2A_SDVX_H
|
||||
|
||||
#include "aciodrv/device.h"
|
||||
|
||||
#include "bio2/bi2a-sdvx.h"
|
||||
|
||||
/**
|
||||
* Initialize a BI2A node.
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to initialize (0 based).
|
||||
* @return True if successful, false on error.
|
||||
* @note This module is supposed to be used in combination with the common
|
||||
* device driver foundation.
|
||||
* @see driver.h
|
||||
*/
|
||||
bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
|
||||
bool bio2drv_bi2a_sdvx_init(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id);
|
||||
|
||||
/**
|
||||
* Poll the board
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param state Pointer to a state struct to return the current state to
|
||||
* (optional, NULL for none).
|
||||
@@ -26,6 +32,7 @@ bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
|
||||
* @see driver.h
|
||||
*/
|
||||
bool bio2drv_bi2a_sdvx_poll(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
const struct bi2a_sdvx_state_out *pout,
|
||||
struct bi2a_sdvx_state_in *pin);
|
||||
@@ -33,6 +40,7 @@ bool bio2drv_bi2a_sdvx_poll(
|
||||
/**
|
||||
* Set the BIO2 BI2A SDVX digital amp level
|
||||
*
|
||||
* @param device Context of opened device
|
||||
* @param node_id Id of the node to query (0 based).
|
||||
* @param primary primary volume (96-0)
|
||||
* @param headphone headphone volume (96-0)
|
||||
@@ -42,6 +50,7 @@ bool bio2drv_bi2a_sdvx_poll(
|
||||
* @note Note 96 is lowest volume level, 0 is highest
|
||||
*/
|
||||
bool bio2drv_bi2a_sdvx_amp(
|
||||
struct aciodrv_device_ctx *device,
|
||||
uint8_t node_id,
|
||||
uint8_t unused_1,
|
||||
uint8_t unused_2,
|
||||
|
||||
@@ -341,14 +341,14 @@ static HRESULT my_MFEnumDeviceSources(
|
||||
|
||||
for (UINT32 i = 0; i < nsrcs; ++i) {
|
||||
api = (*pppSourceActivate)[i];
|
||||
|
||||
|
||||
ret = com_proxy_wrap(&api_proxy, api, sizeof(*api->lpVtbl));
|
||||
|
||||
|
||||
if (ret != S_OK) {
|
||||
log_warning("Wrapping com proxy failed: %08lx", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
api_vtbl = api_proxy->vptr;
|
||||
|
||||
real_GetAllocatedString = api_vtbl->GetAllocatedString;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define D3D9EXHOOK_CONFIG_GFX_CONFINED_KEY "gfx.confined"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_WIDTH_KEY "gfx.window_width"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_HEIGHT_KEY "gfx.window_height"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY "gfx.window_x"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY "gfx.window_y"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY "gfx.forced_refresh_rate"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEVICE_ADAPTER_KEY "gfx.device_adapter"
|
||||
#define D3D9EXHOOK_CONFIG_GFX_FORCE_ORIENTATION_KEY "gfx.force_orientation"
|
||||
@@ -24,6 +26,8 @@
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_CONFINED_VALUE false
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCED_RR_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_DEVICE_ADAPTER_VALUE -1
|
||||
#define D3D9EXHOOK_CONFIG_GFX_DEFAULT_FORCE_ORIENTATION_VALUE -1
|
||||
@@ -62,6 +66,18 @@ void d3d9exhook_config_gfx_init(struct cconfig *config)
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE,
|
||||
"Windowed height, -1 for default size");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE,
|
||||
"Windowed X, -1 for default X position");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE,
|
||||
"Windowed Y, -1 for default Y position");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY,
|
||||
@@ -161,6 +177,30 @@ void d3d9exhook_config_gfx_get(
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
|
||||
&config_gfx->window_x,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_X_KEY,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_X_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
|
||||
&config_gfx->window_y,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
D3D9EXHOOK_CONFIG_GFX_WINDOW_Y_KEY,
|
||||
D3D9EXHOOK_CONFIG_GFX_DEFAULT_WINDOW_Y_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
D3D9EXHOOK_CONFIG_GFX_FORCED_REFRESHRATE_KEY,
|
||||
|
||||
@@ -15,6 +15,8 @@ struct d3d9exhook_config_gfx {
|
||||
bool confined;
|
||||
int32_t window_width;
|
||||
int32_t window_height;
|
||||
int32_t window_x;
|
||||
int32_t window_y;
|
||||
int32_t forced_refresh_rate;
|
||||
int32_t device_adapter;
|
||||
int32_t force_orientation;
|
||||
|
||||
@@ -45,6 +45,18 @@ static HRESULT STDCALL my_CreateDeviceEx(
|
||||
D3DDISPLAYMODEEX *fdm,
|
||||
IDirect3DDevice9Ex **pdev);
|
||||
|
||||
static HRESULT STDCALL my_EnumAdapterModes(
|
||||
IDirect3D9Ex *self,
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE *pMode);
|
||||
|
||||
static UINT STDCALL my_GetAdapterModeCount(
|
||||
IDirect3D9Ex *self,
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format);
|
||||
|
||||
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api);
|
||||
|
||||
static WNDPROC real_WndProc;
|
||||
@@ -88,12 +100,25 @@ static bool d3d9ex_confined;
|
||||
static int32_t d3d9ex_force_refresh_rate = -1;
|
||||
static int32_t d3d9ex_window_width = -1;
|
||||
static int32_t d3d9ex_window_height = -1;
|
||||
static int32_t d3d9ex_window_x = -1;
|
||||
static int32_t d3d9ex_window_y = -1;
|
||||
static bool d3d9ex_window_framed;
|
||||
static int32_t d3d9ex_device_adapter = -1;
|
||||
static int32_t d3d9ex_force_orientation = -1;
|
||||
static int32_t d3d9ex_force_screen_res_width = -1;
|
||||
static int32_t d3d9ex_force_screen_res_height = -1;
|
||||
|
||||
static bool check_d3d9ex_force_enum()
|
||||
{
|
||||
if (d3d9ex_force_refresh_rate != -1 &&
|
||||
d3d9ex_force_screen_res_width != -1 &&
|
||||
d3d9ex_force_screen_res_height != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static const struct hook_symbol d3d9ex_hook_syms[] = {
|
||||
@@ -130,11 +155,16 @@ static HWND STDCALL my_CreateWindowExA(
|
||||
HINSTANCE hInstance,
|
||||
LPVOID lpParam)
|
||||
{
|
||||
if (d3d9ex_windowed && d3d9ex_window_framed) {
|
||||
/* use a different style */
|
||||
dwStyle |= WS_OVERLAPPEDWINDOW;
|
||||
/* also show mouse cursor */
|
||||
ShowCursor(TRUE);
|
||||
if (d3d9ex_windowed) {
|
||||
if (d3d9ex_window_framed) {
|
||||
/* use a different style */
|
||||
dwStyle |= WS_OVERLAPPEDWINDOW;
|
||||
/* also show mouse cursor */
|
||||
ShowCursor(TRUE);
|
||||
} else {
|
||||
dwStyle = dwStyle & ~WS_OVERLAPPEDWINDOW;
|
||||
ShowCursor(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
HWND hwnd = real_CreateWindowExA(
|
||||
@@ -157,11 +187,7 @@ static HWND STDCALL my_CreateWindowExA(
|
||||
static BOOL STDCALL
|
||||
my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
|
||||
{
|
||||
if (d3d9ex_windowed && d3d9ex_window_framed) {
|
||||
/* we have to adjust the window size, because the window needs to be a
|
||||
slightly bigger than the rendering resolution (window caption and
|
||||
stuff is included in the window size) */
|
||||
|
||||
if (d3d9ex_windowed) {
|
||||
if (d3d9ex_window_width != -1 && d3d9ex_window_height != -1) {
|
||||
log_misc(
|
||||
"Overriding window size from %dx%d with %dx%d",
|
||||
@@ -173,14 +199,31 @@ my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
|
||||
nWidth = d3d9ex_window_width;
|
||||
nHeight = d3d9ex_window_height;
|
||||
}
|
||||
if (d3d9ex_window_x != -1 && d3d9ex_window_y != -1) {
|
||||
log_misc(
|
||||
"Overriding window position from %dx%d with %dx%d",
|
||||
X,
|
||||
Y,
|
||||
d3d9ex_window_x,
|
||||
d3d9ex_window_y);
|
||||
|
||||
WINDOWPOS wp;
|
||||
calc_win_size_with_framed(hWnd, X, Y, nWidth, nHeight, &wp);
|
||||
SetWindowPos(hWnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
|
||||
X = wp.x;
|
||||
Y = wp.y;
|
||||
nWidth = wp.cx;
|
||||
nHeight = wp.cy;
|
||||
X = d3d9ex_window_x;
|
||||
Y = d3d9ex_window_y;
|
||||
}
|
||||
|
||||
if (d3d9ex_window_framed) {
|
||||
/* we have to adjust the window size, because the window needs to
|
||||
be a slightly bigger than the rendering resolution (window caption
|
||||
and stuff is included in the window size) */
|
||||
|
||||
WINDOWPOS wp;
|
||||
calc_win_size_with_framed(hWnd, X, Y, nWidth, nHeight, &wp);
|
||||
SetWindowPos(hWnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
|
||||
X = wp.x;
|
||||
Y = wp.y;
|
||||
nWidth = wp.cx;
|
||||
nHeight = wp.cy;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL result = real_MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
|
||||
@@ -392,6 +435,54 @@ static HRESULT STDCALL my_CreateDeviceEx(
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT STDCALL my_EnumAdapterModes(
|
||||
IDirect3D9Ex *self,
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE *pMode)
|
||||
{
|
||||
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
|
||||
HRESULT hr;
|
||||
|
||||
if (d3d9ex_device_adapter>= 0) {
|
||||
Adapter = d3d9ex_device_adapter;
|
||||
}
|
||||
|
||||
hr = IDirect3D9Ex_EnumAdapterModes(real, Adapter, Format, Mode, pMode);
|
||||
|
||||
if (check_d3d9ex_force_enum()) {
|
||||
log_info("EnumAdapterModes: Forcing mode");
|
||||
pMode->Width = d3d9ex_force_screen_res_width;
|
||||
pMode->Height = d3d9ex_force_screen_res_height;
|
||||
pMode->RefreshRate = d3d9ex_force_refresh_rate;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static UINT STDCALL my_GetAdapterModeCount(
|
||||
IDirect3D9Ex *self,
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format)
|
||||
{
|
||||
IDirect3D9Ex *real = com_proxy_downcast(self)->real;
|
||||
UINT res;
|
||||
|
||||
if (d3d9ex_device_adapter>= 0) {
|
||||
Adapter = d3d9ex_device_adapter;
|
||||
}
|
||||
|
||||
res = IDirect3D9Ex_GetAdapterModeCount(real, Adapter, Format);
|
||||
|
||||
if (check_d3d9ex_force_enum()) {
|
||||
log_info("GetAdapterModeCount: Forcing single return");
|
||||
res = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
|
||||
{
|
||||
HRESULT hr;
|
||||
@@ -414,6 +505,8 @@ static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
|
||||
api_vtbl = api_proxy->vptr;
|
||||
|
||||
api_vtbl->CreateDeviceEx = my_CreateDeviceEx;
|
||||
api_vtbl->EnumAdapterModes = my_EnumAdapterModes;
|
||||
api_vtbl->GetAdapterModeCount = my_GetAdapterModeCount;
|
||||
|
||||
*api = (IDirect3D9Ex *) api_proxy;
|
||||
|
||||
@@ -451,6 +544,8 @@ void d3d9ex_configure(struct d3d9exhook_config_gfx *gfx_config)
|
||||
d3d9ex_window_framed = gfx_config->framed;
|
||||
d3d9ex_window_width = gfx_config->window_width;
|
||||
d3d9ex_window_height = gfx_config->window_height;
|
||||
d3d9ex_window_x = gfx_config->window_x;
|
||||
d3d9ex_window_y = gfx_config->window_y;
|
||||
|
||||
d3d9ex_force_refresh_rate = gfx_config->forced_refresh_rate;
|
||||
d3d9ex_device_adapter = gfx_config->device_adapter;
|
||||
|
||||
13
src/main/ddrhook-util/Module.mk
Normal file
13
src/main/ddrhook-util/Module.mk
Normal file
@@ -0,0 +1,13 @@
|
||||
libs += ddrhook-util
|
||||
|
||||
libs_ddrhook-util := \
|
||||
hook \
|
||||
hooklib \
|
||||
util \
|
||||
|
||||
src_ddrhook-util := \
|
||||
dinput.c \
|
||||
gfx.c \
|
||||
guid.c \
|
||||
misc.c \
|
||||
monitor.c \
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <initguid.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "ddrhook/monitor.h"
|
||||
#include "ddrhook-util/monitor.h"
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ddrhook/gfx.h"
|
||||
#include "ddrhook-util/gfx.h"
|
||||
|
||||
#include "hook/pe.h"
|
||||
#include "hook/table.h"
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "ddrhook/monitor.h"
|
||||
#include "ddrhook-util/monitor.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
@@ -5,6 +5,7 @@ deplibs_ddrhook := \
|
||||
|
||||
libs_ddrhook := \
|
||||
acioemu \
|
||||
ddrhook-util \
|
||||
p3ioemu \
|
||||
p3io \
|
||||
hook \
|
||||
@@ -17,12 +18,7 @@ src_ddrhook := \
|
||||
extio.c \
|
||||
dllmain.c \
|
||||
_com4.c \
|
||||
dinput.c \
|
||||
gfx.c \
|
||||
guid.c \
|
||||
master.c \
|
||||
misc.c \
|
||||
monitor.c \
|
||||
p3io.c \
|
||||
usbmem.c \
|
||||
spike.c
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
#include "bemanitools/ddrio.h"
|
||||
#include "bemanitools/eamio.h"
|
||||
|
||||
#include "ddrhook-util/gfx.h"
|
||||
|
||||
#include "ddrhook/_com4.h"
|
||||
#include "ddrhook/extio.h"
|
||||
#include "ddrhook/gfx.h"
|
||||
#include "ddrhook/master.h"
|
||||
#include "ddrhook/p3io.h"
|
||||
#include "ddrhook/spike.h"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "ddrhook/master.h"
|
||||
#include "ddrhook/dinput.h"
|
||||
#include "ddrhook/gfx.h"
|
||||
#include "ddrhook/misc.h"
|
||||
#include "ddrhook/monitor.h"
|
||||
|
||||
#include "ddrhook-util/dinput.h"
|
||||
#include "ddrhook-util/gfx.h"
|
||||
#include "ddrhook-util/misc.h"
|
||||
#include "ddrhook-util/monitor.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ dlls += \
|
||||
|
||||
libs_eamio-icca := \
|
||||
aciodrv \
|
||||
aciomgr \
|
||||
cconfig \
|
||||
util \
|
||||
|
||||
src_eamio-icca := \
|
||||
config-icc.c \
|
||||
eamio-icca.c \
|
||||
|
||||
55
src/main/eamio-icca/config-icc.c
Normal file
55
src/main/eamio-icca/config-icc.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "eamio-icca/config-icc.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define EAMIO_ICCA_CONFIG_ICC_PORT_KEY "icc.port"
|
||||
#define EAMIO_ICCA_CONFIG_ICC_BAUD_KEY "icc.baud"
|
||||
|
||||
#define EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE "COM1"
|
||||
#define EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE 57600
|
||||
|
||||
void eamio_icca_config_icc_init(struct cconfig *config)
|
||||
{
|
||||
cconfig_util_set_str(
|
||||
config,
|
||||
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE,
|
||||
"ICCA serial port");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE,
|
||||
"ICCA bus baudrate (real devices expect 57600)");
|
||||
}
|
||||
|
||||
void eamio_icca_config_icc_get(
|
||||
struct icc_config *config_icc, struct cconfig *config)
|
||||
{
|
||||
if (!cconfig_util_get_str(
|
||||
config,
|
||||
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
|
||||
config_icc->port,
|
||||
sizeof(config_icc->port) - 1,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'",
|
||||
EAMIO_ICCA_CONFIG_ICC_PORT_KEY,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_PORT_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
|
||||
&config_icc->baud,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
EAMIO_ICCA_CONFIG_ICC_BAUD_KEY,
|
||||
EAMIO_ICCA_CONFIG_ICC_DEFAULT_BAUD_VALUE);
|
||||
}
|
||||
}
|
||||
18
src/main/eamio-icca/config-icc.h
Normal file
18
src/main/eamio-icca/config-icc.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef EAMIO_ICCA_CONFIG_ICC_H
|
||||
#define EAMIO_ICCA_CONFIG_ICC_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
struct icc_config {
|
||||
char port[64];
|
||||
int32_t baud;
|
||||
};
|
||||
|
||||
void eamio_icca_config_icc_init(struct cconfig *config);
|
||||
|
||||
void eamio_icca_config_icc_get(
|
||||
struct icc_config *config_icc, struct cconfig *config);
|
||||
|
||||
#endif
|
||||
@@ -8,13 +8,21 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "aciomgr/manager.h"
|
||||
#include "aciodrv/device.h"
|
||||
#include "aciodrv/icca.h"
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
|
||||
#include "cconfig/cconfig-main.h"
|
||||
#include "eamio-icca/config-icc.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define IDLE_RESPONSES_BETWEEN_FELICA_POLLS 5
|
||||
#define NUMBER_OF_EMULATED_READERS 2
|
||||
#define INVALID_NODE_ID -1
|
||||
|
||||
static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
|
||||
EAM_IO_KEYPAD_3,
|
||||
EAM_IO_KEYPAD_6,
|
||||
@@ -32,7 +40,16 @@ static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
|
||||
EAM_IO_KEYPAD_5,
|
||||
EAM_IO_KEYPAD_8};
|
||||
|
||||
static struct ac_io_icca_state eam_io_icca_state[2];
|
||||
static struct ac_io_icca_state eam_io_icca_state[NUMBER_OF_EMULATED_READERS];
|
||||
|
||||
static struct aciomgr_port_dispatcher *acio_manager_ctx;
|
||||
|
||||
static int32_t icca_node_id[NUMBER_OF_EMULATED_READERS];
|
||||
|
||||
static bool icca_is_slotted[NUMBER_OF_EMULATED_READERS];
|
||||
|
||||
static int32_t icca_poll_counter[NUMBER_OF_EMULATED_READERS];
|
||||
static uint8_t icca_last_nonbusy_state[NUMBER_OF_EMULATED_READERS];
|
||||
|
||||
void eam_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
@@ -40,30 +57,113 @@ void eam_io_set_loggers(
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal)
|
||||
{
|
||||
aciomgr_set_loggers(misc, info, warning, fatal);
|
||||
|
||||
log_to_external(misc, info, warning, fatal);
|
||||
}
|
||||
|
||||
// all of these are referred to internally as ICCA
|
||||
static bool check_if_icca(int node_id)
|
||||
{
|
||||
char product[ACIOMGR_NODE_PRODUCT_CODE_LEN];
|
||||
aciomgr_get_node_product_ident(acio_manager_ctx, node_id, product);
|
||||
|
||||
if (!memcmp(product, "ICCA", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
|
||||
return true;
|
||||
}
|
||||
if (!memcmp(product, "ICCB", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
|
||||
return true;
|
||||
}
|
||||
if (!memcmp(product, "ICCC", ACIOMGR_NODE_PRODUCT_CODE_LEN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eam_io_init(
|
||||
thread_create_t create, thread_join_t join, thread_destroy_t destroy)
|
||||
{
|
||||
if (!aciodrv_device_open("COM1", 57600)) {
|
||||
log_warning("Opening acio device on COM1 failed");
|
||||
struct cconfig *config;
|
||||
struct icc_config config_icc;
|
||||
|
||||
config = cconfig_init();
|
||||
|
||||
eamio_icca_config_icc_init(config);
|
||||
|
||||
if (!cconfig_main_config_init(
|
||||
config,
|
||||
"--icc-config",
|
||||
"eamio-icc.conf",
|
||||
"--help",
|
||||
"-h",
|
||||
"eamio-icca",
|
||||
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
|
||||
cconfig_finit(config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
eamio_icca_config_icc_get(&config_icc, config);
|
||||
|
||||
cconfig_finit(config);
|
||||
|
||||
acio_manager_ctx = aciomgr_port_init(config_icc.port, config_icc.baud);
|
||||
|
||||
if (acio_manager_ctx == NULL) {
|
||||
log_warning("Opening acio device on %s failed", config_icc.port);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
if (!aciodrv_icca_init(i)) {
|
||||
log_warning("Initializing icca %d failed", i);
|
||||
return false;
|
||||
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
|
||||
|
||||
for (uint8_t i = 0; i < NUMBER_OF_EMULATED_READERS; i++) {
|
||||
icca_node_id[i] = INVALID_NODE_ID;
|
||||
|
||||
for (uint8_t nid = 0; nid < aciomgr_get_node_count(acio_manager_ctx); ++nid) {
|
||||
if (check_if_icca(nid)) {
|
||||
bool existing_reader = false;
|
||||
|
||||
for (uint8_t j = 0; j < i; j++) {
|
||||
if (nid == icca_node_id[j]) {
|
||||
existing_reader = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing_reader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
icca_node_id[i] = nid;
|
||||
icca_poll_counter[i] = 0;
|
||||
icca_is_slotted[i] = aciodrv_icca_is_slotted(device, nid);
|
||||
icca_last_nonbusy_state[i] = 0;
|
||||
|
||||
log_misc("ICC reader %d is_slotted: %d", nid, icca_is_slotted[i]);
|
||||
|
||||
if (!aciodrv_icca_init(device, icca_node_id[i])) {
|
||||
log_warning("Initializing icca %d failed", i);
|
||||
icca_node_id[i] = INVALID_NODE_ID;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (icca_node_id[0] == INVALID_NODE_ID) {
|
||||
log_warning("No ICC readers detected");
|
||||
return false;
|
||||
}
|
||||
|
||||
aciomgr_port_checkin(acio_manager_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void eam_io_fini(void)
|
||||
{
|
||||
aciodrv_device_close();
|
||||
aciomgr_port_fini(acio_manager_ctx);
|
||||
}
|
||||
|
||||
uint16_t eam_io_get_keypad_state(uint8_t unit_no)
|
||||
@@ -85,13 +185,31 @@ uint8_t eam_io_get_sensor_state(uint8_t unit_no)
|
||||
{
|
||||
uint8_t sensors = 0;
|
||||
|
||||
if ((eam_io_icca_state[unit_no].sensor_state &
|
||||
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
|
||||
sensors |= (1 << EAM_IO_SENSOR_BACK);
|
||||
}
|
||||
if ((eam_io_icca_state[unit_no].sensor_state &
|
||||
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
|
||||
sensors |= (1 << EAM_IO_SENSOR_FRONT);
|
||||
if (icca_is_slotted[unit_no]) {
|
||||
if ((eam_io_icca_state[unit_no].sensor_state &
|
||||
AC_IO_ICCA_SENSOR_MASK_BACK_ON) > 0) {
|
||||
sensors |= (1 << EAM_IO_SENSOR_BACK);
|
||||
}
|
||||
if ((eam_io_icca_state[unit_no].sensor_state &
|
||||
AC_IO_ICCA_SENSOR_MASK_FRONT_ON) > 0) {
|
||||
sensors |= (1 << EAM_IO_SENSOR_FRONT);
|
||||
}
|
||||
} else {
|
||||
// wavepass readers always report (EAM_IO_SENSOR_BACK + EAM_IO_SENSOR_FRONT) + type
|
||||
// but because we can't report status_code back directly
|
||||
// and libacio actually just ignores the sensor_state other then the type
|
||||
// we just return this state like we're a slotted reader so the emulation takes card of it
|
||||
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_GOT_UID) {
|
||||
sensors |= (1 << EAM_IO_SENSOR_BACK);
|
||||
sensors |= (1 << EAM_IO_SENSOR_FRONT);
|
||||
}
|
||||
|
||||
// continue reporting last state during busy
|
||||
if (eam_io_icca_state[unit_no].status_code == AC_IO_ICCA_STATUS_BUSY_NEW) {
|
||||
sensors = icca_last_nonbusy_state[unit_no];
|
||||
} else {
|
||||
icca_last_nonbusy_state[unit_no] = sensors;
|
||||
}
|
||||
}
|
||||
|
||||
return sensors;
|
||||
@@ -109,33 +227,78 @@ uint8_t eam_io_read_card(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes)
|
||||
|
||||
bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd)
|
||||
{
|
||||
// this node is not setup, just return "success""
|
||||
if (icca_node_id[unit_no] == INVALID_NODE_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ignore these for wavepass
|
||||
if (!icca_is_slotted[unit_no]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
|
||||
|
||||
bool response = false;
|
||||
switch (cmd) {
|
||||
case EAM_IO_CARD_SLOT_CMD_CLOSE:
|
||||
return aciodrv_icca_set_state(
|
||||
unit_no, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
|
||||
response = aciodrv_icca_set_state(
|
||||
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
|
||||
|
||||
case EAM_IO_CARD_SLOT_CMD_OPEN:
|
||||
return aciodrv_icca_set_state(
|
||||
unit_no, AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
|
||||
response = aciodrv_icca_set_state(
|
||||
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
|
||||
|
||||
case EAM_IO_CARD_SLOT_CMD_EJECT:
|
||||
return aciodrv_icca_set_state(
|
||||
unit_no, AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
|
||||
response = aciodrv_icca_set_state(
|
||||
device, icca_node_id[unit_no], AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
|
||||
|
||||
case EAM_IO_CARD_SLOT_CMD_READ:
|
||||
return aciodrv_icca_read_card(unit_no, NULL) &&
|
||||
aciodrv_icca_get_state(unit_no, &eam_io_icca_state[unit_no]);
|
||||
response = aciodrv_icca_read_card(device, icca_node_id[unit_no], NULL) &&
|
||||
aciodrv_icca_get_state(
|
||||
device, icca_node_id[unit_no], &eam_io_icca_state[unit_no]);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
aciomgr_port_checkin(acio_manager_ctx);
|
||||
|
||||
return false;
|
||||
return response;
|
||||
}
|
||||
|
||||
bool eam_io_poll(uint8_t unit_no)
|
||||
{
|
||||
return aciodrv_icca_get_state(unit_no, &eam_io_icca_state[unit_no]);
|
||||
// this node is not setup, just return "success""
|
||||
if (icca_node_id[unit_no] == INVALID_NODE_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool response = aciodrv_icca_get_state(
|
||||
aciomgr_port_checkout(acio_manager_ctx),
|
||||
icca_node_id[unit_no],
|
||||
&eam_io_icca_state[unit_no]);
|
||||
aciomgr_port_checkin(acio_manager_ctx);
|
||||
|
||||
if (response && !icca_is_slotted[unit_no]) {
|
||||
// we handle wavepass a bit differently to handle polling felica
|
||||
if (eam_io_icca_state[unit_no].status_code != AC_IO_ICCA_STATUS_BUSY_NEW) {
|
||||
++icca_poll_counter[unit_no];
|
||||
}
|
||||
|
||||
// we must manually call this every few polls to actually update the felica state
|
||||
// we don't do it every poll, since card polling isn't that time sensitive of an operation
|
||||
// libacio does it every 5ish polls after the last AC_IO_ICCA_STATUS_BUSY_NEW message
|
||||
if (icca_poll_counter[unit_no] >= IDLE_RESPONSES_BETWEEN_FELICA_POLLS) {
|
||||
response = aciodrv_icca_poll_felica(
|
||||
aciomgr_port_checkout(acio_manager_ctx),
|
||||
icca_node_id[unit_no]);
|
||||
aciomgr_port_checkin(acio_manager_ctx);
|
||||
|
||||
icca_poll_counter[unit_no] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
const struct eam_io_config_api *eam_io_get_config_api(void)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
log_to_writer(log_writer_stdout, NULL);
|
||||
|
||||
eam_io_set_loggers(
|
||||
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
|
||||
|
||||
|
||||
@@ -25,16 +25,11 @@ struct file_entry {
|
||||
static struct array hooked_files;
|
||||
static CRITICAL_SECTION hooked_files_cs;
|
||||
|
||||
|
||||
BOOL my_GetFileInformationByHandle(
|
||||
HANDLE hFile,
|
||||
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
|
||||
);
|
||||
HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
|
||||
|
||||
BOOL (*real_GetFileInformationByHandle)(
|
||||
HANDLE hFile,
|
||||
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
|
||||
);
|
||||
BOOL (*real_GetFileInformationByHandle)
|
||||
(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
|
||||
|
||||
static const struct hook_symbol memfile_hook_kernel32_syms[] = {
|
||||
{.name = "GetFileInformationByHandle",
|
||||
@@ -42,7 +37,6 @@ static const struct hook_symbol memfile_hook_kernel32_syms[] = {
|
||||
.link = (void **) &real_GetFileInformationByHandle},
|
||||
};
|
||||
|
||||
|
||||
void memfile_hook_init(void)
|
||||
{
|
||||
array_init(&hooked_files);
|
||||
@@ -82,7 +76,10 @@ void memfile_hook_fini(void)
|
||||
}
|
||||
|
||||
void memfile_hook_add_fd(
|
||||
const char *path, enum memfile_hook_path_mode path_mode, const void *data, uint32_t sz)
|
||||
const char *path,
|
||||
enum memfile_hook_path_mode path_mode,
|
||||
const void *data,
|
||||
uint32_t sz)
|
||||
{
|
||||
log_assert(path != NULL);
|
||||
|
||||
@@ -110,7 +107,11 @@ void memfile_hook_add_fd(
|
||||
|
||||
LeaveCriticalSection(&hooked_files_cs);
|
||||
|
||||
log_misc("memfile_hook_add_fd: path %s, mode %d, data size %d", path, path_mode, sz);
|
||||
log_misc(
|
||||
"memfile_hook_add_fd: path %s, mode %d, data size %d",
|
||||
path,
|
||||
path_mode,
|
||||
sz);
|
||||
}
|
||||
|
||||
static struct file_entry *memfile_hook_match_irp(const struct irp *irp)
|
||||
@@ -155,7 +156,10 @@ static HRESULT memfile_hook_irp_read(struct file_entry *entry, struct irp *irp)
|
||||
size_t nread = min(entry->sz - entry->pos, irp->read.nbytes);
|
||||
|
||||
if (nread > 0) {
|
||||
memcpy(irp->read.bytes + irp->read.pos, (uint8_t*)entry->data + entry->pos, nread);
|
||||
memcpy(
|
||||
irp->read.bytes + irp->read.pos,
|
||||
(uint8_t *) entry->data + entry->pos,
|
||||
nread);
|
||||
|
||||
entry->pos += nread;
|
||||
irp->read.pos += nread;
|
||||
@@ -248,9 +252,7 @@ HRESULT memfile_hook_dispatch_irp(struct irp *irp)
|
||||
|
||||
// this isn't a standard iohook IRP atm.
|
||||
BOOL my_GetFileInformationByHandle(
|
||||
HANDLE hFile,
|
||||
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
|
||||
)
|
||||
HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
|
||||
{
|
||||
struct file_entry *entry;
|
||||
for (size_t i = 0; i < hooked_files.nitems; i++) {
|
||||
|
||||
@@ -32,7 +32,10 @@ enum memfile_hook_path_mode {
|
||||
* @param sz size of file
|
||||
*/
|
||||
void memfile_hook_add_fd(
|
||||
const char *path, enum memfile_hook_path_mode path_mode, const void *data, uint32_t sz);
|
||||
const char *path,
|
||||
enum memfile_hook_path_mode path_mode,
|
||||
const void *data,
|
||||
uint32_t sz);
|
||||
|
||||
/**
|
||||
* iohook dispatch function. Needs to be installed.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user