Skip to content

Commit ce83292

Browse files
committed
battery: Decode more normal and manufacturing commands
Signed-off-by: Daniel Schaefer <[email protected]>
1 parent bde7532 commit ce83292

File tree

1 file changed

+149
-19
lines changed

1 file changed

+149
-19
lines changed

framework_lib/src/battery.rs

Lines changed: 149 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@ use alloc::vec::Vec;
55

66
use crate::chromium_ec::i2c_passthrough::*;
77
use crate::chromium_ec::{CrosEc, EcResult};
8-
//use crate::os_specific;
98

109
#[repr(u16)]
1110
enum SmartBatReg {
1211
Mode = 0x03,
1312
Temp = 0x08,
13+
Voltage = 0x09,
1414
ManufactureDate = 0x1B,
1515
SerialNum = 0x1C,
1616
CycleCount = 0x17,
1717
/// String
1818
ManufacturerName = 0x20,
1919
DeviceName = 0x21,
2020
Soh = 0x4F,
21+
CellVoltage1 = 0x3C,
22+
CellVoltage2 = 0x3D,
23+
CellVoltage3 = 0x3E,
24+
CellVoltage4 = 0x3F,
2125
}
2226

2327
#[repr(u16)]
@@ -33,6 +37,9 @@ enum ManufReg {
3337
LifeTimeDataBlock1 = 0x60,
3438
LifeTimeDataBlock2 = 0x61,
3539
LifeTimeDataBlock3 = 0x62,
40+
LifeTimeDataBlock4 = 0x63,
41+
LifeTimeDataBlock5 = 0x64,
42+
Soh = 0x77,
3643
}
3744

3845
pub struct SmartBattery {
@@ -51,21 +58,33 @@ impl SmartBattery {
5158
}
5259
}
5360

61+
fn unseal(&self, ec: &CrosEc, key1: u16, key2: u16) -> EcResult<()> {
62+
i2c_write_block(ec, self.i2c_port, self.i2c_addr >> 1, 0x00, &key1.to_le_bytes())?;
63+
i2c_write_block(ec, self.i2c_port, self.i2c_addr >> 1, 0x00, &key2.to_le_bytes())?;
64+
Ok(())
65+
}
66+
67+
fn seal(&self, ec: &CrosEc) -> EcResult<()> {
68+
i2c_write(ec, self.i2c_port, self.i2c_addr >> 1, 0x00, &[0x30, 0x00])?;
69+
Ok(())
70+
}
71+
5472
fn read_bytes(&self, ec: &CrosEc, addr: u16, len: u16) -> EcResult<Vec<u8>> {
55-
let i2c_response = i2c_read(ec, self.i2c_port, self.i2c_addr >> 1, addr, len)?;
73+
let i2c_response = i2c_read(ec, self.i2c_port, self.i2c_addr >> 1, addr, len + 1)?;
5674
i2c_response.is_successful()?;
57-
Ok(i2c_response.data)
75+
debug_assert_eq!(i2c_response.data[0], len as u8);
76+
Ok(i2c_response.data[1..].to_vec())
5877
}
59-
fn read_i16(&self, ec: &CrosEc, addr: u16) -> EcResult<i16> {
78+
fn read_i16(&self, ec: &CrosEc, addr: u16) -> EcResult<u16> {
6079
let i2c_response = i2c_read(ec, self.i2c_port, self.i2c_addr >> 1, addr, 0x02)?;
6180
i2c_response.is_successful()?;
62-
Ok(i16::from_le_bytes([
63-
i2c_response.data[1],
81+
Ok(u16::from_le_bytes([
82+
i2c_response.data[0],
6483
i2c_response.data[1],
6584
]))
6685
}
6786
fn read_string(&self, ec: &CrosEc, addr: u16) -> EcResult<String> {
68-
let i2c_response = i2c_read(ec, self.i2c_port, self.i2c_addr >> 1, addr, 16)?;
87+
let i2c_response = i2c_read(ec, self.i2c_port, self.i2c_addr >> 1, addr, 32)?;
6988
i2c_response.is_successful()?;
7089

7190
// First byte is the returned string length
@@ -87,9 +106,17 @@ impl SmartBattery {
87106
"Manuf Date: {:04X?}",
88107
self.read_i16(ec, SmartBatReg::ManufactureDate as u16)?
89108
);
109+
let temp = self.read_i16(ec, SmartBatReg::Temp as u16)?;
90110
println!(
91-
"Temperature: {:?}",
92-
self.read_i16(ec, SmartBatReg::Temp as u16)?
111+
"Temperature: {}.{}C",
112+
temp / 100,
113+
temp % 100
114+
);
115+
let voltage = self.read_i16(ec, SmartBatReg::Voltage as u16)?;
116+
println!(
117+
"Voltage: {}.{}V",
118+
voltage / 1000,
119+
voltage % 1000
93120
);
94121
println!(
95122
"Cycle Count: {:?}",
@@ -103,13 +130,19 @@ impl SmartBattery {
103130
"Manuf Name: {}",
104131
self.read_string(ec, SmartBatReg::ManufacturerName as u16)?
105132
);
106-
println!(
107-
"StateOfHealth: {:?}",
108-
self.read_i16(ec, SmartBatReg::Soh as u16)?
109-
);
133+
134+
// Default key - does not work on our battery, it's changed during manufacturing!
135+
self.unseal(ec, 0x0414, 0x3672).unwrap();
110136

111137
// Need to unseal for access
112138
// SE [US] [FA]
139+
let soh = self.read_bytes(ec, ManufReg::Soh as u16, 4)?;
140+
println!(
141+
"StateOfHealth: {}mAh, {}.{}Wh",
142+
u16::from_le_bytes([soh[0], soh[1]]),
143+
u16::from_le_bytes([soh[2], soh[3]]) / 100,
144+
u16::from_le_bytes([soh[2], soh[3]]) % 100,
145+
);
113146
println!(
114147
"Safety Alert: {:?}",
115148
self.read_i16(&ec, ManufReg::SafetyAlert as u16)?
@@ -126,21 +159,118 @@ impl SmartBattery {
126159
"PFStatus: {:?}",
127160
self.read_i16(&ec, ManufReg::SafetyAlert as u16)?
128161
);
162+
let lifetime1 = self.read_bytes(ec, ManufReg::LifeTimeDataBlock1 as u16, 32)?;
163+
println!("LifeTime1");
129164
println!(
130-
"LifeTime1 {:X?}",
131-
self.read_bytes(ec, ManufReg::LifeTimeDataBlock1 as u16, 4)?
165+
" Cell 1 Max Voltage: {}mV",
166+
u16::from_le_bytes([lifetime1[0], lifetime1[1]])
132167
);
133168
println!(
134-
"LifeTime2 {:X?}",
135-
self.read_bytes(ec, ManufReg::LifeTimeDataBlock2 as u16, 4)?
169+
" Min Voltage: {}mV",
170+
u16::from_le_bytes([lifetime1[8], lifetime1[9]])
171+
);
172+
println!(
173+
" Cell 2 Max Voltage: {}mV",
174+
u16::from_le_bytes([lifetime1[2], lifetime1[3]])
175+
);
176+
println!(
177+
" Min Voltage: {}mV",
178+
u16::from_le_bytes([lifetime1[10], lifetime1[11]])
179+
);
180+
println!(
181+
" Cell 3 Max Voltage: {}mV",
182+
u16::from_le_bytes([lifetime1[4], lifetime1[5]])
183+
);
184+
println!(
185+
" Min Voltage: {}mV",
186+
u16::from_le_bytes([lifetime1[12], lifetime1[13]])
187+
);
188+
println!(
189+
" Cell 4 Max Voltage: {}mV",
190+
u16::from_le_bytes([lifetime1[6], lifetime1[7]])
191+
);
192+
println!(
193+
" Min Voltage: {}mV",
194+
u16::from_le_bytes([lifetime1[14], lifetime1[15]])
195+
);
196+
println!(
197+
" Max Delta Cell Voltage: {}mV",
198+
u16::from_le_bytes([lifetime1[16], lifetime1[17]])
199+
);
200+
println!(
201+
" Max Charge Current: {}mA",
202+
u16::from_le_bytes([lifetime1[18], lifetime1[19]])
203+
);
204+
println!(
205+
" Max Discharge Current: {}mA",
206+
u16::from_le_bytes([lifetime1[20], lifetime1[21]])
207+
);
208+
println!(
209+
" Max Avg Dsg Current: {}mA",
210+
u16::from_le_bytes([lifetime1[22], lifetime1[23]])
211+
);
212+
println!(
213+
" Max Avg Dsg Power: {}mW",
214+
u16::from_le_bytes([lifetime1[24], lifetime1[25]])
215+
);
216+
println!(
217+
" Max Temp Cell: {}C",
218+
lifetime1[27]
219+
);
220+
println!(
221+
" Min Temp Cell: {}C",
222+
lifetime1[28]
223+
);
224+
println!(
225+
" Max Delta Cell temp: {}K",
226+
lifetime1[29]
227+
);
228+
println!(
229+
" Max Temp Int Sensor: {}C",
230+
lifetime1[29]
231+
);
232+
println!(
233+
" Min Temp Int Sensor: {}C",
234+
lifetime1[30]
235+
);
236+
println!(
237+
" Max Temp Fet: {}C",
238+
lifetime1[31]
239+
);
240+
let lifetime2 = self.read_bytes(ec, ManufReg::LifeTimeDataBlock2 as u16, 20)?; // 8?
241+
println!("LifeTime2");
242+
println!(" No. of Shutdowns: {}
243+
No. of Partial Resets: {}
244+
No. of Full Resets: {}
245+
No. of WDT resets: {}
246+
CB Time Cell 1: {}
247+
CB Time Cell 2: {}
248+
CB Time Cell 3: {}
249+
CB Time Cell 4: {}",
250+
lifetime2[0],
251+
lifetime2[1],
252+
lifetime2[2],
253+
lifetime2[3],
254+
lifetime2[4],
255+
lifetime2[5],
256+
lifetime2[6],
257+
lifetime2[7],
136258
);
137259
println!(
138260
"LifeTime3 {:X?}",
139261
self.read_bytes(ec, ManufReg::LifeTimeDataBlock3 as u16, 4)?
140262
);
263+
println!(
264+
"LifeTime4 {:X?}",
265+
self.read_bytes(ec, ManufReg::LifeTimeDataBlock4 as u16, 32)?
266+
);
267+
println!(
268+
"LifeTime5 {:X?}",
269+
self.read_bytes(ec, ManufReg::LifeTimeDataBlock5 as u16, 32)?
270+
);
141271

142-
// i2c_write(ec, i2c_port, (i2c_addr + 2) >> 1, 0x70, &[0x00])?;
143-
// os_specific::sleep(50_000);
272+
// Seal back again after we're finished
273+
self.seal(ec).unwrap();
144274

145275
Ok(())
146276
}

0 commit comments

Comments
 (0)