Change module/method visibility

This commit is contained in:
Luke
2020-04-21 21:07:30 +12:00
parent 44fb0ee139
commit e21a6e3fb3
6 changed files with 137 additions and 125 deletions

4
Cargo.lock generated
View File

@@ -444,7 +444,7 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
[[package]] [[package]]
name = "rog-core" name = "rog-core"
version = "0.3.2" version = "0.3.3"
dependencies = [ dependencies = [
"dbus", "dbus",
"env_logger 0.7.1", "env_logger 0.7.1",
@@ -457,7 +457,7 @@ dependencies = [
[[package]] [[package]]
name = "rog-lib" name = "rog-lib"
version = "0.4.0" version = "0.4.1"
dependencies = [ dependencies = [
"aho-corasick 0.7.10", "aho-corasick 0.7.10",
"gumdrop", "gumdrop",

View File

@@ -6,19 +6,19 @@ use dbus::{
use log::{error, info, warn}; use log::{error, info, warn};
use rog_lib::{ use rog_lib::{
core::RogCore, core::RogCore,
laptops::{match_laptop, Laptop}, laptops::{match_laptop, LaptopRunner},
}; };
use std::error::Error; use std::error::Error;
use std::time::Duration; use std::time::Duration;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub struct Daemon { pub(crate) struct Daemon {
rogcore: RogCore, rogcore: RogCore,
laptop: Box<dyn Laptop>, laptop: Box<dyn LaptopRunner>,
} }
impl Daemon { impl Daemon {
pub fn new() -> Self { pub(crate) fn new() -> Self {
let laptop = match_laptop(); let laptop = match_laptop();
Daemon { Daemon {
@@ -36,7 +36,7 @@ impl Daemon {
} }
} }
pub fn start() -> Result<(), Box<dyn Error>> { pub(crate) fn start() -> Result<(), Box<dyn Error>> {
let mut connection = Connection::new_system().map_or_else( let mut connection = Connection::new_system().map_or_else(
|err| { |err| {
error!("{:?}", err); error!("{:?}", err);
@@ -96,8 +96,6 @@ impl Daemon {
// 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(&connection); tree.start_receive(&connection);
let mut key_buf = [0u8; 32];
let hotkey_group_bytes = Vec::from(daemon.borrow().laptop.hotkey_group_bytes());
loop { loop {
connection connection
.process(Duration::from_millis(10)) .process(Duration::from_millis(10))
@@ -105,29 +103,16 @@ impl Daemon {
error!("{:?}", err); error!("{:?}", err);
false false
}); });
// READ KEYBOARD
// TODO: this needs to move to a thread, but there is unsafety
let mut borrowed_daemon = daemon.borrow_mut();
match borrowed_daemon
.rogcore
.poll_keyboard(&hotkey_group_bytes, &mut key_buf)
{
Ok(read) => {
// Doing this because the Laptop trait takes RogCore, but RogCore contains laptop
// and this makes the borrow checker unhappy, but it's safe for this
let mut rogcore = unsafe { &mut (*daemon.as_ptr()).rogcore };
if let Some(_count) = read { // TODO: this needs to move to a thread, but there is unsafety
borrowed_daemon let borrowed_daemon = daemon.borrow_mut();
.laptop let mut rogcore = unsafe { &mut (*daemon.as_ptr()).rogcore };
.do_hotkey_action(&mut rogcore, key_buf[1]) borrowed_daemon
.unwrap_or_else(|err| { .laptop
warn!("{:?}", err); .run(&mut rogcore)
}); .unwrap_or_else(|err| {
} error!("{:?}", err);
} });
Err(err) => error!("{:?}", err),
}
} }
} }
} }

View File

@@ -5,7 +5,7 @@ use crate::{
}; };
use aho_corasick::AhoCorasick; use aho_corasick::AhoCorasick;
use gumdrop::Options; use gumdrop::Options;
use log::{debug, warn}; use log::warn;
use rusb::DeviceHandle; use rusb::DeviceHandle;
use std::process::Command; use std::process::Command;
use std::str::FromStr; use std::str::FromStr;
@@ -35,14 +35,14 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
pub struct RogCore { pub struct RogCore {
handle: DeviceHandle<rusb::GlobalContext>, handle: DeviceHandle<rusb::GlobalContext>,
initialised: bool, initialised: bool,
led_iface_num: u8, led_endpoint: u8,
keys_endpoint: u8, keys_endpoint: u8,
config: Config, config: Config,
virt_keys: VirtKeys, virt_keys: VirtKeys,
} }
impl RogCore { impl RogCore {
pub fn new(laptop: &dyn Laptop) -> Result<RogCore, AuraError> { pub fn new(laptop: &dyn LaptopRunner) -> Result<RogCore, AuraError> {
let mut dev_handle = RogCore::get_device(laptop.usb_vendor(), laptop.usb_product())?; let mut dev_handle = RogCore::get_device(laptop.usb_vendor(), laptop.usb_product())?;
dev_handle.set_active_configuration(0).unwrap_or(()); dev_handle.set_active_configuration(0).unwrap_or(());
@@ -50,11 +50,10 @@ impl RogCore {
// Interface with outputs // Interface with outputs
let mut led_interface_num = 0; let mut led_interface_num = 0;
let mut keys_interface_num = 0; let mut keys_interface_num = 0;
let keys_endpoint = 0x83;
for iface in dev_config.interfaces() { for iface in dev_config.interfaces() {
for desc in iface.descriptors() { for desc in iface.descriptors() {
for endpoint in desc.endpoint_descriptors() { for endpoint in desc.endpoint_descriptors() {
if endpoint.address() == keys_endpoint { if endpoint.address() == laptop.key_iface_num() {
keys_interface_num = desc.interface_number(); keys_interface_num = desc.interface_number();
} else if endpoint.address() == laptop.led_iface_num() { } else if endpoint.address() == laptop.led_iface_num() {
led_interface_num = desc.interface_number(); led_interface_num = desc.interface_number();
@@ -72,22 +71,22 @@ impl RogCore {
Ok(RogCore { Ok(RogCore {
handle: dev_handle, handle: dev_handle,
initialised: false, initialised: false,
led_iface_num: led_interface_num, led_endpoint: led_interface_num,
keys_endpoint, keys_endpoint: keys_interface_num,
config: Config::default().read(), config: Config::default().read(),
virt_keys: VirtKeys::new(), virt_keys: VirtKeys::new(),
}) })
} }
pub fn virt_keys(&mut self) -> &mut VirtKeys { pub(crate) fn virt_keys(&mut self) -> &mut VirtKeys {
&mut self.virt_keys &mut self.virt_keys
} }
pub fn config(&self) -> &Config { pub(crate) fn config(&self) -> &Config {
&self.config &self.config
} }
pub fn config_mut(&mut self) -> &mut Config { pub(crate) fn config_mut(&mut self) -> &mut Config {
&mut self.config &mut self.config
} }
@@ -113,7 +112,7 @@ impl RogCore {
fn aura_write_messages(&mut self, messages: &[&[u8]]) -> Result<(), AuraError> { fn aura_write_messages(&mut self, messages: &[&[u8]]) -> Result<(), AuraError> {
self.handle self.handle
.claim_interface(self.led_iface_num) .claim_interface(self.led_endpoint)
.map_err(|err| AuraError::UsbError(err))?; .map_err(|err| AuraError::UsbError(err))?;
if !self.initialised { if !self.initialised {
@@ -133,42 +132,19 @@ impl RogCore {
self.aura_write(&LED_APPLY)?; self.aura_write(&LED_APPLY)?;
self.handle self.handle
.release_interface(self.led_iface_num) .release_interface(self.led_endpoint)
.map_err(|err| AuraError::UsbError(err))?; .map_err(|err| AuraError::UsbError(err))?;
Ok(()) Ok(())
} }
pub fn aura_brightness_bytes(brightness: u8) -> Result<[u8; 17], AuraError> { /// Write the bytes read from the device interrupt to the buffer arg, and returns the
// TODO: check brightness range /// count of bytes written
let mut bright = [0u8; LED_MSG_LEN]; ///
bright[0] = 0x5a; /// `report_filter_bytes` is used to filter the data read from the interupt so
bright[1] = 0xba; /// only the relevant byte array is returned.
bright[2] = 0xc5; pub(crate) fn poll_keyboard(
bright[3] = 0xc4;
bright[4] = brightness;
Ok(bright)
}
pub fn aura_set_and_save(
&mut self, &mut self,
supported_modes: &[BuiltInModeByte], report_filter_bytes: &[u8],
bytes: &[u8],
) -> Result<(), AuraError> {
let mode = BuiltInModeByte::from(bytes[3]);
if supported_modes.contains(&mode) || bytes[1] == 0xba {
let messages = [bytes];
self.aura_write_messages(&messages)?;
self.config.set_field_from(bytes);
self.config.write();
return Ok(());
}
warn!("{:?} not supported", BuiltInModeByte::from(mode));
Err(AuraError::NotSupported)
}
pub fn poll_keyboard(
&mut self,
hotkey_group_bytes: &[u8],
buf: &mut [u8; 32], buf: &mut [u8; 32],
) -> Result<Option<usize>, AuraError> { ) -> Result<Option<usize>, AuraError> {
let res = let res =
@@ -177,7 +153,7 @@ impl RogCore {
.read_interrupt(self.keys_endpoint, buf, Duration::from_micros(1)) .read_interrupt(self.keys_endpoint, buf, Duration::from_micros(1))
{ {
Ok(o) => { Ok(o) => {
if hotkey_group_bytes.contains(&buf[0]) { if report_filter_bytes.contains(&buf[0]) {
Ok(Some(o)) Ok(Some(o))
} else { } else {
Ok(None) Ok(None)
@@ -188,14 +164,22 @@ impl RogCore {
res res
} }
pub fn suspend(&self) { /// A direct call to systemd to suspend the PC.
///
/// This avoids desktop environments being required to handle it
/// (which means it works while in a TTY also)
pub(crate) fn suspend_with_systemd(&self) {
std::process::Command::new("systemctl") std::process::Command::new("systemctl")
.arg("suspend") .arg("suspend")
.spawn() .spawn()
.map_or_else(|err| warn!("Failed to suspend: {}", err), |_| {}); .map_or_else(|err| warn!("Failed to suspend: {}", err), |_| {});
} }
pub fn toggle_airplane_mode(&self) { /// A direct call to rfkill to suspend wireless devices.
///
/// This avoids desktop environments being required to handle it (which
/// means it works while in a TTY also)
pub(crate) fn toggle_airplane_mode(&self) {
match Command::new("rfkill").arg("list").output() { match Command::new("rfkill").arg("list").output() {
Ok(output) => { Ok(output) => {
if output.status.success() { if output.status.success() {
@@ -229,16 +213,40 @@ impl RogCore {
} }
} }
} }
pub fn aura_brightness_bytes(brightness: u8) -> Result<[u8; 17], AuraError> {
// TODO: check brightness range
Ok([
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
])
}
pub fn aura_set_and_save(
&mut self,
supported_modes: &[BuiltInModeByte],
bytes: &[u8],
) -> Result<(), AuraError> {
let mode = BuiltInModeByte::from(bytes[3]);
if supported_modes.contains(&mode) || bytes[1] == 0xba {
let messages = [bytes];
self.aura_write_messages(&messages)?;
self.config.set_field_from(bytes);
self.config.write();
return Ok(());
}
warn!("{:?} not supported", BuiltInModeByte::from(mode));
Err(AuraError::NotSupported)
}
} }
pub struct Backlight { pub(crate) struct Backlight {
backlight: sysfs_class::Backlight, backlight: sysfs_class::Backlight,
step: u64, step: u64,
max: u64, max: u64,
} }
impl Backlight { impl Backlight {
pub fn new(id: &str) -> Result<Backlight, std::io::Error> { pub(crate) fn new(id: &str) -> Result<Backlight, std::io::Error> {
for bl in sysfs_class::Backlight::iter() { for bl in sysfs_class::Backlight::iter() {
let bl = bl?; let bl = bl?;
if bl.id() == id { if bl.id() == id {
@@ -253,7 +261,7 @@ impl Backlight {
} }
panic!("Backlight not found") panic!("Backlight not found")
} }
pub fn step_up(&self) { pub(crate) fn step_up(&self) {
let brightness = self let brightness = self
.backlight .backlight
.brightness() .brightness()
@@ -268,7 +276,7 @@ impl Backlight {
); );
} }
} }
pub fn step_down(&self) { pub(crate) fn step_down(&self) {
let brightness = self let brightness = self
.backlight .backlight
.brightness() .brightness()

View File

@@ -5,7 +5,7 @@ use crate::virt_device::ConsumerKeys;
//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; //use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState};
use log::info; use log::info;
pub fn match_laptop() -> Box<dyn Laptop> { pub fn match_laptop() -> Box<dyn LaptopRunner> {
let dmi = sysfs_class::DmiId::default(); let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().unwrap(); let board_name = dmi.board_name().unwrap();
match board_name.as_str() { match board_name.as_str() {
@@ -17,25 +17,31 @@ pub fn match_laptop() -> Box<dyn Laptop> {
} }
} }
/// All laptop models should implement this trait /// All laptop models should implement this trait. The role of a `Laptop` is to
/// "drive" the `RogCore`.
/// ///
/// `do_hotkey_action` is passed the byte that a hotkey emits, and is expected to /// `do_hotkey_action` is passed the byte that a hotkey emits, and is expected to
/// perform whichever action matches that. For now the only key bytes passed in are /// perform whichever action matches that. For now the only key bytes passed in are
/// the ones which match `byte[0] == hotkey_group_byte`. On the GX502GW the keyboard /// the ones which match `byte[0] == hotkey_group_byte`. On the GX502GW the keyboard
/// has 3 explicit groups: main, vol+media, and the ones that the Linux kernel doesn't /// has 3 explicit groups: main, vol+media, and the ones that the Linux kernel doesn't
/// map. /// map.
pub trait Laptop { pub(crate) trait Laptop {
fn do_hotkey_action(&self, core: &mut RogCore, key_byte: u8) -> Result<(), AuraError>;
fn hotkey_group_bytes(&self) -> &[u8]; fn hotkey_group_bytes(&self) -> &[u8];
fn led_iface_num(&self) -> u8;
fn supported_modes(&self) -> &[BuiltInModeByte];
fn usb_vendor(&self) -> u16;
fn usb_product(&self) -> u16;
fn board_name(&self) -> &str; fn board_name(&self) -> &str;
fn prod_family(&self) -> &str; fn prod_family(&self) -> &str;
} }
pub struct LaptopGX502GW { /// The public interface for running a laptop. Primarily used by the daemon.
pub trait LaptopRunner {
fn run(&self, core: &mut RogCore) -> Result<(), AuraError>;
fn led_iface_num(&self) -> u8;
fn key_iface_num(&self) -> u8;
fn usb_vendor(&self) -> u16;
fn usb_product(&self) -> u16;
fn supported_modes(&self) -> &[BuiltInModeByte];
}
pub(crate) struct LaptopGX502GW {
usb_vendor: u16, usb_vendor: u16,
usb_product: u16, usb_product: u16,
board_name: &'static str, board_name: &'static str,
@@ -44,6 +50,7 @@ pub struct LaptopGX502GW {
min_led_bright: u8, min_led_bright: u8,
max_led_bright: u8, max_led_bright: u8,
led_iface_num: u8, led_iface_num: u8,
key_iface_num: u8,
supported_modes: [BuiltInModeByte; 12], supported_modes: [BuiltInModeByte; 12],
backlight: Backlight, backlight: Backlight,
} }
@@ -60,6 +67,7 @@ impl LaptopGX502GW {
min_led_bright: 0x00, min_led_bright: 0x00,
max_led_bright: 0x03, max_led_bright: 0x03,
led_iface_num: 0x81, led_iface_num: 0x81,
key_iface_num: 0x83,
supported_modes: [ supported_modes: [
BuiltInModeByte::Stable, BuiltInModeByte::Stable,
BuiltInModeByte::Breathe, BuiltInModeByte::Breathe,
@@ -78,10 +86,14 @@ impl LaptopGX502GW {
} }
} }
} }
impl Laptop for LaptopGX502GW {
impl LaptopRunner for LaptopGX502GW {
// TODO: This really needs to match against u16 in future // TODO: This really needs to match against u16 in future
fn do_hotkey_action(&self, rogcore: &mut RogCore, key_byte: u8) -> Result<(), AuraError> { fn run(&self, rogcore: &mut RogCore) -> Result<(), AuraError> {
match GX502GWKeys::from(key_byte) { let mut key_buf = [0u8; 32];
rogcore.poll_keyboard(&self.hotkey_group_bytes, &mut key_buf)?;
match GX502GWKeys::from(key_buf[1]) {
GX502GWKeys::LedBrightUp => { GX502GWKeys::LedBrightUp => {
let mut bright = rogcore.config().brightness; let mut bright = rogcore.config().brightness;
if bright < self.max_led_bright { if bright < self.max_led_bright {
@@ -135,7 +147,7 @@ impl Laptop for LaptopGX502GW {
} }
GX502GWKeys::Sleep => { GX502GWKeys::Sleep => {
// Direct call to systemd // Direct call to systemd
rogcore.suspend(); rogcore.suspend_with_systemd();
//rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]); //rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]);
// Power menu // Power menu
//rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]); //rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]);
@@ -160,48 +172,52 @@ impl Laptop for LaptopGX502GW {
} }
GX502GWKeys::None => { GX502GWKeys::None => {
if key_byte != 0 { if key_buf[1] != 0 {
info!( info!(
"Unmapped key, attempt to pass to virtual device: {:?}, {:X?}", "Unmapped key, attempt to pass to virtual device: {:X?}",
&key_byte, &key_byte &key_buf[1]
); );
let mut bytes = [0u8; 8]; let mut bytes = [0u8; 8];
// TODO: code page // TODO: code page
bytes[0] = 0x02; bytes[0] = 0x02;
bytes[1] = key_byte; bytes[1] = key_buf[1];
rogcore.virt_keys().press(bytes); rogcore.virt_keys().press(bytes);
} }
} }
} }
Ok(()) Ok(())
} }
fn hotkey_group_bytes(&self) -> &[u8] {
&self.hotkey_group_bytes
}
fn supported_modes(&self) -> &[BuiltInModeByte] {
&self.supported_modes
}
fn usb_vendor(&self) -> u16 {
self.usb_vendor
}
fn usb_product(&self) -> u16 {
self.usb_product
}
fn board_name(&self) -> &str {
&self.board_name
}
fn prod_family(&self) -> &str {
&self.prod_family
}
fn led_iface_num(&self) -> u8 { fn led_iface_num(&self) -> u8 {
self.led_iface_num self.led_iface_num
} }
fn key_iface_num(&self) -> u8 {
self.key_iface_num
}
fn usb_vendor(&self) -> u16 {
self.usb_vendor
}
fn usb_product(&self) -> u16 {
self.usb_product
}
fn supported_modes(&self) -> &[BuiltInModeByte] {
&self.supported_modes
}
} }
pub enum GX502GWKeys { impl Laptop for LaptopGX502GW {
fn hotkey_group_bytes(&self) -> &[u8] {
&self.hotkey_group_bytes
}
fn board_name(&self) -> &str {
&self.board_name
}
fn prod_family(&self) -> &str {
&self.prod_family
}
}
pub(crate) enum GX502GWKeys {
Rog = 0x38, Rog = 0x38,
MicToggle = 0x7C, MicToggle = 0x7C,
Fan = 0xAE, Fan = 0xAE,

View File

@@ -1,7 +1,9 @@
pub mod aura; mod aura;
/// Contains mostly only what is required for parsing CLI options /// Contains mostly only what is required for parsing CLI options
pub mod cli_options; pub mod cli_options;
pub mod config; mod config;
/// The core module which allows writing to LEDs or polling the
/// laptop keyboard attached devices
pub mod core; pub mod core;
mod error; mod error;
pub mod laptops; pub mod laptops;

View File

@@ -1,11 +1,11 @@
use uhid_virt::{Bus, CreateParams, UHIDDevice}; use uhid_virt::{Bus, CreateParams, UHIDDevice};
pub struct VirtKeys { pub(crate) struct VirtKeys {
pub device: UHIDDevice<std::fs::File>, device: UHIDDevice<std::fs::File>,
} }
impl VirtKeys { impl VirtKeys {
pub fn new() -> Self { pub(crate) fn new() -> Self {
VirtKeys { VirtKeys {
device: UHIDDevice::create(CreateParams { device: UHIDDevice::create(CreateParams {
name: String::from("Virtual ROG buttons"), name: String::from("Virtual ROG buttons"),
@@ -71,7 +71,7 @@ impl VirtKeys {
} }
} }
pub fn press(&mut self, input: [u8; 8]) { pub(crate) fn press(&mut self, input: [u8; 8]) {
self.device.write(&input).unwrap(); self.device.write(&input).unwrap();
let mut reset = [0u8; 8]; let mut reset = [0u8; 8];
reset[0] = input[0]; reset[0] = input[0];
@@ -79,8 +79,9 @@ impl VirtKeys {
} }
} }
#[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ConsumerKeys { pub(crate) enum ConsumerKeys {
Power = 0x30, Power = 0x30,
Sleep = 0x32, Sleep = 0x32,
Menu = 0x0040, Menu = 0x0040,