Skip to content

Commit cd16f33

Browse files
committed
Read stylus battery level
Tested on Linux with USI stylus. Hardcoded to our firmware with report ID. Guaranteed won't work on other systems. I assume it will work on Windows with USI. It won't work with MPP styluses. Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 84a09f3 commit cd16f33

File tree

5 files changed

+73
-0
lines changed

5 files changed

+73
-0
lines changed

EXAMPLES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,10 @@ ALS: 76 Lux
138138
APU: 42 C
139139
Fan Speed: 0 RPM
140140
```
141+
142+
## Stylus (Framework 12)
143+
144+
```
145+
> sudo framework_tool --stylus-battery
146+
Stylus Battery Strength: 77%
147+
```

framework_lib/src/commandline/clap_std.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ struct ClapCli {
184184
#[arg(long)]
185185
touchscreen_enable: Option<bool>,
186186

187+
/// Check stylus battery level (USI 2.0 stylus only)
188+
#[clap(value_enum)]
189+
#[arg(long)]
190+
stylus_battery: bool,
191+
187192
/// Get EC console, choose whether recent or to follow the output
188193
#[clap(value_enum)]
189194
#[arg(long)]
@@ -360,6 +365,7 @@ pub fn parse(args: &[String]) -> Cli {
360365
rgbkbd: args.rgbkbd,
361366
tablet_mode: args.tablet_mode,
362367
touchscreen_enable: args.touchscreen_enable,
368+
stylus_battery: args.stylus_battery,
363369
console: args.console,
364370
reboot_ec: args.reboot_ec,
365371
hash: args.hash.map(|x| x.into_os_string().into_string().unwrap()),

framework_lib/src/commandline/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub struct Cli {
181181
pub rgbkbd: Vec<u64>,
182182
pub tablet_mode: Option<TabletModeArg>,
183183
pub touchscreen_enable: Option<bool>,
184+
pub stylus_battery: bool,
184185
pub console: Option<ConsoleArg>,
185186
pub reboot_ec: Option<RebootEcArg>,
186187
pub hash: Option<String>,
@@ -333,6 +334,18 @@ fn active_mode(mode: &FwMode, reference: FwMode) -> &'static str {
333334
}
334335
}
335336

337+
#[cfg(feature = "hidapi")]
338+
fn print_stylus_battery_level() {
339+
loop {
340+
if let Some(level) = touchscreen::get_battery_level() {
341+
println!("Stylus Battery Strength: {}%", level);
342+
return;
343+
} else {
344+
debug!("Stylus Battery Strength: Unknown");
345+
}
346+
}
347+
}
348+
336349
fn print_versions(ec: &CrosEc) {
337350
println!("UEFI BIOS");
338351
if let Some(smbios) = get_smbios() {
@@ -811,6 +824,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
811824
if touchscreen::enable_touch(*_enable).is_none() {
812825
error!("Failed to enable/disable touch");
813826
}
827+
} else if args.stylus_battery {
828+
#[cfg(feature = "hidapi")]
829+
print_stylus_battery_level();
830+
#[cfg(not(feature = "hidapi"))]
831+
error!("Not build with hidapi feature");
814832
} else if let Some(console_arg) = &args.console {
815833
match console_arg {
816834
ConsoleArg::Follow => {

framework_lib/src/commandline/uefi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub fn parse(args: &[String]) -> Cli {
9494
rgbkbd: vec![],
9595
tablet_mode: None,
9696
touchscreen_enable: None,
97+
stylus_battery: false,
9798
console: None,
9899
reboot_ec: None,
99100
hash: None,

framework_lib/src/touchscreen.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,35 @@ impl TouchScreen for HidapiTouchScreen {
110110
Some(buf[msg_len..msg_len + read_len].to_vec())
111111
}
112112

113+
fn get_battery_status(&self) -> Option<u8> {
114+
let mut msg = [0u8; 0x40];
115+
msg[0] = 0x0D;
116+
self.device.read(&mut msg).ok()?;
117+
// println!(" Tip Switch {}%", msg[12]);
118+
// println!(" Barrell Switch: {}%", msg[12]);
119+
// println!(" Eraser: {}%", msg[12]);
120+
// println!(" Invert: {}%", msg[12]);
121+
// println!(" In Range: {}%", msg[12]);
122+
// println!(" 2nd Barrel Switch:{}%", msg[12]);
123+
// println!(" X {}%", msg[12]);
124+
// println!(" Y {}%", msg[12]);
125+
// println!(" Tip Pressure: {}%", msg[12]);
126+
// println!(" X Tilt: {}%", msg[12]);
127+
// println!(" Y Tilt: {}%", msg[12]);
128+
debug!(" Battery Strength: {}%", msg[12]);
129+
debug!(
130+
" Barrel Pressure: {}",
131+
u16::from_le_bytes([msg[13], msg[14]])
132+
);
133+
debug!(" Transducer Index: {}", msg[15]);
134+
135+
if msg[12] == 0 {
136+
None
137+
} else {
138+
Some(msg[12])
139+
}
140+
}
141+
113142
fn get_stylus_fw(&self) -> Option<()> {
114143
let mut msg = [0u8; 0x40];
115144
msg[0] = REPORT_ID_USI_VER;
@@ -190,6 +219,18 @@ pub trait TouchScreen {
190219
}
191220

192221
fn get_stylus_fw(&self) -> Option<()>;
222+
fn get_battery_status(&self) -> Option<u8>;
223+
}
224+
225+
pub fn get_battery_level() -> Option<u8> {
226+
for skip in 0..5 {
227+
if let Some(device) = HidapiTouchScreen::open_device(0x000D, skip) {
228+
if let Some(level) = device.get_battery_status() {
229+
return Some(level);
230+
}
231+
}
232+
}
233+
None
193234
}
194235

195236
pub fn print_fw_ver() -> Option<()> {

0 commit comments

Comments
 (0)