autd3_driver/firmware/fpga/
fpga_state.rs1use autd3_core::{firmware::Segment, link::RxMessage};
2
3#[repr(C)]
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct FPGAState(u8);
7
8impl FPGAState {
9 const THERMAL_ASSERT_BIT: u8 = 1 << 0;
10 const CURRENT_MOD_SEGMENT_BIT: u8 = 1 << 1;
11 const CURRENT_STM_SEGMENT_BIT: u8 = 1 << 2;
12 const CURRENT_GAIN_SEGMENT_BIT: u8 = 1 << 2;
13 const IS_GAIN_MODE_BIT: u8 = 1 << 3;
14 const READS_FPGA_STATE_ENABLED: u8 = 1 << 7;
15
16 const fn contains(&self, bit: u8) -> bool {
17 (self.0 & bit) != 0
18 }
19}
20
21impl FPGAState {
22 #[doc(hidden)]
23 pub const fn bits(&self) -> u8 {
24 self.0
25 }
26
27 #[must_use]
29 pub const fn is_thermal_assert(&self) -> bool {
30 self.contains(Self::THERMAL_ASSERT_BIT)
31 }
32
33 #[must_use]
35 pub const fn current_mod_segment(&self) -> Segment {
36 if self.contains(Self::CURRENT_MOD_SEGMENT_BIT) {
37 Segment::S1
38 } else {
39 Segment::S0
40 }
41 }
42
43 #[must_use]
45 pub const fn current_stm_segment(&self) -> Option<Segment> {
46 if !self.is_stm_mode() {
47 return None;
48 }
49 if self.contains(Self::CURRENT_STM_SEGMENT_BIT) {
50 Some(Segment::S1)
51 } else {
52 Some(Segment::S0)
53 }
54 }
55
56 #[must_use]
58 pub const fn current_gain_segment(&self) -> Option<Segment> {
59 if !self.is_gain_mode() {
60 return None;
61 }
62 if self.contains(Self::CURRENT_GAIN_SEGMENT_BIT) {
63 Some(Segment::S1)
64 } else {
65 Some(Segment::S0)
66 }
67 }
68
69 #[must_use]
71 pub const fn is_gain_mode(&self) -> bool {
72 self.contains(Self::IS_GAIN_MODE_BIT)
73 }
74
75 #[must_use]
77 pub const fn is_stm_mode(&self) -> bool {
78 !self.is_gain_mode()
79 }
80
81 #[doc(hidden)]
82 #[must_use]
83 pub fn from_rx(msg: &RxMessage) -> Option<Self> {
84 let flag = FPGAState(msg.data());
85 if !flag.contains(Self::READS_FPGA_STATE_ENABLED) {
86 return None;
87 }
88 Some(flag)
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use std::mem::size_of;
95
96 use super::*;
97
98 #[test]
99 fn size() {
100 assert_eq!(1, size_of::<FPGAState>());
101 }
102
103 #[test]
104 fn bits() {
105 let state = FPGAState(0b1010_1101);
106 assert_eq!(0b1010_1101, state.bits());
107 }
108
109 #[rstest::rstest]
110 #[case(false, 0b0)]
111 #[case(true, 0b1)]
112 fn is_thermal_assert(#[case] expected: bool, #[case] state: u8) {
113 assert_eq!(expected, FPGAState(state).is_thermal_assert());
114 }
115
116 #[rstest::rstest]
117 #[case(Segment::S0, 0b00)]
118 #[case(Segment::S1, 0b10)]
119 fn current_mod_segment(#[case] expected: Segment, #[case] state: u8) {
120 assert_eq!(expected, FPGAState(state).current_mod_segment());
121 }
122
123 #[rstest::rstest]
124 #[case(false, 0b0000)]
125 #[case(true, 0b1000)]
126 fn is_gain_mode(#[case] expected: bool, #[case] state: u8) {
127 assert_eq!(expected, FPGAState(state).is_gain_mode());
128 }
129
130 #[rstest::rstest]
131 #[case(false, 0b1000)]
132 #[case(true, 0b0000)]
133 fn is_stm_mode(#[case] expected: bool, #[case] state: u8) {
134 assert_eq!(expected, FPGAState(state).is_stm_mode());
135 }
136
137 #[rstest::rstest]
138 #[case(None, 0b1000)]
139 #[case(Some(Segment::S0), 0b0000)]
140 #[case(Some(Segment::S1), 0b0100)]
141 fn current_stm_segment(#[case] expected: Option<Segment>, #[case] state: u8) {
142 assert_eq!(expected, FPGAState(state).current_stm_segment());
143 }
144
145 #[rstest::rstest]
146 #[case(None, 0b0000)]
147 #[case(Some(Segment::S0), 0b1000)]
148 #[case(Some(Segment::S1), 0b1100)]
149 fn current_gain_segment(#[case] expected: Option<Segment>, #[case] state: u8) {
150 assert_eq!(expected, FPGAState(state).current_gain_segment());
151 }
152}