gamebridge: implement simple protocol

This commit is contained in:
Cadey Ratio 2020-05-08 17:54:57 -04:00
parent 7be9a1aef6
commit a8ecacd2ca
8 changed files with 248 additions and 9 deletions

4
.gitignore vendored
View File

@ -71,3 +71,7 @@ sm64config.txt
!/sound/**/*custom*/**/*.aiff
!/assets/**/*custom*.bin
!/assets/**/*custom*/**/*.bin
/target
vblank
input

183
Cargo.lock generated Normal file
View File

@ -0,0 +1,183 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "gamebridge"
version = "0.1.0"
dependencies = [
"anyhow",
"log",
"pretty_env_logger",
]
[[package]]
name = "hermit-abi"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
dependencies = [
"env_logger",
"log",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "regex"
version = "1.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

2
Cargo.toml Normal file
View File

@ -0,0 +1,2 @@
[workspace]
members = [ "./gamebridge" ]

View File

@ -38,10 +38,13 @@ write mode when it starts. The bridge will open this fifo in read mode.
The second one will be called =input= and will be opened by the game in read
mode. The bridge will open this fifo in write mode.
On every frame, the game will write the text ="OK\n"= to the vblank fifo. This
will signal the bridge that it should write four bytes of data to the input
On every frame, the game *MUST* write the text ="OK\n"= to the vblank fifo. This
will signal the bridge that it *MUST* write four bytes of data to the input
fifo, conforming to the [[http://tasvideos.org/EmulatorResources/Mupen/M64.html#ControllerData][Controller Data]] specification of the Mupen64 format.
This data will be interpreted by the game as actions for Mario to take.
The bridge *MUST* block on waiting for the vblank fifo to be written to by the
game and the game *MUST* block on the input fifo being written to by the bridge.
When the game is exiting, the game *SHOULD* write ="BYE"= to the vblank fifo.
When the bridge recieves a ="BYE"= message, it *MUST* exit.

View File

@ -7,3 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0"
log = "0.4"
pretty_env_logger = "0.4"

View File

@ -1,3 +1,29 @@
fn main() {
println!("Hello, world!");
use log::{debug, info, warn};
use std::{
fs::{File, OpenOptions},
io::{Read, Write},
str::from_utf8,
};
fn main() -> anyhow::Result<()> {
pretty_env_logger::try_init()?;
let controller_data = [0; 4];
let mut vblank = File::open("vblank")?;
let mut input = OpenOptions::new().write(true).open("input")?;
info!("[gamebridge::rust] ready");
loop {
let mut data = [0; 3];
info!("waiting for vblank");
vblank.read(&mut data)?;
let str = from_utf8(&data)?;
debug!("got data: {}", str);
if str == "BYE" {
warn!("asked to exit by the game");
return Ok(());
}
input.write(&controller_data)?;
}
}

View File

@ -21,10 +21,12 @@ in pkgs.mkShell {
# build tools
gnumake
clang_10
gdb
# gamebridge
rustc
cargo
rls
rustfmt
];
}

View File

@ -17,12 +17,21 @@ static FILE *input;
#define vblank_fname "vblank"
#define input_fname "input"
#define ok "OK\n"
#define bye "BYE"
static void gamebridge_close(void) {
fwrite(bye, 1, strlen(bye), vblank);
}
static void gamebridge_init(void) {
if (!configGameBridge) {
return;
}
printf("[gamebridge] starting...\n");
fflush(stdout);
unlink(vblank_fname);
unlink(input_fname);
@ -40,13 +49,18 @@ static void gamebridge_init(void) {
assert(result < 0);
}
vblank = fopen(vblank_fname, "w");
input = fopen(input_fname, "rb");
vblank = fopen(vblank_fname, "w+");
input = fopen(input_fname, "rb+");
assert(vblank);
assert(input);
setvbuf(vblank, NULL, _IONBF, 0);
setvbuf(input, NULL, _IONBF, 0);
printf("[gamebridge] starting rust daemon\n");
fflush(stdout);
system("./target/debug/gamebridge &");
atexit(gamebridge_close);
}
static void gamebridge_read(OSContPad *pad) {
@ -54,13 +68,15 @@ static void gamebridge_read(OSContPad *pad) {
return;
}
char* ok = "OK\n";
fwrite(ok, 1, sizeof(ok), vblank);
printf("[gamebridge] waiting for input\n");
fwrite(ok, 1, strlen(ok), vblank);
uint8_t bytes[4] = {0};
fread(bytes, 1, 4, input);
pad->button = (bytes[0] << 8) | bytes[1];
pad->stick_x = bytes[2];
pad->stick_y = bytes[3];
printf("[gamebridge] %02x%02x %02x%02x\n", bytes[0], bytes[1], bytes[2], bytes[3]);
fflush(stdout);
}
struct ControllerAPI controller_gamebridge = {