I can haz Lua?

This commit is contained in:
2026-02-12 14:34:21 +01:00
parent dcb205394d
commit 4a56e7d1dd
7 changed files with 288 additions and 13 deletions

120
Cargo.lock generated
View File

@@ -1779,6 +1779,16 @@ dependencies = [
"piper", "piper",
] ]
[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "built" name = "built"
version = "0.8.0" version = "0.8.0"
@@ -2769,6 +2779,15 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "g13-os"
version = "0.1.0"
dependencies = [
"embedded-graphics",
"g13-driver",
"mlua",
]
[[package]] [[package]]
name = "gethostname" name = "gethostname"
version = "1.1.0" version = "1.1.0"
@@ -3428,6 +3447,15 @@ dependencies = [
"imgref", "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]] [[package]]
name = "mach2" name = "mach2"
version = "0.4.3" version = "0.4.3"
@@ -3528,6 +3556,55 @@ dependencies = [
"windows-sys 0.61.2", "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]] [[package]]
name = "moxcms" name = "moxcms"
version = "0.7.11" version = "0.7.11"
@@ -4109,6 +4186,15 @@ dependencies = [
"libredox", "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]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "5.0.0" version = "5.0.0"
@@ -4317,6 +4403,28 @@ dependencies = [
"toml_edit", "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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@@ -4775,6 +4883,16 @@ dependencies = [
"serde_derive", "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]] [[package]]
name = "serde_core" name = "serde_core"
version = "1.0.228" version = "1.0.228"
@@ -5793,7 +5911,7 @@ dependencies = [
"ndk-sys 0.6.0+11769913", "ndk-sys 0.6.0+11769913",
"objc", "objc",
"once_cell", "once_cell",
"ordered-float", "ordered-float 5.0.0",
"parking_lot", "parking_lot",
"portable-atomic", "portable-atomic",
"portable-atomic-util", "portable-atomic-util",

View File

@@ -1,7 +1,7 @@
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["driver", "joystick", "mini-game"] members = ["driver", "g13-os", "joystick", "mini-game"]
default-members = ["joystick", "mini-game"] default-members = ["joystick", "mini-game", "g13-os"]
[workspace.package] [workspace.package]
version = "0.1.0" version = "0.1.0"

View File

@@ -24,7 +24,7 @@ pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW;
#[derive(Clone)] #[derive(Clone)]
pub struct G13 { pub struct G13 {
interface: Interface, interface: Interface,
img_buffer: [u8; G13_LCD_BUF_SIZE as usize + 8], img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>,
state: Arc<RwLock<State>>, state: Arc<RwLock<State>>,
} }
@@ -107,7 +107,7 @@ impl G13 {
Ok(Self { Ok(Self {
interface, interface,
img_buffer, img_buffer: Arc::new(RwLock::new(img_buffer)),
state: Arc::new(RwLock::new(Default::default())), state: Arc::new(RwLock::new(Default::default())),
}) })
} }
@@ -191,9 +191,11 @@ impl G13 {
} }
pub fn render(&mut self) -> Result<(), Box<dyn std::error::Error>> { pub fn render(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let img_buffer = self.img_buffer.read().expect("Poisoned");
let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8]; let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8];
buffer[0] = 0x03; 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::<Interrupt, Out>(0x02)?.writer(64); let mut w = self.interface.endpoint::<Interrupt, Out>(0x02)?.writer(64);
w.write_all(&buffer)?; w.write_all(&buffer)?;
@@ -219,6 +221,7 @@ impl DrawTarget for G13 {
where where
I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>>, I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>>,
{ {
let mut img_buffer = self.img_buffer.write().expect("Poisoned");
for p in pixels { 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 { if p.0.x < 0 || p.0.x > G13_LCD_COLUMNS - 1 || p.0.y < 0 || p.0.y > G13_LCD_ROWS - 1 {
continue; continue;
@@ -228,9 +231,9 @@ impl DrawTarget for G13 {
let mask = 1 << (p.0.y.rem_euclid(8)); let mask = 1 << (p.0.y.rem_euclid(8));
if p.1.is_on() { if p.1.is_on() {
self.img_buffer[offset as usize] |= mask; img_buffer[offset as usize] |= mask;
} else { } else {
self.img_buffer[offset as usize] &= !mask; img_buffer[offset as usize] &= !mask;
} }
} }

9
g13-os/Cargo.toml Normal file
View File

@@ -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"] }

87
g13-os/src/main.rs Normal file
View File

@@ -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<dyn std::error::Error>> {
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/*.<lua[u]>
// 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(())
}

View File

@@ -28,7 +28,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut _g13 = g13.clone(); let mut _g13 = g13.clone();
tokio::spawn(async move { 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() let textstyle = TextStyleBuilder::new()
.alignment(Alignment::Center) .alignment(Alignment::Center)
.baseline(embedded_graphics::text::Baseline::Middle) .baseline(embedded_graphics::text::Baseline::Middle)
@@ -39,21 +40,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let now = OffsetDateTime::now_utc().to_offset(offset!(+1)); // GMT+1 let now = OffsetDateTime::now_utc().to_offset(offset!(+1)); // GMT+1
// Render // Render
let string = format!( let time = format!(
"{:0>2}:{:0>2}:{:0>2}", "{:0>2}:{:0>2}:{:0>2}",
now.hour(), now.hour(),
now.minute(), now.minute(),
now.second() now.second()
); );
let date = format!("{}, {} {}", now.weekday(), now.day(), now.month());
_g13.clear(BinaryColor::Off).unwrap(); _g13.clear(BinaryColor::Off).unwrap();
Text::with_text_style( Text::with_text_style(
&string, &time,
Point::new( Point::new(
(G13_LCD_COLUMNS as f64 / 2.0) as i32, (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, textstyle,
) )
.draw(&mut _g13) .draw(&mut _g13)

43
scripts/main.luau Normal file
View File

@@ -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