From 4a56e7d1ddea5bc67c5ad3786b9a5339b17b01b1 Mon Sep 17 00:00:00 2001 From: Avii Date: Thu, 12 Feb 2026 14:34:21 +0100 Subject: [PATCH] I can haz Lua? --- Cargo.lock | 120 ++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- driver/src/lib.rs | 13 +++-- g13-os/Cargo.toml | 9 ++++ g13-os/src/main.rs | 87 +++++++++++++++++++++++++++++++ joystick/src/main.rs | 25 +++++++-- scripts/main.luau | 43 ++++++++++++++++ 7 files changed, 288 insertions(+), 13 deletions(-) create mode 100644 g13-os/Cargo.toml create mode 100644 g13-os/src/main.rs create mode 100644 scripts/main.luau diff --git a/Cargo.lock b/Cargo.lock index 04eba75..d06d34d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,6 +1779,16 @@ dependencies = [ "piper", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "built" version = "0.8.0" @@ -2769,6 +2779,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "g13-os" +version = "0.1.0" +dependencies = [ + "embedded-graphics", + "g13-driver", + "mlua", +] + [[package]] name = "gethostname" version = "1.1.0" @@ -3428,6 +3447,15 @@ dependencies = [ "imgref", ] +[[package]] +name = "luau0-src" +version = "0.18.2+luau708" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed3214ab526e7e7b76c3f324a965d363db94a99ae67f65e67ec6fc499eb5e6d" +dependencies = [ + "cc", +] + [[package]] name = "mach2" version = "0.4.3" @@ -3528,6 +3556,55 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "mlua" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +dependencies = [ + "bstr", + "either", + "erased-serde", + "futures-util", + "libc", + "mlua-sys", + "mlua_derive", + "num-traits", + "parking_lot", + "rustc-hash 2.1.1", + "rustversion", + "serde", + "serde-value", +] + +[[package]] +name = "mlua-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" +dependencies = [ + "cc", + "cfg-if", + "libc", + "luau0-src", + "pkg-config", +] + +[[package]] +name = "mlua_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465bddde514c4eb3b50b543250e97c1d4b284fa3ef7dc0ba2992c77545dbceb2" +dependencies = [ + "itertools 0.14.0", + "once_cell", + "proc-macro-error2", + "proc-macro2", + "quote", + "regex", + "syn", +] + [[package]] name = "moxcms" version = "0.7.11" @@ -4109,6 +4186,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-float" version = "5.0.0" @@ -4317,6 +4403,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -4775,6 +4883,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float 2.10.1", + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -5793,7 +5911,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "objc", "once_cell", - "ordered-float", + "ordered-float 5.0.0", "parking_lot", "portable-atomic", "portable-atomic-util", diff --git a/Cargo.toml b/Cargo.toml index 553f0d1..be5fcaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "3" -members = ["driver", "joystick", "mini-game"] -default-members = ["joystick", "mini-game"] +members = ["driver", "g13-os", "joystick", "mini-game"] +default-members = ["joystick", "mini-game", "g13-os"] [workspace.package] version = "0.1.0" diff --git a/driver/src/lib.rs b/driver/src/lib.rs index 63d71c8..08853d6 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -24,7 +24,7 @@ pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW; #[derive(Clone)] pub struct G13 { interface: Interface, - img_buffer: [u8; G13_LCD_BUF_SIZE as usize + 8], + img_buffer: Arc>, state: Arc>, } @@ -107,7 +107,7 @@ impl G13 { Ok(Self { interface, - img_buffer, + img_buffer: Arc::new(RwLock::new(img_buffer)), state: Arc::new(RwLock::new(Default::default())), }) } @@ -191,9 +191,11 @@ impl G13 { } pub fn render(&mut self) -> Result<(), Box> { + let img_buffer = self.img_buffer.read().expect("Poisoned"); + let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8]; buffer[0] = 0x03; - buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&self.img_buffer); + buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&(*img_buffer)); let mut w = self.interface.endpoint::(0x02)?.writer(64); w.write_all(&buffer)?; @@ -219,6 +221,7 @@ impl DrawTarget for G13 { where I: IntoIterator>, { + let mut img_buffer = self.img_buffer.write().expect("Poisoned"); for p in pixels { if p.0.x < 0 || p.0.x > G13_LCD_COLUMNS - 1 || p.0.y < 0 || p.0.y > G13_LCD_ROWS - 1 { continue; @@ -228,9 +231,9 @@ impl DrawTarget for G13 { let mask = 1 << (p.0.y.rem_euclid(8)); if p.1.is_on() { - self.img_buffer[offset as usize] |= mask; + img_buffer[offset as usize] |= mask; } else { - self.img_buffer[offset as usize] &= !mask; + img_buffer[offset as usize] &= !mask; } } diff --git a/g13-os/Cargo.toml b/g13-os/Cargo.toml new file mode 100644 index 0000000..73447ea --- /dev/null +++ b/g13-os/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "g13-os" +version.workspace = true +edition.workspace = true + +[dependencies] +g13-driver.workspace = true +embedded-graphics = "0.8" +mlua = { version = "0.11.6", features = ["luau-jit", "async", "macros", "serde"] } diff --git a/g13-os/src/main.rs b/g13-os/src/main.rs new file mode 100644 index 0000000..0d20ede --- /dev/null +++ b/g13-os/src/main.rs @@ -0,0 +1,87 @@ +use std::{ + fs, + thread::sleep, + time::{Duration, Instant}, +}; + +use g13_driver::{G13, G13_LCD_COLUMNS, G13_LCD_ROWS}; +use mlua::{ExternalResult, Lua}; + +fn main() -> Result<(), Box> { + let g13 = G13::new()?; + let lua = Lua::new(); + let globals = lua.globals(); + + let g13_table = lua.create_table()?; + + let _g13 = g13.clone(); + g13_table.set( + "set_color", + lua.create_function(move |_, (r, g, b)| _g13.set_lcd_color(r, g, b).into_lua_err())?, + )?; + + let _g13 = g13.clone(); + let fn_clear = lua.create_function(move |_, on| { + let mut _g13 = _g13.clone(); + use embedded_graphics::pixelcolor::BinaryColor; + use embedded_graphics::prelude::*; + let color = if on { + BinaryColor::On + } else { + BinaryColor::Off + }; + _g13.clear(color).into_lua_err() + }); + g13_table.set("clear", fn_clear?)?; + + let mut _g13 = g13.clone(); + let fn_set_pixel = lua.create_function_mut(move |_, (x, y, on)| { + use embedded_graphics::pixelcolor::BinaryColor; + use embedded_graphics::prelude::*; + let color = if on { + BinaryColor::On + } else { + BinaryColor::Off + }; + Pixel(Point::new(x, y), color) + .draw(&mut _g13) + .into_lua_err() + }); + g13_table.set("set_pixel", fn_set_pixel?)?; + + g13_table.set("display_width", G13_LCD_COLUMNS)?; + g13_table.set("display_height", G13_LCD_ROWS)?; + + globals.set("g13", g13_table)?; + + // load all files from dir `./scripts` for now, user configurable later or ~/.config/g13-os/*. + // for now, just main.luau + let main = fs::read_to_string("./scripts/main.luau")?; + + lua.load(main).set_name("main.luau").exec()?; + + if lua.load("setup ~= nil").eval()? { + lua.load("setup()").exec()?; + } + + if lua.load("update ~= nil").eval()? { + let mut _g13 = g13.clone(); + let mut delta: f32 = 0.0; + loop { + let start = Instant::now(); + + lua.load(format!("update({})", delta)).exec()?; + _g13.render()?; + + let duration = Instant::now() - start; + + // 30 fps lock + if duration < Duration::from_millis(33) { + sleep(Duration::from_millis(33) - duration); + } + delta = (Instant::now() - start).as_secs_f32(); + } + } + + Ok(()) +} diff --git a/joystick/src/main.rs b/joystick/src/main.rs index cbed6bd..9624996 100644 --- a/joystick/src/main.rs +++ b/joystick/src/main.rs @@ -28,7 +28,8 @@ async fn main() -> Result<(), Box> { let mut _g13 = g13.clone(); tokio::spawn(async move { - let character_style = MonoTextStyle::new(&FONT_10X20, BinaryColor::On); + let character_style_time = MonoTextStyle::new(&FONT_10X20, BinaryColor::On); + let character_style_date = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); let textstyle = TextStyleBuilder::new() .alignment(Alignment::Center) .baseline(embedded_graphics::text::Baseline::Middle) @@ -39,21 +40,35 @@ async fn main() -> Result<(), Box> { let now = OffsetDateTime::now_utc().to_offset(offset!(+1)); // GMT+1 // Render - let string = format!( + let time = format!( "{:0>2}:{:0>2}:{:0>2}", now.hour(), now.minute(), now.second() ); + let date = format!("{}, {} {}", now.weekday(), now.day(), now.month()); + _g13.clear(BinaryColor::Off).unwrap(); Text::with_text_style( - &string, + &time, Point::new( (G13_LCD_COLUMNS as f64 / 2.0) as i32, - (G13_LCD_ROWS as f64 / 2.0) as i32, + (G13_LCD_ROWS as f64 / 2.0) as i32 - 8, ), - character_style, + character_style_time, + textstyle, + ) + .draw(&mut _g13) + .unwrap(); + + Text::with_text_style( + &date, + Point::new( + (G13_LCD_COLUMNS as f64 / 2.0) as i32, + (G13_LCD_ROWS as f64 / 2.0) as i32 + 8, + ), + character_style_date, textstyle, ) .draw(&mut _g13) diff --git a/scripts/main.luau b/scripts/main.luau new file mode 100644 index 0000000..d9aa58c --- /dev/null +++ b/scripts/main.luau @@ -0,0 +1,43 @@ +name = "DVD" +authors = {"AviiNL"} +description = "Bouncing 'dvd' Logo" + +local width = g13.display_width +local height = g13.display_height + +local x = 22.0 +local y = 6.0 + +local x_direction = 1 +local y_direction = 1 + +local speed = 20 + +local size = 3 + +function update(delta: number) + x = x + speed * delta * x_direction + y = y + speed * delta * y_direction + + if x <= size or x >= width - size then + x_direction = -x_direction + end + + if y <= size or y >= height - size then + y_direction = -y_direction + end + + color_x = (x / width) * 255 + color_y = (y / height) * 255 + color_z = 255 - (color_x + color_y) / 2 + + g13.set_color(color_x/2, color_y/2, color_z/2) + + g13.clear() + + for sy = -size,size do + for sx = -size,size do + g13.set_pixel(x + sx, y + sy, true) + end + end +end