Skip to content

Commit 60ff99f

Browse files
Merge pull request #117 from FrameworkComputer/chargerate
Chargerate
2 parents 2dca47a + cf81dbf commit 60ff99f

File tree

8 files changed

+329
-13
lines changed

8 files changed

+329
-13
lines changed

EXAMPLES.md

+108-13
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,6 @@ LED Matrix
9393
ALS: 76 Lux
9494
```
9595

96-
## Check power (AC and battery) status
97-
98-
```
99-
> sudo ./target/debug/framework_tool --power
100-
AC is: not connected
101-
Battery is: connected
102-
Battery LFCC: 3949 mAh (Last Full Charge Capacity)
103-
Battery Capacity: 2770 mAh
104-
44.729 Wh
105-
Charge level: 70%
106-
Battery discharging
107-
```
108-
10996
## Set custom fan duty/RPM
11097

11198
```
@@ -139,6 +126,7 @@ ALS: 76 Lux
139126
Fan Speed: 0 RPM
140127
```
141128

129+
142130
## Check expansion bay (Framework 16)
143131

144132
```
@@ -149,4 +137,111 @@ Expansion Bay
149137
Hatch closed: true
150138
Board: DualInterposer
151139
Serial Number: FRAXXXXXXXXXXXXXXX
140+
141+
## Check charger and battery status (Framework 12/13/16)
142+
143+
```
144+
> sudo framework_tool --power
145+
Charger Status
146+
AC is: not connected
147+
Charger Voltage: 17048mV
148+
Charger Current: 0mA
149+
Chg Input Current:384mA
150+
Battery SoC: 93%
151+
Battery Status
152+
AC is: not connected
153+
Battery is: connected
154+
Battery LFCC: 3693 mAh (Last Full Charge Capacity)
155+
Battery Capacity: 3409 mAh
156+
58.96 Wh
157+
Charge level: 92%
158+
Battery discharging
159+
```
160+
161+
Get more information
162+
163+
```
164+
> sudo framework_tool --power -vv
165+
Charger Status
166+
AC is: not connected
167+
Charger Voltage: 14824mV
168+
Charger Current: 0mA
169+
Chg Input Current:384mA
170+
Battery SoC: 33%
171+
Battery Status
172+
AC is: not connected
173+
Battery is: connected
174+
Battery LFCC: 4021 mAh (Last Full Charge Capacity)
175+
Battery Capacity: 1300 mAh
176+
19.267 Wh
177+
Charge level: 32%
178+
Manufacturer: NVT
179+
Model Number: FRANGWA
180+
Serial Number: 038F
181+
Battery Type: LION
182+
Present Voltage: 14.821 V
183+
Present Rate: 943 mA
184+
Design Capacity: 3915 mAh
185+
60.604 Wh
186+
Design Voltage: 15.480 V
187+
Cycle Count: 64
188+
Battery discharging
189+
```
190+
191+
### Setting a custom charger current limit
192+
193+
```
194+
# 1C = normal charging rate
195+
# This means charging from 0 to 100% takes 1 hour
196+
# Set charging rate to 0.8C
197+
> sudo framework_tool --charge-rate-limit 0.8
198+
199+
# Limit charge current to the battery to to 2A
200+
# In the output of `framework_tool --power -vv` above you can se "Design Capacity"
201+
# Dividing that by 1h gives you the maximum charging current (1C)
202+
# For example Design Capacity: 3915 mAh => 3915mA
203+
> sudo framework_tool --charge-current-limit 2000
204+
205+
# And then plug in a power adapter
206+
> sudo framework_tool --power
207+
Charger Status
208+
AC is: connected
209+
Charger Voltage: 17800mV
210+
Charger Current: 2000mA
211+
0.51C
212+
Chg Input Current:3084mA
213+
Battery SoC: 87%
214+
Battery Status
215+
AC is: connected
216+
Battery is: connected
217+
Battery LFCC: 3713 mAh (Last Full Charge Capacity)
218+
Battery Capacity: 3215 mAh
219+
56.953 Wh
220+
Charge level: 86%
221+
Battery charging
222+
223+
# Remove limit (set rate to 1C)
224+
> sudo framework_tool --charge-rate-limit 1
225+
226+
# Back to normal
227+
> sudo framework_tool --power
228+
Charger Status
229+
AC is: connected
230+
Charger Voltage: 17800mV
231+
Charger Current: 2740mA
232+
0.70C
233+
Chg Input Current:3084mA
234+
Battery SoC: 92%
235+
Battery Status
236+
AC is: connected
237+
Battery is: connected
238+
Battery LFCC: 3713 mAh (Last Full Charge Capacity)
239+
Battery Capacity: 3387 mAh
240+
60.146 Wh
241+
Charge level: 91%
242+
Battery charging
243+
244+
# Set charge rate/current limit only if battery is >80% charged
245+
> sudo framework_tool --charge-rate-limit 80 0.8
246+
> sudo framework_tool --charge-current-limit 80 2000
152247
```

framework_lib/src/chromium_ec/command.rs

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub enum EcCommands {
4040
I2cPassthrough = 0x009e,
4141
ConsoleSnapshot = 0x0097,
4242
ConsoleRead = 0x0098,
43+
ChargeState = 0x00A0,
44+
ChargeCurrentLimit = 0x00A1,
4345
/// List the features supported by the firmware
4446
GetFeatures = 0x000D,
4547
/// Force reboot, causes host reboot as well

framework_lib/src/chromium_ec/commands.rs

+61
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,67 @@ impl EcRequest<()> for EcRequestConsoleRead {
377377
}
378378
}
379379

380+
#[repr(u8)]
381+
pub enum ChargeStateCmd {
382+
GetState = 0,
383+
GetParam,
384+
SetParam,
385+
NumCmds,
386+
}
387+
388+
#[repr(C, packed)]
389+
pub struct EcRequestChargeStateGetV0 {
390+
pub cmd: u8,
391+
pub param: u32,
392+
}
393+
394+
#[repr(C, packed)]
395+
pub struct EcResponseChargeStateGetV0 {
396+
pub ac: u32,
397+
pub chg_voltage: u32,
398+
pub chg_current: u32,
399+
pub chg_input_current: u32,
400+
pub batt_state_of_charge: u32,
401+
}
402+
403+
impl EcRequest<EcResponseChargeStateGetV0> for EcRequestChargeStateGetV0 {
404+
fn command_id() -> EcCommands {
405+
EcCommands::ChargeState
406+
}
407+
fn command_version() -> u8 {
408+
0
409+
}
410+
}
411+
412+
pub struct EcRequestCurrentLimitV0 {
413+
/// Current limit in mA
414+
pub current: u32,
415+
}
416+
417+
impl EcRequest<()> for EcRequestCurrentLimitV0 {
418+
fn command_id() -> EcCommands {
419+
EcCommands::ChargeCurrentLimit
420+
}
421+
}
422+
423+
pub struct EcRequestCurrentLimitV1 {
424+
/// Current limit in mA
425+
pub current: u32,
426+
/// Battery state of charge is the minimum charge percentage at which
427+
/// the battery charge current limit will apply.
428+
/// When not set, the limit will apply regardless of state of charge.
429+
pub battery_soc: u8,
430+
}
431+
432+
impl EcRequest<()> for EcRequestCurrentLimitV1 {
433+
fn command_id() -> EcCommands {
434+
EcCommands::ChargeCurrentLimit
435+
}
436+
fn command_version() -> u8 {
437+
1
438+
}
439+
}
440+
380441
/// Supported features
381442
#[derive(Debug, FromPrimitive)]
382443
pub enum EcFeatureCode {

framework_lib/src/chromium_ec/mod.rs

+64
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
use crate::ec_binary;
1212
use crate::os_specific;
13+
use crate::power;
1314
use crate::smbios;
1415
#[cfg(feature = "uefi")]
1516
use crate::uefi::shell_get_execution_break_flag;
@@ -394,6 +395,42 @@ impl CrosEc {
394395
Ok((limits.min_percentage, limits.max_percentage))
395396
}
396397

398+
pub fn set_charge_current_limit(&self, current: u32, battery_soc: Option<u32>) -> EcResult<()> {
399+
if let Some(battery_soc) = battery_soc {
400+
let battery_soc = battery_soc as u8;
401+
EcRequestCurrentLimitV1 {
402+
current,
403+
battery_soc,
404+
}
405+
.send_command(self)
406+
} else {
407+
EcRequestCurrentLimitV0 { current }.send_command(self)
408+
}
409+
}
410+
411+
pub fn set_charge_rate_limit(&self, rate: f32, battery_soc: Option<f32>) -> EcResult<()> {
412+
let power_info = power::power_info(self).ok_or(EcError::DeviceError(
413+
"Failed to get battery info".to_string(),
414+
))?;
415+
let battery = power_info
416+
.battery
417+
.ok_or(EcError::DeviceError("No battery present".to_string()))?;
418+
println!("Requested Rate: {}C", rate);
419+
println!("Design Current: {}mA", battery.design_capacity);
420+
let current = (rate * (battery.design_capacity as f32)) as u32;
421+
println!("Limiting Current to: {}mA", current);
422+
if let Some(battery_soc) = battery_soc {
423+
let battery_soc = battery_soc as u8;
424+
EcRequestCurrentLimitV1 {
425+
current,
426+
battery_soc,
427+
}
428+
.send_command(self)
429+
} else {
430+
EcRequestCurrentLimitV0 { current }.send_command(self)
431+
}
432+
}
433+
397434
pub fn set_fp_led_percentage(&self, percentage: u8) -> EcResult<()> {
398435
// Sending bytes manually because the Set command, as opposed to the Get command,
399436
// does not return any data
@@ -1083,6 +1120,33 @@ impl CrosEc {
10831120
}
10841121
}
10851122

1123+
pub fn get_charge_state(&self, power_info: &power::PowerInfo) -> EcResult<()> {
1124+
let res = EcRequestChargeStateGetV0 {
1125+
cmd: ChargeStateCmd::GetState as u8,
1126+
param: 0,
1127+
}
1128+
.send_command(self)?;
1129+
println!("Charger Status");
1130+
println!(
1131+
" AC is: {}",
1132+
if res.ac == 1 {
1133+
"connected"
1134+
} else {
1135+
"not connected"
1136+
}
1137+
);
1138+
println!(" Charger Voltage: {}mV", { res.chg_voltage });
1139+
println!(" Charger Current: {}mA", { res.chg_current });
1140+
if let Some(battery) = &power_info.battery {
1141+
let charge_rate = (res.chg_current as f32) / (battery.design_capacity as f32);
1142+
println!(" {:.2}C", charge_rate);
1143+
}
1144+
println!(" Chg Input Current:{}mA", { res.chg_input_current });
1145+
println!(" Battery SoC: {}%", { res.batt_state_of_charge });
1146+
1147+
Ok(())
1148+
}
1149+
10861150
/// Check features supported by the firmware
10871151
pub fn get_features(&self) -> EcResult<()> {
10881152
let data = EcRequestGetFeatures {}.send_command(self)?;

framework_lib/src/commandline/clap_std.rs

+25
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ struct ClapCli {
155155
#[arg(long)]
156156
charge_limit: Option<Option<u8>>,
157157

158+
/// Get or set max charge current limit
159+
#[arg(long)]
160+
#[clap(num_args = ..2)]
161+
charge_current_limit: Vec<u32>,
162+
163+
/// Get or set max charge current limit
164+
#[arg(long)]
165+
#[clap(num_args = ..2)]
166+
charge_rate_limit: Vec<f32>,
167+
158168
/// Get GPIO value by name
159169
#[arg(long)]
160170
get_gpio: Option<String>,
@@ -305,6 +315,19 @@ pub fn parse(args: &[String]) -> Cli {
305315
1 => Some((None, args.fansetrpm[0])),
306316
_ => None,
307317
};
318+
let charge_current_limit = match args.charge_current_limit.len() {
319+
2 => Some((
320+
args.charge_current_limit[0],
321+
Some(args.charge_current_limit[1]),
322+
)),
323+
1 => Some((args.charge_current_limit[0], None)),
324+
_ => None,
325+
};
326+
let charge_rate_limit = match args.charge_rate_limit.len() {
327+
2 => Some((args.charge_rate_limit[0], Some(args.charge_rate_limit[1]))),
328+
1 => Some((args.charge_rate_limit[0], None)),
329+
_ => None,
330+
};
308331

309332
Cli {
310333
verbosity: args.verbosity.log_level_filter(),
@@ -358,6 +381,8 @@ pub fn parse(args: &[String]) -> Cli {
358381
inputdeck_mode: args.inputdeck_mode,
359382
expansion_bay: args.expansion_bay,
360383
charge_limit: args.charge_limit,
384+
charge_current_limit,
385+
charge_rate_limit,
361386
get_gpio: args.get_gpio,
362387
fp_led_level: args.fp_led_level,
363388
fp_brightness: args.fp_brightness,

framework_lib/src/commandline/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ pub struct Cli {
175175
pub inputdeck_mode: Option<InputDeckModeArg>,
176176
pub expansion_bay: bool,
177177
pub charge_limit: Option<Option<u8>>,
178+
pub charge_current_limit: Option<(u32, Option<u32>)>,
179+
pub charge_rate_limit: Option<(f32, Option<f32>)>,
178180
pub get_gpio: Option<String>,
179181
pub fp_led_level: Option<Option<FpBrightnessArg>>,
180182
pub fp_brightness: Option<Option<u8>>,
@@ -762,6 +764,10 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
762764
}
763765
} else if let Some(maybe_limit) = args.charge_limit {
764766
print_err(handle_charge_limit(&ec, maybe_limit));
767+
} else if let Some((limit, soc)) = args.charge_current_limit {
768+
print_err(ec.set_charge_current_limit(limit, soc));
769+
} else if let Some((limit, soc)) = args.charge_rate_limit {
770+
print_err(ec.set_charge_rate_limit(limit, soc));
765771
} else if let Some(gpio_name) = &args.get_gpio {
766772
print!("Getting GPIO value {}: ", gpio_name);
767773
if let Ok(value) = ec.get_gpio(gpio_name) {
@@ -1081,6 +1087,7 @@ Options:
10811087
--inputdeck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
10821088
--expansion-bay Show status of the expansion bay (Framework 16 only)
10831089
--charge-limit [<VAL>] Get or set battery charge limit (Percentage number as arg, e.g. '100')
1090+
--charge-current-limit [<VAL>] Get or set battery current charge limit (Percentage number as arg, e.g. '100')
10841091
--get-gpio <GET_GPIO> Get GPIO value by name
10851092
--fp-led-level [<VAL>] Get or set fingerprint LED brightness level [possible values: high, medium, low]
10861093
--fp-brightness [<VAL>]Get or set fingerprint LED brightness percentage

0 commit comments

Comments
 (0)