Files
oc2r-rust/crates/opencomputers/examples/redstone-events.rs
2025-11-01 21:48:21 +01:00

75 lines
2.3 KiB
Rust

use oc2r_core::{DEFAULT_DEVICE_PATH, DeviceBus, EventLoop, JsonValueExt, Result};
use opencomputers::RedstoneInterface;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
static RUNNING: AtomicBool = AtomicBool::new(true);
fn main() -> Result<()> {
install_ctrl_c_handler()?;
let mut bus = DeviceBus::connect(DEFAULT_DEVICE_PATH)?;
let mut redstone = RedstoneInterface::attach(&mut bus)?.expect("no redstone interface");
while redstone.try_event()?.is_some() {}
redstone.subscribe()?;
drop(redstone);
let mut events = EventLoop::new(&mut bus);
println!("Listening for redstone events. Press Ctrl+C to exit.");
while RUNNING.load(Ordering::SeqCst) {
let Some(signal) = events.pull_filtered(Some(Duration::from_millis(250)), |signal| {
signal.name() == "redstone"
})?
else {
continue;
};
let args = signal.args();
let device_id = args
.first()
.cloned()
.and_then(|value| value.into_string("redstone device").ok())
.unwrap_or_else(|| "<unknown>".into());
let side = args
.get(1)
.cloned()
.and_then(|value| value.into_string("redstone side").ok())
.unwrap_or_else(|| "?".into());
let level = args
.get(2)
.cloned()
.and_then(|value| value.into_i64("redstone level").ok())
.unwrap_or(-1);
println!("{device_id} {side} -> {level}");
}
while events.pull_timeout(Duration::from_millis(0))?.is_some() {}
let mut redstone = RedstoneInterface::attach(&mut bus)?.expect("redstone interface detached");
while redstone.try_event()?.is_some() {}
redstone.unsubscribe()?;
println!("Exited cleanly.");
Ok(())
}
fn install_ctrl_c_handler() -> Result<()> {
unsafe {
let mut action: libc::sigaction = std::mem::zeroed();
action.sa_flags = libc::SA_RESTART;
action.sa_sigaction = handle_sigint as usize;
libc::sigemptyset(&raw mut action.sa_mask);
if libc::sigaction(libc::SIGINT, &raw const action, std::ptr::null_mut()) != 0 {
return Err(std::io::Error::last_os_error().into());
}
}
Ok(())
}
extern "C" fn handle_sigint(_: libc::c_int) {
RUNNING.store(false, Ordering::SeqCst);
}