gamebridge: Twitch Control #2
|
@ -26,6 +26,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -50,6 +56,7 @@ name = "gamebridge"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"bitflags",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,5 +8,6 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
bitflags = "1.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
bitflags! {
|
||||||
|
// 0x0100 Digital Pad Right
|
||||||
|
// 0x0200 Digital Pad Left
|
||||||
|
// 0x0400 Digital Pad Down
|
||||||
|
// 0x0800 Digital Pad Up
|
||||||
|
// 0x1000 Start
|
||||||
|
// 0x2000 Z
|
||||||
|
// 0x4000 B
|
||||||
|
// 0x8000 A
|
||||||
|
pub(crate) struct HiButtons: u8 {
|
||||||
|
const NONE = 0x00;
|
||||||
|
const DPAD_RIGHT = 0x01;
|
||||||
|
const DPAD_LEFT = 0x02;
|
||||||
|
const DPAD_DOWN = 0x04;
|
||||||
|
const DPAD_UP = 0x08;
|
||||||
|
const START = 0x10;
|
||||||
|
const Z_BUTTON = 0x20;
|
||||||
|
const B_BUTTON = 0x40;
|
||||||
|
const A_BUTTON = 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HiButtons {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.bits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
// 0x0001 C-Right
|
||||||
|
// 0x0002 C-Left
|
||||||
|
// 0x0004 C-Down
|
||||||
|
// 0x0008 C-Up
|
||||||
|
// 0x0010 R
|
||||||
|
// 0x0020 L
|
||||||
|
// 0x0040 (reserved)
|
||||||
|
// 0x0080 (reserved)
|
||||||
|
pub(crate) struct LoButtons: u8 {
|
||||||
|
const NONE = 0x00;
|
||||||
|
const C_RIGHT = 0x01;
|
||||||
|
const C_LEFT = 0x02;
|
||||||
|
const C_DOWN = 0x04;
|
||||||
|
const C_UP = 0x08;
|
||||||
|
const R_BUTTON = 0x10;
|
||||||
|
const L_BUTTON = 0x20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoButtons {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.bits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn test(st: crate::MTState) {
|
||||||
|
let mut lo: LoButtons = LoButtons::NONE;
|
||||||
|
let mut hi: HiButtons = HiButtons::NONE;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
use std::{thread::sleep, time::Duration};
|
||||||
|
let one_second = Duration::new(1, 0);
|
||||||
|
|
||||||
|
hi = HiButtons::A_BUTTON | HiButtons::START;
|
||||||
|
|
||||||
|
{
|
||||||
|
println!("pressing a + start");
|
||||||
|
let mut data = st.write().unwrap();
|
||||||
|
data.controller[0] = hi.bits as u8;
|
||||||
|
data.controller[1] = lo.bits as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(one_second);
|
||||||
|
|
||||||
|
hi.clear();
|
||||||
|
lo.clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
println!("releasing a + start");
|
||||||
|
let mut data = st.write().unwrap();
|
||||||
|
data.controller[0] = hi.bits as u8;
|
||||||
|
data.controller[1] = lo.bits as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(one_second);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,51 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
|
||||||
|
pub(crate) mod controller;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
str::from_utf8,
|
str::from_utf8,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
thread::spawn,
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct State {
|
||||||
|
controller: [u8; 4],
|
||||||
|
last_got: Box<Instant>,
|
||||||
|
ok: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type MTState = Arc<RwLock<State>>;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
pretty_env_logger::try_init()?;
|
pretty_env_logger::try_init()?;
|
||||||
let mut controller_data = [0; 4];
|
|
||||||
|
|
||||||
let mut vblank = File::open("vblank")?;
|
let mut vblank = File::open("vblank")?;
|
||||||
let mut input = OpenOptions::new().write(true).open("input")?;
|
let mut input = OpenOptions::new().write(true).open("input")?;
|
||||||
|
|
||||||
|
let st = {
|
||||||
|
let st = State {
|
||||||
|
controller: [0; 4],
|
||||||
|
last_got: Box::new(Instant::now()),
|
||||||
|
ok: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Arc::new(RwLock::new(st))
|
||||||
|
};
|
||||||
|
|
||||||
info!("ready");
|
info!("ready");
|
||||||
|
|
||||||
|
{
|
||||||
|
let st = st.clone();
|
||||||
|
spawn(move || controller::test(st));
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut data = [0; 3];
|
let mut data = [0; 3];
|
||||||
debug!("waiting for vblank");
|
debug!("waiting for vblank");
|
||||||
|
@ -23,11 +54,14 @@ fn main() -> Result<()> {
|
||||||
debug!("got data: {}", str);
|
debug!("got data: {}", str);
|
||||||
|
|
||||||
match str {
|
match str {
|
||||||
"OK\n" => input.write(&controller_data)?,
|
"OK\n" => {
|
||||||
|
let data = st.read().unwrap();
|
||||||
|
input.write(&data.controller)?
|
||||||
|
}
|
||||||
"BYE" => {
|
"BYE" => {
|
||||||
warn!("asked to exit by the game");
|
warn!("asked to exit by the game");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("got unknown FIFO data {}", str);
|
error!("got unknown FIFO data {}", str);
|
||||||
return Err(anyhow!("unknown FIFO data received"));
|
return Err(anyhow!("unknown FIFO data received"));
|
||||||
|
|
Loading…
Reference in New Issue