mlua-periphery 1.2.4

A Rust-native implementation of lua-periphery for mlua.
use crate::i2c::{Const, I2c};
use i2cdev::core::I2CDevice;
use mlua::{Error::RuntimeError, FromLua, Lua, MultiValue, Table, prelude::LuaError};

#[cfg(not(all(target_os = "linux", any(target_arch = "arm", target_arch = "aarch64"))))]
pub(super) fn handle(_lua: &Lua, _i2c: &I2c, _args: MultiValue) -> Result<(), LuaError> {
    Err(RuntimeError("I²C is unsupported on this device".to_string()))
}

#[cfg(all(target_os = "linux", any(target_arch = "arm", target_arch = "aarch64")))]
pub(super) fn handle(lua: &Lua, i2c: &I2c, args: MultiValue) -> Result<(), LuaError> {
    use i2cdev::linux::LinuxI2CDevice;
    let addr: u16 = u16::from_lua(args[0].clone(), lua)?;
    let messages: Table = Table::from_lua(args[1].clone(), lua)?;
    let mut i2cdev = LinuxI2CDevice::new(i2c.device.clone(), addr).map_err(|err| RuntimeError(err.to_string()))?;
    transfer_(lua, i2c, &mut i2cdev, &messages)
}

#[allow(dead_code)]
fn transfer_<T: I2CDevice + Sized>(lua: &Lua, _i2c: &I2c, i2cdev: &mut T, messages: &Table) -> Result<(), LuaError> {
    for i in 1..=messages.len()? as usize {
        let message: Table = messages.get(i)?;
        let msg_len: usize = message.len()? as usize;

        let msg_flags: u16 = match message.get("flags") {
            Ok(flags) => {
                message.raw_remove("flags")?;
                u16::from_lua(flags, lua)?
            }
            Err(_) => 0,
        };

        if msg_flags & Const::Rd as u16 > 0 {
            for i in 1..=msg_len {
                let c = i2cdev.smbus_read_byte().map_err(|err| RuntimeError(err.to_string()))?;
                message.raw_set(i, c)?;
            }
        } else {
            let mut data = vec![0_u8; msg_len];
            for (i, item) in data.iter_mut().enumerate().take(msg_len) {
                *item = u8::from_lua(message.get(i + 1)?, lua)?;
            }
            i2cdev
                .smbus_write_block_data(0x01, &data)
                .map_err(|err| RuntimeError(err.to_string()))?;
        }
    }

    Ok(())
}