1pub mod desktop;
12pub mod shell;
13pub mod studio;
14
15pub mod ch_strip;
16pub mod reverb;
17
18use {
19 super::{tcat::*, *},
20 ta1394_avc_general::{general::*, *},
21};
22
23const BASE_OFFSET: usize = 0x00a01000;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct TcKonnektSegment<U> {
30 pub data: U,
32 raw: Vec<u8>,
34}
35
36pub trait TcKonnektSegmentSerdes<T> {
38 const NAME: &'static str;
40
41 const OFFSET: usize;
43
44 const SIZE: usize;
46
47 fn serialize(params: &T, raw: &mut [u8]) -> Result<(), String>;
49
50 fn deserialize(params: &mut T, raw: &[u8]) -> Result<(), String>;
52}
53
54fn generate_error(segment_name: &str, cause: &str, raw: &[u8]) -> Error {
55 let msg = format!(
56 "segment: {}, cause: '{}', raw: {:02x?}",
57 segment_name, cause, raw
58 );
59 Error::new(GeneralProtocolError::VendorDependent, &msg)
60}
61
62pub trait TcKonnektSegmentOperation<T>: TcatOperation + TcKonnektSegmentSerdes<T> {
64 fn cache_whole_segment(
66 req: &FwReq,
67 node: &FwNode,
68 segment: &mut TcKonnektSegment<T>,
69 timeout_ms: u32,
70 ) -> Result<(), Error> {
71 assert_eq!(segment.raw.len(), Self::SIZE);
73
74 Self::read(
75 req,
76 node,
77 BASE_OFFSET + Self::OFFSET,
78 &mut segment.raw,
79 timeout_ms,
80 )?;
81
82 Self::deserialize(&mut segment.data, &segment.raw)
83 .map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
84 }
85}
86
87impl<O: TcatOperation + TcKonnektSegmentSerdes<T>, T> TcKonnektSegmentOperation<T> for O {}
88
89pub trait TcKonnektMutableSegmentOperation<T>: TcatOperation + TcKonnektSegmentSerdes<T> {
91 fn update_partial_segment(
93 req: &FwReq,
94 node: &FwNode,
95 params: &T,
96 segment: &mut TcKonnektSegment<T>,
97 timeout_ms: u32,
98 ) -> Result<(), Error> {
99 assert_eq!(segment.raw.len(), Self::SIZE);
101
102 let mut raw = segment.raw.clone();
103 Self::serialize(params, &mut raw)
104 .map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))?;
105
106 (0..Self::SIZE).step_by(4).try_for_each(|pos| {
107 let new = &mut raw[pos..(pos + 4)];
108 if new != &segment.raw[pos..(pos + 4)] {
109 Self::write(req, node, BASE_OFFSET + Self::OFFSET + pos, new, timeout_ms)
110 .map(|_| segment.raw[pos..(pos + 4)].copy_from_slice(new))
111 } else {
112 Ok(())
113 }
114 })?;
115
116 Self::deserialize(&mut segment.data, &raw)
117 .map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
118 }
119
120 fn update_whole_segment(
122 req: &FwReq,
123 node: &FwNode,
124 params: &T,
125 segment: &mut TcKonnektSegment<T>,
126 timeout_ms: u32,
127 ) -> Result<(), Error> {
128 assert_eq!(segment.raw.len(), Self::SIZE);
130
131 let mut raw = segment.raw.clone();
132 Self::serialize(¶ms, &mut raw)
133 .map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))?;
134
135 Self::write(req, node, BASE_OFFSET + Self::OFFSET, &mut raw, timeout_ms)?;
136
137 segment.raw.copy_from_slice(&raw);
138 Self::deserialize(&mut segment.data, &segment.raw)
139 .map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
140 }
141}
142
143pub trait TcKonnektNotifiedSegmentOperation<T> {
145 const NOTIFY_FLAG: u32;
146
147 fn is_notified_segment(_: &TcKonnektSegment<T>, msg: u32) -> bool {
149 msg & Self::NOTIFY_FLAG > 0
150 }
151}
152
153fn serialize_position<T: Eq + std::fmt::Debug>(
154 entries: &[T],
155 entry: &T,
156 raw: &mut [u8],
157 label: &str,
158) -> Result<(), String> {
159 assert!(raw.len() >= 4);
160
161 entries
162 .iter()
163 .position(|t| entry.eq(t))
164 .ok_or_else(|| format!("{} {:?} is not supported", label, entry))
165 .map(|pos| serialize_usize(&pos, raw))
166}
167
168fn deserialize_position<T: Copy + Eq + std::fmt::Debug>(
169 entries: &[T],
170 entry: &mut T,
171 raw: &[u8],
172 label: &str,
173) -> Result<(), String> {
174 assert!(raw.len() >= 4);
175
176 let mut val = 0usize;
177 deserialize_usize(&mut val, raw);
178
179 entries
180 .iter()
181 .nth(val as usize)
182 .ok_or_else(|| format!("{} not found for index {}", label, val))
183 .map(|&e| *entry = e)
184}
185
186#[derive(Debug, Copy, Clone, PartialEq, Eq)]
188pub enum FireWireLedState {
189 Off,
191 On,
193 BlinkFast,
195 BlinkSlow,
197}
198
199impl Default for FireWireLedState {
200 fn default() -> Self {
201 Self::Off
202 }
203}
204
205const FW_LED_STATES: &[FireWireLedState] = &[
206 FireWireLedState::Off,
207 FireWireLedState::On,
208 FireWireLedState::BlinkSlow,
209 FireWireLedState::BlinkFast,
210];
211
212const FW_LED_STATE_LABEL: &str = "FireWire LED state";
213
214fn serialize_fw_led_state(state: &FireWireLedState, raw: &mut [u8]) -> Result<(), String> {
215 serialize_position(FW_LED_STATES, state, raw, FW_LED_STATE_LABEL)
216}
217
218fn deserialize_fw_led_state(state: &mut FireWireLedState, raw: &[u8]) -> Result<(), String> {
219 deserialize_position(FW_LED_STATES, state, raw, FW_LED_STATE_LABEL)
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq)]
224pub enum TcKonnektStandaloneClockRate {
225 R44100,
227 R48000,
229 R88200,
231 R96000,
233}
234
235impl Default for TcKonnektStandaloneClockRate {
236 fn default() -> Self {
237 Self::R44100
238 }
239}
240
241fn serialize_standalone_clock_rate(
242 rate: &TcKonnektStandaloneClockRate,
243 raw: &mut [u8],
244) -> Result<(), String> {
245 assert!(raw.len() >= 4);
246
247 let val = match rate {
248 TcKonnektStandaloneClockRate::R96000 => 4,
249 TcKonnektStandaloneClockRate::R88200 => 3,
250 TcKonnektStandaloneClockRate::R48000 => 2,
251 TcKonnektStandaloneClockRate::R44100 => 1,
252 };
253
254 serialize_u32(&val, raw);
255
256 Ok(())
257}
258
259fn deserialize_standalone_clock_rate(
260 rate: &mut TcKonnektStandaloneClockRate,
261 raw: &[u8],
262) -> Result<(), String> {
263 assert!(raw.len() >= 4);
264
265 let mut val = 0u32;
266 deserialize_u32(&mut val, raw);
267
268 *rate = match val {
269 4 => TcKonnektStandaloneClockRate::R96000,
270 3 => TcKonnektStandaloneClockRate::R88200,
271 2 => TcKonnektStandaloneClockRate::R48000,
272 1 => TcKonnektStandaloneClockRate::R44100,
273 _ => Err(format!(
274 "Unexpected value for standalone clock rate: {}",
275 val
276 ))?,
277 };
278
279 Ok(())
280}
281
282#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
284pub struct TcKonnektMidiMsgParams {
285 pub ch: u8,
287 pub cc: u8,
289}
290
291#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
293pub struct TcKonnektMidiSender {
294 pub normal: TcKonnektMidiMsgParams,
296 pub pushed: TcKonnektMidiMsgParams,
298 pub send_to_port: bool,
300 pub send_to_stream: bool,
302}
303
304impl TcKonnektMidiSender {
305 pub(crate) const SIZE: usize = 36;
306}
307
308fn serialize_midi_sender(sender: &TcKonnektMidiSender, raw: &mut [u8]) -> Result<(), String> {
309 assert!(raw.len() >= TcKonnektMidiSender::SIZE);
310
311 serialize_u8(&sender.normal.ch, &mut raw[..4]);
312 serialize_u8(&sender.normal.cc, &mut raw[4..8]);
313 serialize_u8(&sender.pushed.ch, &mut raw[12..16]);
314 serialize_u8(&sender.pushed.cc, &mut raw[16..20]);
315 serialize_bool(&sender.send_to_port, &mut raw[24..28]);
316 serialize_bool(&sender.send_to_stream, &mut raw[28..32]);
317
318 Ok(())
319}
320
321fn deserialize_midi_sender(sender: &mut TcKonnektMidiSender, raw: &[u8]) -> Result<(), String> {
322 assert!(raw.len() >= TcKonnektMidiSender::SIZE);
323
324 deserialize_u8(&mut sender.normal.ch, &raw[..4]);
325 deserialize_u8(&mut sender.normal.cc, &raw[4..8]);
326 deserialize_u8(&mut sender.pushed.ch, &raw[12..16]);
327 deserialize_u8(&mut sender.pushed.cc, &raw[16..20]);
328 deserialize_bool(&mut sender.send_to_port, &raw[24..28]);
329 deserialize_bool(&mut sender.send_to_stream, &raw[28..32]);
330
331 Ok(())
332}
333
334#[derive(Debug, Copy, Clone, PartialEq, Eq)]
336pub enum TcKonnektLoadedProgram {
337 P0,
339 P1,
341 P2,
343}
344
345impl Default for TcKonnektLoadedProgram {
346 fn default() -> Self {
347 Self::P0
348 }
349}
350
351const LOADED_PROGRAMS: &[TcKonnektLoadedProgram] = &[
352 TcKonnektLoadedProgram::P0,
353 TcKonnektLoadedProgram::P1,
354 TcKonnektLoadedProgram::P2,
355];
356
357const LOADED_PROGRAM_LABEL: &str = "loaded program";
358
359fn serialize_loaded_program(prog: &TcKonnektLoadedProgram, raw: &mut [u8]) -> Result<(), String> {
360 serialize_position(LOADED_PROGRAMS, prog, raw, LOADED_PROGRAM_LABEL)
361}
362
363fn deserialize_loaded_program(prog: &mut TcKonnektLoadedProgram, raw: &[u8]) -> Result<(), String> {
364 deserialize_position(LOADED_PROGRAMS, prog, raw, LOADED_PROGRAM_LABEL)
365}
366
367#[derive(Default, Debug)]
369pub struct TcAvcCmd {
370 pub class_id: u8,
371 pub sequence_id: u8,
372 pub command_id: u16,
373 pub arguments: Vec<u8>,
374 op: VendorDependent,
375}
376
377fn tc_avc_cmd_prepare_vendor_dependent_data(cmd: &mut TcAvcCmd) {
391 cmd.op.data.resize(4 + cmd.arguments.len(), 0);
392
393 cmd.op.data[0] = cmd.class_id;
394 cmd.op.data[1] = 0xff;
395 cmd.op.data[2] = (0xff & (cmd.command_id >> 8)) as u8;
396 cmd.op.data[3] = (0xff & cmd.command_id) as u8;
397 cmd.op.data[4..].copy_from_slice(&cmd.arguments);
398}
399
400fn tc_avc_cmd_parse_vendor_dependent_data(cmd: &mut TcAvcCmd) {
401 cmd.class_id = cmd.op.data[0];
402 cmd.sequence_id = cmd.op.data[1];
403 cmd.command_id = ((cmd.op.data[2] as u16) << 8) | (cmd.op.data[3] as u16);
404 cmd.arguments = cmd.op.data[4..].to_owned();
405}
406
407impl TcAvcCmd {
408 pub fn new(company_id: &[u8; 3]) -> Self {
409 Self {
410 class_id: Default::default(),
411 sequence_id: Default::default(),
412 command_id: Default::default(),
413 arguments: Default::default(),
414 op: VendorDependent {
415 company_id: company_id.clone(),
416 data: vec![0; 4],
418 },
419 }
420 }
421}
422
423impl AvcOp for TcAvcCmd {
424 const OPCODE: u8 = VendorDependent::OPCODE;
425}
426
427impl AvcStatus for TcAvcCmd {
428 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
429 tc_avc_cmd_prepare_vendor_dependent_data(self);
430 AvcStatus::build_operands(&mut self.op, addr)
431 }
432
433 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
434 AvcStatus::parse_operands(&mut self.op, addr, operands)
435 .map(|_| tc_avc_cmd_parse_vendor_dependent_data(self))
436 }
437}
438
439impl AvcControl for TcAvcCmd {
440 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
441 tc_avc_cmd_prepare_vendor_dependent_data(self);
442 AvcControl::build_operands(&mut self.op, addr)
443 }
444
445 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
446 AvcControl::parse_operands(&mut self.op, addr, operands)
447 .map(|_| tc_avc_cmd_parse_vendor_dependent_data(self))
448 }
449}
450
451#[cfg(test)]
452mod test {
453 use super::*;
454
455 #[test]
456 fn tc_avc_operation_operands() {
457 let company_id = [0xfe, 0xdc, 0xba];
458 let operands = [0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10];
459 let mut op = TcAvcCmd::new(&company_id);
460 AvcStatus::parse_operands(&mut op, &AvcAddr::Unit, &operands).unwrap();
461 assert_eq!(op.op.company_id, company_id);
462 assert_eq!(op.class_id, operands[3]);
463 assert_eq!(op.sequence_id, operands[4]);
464 assert_eq!(
465 op.command_id,
466 ((operands[5] as u16) << 8) | (operands[6] as u16)
467 );
468 assert_eq!(op.arguments, operands[7..]);
469
470 let target = AvcStatus::build_operands(&mut op, &AvcAddr::Unit).unwrap();
471 assert_eq!(&target[..4], &operands[..4]);
472 assert_eq!(&target[5..], &operands[5..]);
474
475 let target = AvcControl::build_operands(&mut op, &AvcAddr::Unit).unwrap();
476 assert_eq!(&target[..4], &operands[..4]);
477 assert_eq!(&target[5..], &operands[5..]);
479
480 let mut op = TcAvcCmd::new(&company_id);
481 AvcControl::parse_operands(&mut op, &AvcAddr::Unit, &operands).unwrap();
482 assert_eq!(op.op.company_id, company_id);
483 assert_eq!(op.class_id, operands[3]);
484 assert_eq!(op.sequence_id, operands[4]);
485 assert_eq!(
486 op.command_id,
487 ((operands[5] as u16) << 8) | (operands[6] as u16)
488 );
489 assert_eq!(op.arguments, operands[7..]);
490 }
491}