Lua support: add script handling class with basic I/O

The relevant functions are called and the return types and sizes
verified. The API for the user is not implemented yet.
This commit is contained in:
Thomas Kolb 2021-02-19 23:29:52 +01:00
parent 942f66f7df
commit 62bbff481c
4 changed files with 141 additions and 12 deletions

View file

@ -4,3 +4,9 @@ pub const SAMP_RATE: f32 = 48000.0;
// samples read from stdin per update
pub const SAMPLES_PER_UPDATE: usize = BLOCK_LEN/2;
// LED configuration
pub const NUM_STRIPS: usize = 8;
pub const NUM_LEDS_PER_STRIP: usize = 16;
pub const NUM_LEDS_TOTAL: usize = NUM_STRIPS * NUM_LEDS_PER_STRIP;

View file

@ -5,30 +5,30 @@ use std::collections::VecDeque;
use byteorder::{NativeEndian, ReadBytesExt};
use mlua::Lua;
mod signal_processing;
mod config;
mod userscript;
use crate::signal_processing::SignalProcessing;
use crate::userscript::UserScript;
fn main()
{
let mut stdin = std::io::stdin();
// test the mlua crate
let lua_state = Lua::new();
// set up Lua environment
lua_state.globals().set("get_rust_value", lua_state.create_function(|_, ()| {
Ok(3)
}).unwrap()).unwrap();
println!("Loading user script...");
let user_script = std::fs::read_to_string("test.lua").unwrap();
lua_state.load(&user_script).exec().unwrap();
let script = UserScript::new("test.lua").unwrap();
let lua_func_test : mlua::Function = lua_state.globals().get("test").unwrap();
println!("Calling init()...");
println!("{}", lua_func_test.call::<_, u32>(123).unwrap());
script.init().unwrap();
// set up signal processing
println!("Initializing signal processing...");
let mut sigproc = SignalProcessing::new(config::BLOCK_LEN, config::SAMP_RATE).unwrap();
@ -75,7 +75,10 @@ fn main()
let energy_treble = sigproc.get_energy_in_band(4000.0, config::SAMP_RATE/2.0);
// dump the output
println!("Bass: {:8.2} Mid: {:8.2} Treble: {:8.2}", energy_bass, energy_mid, energy_treble);
println!("Bass: {:11.2} Mid: {:11.2} Treble: {:11.2}", energy_bass, energy_mid, energy_treble);
// call the periodic function in the user script
script.periodic().unwrap();
}
}

95
src/userscript.rs Normal file
View file

@ -0,0 +1,95 @@
// vim: noet
/*
* Module for the Lua scripting interface of Musiclight.
*/
/* Test code for reference
// test the mlua crate
let lua_state = Lua::new();
lua_state.globals().set("get_rust_value", lua_state.create_function(|_, ()| {
Ok(3)
}).unwrap()).unwrap();
let user_script = std::fs::read_to_string("test.lua").unwrap();
lua_state.load(&user_script).exec().unwrap();
let lua_func_test : mlua::Function = lua_state.globals().get("test").unwrap();
println!("{}", lua_func_test.call::<_, u32>(123).unwrap());
*/
use crate::config;
use mlua::Lua;
use mlua::FromLua;
use mlua::Error;
pub struct UserScript
{
lua_state: Lua,
}
impl UserScript
{
pub fn new(user_script_path: &str) -> std::result::Result<UserScript, mlua::Error>
{
let s = UserScript {
lua_state: Lua::new(),
};
// load the user script and execute it to make variables and functions available
let user_script = std::fs::read_to_string(user_script_path)?;
s.lua_state.load(&user_script).exec()?;
Ok(s)
}
pub fn init(&self) -> std::result::Result<(), mlua::Error>
{
// find the init functions
let lua_init_func: mlua::Function = self.lua_state.globals().get("init")?;
lua_init_func.call( (config::NUM_STRIPS, config::NUM_LEDS_PER_STRIP) )?;
Ok(())
}
pub fn periodic(&self) -> std::result::Result<(), mlua::Error>
{
// find the init functions
let lua_periodic_func: mlua::Function = self.lua_state.globals().get("periodic")?;
// call the script's periodic() function, which (hopefully) returns four Tables with color
// values
let rvals = lua_periodic_func.call::<_, mlua::MultiValue>( () )?;
// check the number of returned values
if rvals.len() != 4 {
return Err(Error::RuntimeError("Wrong number of return values from 'periodic'. Expected 4.".to_string()));
}
// convert the Lua Tables to normal vectors
let mut colorlists = Vec::<Vec<f32>>::new();
for rval in rvals {
let table = mlua::Table::from_lua(rval, &self.lua_state)?;
let v = table.sequence_values()
.map(|x| x.unwrap())
.collect::<Vec<f32>>();
// check the length of the color array
if v.len() != config::NUM_LEDS_TOTAL {
return Err(Error::RuntimeError("Number of color values returned from 'periodic' must match number of LEDs given in 'init'.".to_string()));
}
colorlists.push(v);
}
println!("{:?}", colorlists[0][0]);
Ok(())
}
}

25
test.lua Normal file
View file

@ -0,0 +1,25 @@
function init(nstrip, nmod)
print("Initializing with "..nstrip.." strips with "..nmod.." modules each.")
local nled = nstrip * nmod
red = {}
green = {}
blue = {}
white = {}
for i = 1,nled do
red[i] = 0.8
green[i] = 0.1
blue[i] = 0.2
white[i] = 0.1
end
return 0
end
function periodic()
print("Going round and round...")
return red, green, blue, white
end