1use embedded_hal::i2c::{I2c, SevenBitAddress};
4use uom::si::{
5 electric_current::{microampere, milliampere},
6 f32::ElectricCurrent,
7};
8
9use crate::{
10 device::AFE4404,
11 errors::AfeError,
12 modes::{LedMode, ThreeLedsMode, TwoLedsMode},
13 register_structs::R22h,
14};
15
16impl<I2C, MODE> AFE4404<I2C, MODE>
17where
18 I2C: I2c<SevenBitAddress>,
19 MODE: LedMode,
20{
21 fn scale_current(reg_value: u8, prev_2x: bool, curr_2x: bool) -> u8 {
23 if prev_2x == curr_2x {
24 reg_value
25 } else if curr_2x {
26 reg_value / 2
27 } else {
28 reg_value * 2
29 }
30 }
31
32 pub fn set_led1_current(
44 &mut self,
45 current: ElectricCurrent,
46 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
47 let r22h_prev = self.registers.r22h.read()?;
48 let r23h_prev = self.registers.r23h.read()?;
49
50 let high_current = current.get::<milliampere>() > 50.0
51 || (r23h_prev.iled_2x() && (r22h_prev.iled2() > 31 || r22h_prev.iled3() > 31));
52
53 let range = if high_current {
54 ElectricCurrent::new::<milliampere>(100.0)
55 } else {
56 ElectricCurrent::new::<milliampere>(50.0)
57 };
58
59 let quantisation = range / 63.0;
60
61 if current > range || current.get::<milliampere>() < 0.0 {
62 return Err(AfeError::LedCurrentOutsideAllowedRange);
63 }
64
65 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
66 let values = [
67 (current / quantisation).value.round() as u8,
68 Self::scale_current(r22h_prev.iled2(), r23h_prev.iled_2x(), high_current),
69 Self::scale_current(r22h_prev.iled3(), r23h_prev.iled_2x(), high_current),
70 ];
71
72 self.registers.r22h.write(
73 R22h::new()
74 .with_iled1(values[0])
75 .with_iled2(values[1])
76 .with_iled3(values[2]),
77 )?;
78 self.registers
79 .r23h
80 .write(r23h_prev.with_iled_2x(high_current))?;
81
82 Ok(f32::from(values[0]) * quantisation)
83 }
84
85 pub fn set_led2_current(
97 &mut self,
98 current: ElectricCurrent,
99 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
100 let r22h_prev = self.registers.r22h.read()?;
101 let r23h_prev = self.registers.r23h.read()?;
102
103 let high_current = current.get::<milliampere>() > 50.0
104 || (r23h_prev.iled_2x() && (r22h_prev.iled1() > 31 || r22h_prev.iled3() > 31));
105
106 let range = if high_current {
107 ElectricCurrent::new::<milliampere>(100.0)
108 } else {
109 ElectricCurrent::new::<milliampere>(50.0)
110 };
111
112 let quantisation = range / 63.0;
113
114 if current > range || current.get::<milliampere>() < 0.0 {
115 return Err(AfeError::LedCurrentOutsideAllowedRange);
116 }
117
118 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
119 let values = [
120 Self::scale_current(r22h_prev.iled1(), r23h_prev.iled_2x(), high_current),
121 (current / quantisation).value.round() as u8,
122 Self::scale_current(r22h_prev.iled3(), r23h_prev.iled_2x(), high_current),
123 ];
124
125 self.registers.r22h.write(
126 R22h::new()
127 .with_iled1(values[0])
128 .with_iled2(values[1])
129 .with_iled3(values[2]),
130 )?;
131 self.registers
132 .r23h
133 .write(r23h_prev.with_iled_2x(high_current))?;
134
135 Ok(f32::from(values[1]) * quantisation)
136 }
137
138 pub fn get_led1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
144 let r22h_prev = self.registers.r22h.read()?;
145 let r23h_prev = self.registers.r23h.read()?;
146
147 let range = if r23h_prev.iled_2x() {
148 ElectricCurrent::new::<milliampere>(100.0)
149 } else {
150 ElectricCurrent::new::<milliampere>(50.0)
151 };
152 let quantisation = range / 63.0;
153
154 Ok(f32::from(r22h_prev.iled1()) * quantisation)
155 }
156
157 pub fn get_led2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
163 let r22h_prev = self.registers.r22h.read()?;
164 let r23h_prev = self.registers.r23h.read()?;
165
166 let range = if r23h_prev.iled_2x() {
167 ElectricCurrent::new::<milliampere>(100.0)
168 } else {
169 ElectricCurrent::new::<milliampere>(50.0)
170 };
171 let quantisation = range / 63.0;
172
173 Ok(f32::from(r22h_prev.iled2()) * quantisation)
174 }
175
176 pub fn set_offset_led1_current(
183 &mut self,
184 offset: ElectricCurrent,
185 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
186 let r3ah_prev = self.registers.r3Ah.read()?;
187
188 let range = ElectricCurrent::new::<microampere>(7.0);
189 let quantisation = range / 15.0;
190
191 if offset > range || offset < -range {
192 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
193 }
194
195 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
196 let value = (
197 (offset.abs() / quantisation).value.round() as u8,
198 offset.get::<microampere>() < 0.0,
199 );
200
201 self.registers.r3Ah.write(
202 r3ah_prev
203 .with_i_offdac_led1(value.0)
204 .with_pol_offdac_led1(value.1),
205 )?;
206
207 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
208 }
209
210 pub fn set_offset_led2_current(
217 &mut self,
218 offset: ElectricCurrent,
219 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
220 let r3ah_prev = self.registers.r3Ah.read()?;
221
222 let range = ElectricCurrent::new::<microampere>(7.0);
223 let quantisation = range / 15.0;
224
225 if offset > range || offset < -range {
226 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
227 }
228
229 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
230 let value = (
231 (offset.abs() / quantisation).value.round() as u8,
232 offset.get::<microampere>() < 0.0,
233 );
234
235 self.registers.r3Ah.write(
236 r3ah_prev
237 .with_i_offdac_led2(value.0)
238 .with_pol_offdac_led2(value.1),
239 )?;
240
241 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
242 }
243
244 pub fn get_offset_led1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
250 let r3ah_prev = self.registers.r3Ah.read()?;
251
252 let range = ElectricCurrent::new::<microampere>(7.0);
253 let quantisation = range / 15.0;
254
255 Ok(f32::from(r3ah_prev.i_offdac_led1())
256 * quantisation
257 * if r3ah_prev.pol_offdac_led1() {
258 -1.0
259 } else {
260 1.0
261 })
262 }
263
264 pub fn get_offset_led2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
270 let r3ah_prev = self.registers.r3Ah.read()?;
271
272 let range = ElectricCurrent::new::<microampere>(7.0);
273 let quantisation = range / 15.0;
274
275 Ok(f32::from(r3ah_prev.i_offdac_led2())
276 * quantisation
277 * if r3ah_prev.pol_offdac_led2() {
278 -1.0
279 } else {
280 1.0
281 })
282 }
283}
284
285impl<I2C> AFE4404<I2C, ThreeLedsMode>
286where
287 I2C: I2c<SevenBitAddress>,
288{
289 pub fn set_led3_current(
301 &mut self,
302 current: ElectricCurrent,
303 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
304 let r22h_prev = self.registers.r22h.read()?;
305 let r23h_prev = self.registers.r23h.read()?;
306
307 let high_current = current.get::<milliampere>() > 50.0
308 || (r23h_prev.iled_2x() && (r22h_prev.iled1() > 31 || r22h_prev.iled2() > 31));
309
310 let range = if high_current {
311 ElectricCurrent::new::<milliampere>(100.0)
312 } else {
313 ElectricCurrent::new::<milliampere>(50.0)
314 };
315
316 let quantisation = range / 63.0;
317
318 if current > range || current.get::<milliampere>() < 0.0 {
319 return Err(AfeError::LedCurrentOutsideAllowedRange);
320 }
321
322 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
323 let values = [
324 Self::scale_current(r22h_prev.iled1(), r23h_prev.iled_2x(), high_current),
325 Self::scale_current(r22h_prev.iled2(), r23h_prev.iled_2x(), high_current),
326 (current / quantisation).value.round() as u8,
327 ];
328
329 self.registers.r22h.write(
330 R22h::new()
331 .with_iled1(values[0])
332 .with_iled2(values[1])
333 .with_iled3(values[2]),
334 )?;
335 self.registers
336 .r23h
337 .write(r23h_prev.with_iled_2x(high_current))?;
338
339 Ok(f32::from(values[2]) * quantisation)
340 }
341
342 pub fn get_led3_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
348 let r22h_prev = self.registers.r22h.read()?;
349 let r23h_prev = self.registers.r23h.read()?;
350
351 let range = if r23h_prev.iled_2x() {
352 ElectricCurrent::new::<milliampere>(100.0)
353 } else {
354 ElectricCurrent::new::<milliampere>(50.0)
355 };
356 let quantisation = range / 63.0;
357
358 Ok(f32::from(r22h_prev.iled3()) * quantisation)
359 }
360
361 pub fn set_offset_led3_current(
368 &mut self,
369 offset: ElectricCurrent,
370 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
371 let r3ah_prev = self.registers.r3Ah.read()?;
372
373 let range = ElectricCurrent::new::<microampere>(7.0);
374 let quantisation = range / 15.0;
375
376 if offset > range || offset < -range {
377 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
378 }
379
380 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
381 let value = (
382 (offset.abs() / quantisation).value.round() as u8,
383 offset.get::<microampere>() < 0.0,
384 );
385
386 self.registers.r3Ah.write(
387 r3ah_prev
388 .with_i_offdac_amb2_or_i_offdac_led3(value.0)
389 .with_pol_offdac_amb2_or_pol_offdac_led3(value.1),
390 )?;
391
392 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
393 }
394
395 pub fn set_offset_amb_current(
402 &mut self,
403 offset: ElectricCurrent,
404 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
405 let r3ah_prev = self.registers.r3Ah.read()?;
406
407 let range = ElectricCurrent::new::<microampere>(7.0);
408 let quantisation = range / 15.0;
409
410 if offset > range || offset < -range {
411 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
412 }
413
414 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
415 let value = (
416 (offset.abs() / quantisation).value.round() as u8,
417 offset.get::<microampere>() < 0.0,
418 );
419
420 self.registers.r3Ah.write(
421 r3ah_prev
422 .with_i_offdac_amb1(value.0)
423 .with_pol_offdac_amb1(value.1),
424 )?;
425
426 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
427 }
428
429 pub fn get_offset_led3_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
435 let r3ah_prev = self.registers.r3Ah.read()?;
436
437 let range = ElectricCurrent::new::<microampere>(7.0);
438 let quantisation = range / 15.0;
439
440 Ok(f32::from(r3ah_prev.i_offdac_amb2_or_i_offdac_led3())
441 * quantisation
442 * if r3ah_prev.pol_offdac_amb2_or_pol_offdac_led3() {
443 -1.0
444 } else {
445 1.0
446 })
447 }
448
449 pub fn get_offset_amb_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
455 let r3ah_prev = self.registers.r3Ah.read()?;
456
457 let range = ElectricCurrent::new::<microampere>(7.0);
458 let quantisation = range / 15.0;
459
460 Ok(f32::from(r3ah_prev.i_offdac_amb1())
461 * quantisation
462 * if r3ah_prev.pol_offdac_amb1() {
463 -1.0
464 } else {
465 1.0
466 })
467 }
468}
469
470impl<I2C> AFE4404<I2C, TwoLedsMode>
471where
472 I2C: I2c<SevenBitAddress>,
473{
474 pub fn set_offset_amb1_current(
481 &mut self,
482 offset: ElectricCurrent,
483 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
484 let r3ah_prev = self.registers.r3Ah.read()?;
485
486 let range = ElectricCurrent::new::<microampere>(7.0);
487 let quantisation = range / 15.0;
488
489 if offset > range || offset < -range {
490 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
491 }
492
493 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
494 let value = (
495 (offset.abs() / quantisation).value.round() as u8,
496 offset.get::<microampere>() < 0.0,
497 );
498
499 self.registers.r3Ah.write(
500 r3ah_prev
501 .with_i_offdac_amb1(value.0)
502 .with_pol_offdac_amb1(value.1),
503 )?;
504
505 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
506 }
507
508 pub fn set_offset_amb2_current(
515 &mut self,
516 offset: ElectricCurrent,
517 ) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
518 let r3ah_prev = self.registers.r3Ah.read()?;
519
520 let range = ElectricCurrent::new::<microampere>(7.0);
521 let quantisation = range / 15.0;
522
523 if offset > range || offset < -range {
524 return Err(AfeError::OffsetCurrentOutsideAllowedRange);
525 }
526
527 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
528 let value = (
529 (offset.abs() / quantisation).value.round() as u8,
530 offset.get::<microampere>() < 0.0,
531 );
532
533 self.registers.r3Ah.write(
534 r3ah_prev
535 .with_i_offdac_amb2_or_i_offdac_led3(value.0)
536 .with_pol_offdac_amb2_or_pol_offdac_led3(value.1),
537 )?;
538
539 Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
540 }
541
542 pub fn get_offset_amb1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
548 let r3ah_prev = self.registers.r3Ah.read()?;
549
550 let range = ElectricCurrent::new::<microampere>(7.0);
551 let quantisation = range / 15.0;
552
553 Ok(f32::from(r3ah_prev.i_offdac_amb1())
554 * quantisation
555 * if r3ah_prev.pol_offdac_amb1() {
556 -1.0
557 } else {
558 1.0
559 })
560 }
561
562 pub fn get_offset_amb2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
568 let r3ah_prev = self.registers.r3Ah.read()?;
569
570 let range = ElectricCurrent::new::<microampere>(7.0);
571 let quantisation = range / 15.0;
572
573 Ok(f32::from(r3ah_prev.i_offdac_amb2_or_i_offdac_led3())
574 * quantisation
575 * if r3ah_prev.pol_offdac_amb2_or_pol_offdac_led3() {
576 -1.0
577 } else {
578 1.0
579 })
580 }
581}