Clean up the main loop

This commit is contained in:
Luke
2020-04-27 09:25:18 +12:00
parent 8200dc85e6
commit c6fee63789
2 changed files with 116 additions and 110 deletions

View File

@@ -110,7 +110,7 @@ impl RogCore {
let mut file = OpenOptions::new().write(true).open(path)?; let mut file = OpenOptions::new().write(true).open(path)?;
file.write(format!("{:?}\n", self.config.fan_mode).as_bytes())?; file.write(format!("{:?}\n", self.config.fan_mode).as_bytes())?;
info!("Reloaded last saved settings");
Ok(()) Ok(())
} }
@@ -325,7 +325,7 @@ impl RogCore {
pub(crate) async fn poll_keyboard( pub(crate) async fn poll_keyboard(
handle: &DeviceHandle<rusb::GlobalContext>, handle: &DeviceHandle<rusb::GlobalContext>,
endpoint: u8, endpoint: u8,
report_filter_bytes: Vec<u8>, report_filter_bytes: &[u8],
) -> Option<[u8; 32]> { ) -> Option<[u8; 32]> {
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
match handle.read_interrupt(endpoint, &mut buf, Duration::from_millis(200)) { match handle.read_interrupt(endpoint, &mut buf, Duration::from_millis(200)) {

View File

@@ -5,7 +5,7 @@ pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon";
use crate::{core::RogCore, laptops::match_laptop}; use crate::{core::RogCore, laptops::match_laptop};
use dbus::{ use dbus::{
nonblock::Process, nonblock::Process,
tree::{Factory, MethodErr}, tree::{Factory, MTSync, Method, MethodErr, Tree},
}; };
use dbus_tokio::connection; use dbus_tokio::connection;
@@ -14,6 +14,18 @@ use std::error::Error;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
type LedMsgType = Arc<Mutex<Option<Vec<u8>>>>;
type EffectType = Arc<Mutex<Option<Vec<Vec<u8>>>>>;
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
// - read interrupt must timeout, minimum of 1ms
// - for a single usb packet, 2ms total.
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
//
// DBUS processing takes 6ms if not tokiod
pub async fn start_daemon() -> Result<(), Box<dyn Error>> { pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
let laptop = match_laptop(); let laptop = match_laptop();
let mut rogcore = RogCore::new(&*laptop).map_or_else( let mut rogcore = RogCore::new(&*laptop).map_or_else(
@@ -28,7 +40,6 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
); );
// Reload settings // Reload settings
rogcore.reload().await?; rogcore.reload().await?;
info!("Reloaded last saved settings");
let (resource, connection) = connection::new_system_sync()?; let (resource, connection) = connection::new_system_sync()?;
tokio::spawn(async { tokio::spawn(async {
@@ -40,125 +51,39 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
.request_name(DBUS_IFACE, false, true, false) .request_name(DBUS_IFACE, false, true, false)
.await?; .await?;
let factory = Factory::new_sync::<()>(); let (tree, input, effect) = dbus_create_tree();
let input: Arc<Mutex<Option<Vec<u8>>>> = Arc::new(Mutex::new(None));
let effect: Arc<Mutex<Option<Vec<Vec<u8>>>>> = Arc::new(Mutex::new(None));
let tree = factory.tree(()).add(
factory.object_path(DBUS_PATH, ()).add(
factory
.interface(DBUS_IFACE, ())
.add_m(
factory
// method for ledmessage
.method("ledmessage", (), {
let input = input.clone();
move |m| {
let bytes: Vec<u8> = m.msg.read1()?;
if let Ok(mut lock) = input.try_lock() {
*lock = Some(bytes.to_vec());
let mret = m
.msg
.method_return()
.append1(&format!("Wrote {:x?}", bytes));
return Ok(vec![mret]);
} else {
return Err(MethodErr::failed(
"Could not lock daemon for access",
));
}
}
})
.outarg::<&str, _>("reply")
.inarg::<Vec<u8>, _>("bytearray"),
)
.add_m(
factory
// method for ledmessage
.method("ledeffect", (), {
let effect = effect.clone();
move |m| {
if let Ok(mut lock) = effect.try_lock() {
let mut iter = m.msg.iter_init();
let byte_array: Vec<Vec<u8>> = vec![
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
];
*lock = Some(byte_array);
let mret =
m.msg.method_return().append1(&format!("Got effect part"));
return Ok(vec![mret]);
} else {
return Err(MethodErr::failed(
"Could not lock daemon for access",
));
}
}
})
.outarg::<&str, _>("reply")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray"),
),
),
);
// We add the tree to the connection so that incoming method calls will be handled. // We add the tree to the connection so that incoming method calls will be handled.
tree.start_receive_send(&*connection); tree.start_receive_send(&*connection);
let supported = Vec::from(laptop.supported_modes());
let key_buf: Arc<Mutex<Option<[u8; 32]>>> = Arc::new(Mutex::new(None)); let key_buf: Arc<Mutex<Option<[u8; 32]>>> = Arc::new(Mutex::new(None));
let handle = unsafe { &*(rogcore.get_raw_device_handle()) }; {
let endpoint = laptop.key_endpoint(); let usb_dev_handle = unsafe { &*(rogcore.get_raw_device_handle()) };
let report_filter_bytes = laptop.key_filter().to_owned(); let keyboard_endpoint = laptop.key_endpoint();
let report_filter_bytes = laptop.key_filter().to_owned();
let key_buf1 = key_buf.clone(); let key_buf1 = key_buf.clone();
// This is *not* safe // This is *not* safe
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
let data = RogCore::poll_keyboard(handle, endpoint, report_filter_bytes.clone()).await; let data =
if let Some(stuff) = data { RogCore::poll_keyboard(usb_dev_handle, keyboard_endpoint, &report_filter_bytes)
if let Ok(mut lock) = key_buf1.lock() { .await;
lock.replace(stuff); if let Some(stuff) = data {
// If we have some data to show, we *must* lock
if let Ok(mut lock) = key_buf1.lock() {
lock.replace(stuff);
}
} }
} }
} });
}); }
let supported = Vec::from(laptop.supported_modes());
// When any action occurs this time is reset // When any action occurs this time is reset
let mut time_mark = Instant::now(); let mut time_mark = Instant::now();
loop { loop {
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
// - read interrupt must timeout, minimum of 1ms
// - for a single usb packet, 2ms total.
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
// DBUS processing takes 6ms....
connection.process_all(); connection.process_all();
// 700u per write
if let Ok(mut lock) = input.try_lock() { if let Ok(mut lock) = input.try_lock() {
if let Some(bytes) = &*lock { if let Some(bytes) = &*lock {
// It takes up to 20 milliseconds to write a complete colour block here // It takes up to 20 milliseconds to write a complete colour block here
@@ -202,3 +127,84 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
} }
} }
} }
fn dbus_create_ledmsg_method(msg: LedMsgType) -> Method<MTSync, ()> {
let factory = Factory::new_sync::<()>();
factory
// method for ledmessage
.method("ledmessage", (), {
move |m| {
let bytes: Vec<u8> = m.msg.read1()?;
if let Ok(mut lock) = msg.try_lock() {
*lock = Some(bytes.to_vec());
let mret = m
.msg
.method_return()
.append1(&format!("Wrote {:x?}", bytes));
return Ok(vec![mret]);
} else {
return Err(MethodErr::failed("Could not lock daemon for access"));
}
}
})
.outarg::<&str, _>("reply")
.inarg::<Vec<u8>, _>("bytearray")
}
fn dbus_create_ledeffect_method(effect: EffectType) -> Method<MTSync, ()> {
let factory = Factory::new_sync::<()>();
factory
// method for ledmessage
.method("ledeffect", (), {
move |m| {
if let Ok(mut lock) = effect.try_lock() {
let mut iter = m.msg.iter_init();
let byte_array: Vec<Vec<u8>> = vec![
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
iter.read()?,
];
*lock = Some(byte_array);
let mret = m.msg.method_return().append1(&format!("Got effect part"));
return Ok(vec![mret]);
} else {
return Err(MethodErr::failed("Could not lock daemon for access"));
}
}
})
.outarg::<&str, _>("reply")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
.inarg::<Vec<u8>, _>("bytearray")
}
fn dbus_create_tree() -> (Tree<MTSync, ()>, LedMsgType, EffectType) {
let input: LedMsgType = Arc::new(Mutex::new(None));
let effect: EffectType = Arc::new(Mutex::new(None));
let factory = Factory::new_sync::<()>();
let tree = factory.tree(()).add(
factory.object_path(DBUS_PATH, ()).add(
factory
.interface(DBUS_IFACE, ())
.add_m(dbus_create_ledmsg_method(input.clone()))
.add_m(dbus_create_ledeffect_method(effect.clone())),
),
);
(tree, input, effect)
}