From e402e3f3af310bedfb17f3692db8b77a59ef4622 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:00:44 -0800 Subject: [PATCH] Get charge control command --- crosec/src/commands/charge_control.rs | 131 +++++++++++++++++++----- ectool/src/charge_control_subcommand.rs | 10 +- 2 files changed, 109 insertions(+), 32 deletions(-) diff --git a/crosec/src/commands/charge_control.rs b/crosec/src/commands/charge_control.rs index 73ff4ba..3077552 100644 --- a/crosec/src/commands/charge_control.rs +++ b/crosec/src/commands/charge_control.rs @@ -4,6 +4,7 @@ use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; use bytemuck::{Pod, Zeroable}; use std::os::fd::AsRawFd; +use strum_macros::FromRepr; #[repr(C)] #[derive(Pod, Zeroable, Copy, Clone, Default, Debug)] @@ -13,7 +14,7 @@ pub struct Sustainer { } #[derive(Debug)] -pub enum ChargeControl { +pub enum SetChargeControl { Normal(Option), Idle, Discharge, @@ -33,43 +34,119 @@ pub struct EcParamsChargeControl { sustain: Sustainer, } -const CHARGE_CONTROL_MODE_SET: u8 = 0; -// const CHARGE_CONTROL_MODE_GET: u8 = 1; +impl EcParamsChargeControl { + /// Get params to just get the charge control + fn get() -> Self { + let mut params = Self::zeroed(); + params.command = ChargeControlCommand::Get as u8; + params + } +} + +impl SetChargeControl { + fn to_set_params(&self) -> EcParamsChargeControl { + EcParamsChargeControl { + command: ChargeControlCommand::Set as u8, + mode: match self { + SetChargeControl::Normal(_) => ChargeControlMode::Normal, + SetChargeControl::Idle => ChargeControlMode::Idle, + SetChargeControl::Discharge => ChargeControlMode::Discharge, + } as u32, + reserved: Default::default(), + sustain: match self { + SetChargeControl::Normal(sustain) => sustain.unwrap_or(Sustainer { + min_percent: -1, + max_percent: -1, + }), + _ => Default::default(), + }, + } + } +} -const CHARGE_CONTROL_COMMAND_NORMAL: u32 = 0; -const CHARGE_CONTROL_COMMAND_IDLE: u32 = 1; -const CHARGE_CONTROL_COMMAND_DISCHARGE: u32 = 2; +#[repr(C, align(4))] +#[derive(Pod, Zeroable, Clone, Copy)] +pub struct EcResponseChargeControl { + mode: u32, + sustainer: Sustainer, + reserved: u16, +} + +#[repr(u8)] +#[derive(FromRepr)] +enum ChargeControlCommand { + Set, + Get, +} + +#[repr(u32)] +#[derive(FromRepr, Debug, Clone, Copy)] +pub enum ChargeControlMode { + Normal, + Idle, + Discharge, +} -pub fn get_charge_control(_file: &mut File) -> EcCmdResult { - panic!("Not implemented yet"); +#[derive(Debug, Clone, Copy)] +pub struct ChargeControlStatus { + pub mode: ChargeControlMode, + pub sustainer: Option, +} + +impl TryFrom for ChargeControlStatus { + type Error = String; + + fn try_from(value: EcResponseChargeControl) -> Result { + Ok(Self { + mode: { + let charge_control_mode = value.mode; + ChargeControlMode::from_repr(charge_control_mode).ok_or(format!( + "Invalid charge control mode: {charge_control_mode}" + ))? + }, + sustainer: { + let sustainer = value.sustainer; + match sustainer { + Sustainer { + min_percent: -1, + max_percent: -1, + } => Ok(None), + Sustainer { + min_percent: 0..=100, + max_percent: 0..=100, + } => Ok(Some(sustainer)), + sustainer => Err(format!("Invalid sustainer value: {sustainer:?}")), + } + }?, + }) + } +} + +/// Not all Chromebooks support this. You can check if it's supported using [`supports_get_and_sustainer`] +pub fn get_charge_control(file: &mut File) -> EcCmdResult { + let charge_control: EcResponseChargeControl = ec_command_bytemuck( + CrosEcCmd::ChargeControl, + 2, + &EcParamsChargeControl::get(), + file.as_raw_fd(), + )?; + Ok(charge_control.try_into().unwrap()) } pub fn set_charge_control( file: &mut File, - charge_control: ChargeControl, + charge_control: SetChargeControl, ) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::ChargeControl, { - let version = ec_cmd_get_cmd_versions(file, CrosEcCmd::ChargeControl)?; - Ok(if version & V2 != 0 { 2 } else { 1 }) + Ok(if supports_get_and_sustainer(file)? { + 2 + } else { + 1 + }) }?, - &EcParamsChargeControl { - command: CHARGE_CONTROL_MODE_SET, - mode: match charge_control { - ChargeControl::Normal(_) => CHARGE_CONTROL_COMMAND_NORMAL, - ChargeControl::Idle => CHARGE_CONTROL_COMMAND_IDLE, - ChargeControl::Discharge => CHARGE_CONTROL_COMMAND_DISCHARGE, - }, - reserved: Default::default(), - sustain: match charge_control { - ChargeControl::Normal(sustain) => sustain.unwrap_or(Sustainer { - min_percent: -1, - max_percent: -1, - }), - _ => Default::default(), - }, - }, + &charge_control.to_set_params(), file.as_raw_fd(), )?; Ok(()) diff --git a/ectool/src/charge_control_subcommand.rs b/ectool/src/charge_control_subcommand.rs index dd2255e..986c04e 100644 --- a/ectool/src/charge_control_subcommand.rs +++ b/ectool/src/charge_control_subcommand.rs @@ -4,7 +4,7 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crosec::{ commands::charge_control::{ - get_charge_control, set_charge_control, supports_get_and_sustainer, ChargeControl, + get_charge_control, set_charge_control, supports_get_and_sustainer, SetChargeControl, Sustainer, }, CROS_EC_PATH, @@ -46,7 +46,7 @@ pub fn charge_control_subcommand(command: Option) -> Re let max_percent = max_percent.unwrap_or(min_percent); set_charge_control( &mut file, - ChargeControl::Normal(Some(Sustainer { + SetChargeControl::Normal(Some(Sustainer { min_percent: min_percent as i8, max_percent: max_percent as i8, })), @@ -54,17 +54,17 @@ pub fn charge_control_subcommand(command: Option) -> Re println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); } None => { - set_charge_control(&mut file, ChargeControl::Normal(None))?; + set_charge_control(&mut file, SetChargeControl::Normal(None))?; println!("Set charge control to normal"); } }, ChargeControlSubcommand::Idle => { println!("Set charge control to idle"); - set_charge_control(&mut file, ChargeControl::Idle)?; + set_charge_control(&mut file, SetChargeControl::Idle)?; } ChargeControlSubcommand::Discharge => { println!("Set charge control to discharge"); - set_charge_control(&mut file, ChargeControl::Discharge)?; + set_charge_control(&mut file, SetChargeControl::Discharge)?; } }, }