diff --git a/EXAMPLES.md b/EXAMPLES.md index 7b915984..8ed7d1c0 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -173,13 +173,13 @@ ALS: 76 Lux ``` ### Accelerometer (Framework 12) + ``` > sudo framework_tool --sensors -ALS: 0 Lux Accelerometers: - Lid Angle: 122 Deg - Sensor 1: X=+0.00G Y=+0.84G, Z=+0.52G - Sensor 2: X=-0.03G Y=+0.00G, Z=+1.01G + Lid Angle: 118 Deg + Lid Sensor: X=+0.00G Y=+0.86G, Z=+0.53G + Base Sensor: X=-0.03G Y=-0.07G, Z=+1.02G ``` ## Set custom fan duty/RPM diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index 54b8db52..e1048ea9 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -33,6 +33,7 @@ pub enum EcCommands { PwmSetKeyboardBacklight = 0x0023, PwmSetFanDuty = 0x0024, PwmSetDuty = 0x0025, + MotionSense = 0x002B, PwmGetDuty = 0x0026, SetTabletMode = 0x0031, AutoFanCtrl = 0x0052, diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 38cafeb6..1dec8b19 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -282,6 +282,134 @@ impl EcRequest for EcRequestPwmGetDuty { } } +#[repr(u8)] +pub enum MotionSenseCmd { + Dump = 0, + Info = 1, +} + +#[repr(C, packed)] +pub struct EcRequestMotionSenseDump { + /// MotionSenseCmd::Dump + pub cmd: u8, + /// Maximal number of sensor the host is expecting. + /// 0 means the host is only interested in the number + /// of sensors controlled by the EC. + pub max_sensor_count: u8, +} + +#[repr(C, packed)] +pub struct EcResponseMotionSenseDump { + /// Flags representing the motion sensor module + pub module_flags: u8, + + /// Number of sensors managed directly by the EC + pub sensor_count: u8, + + /// Sensor data is truncated if response_max is too small + /// for holding all the data. + pub sensor: [u8; 0], +} + +impl EcRequest for EcRequestMotionSenseDump { + fn command_id() -> EcCommands { + EcCommands::MotionSense + } + fn command_version() -> u8 { + 1 + } +} + +#[derive(Debug, FromPrimitive, PartialEq)] +pub enum MotionSenseType { + Accel = 0, + Gyro = 1, + Mag = 2, + Prox = 3, + Light = 4, + Activity = 5, + Baro = 6, + Sync = 7, + LightRgb = 8, +} + +#[derive(Debug, FromPrimitive)] +pub enum MotionSenseLocation { + Base = 0, + Lid = 1, + Camera = 2, +} + +#[derive(Debug, FromPrimitive)] +pub enum MotionSenseChip { + Kxcj9 = 0, + Lsm6ds0 = 1, + Bmi160 = 2, + Si1141 = 3, + Si1142 = 4, + Si1143 = 5, + Kx022 = 6, + L3gd20h = 7, + Bma255 = 8, + Bmp280 = 9, + Opt3001 = 10, + Bh1730 = 11, + Gpio = 12, + Lis2dh = 13, + Lsm6dsm = 14, + Lis2de = 15, + Lis2mdl = 16, + Lsm6ds3 = 17, + Lsm6dso = 18, + Lng2dm = 19, + Tcs3400 = 20, + Lis2dw12 = 21, + Lis2dwl = 22, + Lis2ds = 23, + Bmi260 = 24, + Icm426xx = 25, + Icm42607 = 26, + Bma422 = 27, + Bmi323 = 28, + Bmi220 = 29, + Cm32183 = 30, + Veml3328 = 31, +} + +#[repr(C, packed)] +pub struct EcRequestMotionSenseInfo { + /// MotionSenseCmd::Info + pub cmd: u8, + /// Sensor index + pub sensor_num: u8, +} + +#[repr(C)] +pub struct EcResponseMotionSenseInfo { + /// See enum MotionSenseInfo + pub sensor_type: u8, + /// See enum MotionSenseLocation + pub location: u8, + /// See enum MotionSenseChip + pub chip: u8, +} + +#[derive(Debug)] +pub struct MotionSenseInfo { + pub sensor_type: MotionSenseType, + pub location: MotionSenseLocation, + pub chip: MotionSenseChip, +} + +impl EcRequest for EcRequestMotionSenseInfo { + fn command_id() -> EcCommands { + EcCommands::MotionSense + } + fn command_version() -> u8 { + 1 + } +} + pub enum TabletModeOverride { Default = 0, ForceTablet = 1, diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index afdaef0c..fcda9ecb 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -353,6 +353,43 @@ impl CrosEc { )) } + pub fn motionsense_sensor_count(&self) -> EcResult { + EcRequestMotionSenseDump { + cmd: MotionSenseCmd::Dump as u8, + max_sensor_count: 0, + } + .send_command(self) + .map(|res| res.sensor_count) + } + + pub fn motionsense_sensor_info(&self) -> EcResult> { + let count = self.motionsense_sensor_count()?; + + let mut sensors = vec![]; + for sensor_num in 0..count { + let info = EcRequestMotionSenseInfo { + cmd: MotionSenseCmd::Info as u8, + sensor_num, + } + .send_command(self)?; + sensors.push(MotionSenseInfo { + sensor_type: FromPrimitive::from_u8(info.sensor_type).unwrap(), + location: FromPrimitive::from_u8(info.location).unwrap(), + chip: FromPrimitive::from_u8(info.chip).unwrap(), + }); + } + Ok(sensors) + } + + pub fn motionsense_sensor_list(&self) -> EcResult { + EcRequestMotionSenseDump { + cmd: MotionSenseCmd::Dump as u8, + max_sensor_count: 0, + } + .send_command(self) + .map(|res| res.sensor_count) + } + /// Get current status of Framework Laptop's microphone and camera privacy switches /// [true = device enabled/connected, false = device disabled] pub fn get_privacy_info(&self) -> EcResult<(bool, bool)> { diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index f365d57a..ba89af1d 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -1,5 +1,6 @@ //! Get information about system power (battery, AC, PD ports) +use alloc::format; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; @@ -10,11 +11,11 @@ use log::Level; use crate::ccgx::{AppVersion, Application, BaseVersion, ControllerVersion, MainPdVersions}; use crate::chromium_ec::command::EcRequestRaw; -use crate::chromium_ec::commands::{EcRequestReadPdVersion, EcRequestUsbPdPowerInfo}; -use crate::chromium_ec::{print_err_ref, CrosEc, CrosEcDriver, EcResult}; +use crate::chromium_ec::commands::*; +use crate::chromium_ec::*; use crate::smbios; use crate::smbios::get_platform; -use crate::util::Platform; +use crate::util::{Platform, PlatformFamily}; /// Maximum length of strings in memmap const EC_MEMMAP_TEXT_MAX: u16 = 8; @@ -245,9 +246,15 @@ pub fn print_memmap_version_info(ec: &CrosEc) { } /// Not supported on TGL EC -pub fn get_als_reading(ec: &CrosEc) -> Option { +pub fn get_als_reading(ec: &CrosEc, index: usize) -> Option { let als = ec.read_memory(EC_MEMMAP_ALS, 0x04)?; - Some(u32::from_le_bytes([als[0], als[1], als[2], als[3]])) + let offset = index + 4 * index; + Some(u32::from_le_bytes([ + als[offset], + als[1 + offset], + als[2 + offset], + als[3 + offset], + ])) } pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, LidAngle) { @@ -274,8 +281,40 @@ pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, LidAngle) { } pub fn print_sensors(ec: &CrosEc) { - let als_int = get_als_reading(ec).unwrap(); - println!("ALS: {:>4} Lux", als_int); + let mut has_als = false; + let mut accel_locations = vec![]; + + match ec.motionsense_sensor_info() { + Ok(sensors) => { + info!("Sensors: {}", sensors.len()); + for sensor in sensors { + info!(" Type: {:?}", sensor.sensor_type); + info!(" Location: {:?}", sensor.location); + info!(" Chip: {:?}", sensor.chip); + if sensor.sensor_type == MotionSenseType::Light { + has_als = true; + } + if sensor.sensor_type == MotionSenseType::Accel { + accel_locations.push(sensor.location); + } + } + } + Err(EcError::Response(EcResponseStatus::InvalidCommand)) => { + debug!("Motionsense commands not supported") + } + err => _ = print_err(err), + } + + // If we can't detect it based on motionsense + let als_family = matches!( + smbios::get_family(), + Some(PlatformFamily::Framework13) | Some(PlatformFamily::Framework16) + ); + + if has_als || als_family { + let als_int = get_als_reading(ec, 0).unwrap(); + println!("ALS: {:>4} Lux", als_int); + } // bit 4 = busy // bit 7 = present @@ -294,18 +333,22 @@ pub fn print_sensors(ec: &CrosEc) { debug!(" Status Bit: {} 0x{:X}", acc_status, acc_status); debug!(" Present: {}", present); debug!(" Busy: {}", (acc_status & 0x8) > 0); - print!(" Lid Angle: "); + print!(" Lid Angle: "); if lid_angle == LID_ANGLE_UNRELIABLE { println!("Unreliable"); } else { println!("{} Deg", lid_angle); } - println!(" Sensor 1: {}", AccelData::from(accel_1)); - println!(" Sensor 2: {}", AccelData::from(accel_2)); - // Accelerometers - // Lid Angle: 26 Deg - // Sensor 1: 00.00 X 00.00 Y 00.00 Z - // Sensor 2: 00.00 X 00.00 Y 00.00 Z + println!( + " {:<12} {}", + format!("{:?} Sensor:", accel_locations[0]), + AccelData::from(accel_1) + ); + println!( + " {:<12} {}", + format!("{:?} Sensor:", accel_locations[1]), + AccelData::from(accel_2) + ); } } diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index c5cfef29..935f0dc7 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -6,7 +6,7 @@ use std::prelude::v1::*; use std::io::ErrorKind; use crate::util::Config; -pub use crate::util::Platform; +pub use crate::util::{Platform, PlatformFamily}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use smbioslib::*; @@ -271,6 +271,10 @@ pub fn get_baseboard_version() -> Option { }) } +pub fn get_family() -> Option { + get_platform().and_then(Platform::which_family) +} + pub fn get_platform() -> Option { #[cfg(feature = "uefi")] let mut cached_platform = CACHED_PLATFORM.lock();