@@ -5,19 +5,23 @@ use alloc::vec::Vec;
55
66use crate :: chromium_ec:: i2c_passthrough:: * ;
77use crate :: chromium_ec:: { CrosEc , EcResult } ;
8- //use crate::os_specific;
98
109#[ repr( u16 ) ]
1110enum 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
3845pub 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