firewire_fireworks_protocols/
hw_info.rs1use super::*;
31
32const CATEGORY_HWINFO: u32 = 0;
33
34const CMD_HWINFO: u32 = 0;
35const CMD_METER: u32 = 1;
36const CMD_CHANGE_RESP_ADDR: u32 = 2;
37const CMD_READ_SESSION_BLOCK: u32 = 3;
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct HwInfo {
42 pub caps: Vec<HwCap>,
43 pub guid: u64,
44 pub hw_type: u32,
45 pub hw_version: u32,
46 pub vendor_name: String,
47 pub model_name: String,
48 pub clk_srcs: Vec<ClkSrc>,
49 pub rx_channels: [usize; 3],
50 pub tx_channels: [usize; 3],
51 pub phys_outputs: Vec<PhysGroupEntry>,
52 pub phys_inputs: Vec<PhysGroupEntry>,
53 pub midi_outputs: usize,
54 pub midi_inputs: usize,
55 pub clk_rates: Vec<u32>,
56 pub dsp_version: u32,
57 pub arm_version: u32,
58 pub mixer_playbacks: usize,
59 pub mixer_captures: usize,
60 pub fpga_version: u32,
61}
62
63impl Default for HwInfo {
64 fn default() -> Self {
65 Self {
66 caps: Vec::new(),
67 guid: 0,
68 hw_type: 0,
69 hw_version: 0,
70 vendor_name: String::new(),
71 model_name: String::new(),
72 clk_srcs: Vec::new(),
73 rx_channels: [0; 3],
74 tx_channels: [0; 3],
75 phys_outputs: Vec::new(),
76 phys_inputs: Vec::new(),
77 midi_outputs: 0,
78 midi_inputs: 0,
79 clk_rates: Vec::new(),
80 dsp_version: 0,
81 arm_version: 0,
82 mixer_playbacks: 0,
83 mixer_captures: 0,
84 fpga_version: 0,
85 }
86 }
87}
88
89#[allow(dead_code)]
91const HW_TYPE_O400F: u32 = 0x0000400f;
92#[allow(dead_code)]
93const HW_TYPE_O1200F: u32 = 0x0001200f;
94#[allow(dead_code)]
95const HW_TYPE_AF2: u32 = 0x00000af2;
96#[allow(dead_code)]
97const HW_TYPE_AF4: u32 = 0x00000af4;
98#[allow(dead_code)]
99const HW_TYPE_AF8: u32 = 0x00000af8;
100#[allow(dead_code)]
101const HW_TYPE_AF9: u32 = 0x00000af9;
102#[allow(dead_code)]
103const HW_TYPE_AF12: u32 = 0x0000af12;
104#[allow(dead_code)]
105const HW_TYPE_RIP: u32 = 0x00afb9;
106
107impl HwInfo {
108 fn parse(&mut self, quads: &[u32]) -> Result<(), Error> {
109 self.caps = Self::parse_caps(quads[0]);
110 self.guid = ((quads[1] as u64) << 32) | (quads[2] as u64);
111 self.hw_type = quads[3];
112 self.hw_version = quads[4];
113 self.vendor_name = Self::parse_text(&quads[5..13])?;
114 self.model_name = Self::parse_text(&quads[13..21])?;
115 self.clk_srcs = Self::parse_supported_clk_srcs(quads[21]);
116 self.rx_channels = [quads[22] as usize, quads[45] as usize, quads[47] as usize];
117 self.tx_channels = [quads[23] as usize, quads[46] as usize, quads[48] as usize];
118 self.phys_outputs = Self::parse_phys_groups(&quads[26..31]);
119 self.phys_inputs = Self::parse_phys_groups(&quads[31..36]);
120 self.midi_outputs = quads[36] as usize;
121 self.midi_inputs = quads[37] as usize;
122 self.clk_rates = Self::parse_supported_clk_rates(quads[38], quads[39]);
123 self.dsp_version = quads[40];
124 self.arm_version = quads[41];
125 self.mixer_playbacks = quads[42] as usize;
126 self.mixer_captures = quads[43] as usize;
127 self.fpga_version = quads[44];
128
129 Ok(())
130 }
131
132 fn parse_caps(flags: u32) -> Vec<HwCap> {
133 (0..16)
134 .filter(|i| (1 << i) & flags > 0)
135 .map(|i| {
136 let mut cap = HwCap::default();
137 deserialize_hw_cap(&mut cap, i);
138 cap
139 })
140 .collect()
141 }
142
143 fn parse_text(quads: &[u32]) -> Result<String, Error> {
144 let mut literal = Vec::new();
145 quads.iter().for_each(|quad| {
146 literal.extend_from_slice(&quad.to_be_bytes());
147 });
148 if let Ok(text) = std::str::from_utf8(&literal) {
149 if let Some(pos) = text.find('\0') {
150 return Ok(text[0..pos].to_string());
151 }
152 }
153 Err(Error::new(FileError::Io, "Fail to parse string."))
154 }
155
156 fn parse_supported_clk_srcs(flags: u32) -> Vec<ClkSrc> {
157 (0..6)
158 .filter(|&i| (1 << i) & flags > 0)
159 .map(|i| {
160 let mut src = ClkSrc::default();
161 deserialize_clock_source(&mut src, i as u32);
162 src
163 })
164 .collect()
165 }
166
167 fn parse_supported_clk_rates(max: u32, min: u32) -> Vec<u32> {
168 [32000, 44100, 48000, 88200, 96000, 176400, 192000]
169 .iter()
170 .filter(|&r| *r >= min && *r <= max)
171 .copied()
172 .collect()
173 }
174
175 fn parse_phys_groups(quads: &[u32]) -> Vec<PhysGroupEntry> {
176 let count = quads[0] as usize;
177
178 let mut bytes = Vec::new();
179 quads[1..].iter().for_each(|quad| {
180 bytes.extend_from_slice(&quad.to_be_bytes());
181 });
182
183 (0..count)
184 .map(|i| {
185 let pos = i * 2;
186 let mut entry = PhysGroupEntry::default();
187 deserialize_phys_group_type(&mut entry.group_type, bytes[pos]);
188 entry.group_count = bytes[pos + 1] as usize;
189 entry
190 })
191 .collect()
192 }
193}
194
195const HWINFO_QUADS: usize = 65;
196
197impl<O, P> EfwWhollyCachableParamsOperation<P, HwInfo> for O
198where
199 O: EfwHardwareSpecification,
200 P: EfwProtocolExtManual,
201{
202 fn cache_wholly(proto: &mut P, states: &mut HwInfo, timeout_ms: u32) -> Result<(), Error> {
203 let mut params = vec![0; HWINFO_QUADS];
204 proto
205 .transaction(CATEGORY_HWINFO, CMD_HWINFO, &[], &mut params, timeout_ms)
206 .and_then(|_| states.parse(¶ms))
207 }
208}
209
210#[derive(Debug, Clone, PartialEq, Eq)]
212pub struct HwMeter {
213 pub detected_clk_srcs: Vec<(ClkSrc, bool)>,
214 pub detected_midi_inputs: [bool; 2],
215 pub detected_midi_outputs: [bool; 2],
216 pub guitar_charging: bool,
217 pub guitar_stereo_connect: bool,
218 pub guitar_hex_signal: bool,
219 pub phys_output_meters: Vec<i32>,
220 pub phys_input_meters: Vec<i32>,
221}
222
223impl Default for HwMeter {
224 fn default() -> Self {
225 Self {
226 detected_clk_srcs: Vec::new(),
227 detected_midi_inputs: [false; 2],
228 detected_midi_outputs: [false; 2],
229 guitar_charging: false,
230 guitar_stereo_connect: false,
231 guitar_hex_signal: false,
232 phys_output_meters: Vec::new(),
233 phys_input_meters: Vec::new(),
234 }
235 }
236}
237
238impl HwMeter {
239 pub fn new(clk_srcs: &[ClkSrc], phys_inputs: usize, phys_outputs: usize) -> Self {
241 let mut meter = Self::default();
242
243 meter.detected_clk_srcs = clk_srcs.iter().map(|&src| (src, false)).collect();
244 meter.phys_output_meters = vec![0; phys_outputs];
245 meter.phys_input_meters = vec![0; phys_inputs];
246
247 meter
248 }
249
250 fn parse(&mut self, quads: &[u32]) {
251 let flags = quads[0];
252
253 self.detected_clk_srcs
254 .iter_mut()
255 .for_each(|(src, detected)| {
256 let pos = serialize_clock_source(src);
257 *detected = (1 << pos) & flags > 0
258 });
259
260 self.detected_midi_inputs
263 .iter_mut()
264 .enumerate()
265 .for_each(|(i, detected)| *detected = (1 << (8 + i)) & flags > 0);
266 self.detected_midi_outputs
267 .iter_mut()
268 .enumerate()
269 .for_each(|(i, detected)| *detected = (1 << (8 + i)) & flags > 0);
270
271 self.guitar_charging = (1 << 29) & flags > 0;
272 self.guitar_stereo_connect = (1 << 30) & flags > 0;
273 self.guitar_hex_signal = (1 << 31) & flags > 0;
274
275 let phys_outputs = quads[5] as usize;
276 let phys_inputs = quads[6] as usize;
277 self.phys_output_meters
278 .iter_mut()
279 .take(phys_outputs)
280 .enumerate()
281 .for_each(|(i, val)| *val = (quads[9 + i] >> 8) as i32);
282 self.phys_input_meters
283 .iter_mut()
284 .take(phys_inputs)
285 .enumerate()
286 .for_each(|(i, val)| *val = (quads[9 + i + phys_outputs] >> 8) as i32);
287 }
288}
289
290const METER_QUADS: usize = 110;
291
292impl<O, P> EfwWhollyCachableParamsOperation<P, HwMeter> for O
293where
294 O: EfwHardwareSpecification,
295 P: EfwProtocolExtManual,
296{
297 fn cache_wholly(proto: &mut P, states: &mut HwMeter, timeout_ms: u32) -> Result<(), Error> {
298 let mut params = vec![0; METER_QUADS];
299 proto
300 .transaction(CATEGORY_HWINFO, CMD_METER, &[], &mut params, timeout_ms)
301 .map(|_| states.parse(¶ms))
302 }
303}
304
305#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
307pub struct EfwRespAddr(u64);
308
309impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwRespAddr> for O
310where
311 O: EfwHardwareSpecification,
312 P: EfwProtocolExtManual,
313{
314 fn update_wholly(proto: &mut P, states: &EfwRespAddr, timeout_ms: u32) -> Result<(), Error> {
315 let args = [(states.0 >> 32) as u32, (states.0 & 0xffffffff) as u32];
316 let mut params = Vec::new();
317 proto.transaction(
318 CATEGORY_HWINFO,
319 CMD_CHANGE_RESP_ADDR,
320 &args,
321 &mut params,
322 timeout_ms,
323 )
324 }
325}
326
327#[derive(Default, Debug, Clone, PartialEq, Eq)]
329pub struct EfwSessionBlock {
330 pub offset: u32,
332 pub data: Vec<u32>,
334}
335
336impl<O, P> EfwWhollyCachableParamsOperation<P, EfwSessionBlock> for O
337where
338 O: EfwHardwareSpecification,
339 P: EfwProtocolExtManual,
340{
341 fn cache_wholly(
342 proto: &mut P,
343 states: &mut EfwSessionBlock,
344 timeout_ms: u32,
345 ) -> Result<(), Error> {
346 assert_eq!(states.offset % 4, 0);
347
348 let args = [states.offset / 4, states.data.len() as u32];
350 let mut params = vec![0; 2 + states.data.len()];
351 proto
352 .transaction(
353 CATEGORY_HWINFO,
354 CMD_READ_SESSION_BLOCK,
355 &args,
356 &mut params,
357 timeout_ms,
358 )
359 .map(|_| states.data.copy_from_slice(¶ms[2..]))
360 }
361}