diff --git a/EXAMPLES.md b/EXAMPLES.md index 9f77e50..78ab79e 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -484,7 +484,7 @@ Board IDs F75303_CPU: 44 C F75303_DDR: 39 C APU: 62 C - Fan Speed: 0 RPM + API Fan: 0 RPM ``` ## Check sensors @@ -517,7 +517,7 @@ Accelerometers: F75303_CPU: 41 C F75303_DDR: 37 C APU: 42 C - Fan Speed: 7281 RPM + APU Fan: 7281 RPM # Set a target RPM (all or just fan ID=0) > sudo framework_tool --fansetrpm 3141 @@ -527,7 +527,7 @@ Accelerometers: F75303_CPU: 42 C F75303_DDR: 37 C APU: 44 C - Fan Speed: 3171 RPM + APU Fan: 3171 RPM # And back to normal > sudo framework_tool --autofanctrl @@ -536,7 +536,7 @@ Accelerometers: F75303_CPU: 40 C F75303_DDR: 38 C APU: 42 C - Fan Speed: 0 RPM + APU Fan: 0 RPM # Or just for a specific fan (e.g. on Framework Desktop) > sudo framework_tool --autofanctrl 0 diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index a4816ae..f2b0c69 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -2063,6 +2063,7 @@ fn selftest(ec: &CrosEc) -> Option<()> { println!("Specify custom platform parameters with --pd-ports --pd-addrs"); return None; }; + let family = smbios::get_platform().and_then(Platform::which_family); println!(" Dump EC memory region"); if let Some(mem) = ec.dump_mem_region() { @@ -2091,10 +2092,12 @@ fn selftest(ec: &CrosEc) -> Option<()> { println!(" - OK"); println!(" Getting AC info from EC"); - // All our laptops have at least 4 PD ports so far - if power::get_pd_info(ec, 4).iter().any(|x| x.is_err()) { - println!(" Failed to get PD Info from EC"); - return None; + if family != Some(PlatformFamily::FrameworkDesktop) { + // All our laptops have at least 4 PD ports so far + if power::get_pd_info(ec, 4).iter().any(|x| x.is_err()) { + println!(" Failed to get PD Info from EC"); + return None; + } } print!("Reading PD Version from EC"); @@ -2112,16 +2115,28 @@ fn selftest(ec: &CrosEc) -> Option<()> { let pd_01 = PdController::new(PdPort::Right01, ec.clone()); let pd_23 = PdController::new(PdPort::Left23, ec.clone()); - print!(" Getting PD01 info through I2C tunnel"); - print_err(pd_01.get_silicon_id())?; - print_err(pd_01.get_device_info())?; - print_err(pd_01.get_fw_versions())?; - println!(" - OK"); - print!(" Getting PD23 info through I2C tunnel"); - print_err(pd_23.get_silicon_id())?; - print_err(pd_23.get_device_info())?; - print_err(pd_23.get_fw_versions())?; - println!(" - OK"); + let pd_back = PdController::new(PdPort::Back, ec.clone()); + if family != Some(PlatformFamily::FrameworkDesktop) { + print!(" Getting PD01 info through I2C tunnel"); + print_err(pd_01.get_silicon_id())?; + print_err(pd_01.get_device_info())?; + print_err(pd_01.get_fw_versions())?; + println!(" - OK"); + print!(" Getting PD23 info through I2C tunnel"); + print_err(pd_23.get_silicon_id())?; + print_err(pd_23.get_device_info())?; + print_err(pd_23.get_fw_versions())?; + println!(" - OK"); + } else if matches!( + family, + Some(PlatformFamily::FrameworkDesktop) | Some(PlatformFamily::Framework16) + ) { + print!(" Getting Back PD info through I2C tunnel"); + print_err(pd_back.get_silicon_id())?; + print_err(pd_back.get_device_info())?; + print_err(pd_back.get_fw_versions())?; + println!(" - OK"); + } Some(()) } diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 4b07208..ede511d 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -419,7 +419,8 @@ pub fn print_thermal(ec: &CrosEc) { println!(" F75303_DDR: {:>4}", TempSensor::from(temps[1])); println!(" F75303_AMB: {:>4}", TempSensor::from(temps[2])); println!(" APU: {:>4}", TempSensor::from(temps[3])); - 4 + println!(" Virtual: {:>4}", TempSensor::from(temps[4])); + 3 } _ => { @@ -444,13 +445,25 @@ pub fn print_thermal(ec: &CrosEc) { } for i in 0..EC_FAN_SPEED_ENTRIES { + let name = match (i, family) { + (0, Some(PlatformFamily::Framework12)) => "APU Fan".to_string(), + (0, Some(PlatformFamily::Framework13)) => "APU Fan".to_string(), + (0, Some(PlatformFamily::Framework16)) => "Left Fan".to_string(), + (1, Some(PlatformFamily::Framework16)) => "Right Fan".to_string(), + (0, Some(PlatformFamily::FrameworkDesktop)) => "APU Fan".to_string(), + (1, Some(PlatformFamily::FrameworkDesktop)) => "Front Fan".to_string(), + (2, Some(PlatformFamily::FrameworkDesktop)) => "Third Fan".to_string(), + _ => format!("Fan {i}"), + }; + let name = format!("{name}:"); + let fan = u16::from_le_bytes([fans[i * 2], fans[1 + i * 2]]); if fan == EC_FAN_SPEED_STALLED_DEPRECATED { - println!(" Fan Speed: {:>4} RPM (Stalled)", fan); + println!(" {name:<11} {:>4} RPM (Stalled)", fan); } else if fan == EC_FAN_SPEED_NOT_PRESENT { - info!(" Fan Speed: Not present"); + info!(" {name:<11} Not present"); } else { - println!(" Fan Speed: {:>4} RPM", fan); + println!(" {name:<11} {:>4} RPM", fan); } } } @@ -782,110 +795,116 @@ impl From for CypdPdDataRole { } pub fn get_and_print_cypd_pd_info(ec: &CrosEc) { + // All of our systems have a maximum of 4 PD enabled ports let ports = 4u8; for port in 0..ports { - println!("USB-C Port {}:", port); - let result = EcRequestGetPdPortState { port }.send_command(ec); - match result { - Ok(info) => { - let c_state = CypdTypeCState::from(info.c_state); - let connected = !matches!(c_state, CypdTypeCState::Nothing); - let power_role = CypdPdPowerRole::from(info.power_role); - let data_role = CypdPdDataRole::from(info.data_role); - let voltage = { info.voltage }; - let current = { info.current }; - let watts_mw = voltage as u32 * current as u32 / 1000; - let has_pd_contract = info.pd_state != 0; - println!( - " PD Contract: {}", - if info.pd_state != 0 { "Yes" } else { "No" } - ); - println!(" Power Role: {:?}", power_role); - println!(" Data Role: {:?}", data_role); - if connected { - println!( - " VCONN: {}", - if info.vconn != 0 { "On" } else { "Off" } - ); - println!( - " Negotiated: {}.{:03} V, {} mA, {}.{} W", - voltage / 1000, - voltage % 1000, - current, - watts_mw / 1000, - watts_mw % 1000, - ); - println!( - " CC Polarity: {}", - match info.cc_polarity { - 0 => "CC1", - 1 => "CC2", - 2 => "CC1 (Debug)", - 3 => "CC2 (Debug)", - _ => "Unknown", - } - ); - } - if has_pd_contract { - println!(" Port Partner: {:?}", c_state); - println!( - " EPR: {}{}", - if info.epr_active != 0 { - "Active" - } else { - "Inactive" - }, - if info.epr_support != 0 { - " (Supported)" - } else { - "" - } - ); - if power_role == CypdPdPowerRole::Sink { - println!( - " Sink Active: {}", - if info.active_port != 0 { "Yes" } else { "No" } - ); - } - } - let alt = info.pd_alt_mode_status; - // Bits 0-1 indicate DP alt mode is active (bit 0 = DFP_D/TBT, - // bit 1 = UFP_D). Only show when actually in DP alt mode. - if connected && (alt & 0x03) != 0 { - let mut modes = vec![]; - if alt & 0x01 != 0 { - modes.push("DFP_D Connected"); - } - if alt & 0x02 != 0 { - modes.push("UFP_D Connected"); - } - if alt & 0x04 != 0 { - modes.push("Power Low"); - } - if alt & 0x08 != 0 { - modes.push("Enabled"); - } - if alt & 0x10 != 0 { - modes.push("Multi-Function"); - } - if alt & 0x20 != 0 { - modes.push("USB Config"); - } - if alt & 0x40 != 0 { - modes.push("Exit Request"); - } - if alt & 0x80 != 0 { - modes.push("HPD High"); - } - println!(" DP Alt Mode: {} (0x{:02X})", modes.join(", "), alt); - } + let info = match result { + Ok(info) => info, + Err(EcError::Response(EcResponseStatus::InvalidParameter)) => { + debug!("Port {port} does not exist"); + continue; } Err(e) => { print_err::<()>(Err(e)); + continue; + } + }; + + println!("USB-C Port {}:", port); + let c_state = CypdTypeCState::from(info.c_state); + let connected = !matches!(c_state, CypdTypeCState::Nothing); + let power_role = CypdPdPowerRole::from(info.power_role); + let data_role = CypdPdDataRole::from(info.data_role); + let voltage = { info.voltage }; + let current = { info.current }; + let watts_mw = voltage as u32 * current as u32 / 1000; + let has_pd_contract = info.pd_state != 0; + + println!( + " PD Contract: {}", + if info.pd_state != 0 { "Yes" } else { "No" } + ); + println!(" Power Role: {:?}", power_role); + println!(" Data Role: {:?}", data_role); + if connected { + println!( + " VCONN: {}", + if info.vconn != 0 { "On" } else { "Off" } + ); + println!( + " Negotiated: {}.{:03} V, {} mA, {}.{} W", + voltage / 1000, + voltage % 1000, + current, + watts_mw / 1000, + watts_mw % 1000, + ); + println!( + " CC Polarity: {}", + match info.cc_polarity { + 0 => "CC1", + 1 => "CC2", + 2 => "CC1 (Debug)", + 3 => "CC2 (Debug)", + _ => "Unknown", + } + ); + } + if has_pd_contract { + println!(" Port Partner: {:?}", c_state); + println!( + " EPR: {}{}", + if info.epr_active != 0 { + "Active" + } else { + "Inactive" + }, + if info.epr_support != 0 { + " (Supported)" + } else { + "" + } + ); + if power_role == CypdPdPowerRole::Sink { + println!( + " Sink Active: {}", + if info.active_port != 0 { "Yes" } else { "No" } + ); + } + } + let alt = info.pd_alt_mode_status; + // Bits 0-1 indicate DP alt mode is active (bit 0 = DFP_D/TBT, + // bit 1 = UFP_D). Only show when actually in DP alt mode. + if connected && (alt & 0x03) != 0 { + let mut modes = vec![]; + if alt & 0x01 != 0 { + modes.push("DFP_D Connected"); + } + if alt & 0x02 != 0 { + modes.push("UFP_D Connected"); + } + if alt & 0x04 != 0 { + modes.push("Power Low"); + } + if alt & 0x08 != 0 { + modes.push("Enabled"); + } + if alt & 0x10 != 0 { + modes.push("Multi-Function"); + } + if alt & 0x20 != 0 { + modes.push("USB Config"); + } + if alt & 0x40 != 0 { + modes.push("Exit Request"); + } + if alt & 0x80 != 0 { + modes.push("HPD High"); } + println!(" DP Alt Mode: {} (0x{:02X})", modes.join(", "), alt); } } }