ina3221_dd/
driver.rs

1use super::{I2c, RegisterInterface, bisync, only_async, only_sync};
2use crate::{
3    AlertFlags, AveragingMode, BUS_VOLTAGE_LSB_MV, ChannelId, ConversionTime, Ina3221Error,
4    Ina3221Interface, Ina3221LowLevel, OperatingMode, SHUNT_VOLTAGE_LSB_UV,
5};
6
7#[bisync]
8impl<I2CBus, E> RegisterInterface for Ina3221Interface<I2CBus>
9where
10    I2CBus: I2c<Error = E>,
11    E: core::fmt::Debug,
12{
13    type AddressType = u8;
14    type Error = Ina3221Error<E>;
15    async fn read_register(
16        &mut self,
17        address: u8,
18        _size_bits: u32,
19        data: &mut [u8],
20    ) -> Result<(), Self::Error> {
21        self.i2c_bus
22            .write_read(self.address, &[address], data)
23            .await
24            .map_err(Ina3221Error::I2c)
25    }
26    async fn write_register(
27        &mut self,
28        address: u8,
29        _size_bits: u32,
30        data: &[u8],
31    ) -> Result<(), Self::Error> {
32        let mut buffer = [0u8; 5];
33        if (1 + data.len()) > buffer.len() {
34            return Err(Ina3221Error::NotSupported(
35                "Write data length exceeds buffer",
36            ));
37        }
38        buffer[0] = address;
39        buffer[1..1 + data.len()].copy_from_slice(data);
40        self.i2c_bus
41            .write(self.address, &buffer[..1 + data.len()])
42            .await
43            .map_err(Ina3221Error::I2c)
44    }
45}
46
47pub struct Ina3221<
48    I2CImpl: RegisterInterface<AddressType = u8, Error = Ina3221Error<I2CBusErr>>,
49    I2CBusErr: core::fmt::Debug,
50> {
51    pub ll: Ina3221LowLevel<I2CImpl>,
52    _marker: core::marker::PhantomData<I2CBusErr>,
53}
54
55impl<I2CBus, E> Ina3221<Ina3221Interface<I2CBus>, E>
56where
57    I2CBus: I2c<Error = E>,
58    E: core::fmt::Debug,
59{
60    pub fn new(i2c: I2CBus, address: u8) -> Self {
61        Self {
62            ll: Ina3221LowLevel::new(Ina3221Interface::new(i2c, address)),
63            _marker: core::marker::PhantomData,
64        }
65    }
66}
67
68include!("bisync_helpers.rs");
69
70impl<I2CImpl, I2CBusErr> Ina3221<I2CImpl, I2CBusErr>
71where
72    I2CImpl: RegisterInterface<AddressType = u8, Error = Ina3221Error<I2CBusErr>>,
73    I2CBusErr: core::fmt::Debug,
74{
75    // =========================================================================
76    // Voltage and Current Measurements
77    // =========================================================================
78
79    /// Get bus voltage for a specific channel in millivolts
80    /// INA3221 measures 0-26V range with 8mV LSB resolution
81    #[bisync]
82    pub async fn get_bus_voltage_mv(
83        &mut self,
84        channel: ChannelId,
85    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
86        let mut op = match channel {
87            ChannelId::Channel1 => self.ll.channel_1_bus_voltage(),
88            ChannelId::Channel2 => self.ll.channel_2_bus_voltage(),
89            ChannelId::Channel3 => self.ll.channel_3_bus_voltage(),
90        };
91
92        let bus_data = read_internal(&mut op).await?;
93
94        let raw_value = bus_data.bus_data() as u16;
95        let sign = bus_data.sign();
96
97        let voltage_mv = if sign {
98            -(raw_value as f32 * BUS_VOLTAGE_LSB_MV)
99        } else {
100            raw_value as f32 * BUS_VOLTAGE_LSB_MV
101        };
102
103        Ok(voltage_mv)
104    }
105
106    /// Get shunt voltage for a specific channel in microvolts
107    /// INA3221 measures ±163.8mV range with 40µV LSB resolution
108    #[bisync]
109    pub async fn get_shunt_voltage_uv(
110        &mut self,
111        channel: ChannelId,
112    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
113        let mut op = match channel {
114            ChannelId::Channel1 => self.ll.channel_1_shunt_voltage(),
115            ChannelId::Channel2 => self.ll.channel_2_shunt_voltage(),
116            ChannelId::Channel3 => self.ll.channel_3_shunt_voltage(),
117        };
118
119        let shunt_data = read_internal(&mut op).await?;
120
121        let raw_value = shunt_data.shunt_data() as u16;
122        let sign = shunt_data.sign();
123
124        let voltage_uv = if sign {
125            -(raw_value as f32 * SHUNT_VOLTAGE_LSB_UV)
126        } else {
127            raw_value as f32 * SHUNT_VOLTAGE_LSB_UV
128        };
129
130        Ok(voltage_uv)
131    }
132
133    /// Calculate current in milliamps for a specific channel
134    /// shunt_resistor_mohms: Shunt resistor value in milliohms
135    #[bisync]
136    pub async fn get_current_ma(
137        &mut self,
138        channel: ChannelId,
139        shunt_resistor_mohms: f32,
140    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
141        let shunt_voltage_uv = self.get_shunt_voltage_uv(channel).await?;
142        // I = V / R; V in µV, R in mΩ → I in mA
143        Ok(shunt_voltage_uv / shunt_resistor_mohms)
144    }
145
146    /// Calculate power in milliwatts for a specific channel
147    /// shunt_resistor_mohms: Shunt resistor value in milliohms
148    #[bisync]
149    pub async fn get_power_mw(
150        &mut self,
151        channel: ChannelId,
152        shunt_resistor_mohms: f32,
153    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
154        let bus_voltage_mv = self.get_bus_voltage_mv(channel).await?;
155        let current_ma = self.get_current_ma(channel, shunt_resistor_mohms).await?;
156        // P = V * I; V in mV, I in mA → P in µW, divide by 1000 for mW
157        Ok((bus_voltage_mv * current_ma) / 1000.0)
158    }
159
160    // =========================================================================
161    // Channel Configuration
162    // =========================================================================
163
164    /// Enable or disable a specific channel
165    #[bisync]
166    pub async fn set_channel_enable(
167        &mut self,
168        channel: ChannelId,
169        enable: bool,
170    ) -> Result<(), Ina3221Error<I2CBusErr>> {
171        let mut op = self.ll.configuration();
172        modify_internal(&mut op, |r| match channel {
173            ChannelId::Channel1 => r.set_ch_1_enable(enable),
174            ChannelId::Channel2 => r.set_ch_2_enable(enable),
175            ChannelId::Channel3 => r.set_ch_3_enable(enable),
176        })
177        .await
178    }
179
180    /// Check if a specific channel is enabled
181    #[bisync]
182    pub async fn is_channel_enabled(
183        &mut self,
184        channel: ChannelId,
185    ) -> Result<bool, Ina3221Error<I2CBusErr>> {
186        let mut op = self.ll.configuration();
187        let config = read_internal(&mut op).await?;
188        Ok(match channel {
189            ChannelId::Channel1 => config.ch_1_enable(),
190            ChannelId::Channel2 => config.ch_2_enable(),
191            ChannelId::Channel3 => config.ch_3_enable(),
192        })
193    }
194
195    /// Enable or disable all channels at once
196    #[bisync]
197    pub async fn set_all_channels_enable(
198        &mut self,
199        ch1: bool,
200        ch2: bool,
201        ch3: bool,
202    ) -> Result<(), Ina3221Error<I2CBusErr>> {
203        let mut op = self.ll.configuration();
204        modify_internal(&mut op, |r| {
205            r.set_ch_1_enable(ch1);
206            r.set_ch_2_enable(ch2);
207            r.set_ch_3_enable(ch3);
208        })
209        .await
210    }
211
212    // =========================================================================
213    // Operating Mode Configuration
214    // =========================================================================
215
216    /// Get the current operating mode
217    #[bisync]
218    pub async fn get_operating_mode(&mut self) -> Result<OperatingMode, Ina3221Error<I2CBusErr>> {
219        let mut op = self.ll.configuration();
220        let config = read_internal(&mut op).await?;
221        Ok(OperatingMode::from_raw(config.operating_mode() as u8))
222    }
223
224    /// Set the operating mode
225    #[bisync]
226    pub async fn set_operating_mode(
227        &mut self,
228        mode: OperatingMode,
229    ) -> Result<(), Ina3221Error<I2CBusErr>> {
230        let mut op = self.ll.configuration();
231        modify_internal(&mut op, |r| r.set_operating_mode(mode as u8)).await
232    }
233
234    /// Get the averaging mode
235    #[bisync]
236    pub async fn get_averaging_mode(&mut self) -> Result<AveragingMode, Ina3221Error<I2CBusErr>> {
237        let mut op = self.ll.configuration();
238        let config = read_internal(&mut op).await?;
239        Ok(AveragingMode::from_raw(config.averaging_mode() as u8))
240    }
241
242    /// Set the averaging mode (number of samples to average)
243    #[bisync]
244    pub async fn set_averaging_mode(
245        &mut self,
246        mode: AveragingMode,
247    ) -> Result<(), Ina3221Error<I2CBusErr>> {
248        let mut op = self.ll.configuration();
249        modify_internal(&mut op, |r| r.set_averaging_mode(mode as u8)).await
250    }
251
252    /// Get the bus voltage conversion time
253    #[bisync]
254    pub async fn get_vbus_conversion_time(
255        &mut self,
256    ) -> Result<ConversionTime, Ina3221Error<I2CBusErr>> {
257        let mut op = self.ll.configuration();
258        let config = read_internal(&mut op).await?;
259        Ok(ConversionTime::from_raw(config.vbus_conversion_time() as u8))
260    }
261
262    /// Set the bus voltage conversion time
263    #[bisync]
264    pub async fn set_vbus_conversion_time(
265        &mut self,
266        time: ConversionTime,
267    ) -> Result<(), Ina3221Error<I2CBusErr>> {
268        let mut op = self.ll.configuration();
269        modify_internal(&mut op, |r| r.set_vbus_conversion_time(time as u8)).await
270    }
271
272    /// Get the shunt voltage conversion time
273    #[bisync]
274    pub async fn get_vshunt_conversion_time(
275        &mut self,
276    ) -> Result<ConversionTime, Ina3221Error<I2CBusErr>> {
277        let mut op = self.ll.configuration();
278        let config = read_internal(&mut op).await?;
279        Ok(ConversionTime::from_raw(
280            config.vshunt_conversion_time() as u8
281        ))
282    }
283
284    /// Set the shunt voltage conversion time
285    #[bisync]
286    pub async fn set_vshunt_conversion_time(
287        &mut self,
288        time: ConversionTime,
289    ) -> Result<(), Ina3221Error<I2CBusErr>> {
290        let mut op = self.ll.configuration();
291        modify_internal(&mut op, |r| r.set_vshunt_conversion_time(time as u8)).await
292    }
293
294    // =========================================================================
295    // Alert Limits
296    // =========================================================================
297
298    /// Get the critical alert limit for a channel in microvolts
299    #[bisync]
300    pub async fn get_critical_alert_limit_uv(
301        &mut self,
302        channel: ChannelId,
303    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
304        let raw = match channel {
305            ChannelId::Channel1 => {
306                let mut op = self.ll.channel_1_critical_alert_limit();
307                read_internal(&mut op).await?.limit_data()
308            }
309            ChannelId::Channel2 => {
310                let mut op = self.ll.channel_2_critical_alert_limit();
311                read_internal(&mut op).await?.limit_data()
312            }
313            ChannelId::Channel3 => {
314                let mut op = self.ll.channel_3_critical_alert_limit();
315                read_internal(&mut op).await?.limit_data()
316            }
317        };
318        Ok(raw as f32 * SHUNT_VOLTAGE_LSB_UV)
319    }
320
321    /// Set the critical alert limit for a channel in microvolts
322    #[bisync]
323    pub async fn set_critical_alert_limit_uv(
324        &mut self,
325        channel: ChannelId,
326        limit_uv: f32,
327    ) -> Result<(), Ina3221Error<I2CBusErr>> {
328        let raw = (limit_uv / SHUNT_VOLTAGE_LSB_UV) as u16;
329        match channel {
330            ChannelId::Channel1 => {
331                let mut op = self.ll.channel_1_critical_alert_limit();
332                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
333            }
334            ChannelId::Channel2 => {
335                let mut op = self.ll.channel_2_critical_alert_limit();
336                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
337            }
338            ChannelId::Channel3 => {
339                let mut op = self.ll.channel_3_critical_alert_limit();
340                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
341            }
342        }
343    }
344
345    /// Get the warning alert limit for a channel in microvolts
346    #[bisync]
347    pub async fn get_warning_alert_limit_uv(
348        &mut self,
349        channel: ChannelId,
350    ) -> Result<f32, Ina3221Error<I2CBusErr>> {
351        let raw = match channel {
352            ChannelId::Channel1 => {
353                let mut op = self.ll.channel_1_warning_alert_limit();
354                read_internal(&mut op).await?.limit_data()
355            }
356            ChannelId::Channel2 => {
357                let mut op = self.ll.channel_2_warning_alert_limit();
358                read_internal(&mut op).await?.limit_data()
359            }
360            ChannelId::Channel3 => {
361                let mut op = self.ll.channel_3_warning_alert_limit();
362                read_internal(&mut op).await?.limit_data()
363            }
364        };
365        Ok(raw as f32 * SHUNT_VOLTAGE_LSB_UV)
366    }
367
368    /// Set the warning alert limit for a channel in microvolts
369    #[bisync]
370    pub async fn set_warning_alert_limit_uv(
371        &mut self,
372        channel: ChannelId,
373        limit_uv: f32,
374    ) -> Result<(), Ina3221Error<I2CBusErr>> {
375        let raw = (limit_uv / SHUNT_VOLTAGE_LSB_UV) as u16;
376        match channel {
377            ChannelId::Channel1 => {
378                let mut op = self.ll.channel_1_warning_alert_limit();
379                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
380            }
381            ChannelId::Channel2 => {
382                let mut op = self.ll.channel_2_warning_alert_limit();
383                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
384            }
385            ChannelId::Channel3 => {
386                let mut op = self.ll.channel_3_warning_alert_limit();
387                modify_internal(&mut op, |r| r.set_limit_data(raw)).await
388            }
389        }
390    }
391
392    /// Get the power-valid upper and lower limits in millivolts
393    #[bisync]
394    pub async fn get_power_valid_limits_mv(
395        &mut self,
396    ) -> Result<(f32, f32), Ina3221Error<I2CBusErr>> {
397        let mut op_upper = self.ll.power_valid_upper_limit();
398        let upper = read_internal(&mut op_upper).await?.limit_data();
399
400        let mut op_lower = self.ll.power_valid_lower_limit();
401        let lower = read_internal(&mut op_lower).await?.limit_data();
402
403        Ok((
404            lower as f32 * BUS_VOLTAGE_LSB_MV,
405            upper as f32 * BUS_VOLTAGE_LSB_MV,
406        ))
407    }
408
409    /// Set the power-valid upper and lower limits in millivolts
410    #[bisync]
411    pub async fn set_power_valid_limits_mv(
412        &mut self,
413        lower_mv: f32,
414        upper_mv: f32,
415    ) -> Result<(), Ina3221Error<I2CBusErr>> {
416        let lower_raw = (lower_mv / BUS_VOLTAGE_LSB_MV) as u16;
417        let upper_raw = (upper_mv / BUS_VOLTAGE_LSB_MV) as u16;
418
419        let mut op_lower = self.ll.power_valid_lower_limit();
420        modify_internal(&mut op_lower, |r| r.set_limit_data(lower_raw)).await?;
421
422        let mut op_upper = self.ll.power_valid_upper_limit();
423        modify_internal(&mut op_upper, |r| r.set_limit_data(upper_raw)).await
424    }
425
426    // =========================================================================
427    // Alert Configuration
428    // =========================================================================
429
430    /// Enable or disable critical alert latch mode
431    #[bisync]
432    pub async fn set_critical_alert_latch(
433        &mut self,
434        enable: bool,
435    ) -> Result<(), Ina3221Error<I2CBusErr>> {
436        let mut op = self.ll.mask_enable();
437        modify_internal(&mut op, |r| r.set_critical_alert_enable(enable)).await
438    }
439
440    /// Enable or disable warning alert latch mode
441    #[bisync]
442    pub async fn set_warning_alert_latch(
443        &mut self,
444        enable: bool,
445    ) -> Result<(), Ina3221Error<I2CBusErr>> {
446        let mut op = self.ll.mask_enable();
447        modify_internal(&mut op, |r| r.set_warning_alert_enable(enable)).await
448    }
449
450    /// Read alert flags (clears flags on read)
451    #[bisync]
452    pub async fn get_alert_flags(&mut self) -> Result<AlertFlags, Ina3221Error<I2CBusErr>> {
453        let mut op = self.ll.mask_enable();
454        let reg = read_internal(&mut op).await?;
455        Ok(AlertFlags {
456            conversion_ready: reg.conversion_ready_flag(),
457            timing_control: reg.timing_control_flag(),
458            power_valid: reg.power_valid_flag(),
459            warning_ch1: reg.warning_flag_ch_1(),
460            warning_ch2: reg.warning_flag_ch_2(),
461            warning_ch3: reg.warning_flag_ch_3(),
462            summation: reg.summation_flag(),
463            critical_ch1: reg.critical_flag_ch_1(),
464            critical_ch2: reg.critical_flag_ch_2(),
465            critical_ch3: reg.critical_flag_ch_3(),
466        })
467    }
468
469    /// Check if conversion is ready
470    #[bisync]
471    pub async fn is_conversion_ready(&mut self) -> Result<bool, Ina3221Error<I2CBusErr>> {
472        let flags = self.get_alert_flags().await?;
473        Ok(flags.conversion_ready)
474    }
475
476    // =========================================================================
477    // Summation Control
478    // =========================================================================
479
480    /// Enable or disable a channel in the shunt voltage summation
481    #[bisync]
482    pub async fn set_summation_channel_enable(
483        &mut self,
484        channel: ChannelId,
485        enable: bool,
486    ) -> Result<(), Ina3221Error<I2CBusErr>> {
487        let mut op = self.ll.mask_enable();
488        modify_internal(&mut op, |r| match channel {
489            ChannelId::Channel1 => r.set_sum_control_ch_1(enable),
490            ChannelId::Channel2 => r.set_sum_control_ch_2(enable),
491            ChannelId::Channel3 => r.set_sum_control_ch_3(enable),
492        })
493        .await
494    }
495
496    /// Get the shunt voltage sum in microvolts
497    #[bisync]
498    pub async fn get_shunt_voltage_sum_uv(&mut self) -> Result<f32, Ina3221Error<I2CBusErr>> {
499        let mut op = self.ll.shunt_voltage_sum();
500        let data = read_internal(&mut op).await?;
501        let raw = data.sum_data() as u16;
502        let sign = data.sign();
503
504        let voltage_uv = if sign {
505            -(raw as f32 * SHUNT_VOLTAGE_LSB_UV)
506        } else {
507            raw as f32 * SHUNT_VOLTAGE_LSB_UV
508        };
509        Ok(voltage_uv)
510    }
511
512    /// Get the shunt voltage sum limit in microvolts
513    #[bisync]
514    pub async fn get_shunt_voltage_sum_limit_uv(&mut self) -> Result<f32, Ina3221Error<I2CBusErr>> {
515        let mut op = self.ll.shunt_voltage_sum_limit();
516        let data = read_internal(&mut op).await?;
517        Ok(data.limit_data() as f32 * SHUNT_VOLTAGE_LSB_UV)
518    }
519
520    /// Set the shunt voltage sum limit in microvolts
521    #[bisync]
522    pub async fn set_shunt_voltage_sum_limit_uv(
523        &mut self,
524        limit_uv: f32,
525    ) -> Result<(), Ina3221Error<I2CBusErr>> {
526        let raw = (limit_uv / SHUNT_VOLTAGE_LSB_UV) as u16;
527        let mut op = self.ll.shunt_voltage_sum_limit();
528        modify_internal(&mut op, |r| r.set_limit_data(raw)).await
529    }
530
531    // =========================================================================
532    // Device Info and Control
533    // =========================================================================
534
535    /// Get the manufacturer ID (should be 0x5449 = "TI")
536    #[bisync]
537    pub async fn get_manufacturer_id(&mut self) -> Result<u16, Ina3221Error<I2CBusErr>> {
538        let mut op = self.ll.manufacturer_id();
539        let id = read_internal(&mut op).await?;
540        Ok(id.manufacturer_id() as u16)
541    }
542
543    /// Get the die ID (should be 0x3220)
544    #[bisync]
545    pub async fn get_die_id(&mut self) -> Result<u16, Ina3221Error<I2CBusErr>> {
546        let mut op = self.ll.die_id();
547        let id = read_internal(&mut op).await?;
548        Ok(id.die_id() as u16)
549    }
550
551    /// Perform software reset
552    #[bisync]
553    pub async fn reset(&mut self) -> Result<(), Ina3221Error<I2CBusErr>> {
554        let mut op = self.ll.configuration();
555        modify_internal(&mut op, |r| r.set_reset(true)).await
556    }
557}
558
559// =============================================================================
560// UOM-based API (behind feature flag)
561// =============================================================================
562
563#[cfg(feature = "uom")]
564impl<I2CImpl, I2CBusErr> Ina3221<I2CImpl, I2CBusErr>
565where
566    I2CImpl: RegisterInterface<AddressType = u8, Error = Ina3221Error<I2CBusErr>>,
567    I2CBusErr: core::fmt::Debug,
568{
569    /// Get bus voltage for a specific channel as ElectricPotential
570    #[bisync]
571    pub async fn get_bus_voltage(
572        &mut self,
573        channel: ChannelId,
574    ) -> Result<crate::ElectricPotential, Ina3221Error<I2CBusErr>> {
575        let mv = self.get_bus_voltage_mv(channel).await?;
576        Ok(crate::ElectricPotential::new::<crate::millivolt>(mv))
577    }
578
579    /// Get shunt voltage for a specific channel as ElectricPotential
580    #[bisync]
581    pub async fn get_shunt_voltage(
582        &mut self,
583        channel: ChannelId,
584    ) -> Result<crate::ElectricPotential, Ina3221Error<I2CBusErr>> {
585        let uv = self.get_shunt_voltage_uv(channel).await?;
586        Ok(crate::ElectricPotential::new::<crate::microvolt>(uv))
587    }
588
589    /// Get current for a specific channel as ElectricCurrent
590    #[bisync]
591    pub async fn get_current(
592        &mut self,
593        channel: ChannelId,
594        shunt_resistor: crate::ElectricalResistance,
595    ) -> Result<crate::ElectricCurrent, Ina3221Error<I2CBusErr>> {
596        let shunt_mohms = shunt_resistor.get::<crate::milliohm>();
597        let ma = self.get_current_ma(channel, shunt_mohms).await?;
598        Ok(crate::ElectricCurrent::new::<crate::milliampere>(ma))
599    }
600
601    /// Set critical alert limit for a channel using ElectricPotential
602    #[bisync]
603    pub async fn set_critical_alert_limit(
604        &mut self,
605        channel: ChannelId,
606        limit: crate::ElectricPotential,
607    ) -> Result<(), Ina3221Error<I2CBusErr>> {
608        let uv = limit.get::<crate::microvolt>();
609        self.set_critical_alert_limit_uv(channel, uv).await
610    }
611
612    /// Set warning alert limit for a channel using ElectricPotential
613    #[bisync]
614    pub async fn set_warning_alert_limit(
615        &mut self,
616        channel: ChannelId,
617        limit: crate::ElectricPotential,
618    ) -> Result<(), Ina3221Error<I2CBusErr>> {
619        let uv = limit.get::<crate::microvolt>();
620        self.set_warning_alert_limit_uv(channel, uv).await
621    }
622
623    /// Set power-valid limits using ElectricPotential
624    #[bisync]
625    pub async fn set_power_valid_limits(
626        &mut self,
627        lower: crate::ElectricPotential,
628        upper: crate::ElectricPotential,
629    ) -> Result<(), Ina3221Error<I2CBusErr>> {
630        let lower_mv = lower.get::<crate::millivolt>();
631        let upper_mv = upper.get::<crate::millivolt>();
632        self.set_power_valid_limits_mv(lower_mv, upper_mv).await
633    }
634}