Skip to content

Commit 7205d8f

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 <[email protected]>
1 parent c86b603 commit 7205d8f

File tree

6 files changed

+77
-1
lines changed

6 files changed

+77
-1
lines changed

EXAMPLES.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ ALS: 76 Lux
139139
Fan Speed: 0 RPM
140140
```
141141

142-
143142
## Check expansion bay (Framework 16)
144143

145144
```
@@ -258,3 +257,10 @@ Battery Status
258257
> sudo framework_tool --charge-rate-limit 80 0.8
259258
> sudo framework_tool --charge-current-limit 80 2000
260259
```
260+
261+
## Stylus (Framework 12)
262+
263+
```
264+
> sudo framework_tool --stylus-battery
265+
Stylus Battery Strength: 77%
266+
```

framework_lib/src/commandline/clap_std.rs

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

201+
/// Check stylus battery level (USI 2.0 stylus only)
202+
#[clap(value_enum)]
203+
#[arg(long)]
204+
stylus_battery: bool,
205+
201206
/// Get EC console, choose whether recent or to follow the output
202207
#[clap(value_enum)]
203208
#[arg(long)]
@@ -390,6 +395,7 @@ pub fn parse(args: &[String]) -> Cli {
390395
rgbkbd: args.rgbkbd,
391396
tablet_mode: args.tablet_mode,
392397
touchscreen_enable: args.touchscreen_enable,
398+
stylus_battery: args.stylus_battery,
393399
console: args.console,
394400
reboot_ec: args.reboot_ec,
395401
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
@@ -184,6 +184,7 @@ pub struct Cli {
184184
pub rgbkbd: Vec<u64>,
185185
pub tablet_mode: Option<TabletModeArg>,
186186
pub touchscreen_enable: Option<bool>,
187+
pub stylus_battery: bool,
187188
pub console: Option<ConsoleArg>,
188189
pub reboot_ec: Option<RebootEcArg>,
189190
pub hash: Option<String>,
@@ -336,6 +337,18 @@ fn active_mode(mode: &FwMode, reference: FwMode) -> &'static str {
336337
}
337338
}
338339

340+
#[cfg(feature = "hidapi")]
341+
fn print_stylus_battery_level() {
342+
loop {
343+
if let Some(level) = touchscreen::get_battery_level() {
344+
println!("Stylus Battery Strength: {}%", level);
345+
return;
346+
} else {
347+
debug!("Stylus Battery Strength: Unknown");
348+
}
349+
}
350+
}
351+
339352
fn print_versions(ec: &CrosEc) {
340353
println!("UEFI BIOS");
341354
if let Some(smbios) = get_smbios() {
@@ -816,6 +829,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
816829
if touchscreen::enable_touch(*_enable).is_none() {
817830
error!("Failed to enable/disable touch");
818831
}
832+
} else if args.stylus_battery {
833+
#[cfg(feature = "hidapi")]
834+
print_stylus_battery_level();
835+
#[cfg(not(feature = "hidapi"))]
836+
error!("Not build with hidapi feature");
819837
} else if let Some(console_arg) = &args.console {
820838
match console_arg {
821839
ConsoleArg::Follow => {

framework_lib/src/commandline/uefi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub fn parse(args: &[String]) -> Cli {
9797
rgbkbd: vec![],
9898
tablet_mode: None,
9999
touchscreen_enable: None,
100+
stylus_battery: false,
100101
console: None,
101102
reboot_ec: None,
102103
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<()> {

framework_lib/src/touchscreen_win.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,8 @@ impl TouchScreen for NativeWinTouchScreen {
166166

167167
None
168168
}
169+
fn get_battery_status(&self) -> Option<u8> {
170+
error!("Get stylus battery status not supported on Windows");
171+
None
172+
}
169173
}

0 commit comments

Comments
 (0)