gamebridge: implement simple protocol
This commit is contained in:
parent
7be9a1aef6
commit
a8ecacd2ca
|
@ -71,3 +71,7 @@ sm64config.txt
|
|||
!/sound/**/*custom*/**/*.aiff
|
||||
!/assets/**/*custom*.bin
|
||||
!/assets/**/*custom*/**/*.bin
|
||||
|
||||
/target
|
||||
vblank
|
||||
input
|
||||
|
|
|
@ -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"
|
|
@ -0,0 +1,2 @@
|
|||
[workspace]
|
||||
members = [ "./gamebridge" ]
|
|
@ -30,7 +30,7 @@ The protocol between the game and the bridge will be as follows (based on the
|
|||
|
||||
The game and the bridge will both need to take care that the files are opened in
|
||||
*unbuffered I/O modes*. This can be done with
|
||||
=setvbuf( f, (char *)NULL, _IONBF, 0 );= in C and is the default in Rust.
|
||||
=setvbuf(f, (char *)NULL, _IONBF, 0);= in C and is the default in Rust.
|
||||
|
||||
The first one will be called =vblank= and will then be opened by the game in
|
||||
write mode when it starts. The bridge will open this fifo in read mode.
|
||||
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ in pkgs.mkShell {
|
|||
# build tools
|
||||
gnumake
|
||||
clang_10
|
||||
gdb
|
||||
|
||||
# gamebridge
|
||||
rustc
|
||||
cargo
|
||||
rls
|
||||
rustfmt
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in New Issue