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