firewire_dice_protocols/tcat/extension/
cmd_section.rs1use super::{caps_section::*, *};
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum RateMode {
13 Low,
15 Middle,
17 High,
19}
20
21impl Default for RateMode {
22 fn default() -> Self {
23 Self::Low
24 }
25}
26
27impl RateMode {
28 const LOW_FLAG: u32 = 0x00010000;
29 const MIDDLE_FLAG: u32 = 0x00020000;
30 const HIGH_FLAG: u32 = 0x00040000;
31
32 pub fn from_sampling_transfer_frequency(freq: u32) -> Self {
34 match freq {
35 0..=48000 => Self::Low,
36 48001..=96000 => Self::Middle,
37 96001.. => Self::High,
38 }
39 }
40
41 pub fn from_clock_rate(rate: ClockRate) -> Self {
43 match rate {
44 ClockRate::R32000
45 | ClockRate::R44100
46 | ClockRate::R48000
47 | ClockRate::AnyLow
48 | ClockRate::None
49 | ClockRate::Reserved(_) => RateMode::Low,
50 ClockRate::R88200 | ClockRate::R96000 | ClockRate::AnyMid => RateMode::Middle,
51 ClockRate::R176400 | ClockRate::R192000 | ClockRate::AnyHigh => RateMode::High,
52 }
53 }
54}
55
56#[derive(Debug, Copy, Clone, PartialEq, Eq)]
58pub enum Opcode {
59 NoOp,
61 LoadRouter(RateMode),
63 LoadStreamConfig(RateMode),
65 LoadRouterStreamConfig(RateMode),
67 LoadConfigFromFlash,
69 StoreConfigToFlash,
71}
72
73impl Opcode {
74 const NOOP_VALUE: u16 = 0x0000;
75 const LOAD_ROUTER_VALUE: u16 = 0x0001;
76 const LOAD_STREAM_CONFIG_VALUE: u16 = 0x0002;
77 const LOAD_ROUTER_STREAM_CONFIG_VALUE: u16 = 0x0003;
78 const LOAD_FLASH_CONFIG_VALUE: u16 = 0x0004;
79 const STORE_FLASH_CONFIG_VALUE: u16 = 0x0005;
80}
81
82const EXECUTE_FLAG: u32 = 0x80000000;
83
84fn serialize_opcode(code: &Opcode, raw: &mut [u8]) {
85 assert!(raw.len() >= 4);
86
87 let mut val = match code {
88 Opcode::NoOp => Opcode::NOOP_VALUE as u32,
89 Opcode::LoadRouter(rate_mode)
90 | Opcode::LoadStreamConfig(rate_mode)
91 | Opcode::LoadRouterStreamConfig(rate_mode) => {
92 let val = match code {
93 Opcode::LoadRouter(_) => Opcode::LOAD_ROUTER_VALUE,
94 Opcode::LoadStreamConfig(_) => Opcode::LOAD_STREAM_CONFIG_VALUE,
95 Opcode::LoadRouterStreamConfig(_) => Opcode::LOAD_ROUTER_STREAM_CONFIG_VALUE,
96 _ => unreachable!(),
97 } as u32;
98
99 let flag = match rate_mode {
100 RateMode::Low => RateMode::LOW_FLAG,
101 RateMode::Middle => RateMode::MIDDLE_FLAG,
102 RateMode::High => RateMode::HIGH_FLAG,
103 };
104 flag | val
105 }
106 Opcode::LoadConfigFromFlash => Opcode::LOAD_FLASH_CONFIG_VALUE as u32,
107 Opcode::StoreConfigToFlash => Opcode::STORE_FLASH_CONFIG_VALUE as u32,
108 };
109
110 val |= EXECUTE_FLAG;
111
112 serialize_u32(&val, raw);
113}
114
115const OPCODE_OFFSET: usize = 0x00;
116const RETURN_OFFSET: usize = 0x04;
117
118pub trait TcatExtensionCommandSectionOperation: TcatExtensionOperation {
120 fn initiate(
122 req: &FwReq,
123 node: &FwNode,
124 sections: &ExtensionSections,
125 caps: &ExtensionCaps,
126 opcode: Opcode,
127 timeout_ms: u32,
128 ) -> Result<u32, Error> {
129 if let Opcode::LoadRouter(_) = opcode {
130 if caps.mixer.is_readonly {
131 Err(Error::new(
132 ProtocolExtensionError::Cmd,
133 "Router configuration is immutable",
134 ))?
135 }
136 } else if let Opcode::LoadStreamConfig(_) = opcode {
137 if !caps.general.dynamic_stream_format {
138 Err(Error::new(
139 ProtocolExtensionError::Cmd,
140 "Stream format configuration is immutable",
141 ))?
142 }
143 } else if let Opcode::LoadRouterStreamConfig(_) = opcode {
144 if caps.mixer.is_readonly && !caps.general.dynamic_stream_format {
145 Err(Error::new(
146 ProtocolExtensionError::Cmd,
147 "Any configuration is immutable",
148 ))?
149 }
150 } else if opcode == Opcode::LoadConfigFromFlash {
151 if !caps.general.storage_avail {
152 Err(Error::new(
153 ProtocolExtensionError::Cmd,
154 "Storage is not available",
155 ))?
156 }
157 } else if opcode == Opcode::StoreConfigToFlash {
158 if !caps.general.storage_avail {
159 Err(Error::new(
160 ProtocolExtensionError::Cmd,
161 "Storage is not available",
162 ))?
163 }
164 }
165
166 let mut raw = [0; 4];
167 serialize_opcode(&opcode, &mut raw);
168 Self::write_extension(
169 req,
170 node,
171 §ions.cmd,
172 OPCODE_OFFSET,
173 &mut raw,
174 timeout_ms,
175 )?;
176
177 let mut count = 0;
178 while count < 10 {
179 std::thread::sleep(std::time::Duration::from_millis(50));
180
181 Self::read_extension(
182 req,
183 node,
184 §ions.cmd,
185 OPCODE_OFFSET,
186 &mut raw,
187 timeout_ms,
188 )
189 .map_err(|e| Error::new(ProtocolExtensionError::Cmd, &e.to_string()))?;
190
191 let mut val = 0u32;
192 deserialize_u32(&mut val, &raw);
193
194 if val & EXECUTE_FLAG == 0 {
195 Self::read_extension(
196 req,
197 node,
198 §ions.cmd,
199 RETURN_OFFSET,
200 &mut raw,
201 timeout_ms,
202 )
203 .map_err(|e| Error::new(ProtocolExtensionError::Cmd, &e.to_string()))?;
204 return Ok(u32::from_be_bytes(raw));
205 }
206 count += 1;
207 }
208
209 Err(Error::new(
210 ProtocolExtensionError::Cmd,
211 "Operation timeout.",
212 ))
213 }
214}
215
216impl<O: TcatExtensionOperation> TcatExtensionCommandSectionOperation for O {}