waveshare_ups_hat_e/
lib.rs1#![doc = include_str!("../README.md")]
5
6pub mod error;
7pub mod registers;
8
9use error::Error;
10use i2cdev::core::I2CDevice;
11use i2cdev::linux::LinuxI2CDevice;
12use registers::{
13 BATTERY_REG, CELL_VOLTAGE_REG, CHARGING_REG, USBC_VBUS_REG,
14 ChargerActivity, ChargingState, UsbCInputState, UsbCPowerDelivery,
15};
16
17pub const DEFAULT_I2C_ADDRESS: u16 = 0x2d;
19
20pub const DEFAULT_I2C_DEV_PATH: &str = "/dev/i2c-1";
22
23#[derive(Debug)]
25pub struct PowerState {
26 pub charging_state: ChargingState,
27 pub charger_activity: ChargerActivity,
28 pub usbc_input_state: UsbCInputState,
29 pub usbc_power_delivery: UsbCPowerDelivery,
30}
31
32#[derive(Debug)]
40pub struct BatteryState {
41 pub millivolts: u16,
42 pub milliamps: i16,
43 pub remaining_percent: u16,
44 pub remaining_capacity_milliamphours: u16,
45 pub remaining_runtime_minutes: u16,
46 pub time_to_full_minutes: u16,
47}
48
49#[derive(Debug)]
51pub struct CellVoltage {
52 pub cell_1_millivolts: u16,
53 pub cell_2_millivolts: u16,
54 pub cell_3_millivolts: u16,
55 pub cell_4_millivolts: u16,
56}
57
58#[derive(Debug)]
60pub struct UsbCVBus {
61 pub millivolts: u16,
62 pub milliamps: u16,
63 pub milliwatts: u16,
64}
65
66pub struct UpsHatE {
72 i2c_bus: LinuxI2CDevice,
73}
74
75impl Default for UpsHatE {
76 fn default() -> Self {
79 let i2c = LinuxI2CDevice::new(DEFAULT_I2C_DEV_PATH, DEFAULT_I2C_ADDRESS)
80 .expect("Failed to open I2C device");
81
82 Self { i2c_bus: i2c }
83 }
84}
85
86impl UpsHatE {
87 pub fn new() -> Self {
90 Self::default()
91 }
92
93 pub fn from_i2c_device(i2c_bus: LinuxI2CDevice) -> Self {
96 Self { i2c_bus }
97 }
98
99 pub fn get_cell_voltage(&mut self) -> Result<CellVoltage, Error> {
100 let data = self.read_block(CELL_VOLTAGE_REG.id, CELL_VOLTAGE_REG.length)?;
101
102 let voltages = CellVoltage {
103 cell_1_millivolts: data[0] as u16 | (data[1] as u16) << 8,
104 cell_2_millivolts: data[2] as u16 | (data[3] as u16) << 8,
105 cell_3_millivolts: data[4] as u16 | (data[5] as u16) << 8,
106 cell_4_millivolts: data[6] as u16 | (data[7] as u16) << 8,
107 };
108
109 Ok(voltages)
110 }
111
112 pub fn get_usbc_vbus(&mut self) -> Result<UsbCVBus, Error> {
113 let data = self.read_block(USBC_VBUS_REG.id, USBC_VBUS_REG.length)?;
114
115 let vbus = UsbCVBus {
116 millivolts: data[0] as u16 | (data[1] as u16) << 8,
117 milliamps: data[2] as u16 | (data[3] as u16) << 8,
118 milliwatts: data[4] as u16 | (data[5] as u16) << 8,
119 };
120
121 Ok(vbus)
122 }
123
124 pub fn get_battery_state(&mut self) -> Result<BatteryState, Error> {
125 let data = self.read_block(BATTERY_REG.id, BATTERY_REG.length)?;
126
127 let milliamps: i16 = {
128 let mut current = data[2] as i32 | (data[3] as i32) << 8;
129 if current > 0x7fff {
131 current -= 0xffff;
132 }
133 current as i16
134 };
135
136 let mut remaining_runtime_minutes: u16 = 0;
137 let mut time_to_full_minutes: u16 = 0;
138
139 if milliamps < 0 {
140 remaining_runtime_minutes = data[8] as u16 | (data[9] as u16) << 8;
142 } else {
143 time_to_full_minutes = data[10] as u16 | (data[11] as u16) << 8;
145 }
146
147 let state = BatteryState {
148 millivolts: data[0] as u16 | (data[1] as u16) << 8,
149 milliamps,
150 remaining_percent: data[4] as u16 | (data[5] as u16) << 8,
151 remaining_capacity_milliamphours: data[6] as u16 | (data[7] as u16) << 8,
152 remaining_runtime_minutes,
153 time_to_full_minutes,
154 };
155
156 Ok(state)
157 }
158
159 pub fn get_power_state(&mut self) -> Result<PowerState, Error> {
160 let data = self.read_block(CHARGING_REG.id, CHARGING_REG.length)?;
161 let byte = data[0];
162
163 let charger_activity = ChargerActivity::try_from(byte & 0b111)?;
164 let usbc_input_state = UsbCInputState::from(byte & (1 << 5) != 0);
165 let usbc_power_delivery = UsbCPowerDelivery::from(byte & (1 << 6) != 0);
166 let charging_state = ChargingState::from(byte & (1 << 7) != 0);
167
168 Ok(PowerState {
169 charging_state,
170 charger_activity,
171 usbc_input_state,
172 usbc_power_delivery,
173 })
174 }
175
176 fn read_block(&mut self, register: u8, length: u8) -> Result<Vec<u8>, Error> {
177 let data = self.i2c_bus.smbus_read_i2c_block_data(register, length)?;
178
179 if data.len() != length as usize {
180 return Err(Error::InvalidDataLen(register, length as usize, data.len()));
181 }
182
183 Ok(data)
184 }
185}