Skip to content

fp-brightness: Add support for V1 host command #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions framework_lib/src/chromium_ec/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -844,10 +844,14 @@ pub enum FpLedBrightnessLevel {
High = 0,
Medium = 1,
Low = 2,
UltraLow = 3,
/// Custom: Only get, never set
Custom = 0xFE,
Auto = 0xFF,
}

#[repr(C, packed)]
pub struct EcRequestFpLedLevelControl {
pub struct EcRequestFpLedLevelControlV0 {
/// See enum FpLedBrightnessLevel
pub set_level: u8,
/// Boolean. >1 to get the level
Expand All @@ -856,12 +860,42 @@ pub struct EcRequestFpLedLevelControl {

#[repr(C, packed)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EcResponseFpLedLevelControl {
pub struct EcResponseFpLedLevelControlV0 {
/// Current brightness, 1-100%
pub percentage: u8,
}

impl EcRequest<EcResponseFpLedLevelControlV0> for EcRequestFpLedLevelControlV0 {
fn command_id() -> EcCommands {
EcCommands::FpLedLevelControl
}
fn command_version() -> u8 {
0
}
}

#[repr(C, packed)]
pub struct EcRequestFpLedLevelControlV1 {
/// Percentage 1-100
pub set_percentage: u8,
/// Boolean. >1 to get the level
pub get_level: u8,
}

#[repr(C, packed)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EcResponseFpLedLevelControlV1 {
/// Current brightness, 1-100%
pub percentage: u8,
/// Requested level. See enum FpLedBrightnessLevel
pub level: u8,
}

impl EcRequest<EcResponseFpLedLevelControl> for EcRequestFpLedLevelControl {
impl EcRequest<EcResponseFpLedLevelControlV1> for EcRequestFpLedLevelControlV1 {
fn command_id() -> EcCommands {
EcCommands::FpLedLevelControl
}
fn command_version() -> u8 {
1
}
}
40 changes: 34 additions & 6 deletions framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,17 @@ impl CrosEc {
Ok((limits.min_percentage, limits.max_percentage))
}

pub fn set_fp_led_percentage(&self, percentage: u8) -> EcResult<()> {
// Sending bytes manually because the Set command, as opposed to the Get command,
// does not return any data
let limits = &[percentage, 0x00];
let data = self.send_command(EcCommands::FpLedLevelControl as u16, 1, limits)?;

util::assert_win_len(data.len(), 0);

Ok(())
}

pub fn set_fp_led_level(&self, level: FpLedBrightnessLevel) -> EcResult<()> {
// Sending bytes manually because the Set command, as opposed to the Get command,
// does not return any data
Expand All @@ -325,16 +336,33 @@ impl CrosEc {
}

/// Get fingerprint led brightness level
pub fn get_fp_led_level(&self) -> EcResult<u8> {
let res = EcRequestFpLedLevelControl {
set_level: 0xFF,
pub fn get_fp_led_level(&self) -> EcResult<(u8, Option<FpLedBrightnessLevel>)> {
let res = EcRequestFpLedLevelControlV1 {
set_percentage: 0xFF,
get_level: 0xFF,
}
.send_command(self)?;
.send_command(self);

// If V1 does not exist, fall back
if let Err(EcError::Response(EcResponseStatus::InvalidVersion)) = res {
let res = EcRequestFpLedLevelControlV0 {
set_level: 0xFF,
get_level: 0xFF,
}
.send_command(self)?;
debug!("Current Brightness: {}%", res.percentage);
return Ok((res.percentage, None));
}

let res = res?;

debug!("Level Raw: {}", res.level);
debug!("Current Brightness: {}%", res.percentage);
debug!("Level Raw: {}", res.level);

Ok(res.level)
// TODO: can turn this into None and log
let level = FromPrimitive::from_u8(res.level)
.ok_or(EcError::DeviceError(format!("Invalid level {}", res.level)))?;
Ok((res.percentage, Some(level)))
}

/// Get the intrusion switch status (whether the chassis is open or not)
Expand Down
9 changes: 7 additions & 2 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,13 @@ struct ClapCli {
#[arg(long)]
get_gpio: Option<String>,

/// Get or set fingerprint LED brightness
/// Get or set fingerprint LED brightness level
#[arg(long)]
fp_brightness: Option<Option<FpBrightnessArg>>,
fp_led_level: Option<Option<FpBrightnessArg>>,

/// Get or set fingerprint LED brightness percentage
#[arg(long)]
fp_brightness: Option<Option<u8>>,

/// Set keyboard backlight percentage or get, if no value provided
#[arg(long)]
Expand Down Expand Up @@ -267,6 +271,7 @@ pub fn parse(args: &[String]) -> Cli {
input_deck_mode: args.input_deck_mode,
charge_limit: args.charge_limit,
get_gpio: args.get_gpio,
fp_led_level: args.fp_led_level,
fp_brightness: args.fp_brightness,
kblight: args.kblight,
tablet_mode: args.tablet_mode,
Expand Down
41 changes: 35 additions & 6 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,17 @@ pub enum FpBrightnessArg {
High,
Medium,
Low,
UltraLow,
Auto,
}
impl From<FpBrightnessArg> for FpLedBrightnessLevel {
fn from(w: FpBrightnessArg) -> FpLedBrightnessLevel {
match w {
FpBrightnessArg::High => FpLedBrightnessLevel::High,
FpBrightnessArg::Medium => FpLedBrightnessLevel::Medium,
FpBrightnessArg::Low => FpLedBrightnessLevel::Low,
FpBrightnessArg::UltraLow => FpLedBrightnessLevel::UltraLow,
FpBrightnessArg::Auto => FpLedBrightnessLevel::Auto,
}
}
}
Expand Down Expand Up @@ -159,7 +163,8 @@ pub struct Cli {
pub input_deck_mode: Option<InputDeckModeArg>,
pub charge_limit: Option<Option<u8>>,
pub get_gpio: Option<String>,
pub fp_brightness: Option<Option<FpBrightnessArg>>,
pub fp_led_level: Option<Option<FpBrightnessArg>>,
pub fp_brightness: Option<Option<u8>>,
pub kblight: Option<Option<u8>>,
pub tablet_mode: Option<TabletModeArg>,
pub console: Option<ConsoleArg>,
Expand Down Expand Up @@ -741,6 +746,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
} else {
println!("Not found");
}
} else if let Some(maybe_led_level) = &args.fp_led_level {
print_err(handle_fp_led_level(&ec, *maybe_led_level));
} else if let Some(maybe_brightness) = &args.fp_brightness {
print_err(handle_fp_brightness(&ec, *maybe_brightness));
} else if let Some(Some(kblight)) = args.kblight {
Expand Down Expand Up @@ -1009,7 +1016,8 @@ Options:
--input-deck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
--charge-limit [<VAL>] Get or set battery charge limit (Percentage number as arg, e.g. '100')
--get-gpio <GET_GPIO> Get GPIO value by name
--fp-brightness [<VAL>]Get or set fingerprint LED brightness level [possible values: high, medium, low]
--fp-led-level [<VAL>] Get or set fingerprint LED brightness level [possible values: high, medium, low]
--fp-brightness [<VAL>]Get or set fingerprint LED brightness percentage
--kblight [<KBLIGHT>] Set keyboard backlight percentage or get, if no value provided
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
--hash <HASH> Hash a file of arbitrary data
Expand Down Expand Up @@ -1355,13 +1363,34 @@ fn handle_charge_limit(ec: &CrosEc, maybe_limit: Option<u8>) -> EcResult<()> {
Ok(())
}

fn handle_fp_brightness(ec: &CrosEc, maybe_brightness: Option<FpBrightnessArg>) -> EcResult<()> {
fn handle_fp_led_level(ec: &CrosEc, maybe_led_level: Option<FpBrightnessArg>) -> EcResult<()> {
if let Some(led_level) = maybe_led_level {
ec.set_fp_led_level(led_level.into())?;
}

let (brightness, level) = ec.get_fp_led_level()?;
// TODO: Rename to power button
println!("Fingerprint LED Brightness");
if let Some(level) = level {
println!(" Requested: {:?}", level);
}
println!(" Brightness: {}%", brightness);

Ok(())
}

fn handle_fp_brightness(ec: &CrosEc, maybe_brightness: Option<u8>) -> EcResult<()> {
if let Some(brightness) = maybe_brightness {
ec.set_fp_led_level(brightness.into())?;
ec.set_fp_led_percentage(brightness)?;
}

let level = ec.get_fp_led_level()?;
println!("Fingerprint LED Brightness: {:?}%", level);
let (brightness, level) = ec.get_fp_led_level()?;
// TODO: Rename to power button
println!("Fingerprint LED Brightness");
if let Some(level) = level {
println!(" Requested: {:?}", level);
}
println!(" Brightness: {}%", brightness);

Ok(())
}
39 changes: 32 additions & 7 deletions framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ pub fn parse(args: &[String]) -> Cli {
input_deck_mode: None,
charge_limit: None,
get_gpio: None,
fp_led_level: None,
fp_brightness: None,
kblight: None,
tablet_mode: None,
Expand Down Expand Up @@ -237,17 +238,41 @@ pub fn parse(args: &[String]) -> Cli {
None
};
found_an_option = true;
} else if arg == "--fp-brightness" {
cli.fp_brightness = if args.len() > i + 1 {
let fp_brightness_arg = &args[i + 1];
if fp_brightness_arg == "high" {
} else if arg == "--fp-led-level" {
cli.fp_led_level = if args.len() > i + 1 {
let fp_led_level_arg = &args[i + 1];
if fp_led_level_arg == "high" {
Some(Some(FpBrightnessArg::High))
} else if fp_brightness_arg == "medium" {
} else if fp_led_level_arg == "medium" {
Some(Some(FpBrightnessArg::Medium))
} else if fp_brightness_arg == "low" {
} else if fp_led_level_arg == "low" {
Some(Some(FpBrightnessArg::Low))
} else if fp_led_level_arg == "ultra-low" {
Some(Some(FpBrightnessArg::UltraLow))
} else if fp_led_level_arg == "auto" {
Some(Some(FpBrightnessArg::Auto))
} else {
println!("Invalid value for --fp-led-level: {}", fp_led_level_arg);
None
}
} else {
Some(None)
};
found_an_option = true;
} else if arg == "--fp-brightness" {
cli.fp_brightness = if args.len() > i + 1 {
if let Ok(fp_brightness_arg) = args[i + 1].parse::<u8>() {
if fp_brightness_arg == 0 || fp_brightness_arg > 100 {
println!(
"Invalid value for --fp-brightness: {}. Must be in the range of 1-100",
fp_brightness_arg
);
None
} else {
Some(Some(fp_brightness_arg))
}
} else {
println!("Invalid value for --fp-brightness: {}", fp_brightness_arg);
println!("Invalid value for --fp-brightness. Must be in the range of 1-100");
None
}
} else {
Expand Down