1use {
24 super::*,
25 crate::{tcelectronic::*, *},
26 glib::{Error, FileError, IsA},
27 hinawa::{
28 prelude::{FwFcpExt, FwFcpExtManual},
29 FwFcp, FwNode,
30 },
31 ta1394_avc_general::{general::*, *},
32};
33
34#[derive(Default, Debug)]
36pub struct WeissMan301Protocol;
37
38impl TcatOperation for WeissMan301Protocol {}
39
40impl TcatGlobalSectionSpecification for WeissMan301Protocol {}
43
44#[derive(Default, Debug)]
46pub struct WeissAvc(FwFcp);
47
48impl Ta1394Avc<Error> for WeissAvc {
49 fn transaction(&self, command_frame: &[u8], timeout_ms: u32) -> Result<Vec<u8>, Error> {
50 let mut resp = vec![0; Self::FRAME_SIZE];
51 self.0
52 .avc_transaction(&command_frame, &mut resp, timeout_ms)
53 .map(|len| {
54 resp.truncate(len);
55 resp
56 })
57 }
58}
59
60fn from_avc_err(err: Ta1394AvcError<Error>) -> Error {
61 match err {
62 Ta1394AvcError::CmdBuild(cause) => Error::new(FileError::Inval, &cause.to_string()),
63 Ta1394AvcError::CommunicationFailure(cause) => cause,
64 Ta1394AvcError::RespParse(cause) => Error::new(FileError::Io, &cause.to_string()),
65 }
66}
67
68impl WeissAvc {
69 pub fn bind(&self, node: &impl IsA<FwNode>) -> Result<(), Error> {
71 self.0.bind(node)
72 }
73
74 pub fn control<O: AvcOp + AvcControl>(
76 &self,
77 addr: &AvcAddr,
78 op: &mut O,
79 timeout_ms: u32,
80 ) -> Result<(), Error> {
81 Ta1394Avc::<Error>::control(self, addr, op, timeout_ms).map_err(|err| from_avc_err(err))
82 }
83
84 pub fn status<O: AvcOp + AvcStatus>(
86 &self,
87 addr: &AvcAddr,
88 op: &mut O,
89 timeout_ms: u32,
90 ) -> Result<(), Error> {
91 Ta1394Avc::<Error>::status(self, addr, op, timeout_ms).map_err(|err| from_avc_err(err))
92 }
93}
94
95#[derive(Debug)]
97pub struct WeissAvcParamCmd {
98 pub numeric_id: u32,
100 pub value: u32,
102 pub reserved: [u32; 4],
104 op: TcAvcCmd,
105}
106
107impl Default for WeissAvcParamCmd {
108 fn default() -> Self {
109 let mut op = TcAvcCmd::new(&WEISS_OUI);
110 op.class_id = 1;
111 op.sequence_id = u8::MAX;
112 op.command_id = 0x8002;
113 Self {
114 numeric_id: u32::MAX,
115 value: u32::MAX,
116 reserved: [u32::MAX; 4],
117 op: TcAvcCmd::new(&WEISS_OUI),
118 }
119 }
120}
121
122impl AvcOp for WeissAvcParamCmd {
123 const OPCODE: u8 = VendorDependent::OPCODE;
124}
125
126fn build_param_command_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), AvcCmdBuildError> {
127 cmd.op.arguments.resize(24, u8::MAX);
128 serialize_u32(&cmd.numeric_id, &mut cmd.op.arguments[..4]);
129 (0..4).for_each(|i| {
130 let pos = 8 + i * 4;
131 serialize_u32(&cmd.reserved[i], &mut cmd.op.arguments[pos..(pos + 4)]);
132 });
133 Ok(())
134}
135
136fn build_param_command_control_data(cmd: &mut WeissAvcParamCmd) -> Result<(), AvcCmdBuildError> {
137 cmd.op.arguments.resize(24, u8::MIN);
138 serialize_u32(&cmd.numeric_id, &mut cmd.op.arguments[..4]);
139 serialize_u32(&cmd.value, &mut cmd.op.arguments[4..8]);
140 (0..4).for_each(|i| {
141 let pos = 8 + i * 4;
142 serialize_u32(&cmd.reserved[i], &mut cmd.op.arguments[pos..(pos + 4)]);
143 });
144 Ok(())
145}
146
147fn parse_param_command_response_data(cmd: &mut WeissAvcParamCmd) -> Result<(), AvcRespParseError> {
148 if cmd.op.arguments.len() < 24 {
149 Err(AvcRespParseError::TooShortResp(24))?
150 }
151
152 deserialize_u32(&mut cmd.numeric_id, &cmd.op.arguments[..4]);
153 deserialize_u32(&mut cmd.value, &cmd.op.arguments[4..8]);
154 (0..4).for_each(|i| {
155 let pos = 8 + i * 4;
156 deserialize_u32(&mut cmd.reserved[i], &cmd.op.arguments[pos..(pos + 4)]);
157 });
158
159 Ok(())
160}
161
162impl AvcStatus for WeissAvcParamCmd {
163 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
164 build_param_command_status_data(self)?;
165 AvcStatus::build_operands(&mut self.op, addr)
166 }
167
168 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
169 AvcStatus::parse_operands(&mut self.op, addr, operands)?;
170 parse_param_command_response_data(self)
171 }
172}
173
174impl AvcControl for WeissAvcParamCmd {
175 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
176 build_param_command_control_data(self)?;
177 AvcControl::build_operands(&mut self.op, addr)
178 }
179
180 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
181 AvcControl::parse_operands(&mut self.op, addr, operands)?;
182 parse_param_command_response_data(self)
183 }
184}
185
186impl WeissMan301Protocol {
187 const PARAM_ID_DIGITAL_CAPTURE_SOURCE: u32 = 0;
188 const PARAM_ID_DIGITAL_OUTPUT_MODE: u32 = 1;
189 const PARAM_ID_WORD_CLOCK_OUTPUT_HALF_RATE: u32 = 2;
190 const PARAM_ID_AESEBU_XLR_OUTPUT_MUTE: u32 = 3;
191 const PARAM_ID_SPDIF_COAXIAL_OUTPUT_MUTE: u32 = 4;
192 const PARAM_ID_ANALOG_OUTPUT_POLARITY_INVERSION: u32 = 5;
193 const PARAM_ID_ANALOG_OUTPUT_FILTER_TYPE: u32 = 6;
194 const PARAM_ID_ANALOG_OUTPUT_MUTE: u32 = 7;
195 const PARAM_ID_ANALOG_OUTPUT_LEVEL: u32 = 8;
196}
197
198pub trait WeissAvcParamConvert<T> {
200 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error>;
202 fn build_control_data(param: &T, cmd: &mut WeissAvcParamCmd) -> Result<(), Error>;
204 fn parse_response_data(param: &mut T, cmd: &WeissAvcParamCmd) -> Result<(), Error>;
206}
207
208#[derive(Debug, Copy, Clone, PartialEq, Eq)]
210pub enum WeissAvcDigitalCaptureSource {
211 AesebuXlr,
213 SpdifCoaxial,
215 SpdifOptical,
217}
218
219impl Default for WeissAvcDigitalCaptureSource {
220 fn default() -> Self {
221 Self::AesebuXlr
222 }
223}
224
225impl WeissAvcParamConvert<WeissAvcDigitalCaptureSource> for WeissMan301Protocol {
226 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
227 cmd.numeric_id = Self::PARAM_ID_DIGITAL_CAPTURE_SOURCE;
228 cmd.value = u32::MAX;
229 Ok(())
230 }
231
232 fn build_control_data(
233 param: &WeissAvcDigitalCaptureSource,
234 cmd: &mut WeissAvcParamCmd,
235 ) -> Result<(), Error> {
236 cmd.numeric_id = Self::PARAM_ID_DIGITAL_CAPTURE_SOURCE;
237 cmd.value = match param {
238 WeissAvcDigitalCaptureSource::SpdifOptical => 2,
239 WeissAvcDigitalCaptureSource::SpdifCoaxial => 1,
240 WeissAvcDigitalCaptureSource::AesebuXlr => 0,
241 };
242 Ok(())
243 }
244
245 fn parse_response_data(
246 param: &mut WeissAvcDigitalCaptureSource,
247 cmd: &WeissAvcParamCmd,
248 ) -> Result<(), Error> {
249 assert_eq!(cmd.numeric_id, Self::PARAM_ID_DIGITAL_CAPTURE_SOURCE);
250 *param = match cmd.value {
251 2 => WeissAvcDigitalCaptureSource::SpdifOptical,
252 1 => WeissAvcDigitalCaptureSource::SpdifCoaxial,
253 _ => WeissAvcDigitalCaptureSource::AesebuXlr,
254 };
255 Ok(())
256 }
257}
258
259#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
263pub struct WeissAvcDigitalOutputMode(pub bool);
264
265impl WeissAvcParamConvert<WeissAvcDigitalOutputMode> for WeissMan301Protocol {
266 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
267 cmd.numeric_id = Self::PARAM_ID_DIGITAL_OUTPUT_MODE;
268 cmd.value = u32::MAX;
269 Ok(())
270 }
271
272 fn build_control_data(
273 param: &WeissAvcDigitalOutputMode,
274 cmd: &mut WeissAvcParamCmd,
275 ) -> Result<(), Error> {
276 cmd.numeric_id = Self::PARAM_ID_DIGITAL_OUTPUT_MODE;
277 cmd.value = if param.0 { 1 } else { 0 };
278 Ok(())
279 }
280
281 fn parse_response_data(
282 param: &mut WeissAvcDigitalOutputMode,
283 cmd: &WeissAvcParamCmd,
284 ) -> Result<(), Error> {
285 assert_eq!(cmd.numeric_id, Self::PARAM_ID_DIGITAL_OUTPUT_MODE);
286 param.0 = cmd.value > 0;
287 Ok(())
288 }
289}
290
291#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
294pub struct WeissAvcWordClockOutputHalfRate(pub bool);
295
296impl WeissAvcParamConvert<WeissAvcWordClockOutputHalfRate> for WeissMan301Protocol {
297 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
298 cmd.numeric_id = Self::PARAM_ID_WORD_CLOCK_OUTPUT_HALF_RATE;
299 cmd.value = u32::MAX;
300 Ok(())
301 }
302
303 fn build_control_data(
304 param: &WeissAvcWordClockOutputHalfRate,
305 cmd: &mut WeissAvcParamCmd,
306 ) -> Result<(), Error> {
307 cmd.numeric_id = Self::PARAM_ID_WORD_CLOCK_OUTPUT_HALF_RATE;
308 cmd.value = if param.0 { 1 } else { 0 };
309 Ok(())
310 }
311
312 fn parse_response_data(
313 param: &mut WeissAvcWordClockOutputHalfRate,
314 cmd: &WeissAvcParamCmd,
315 ) -> Result<(), Error> {
316 assert_eq!(cmd.numeric_id, Self::PARAM_ID_WORD_CLOCK_OUTPUT_HALF_RATE);
317 param.0 = cmd.value > 0;
318 Ok(())
319 }
320}
321
322#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
324pub struct WeissAvcAesebuXlrOutputMute(pub bool);
325
326impl WeissAvcParamConvert<WeissAvcAesebuXlrOutputMute> for WeissMan301Protocol {
327 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
328 cmd.numeric_id = Self::PARAM_ID_AESEBU_XLR_OUTPUT_MUTE;
329 cmd.value = u32::MAX;
330 Ok(())
331 }
332
333 fn build_control_data(
334 param: &WeissAvcAesebuXlrOutputMute,
335 cmd: &mut WeissAvcParamCmd,
336 ) -> Result<(), Error> {
337 cmd.numeric_id = Self::PARAM_ID_AESEBU_XLR_OUTPUT_MUTE;
338 cmd.value = if param.0 { 0 } else { 1 };
339 Ok(())
340 }
341
342 fn parse_response_data(
343 param: &mut WeissAvcAesebuXlrOutputMute,
344 cmd: &WeissAvcParamCmd,
345 ) -> Result<(), Error> {
346 assert_eq!(cmd.numeric_id, Self::PARAM_ID_AESEBU_XLR_OUTPUT_MUTE);
347 param.0 = cmd.value == 0;
348 Ok(())
349 }
350}
351
352#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
354pub struct WeissAvcSpdifCoaxialOutputMute(pub bool);
355
356impl WeissAvcParamConvert<WeissAvcSpdifCoaxialOutputMute> for WeissMan301Protocol {
357 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
358 cmd.numeric_id = Self::PARAM_ID_SPDIF_COAXIAL_OUTPUT_MUTE;
359 cmd.value = u32::MAX;
360 Ok(())
361 }
362
363 fn build_control_data(
364 param: &WeissAvcSpdifCoaxialOutputMute,
365 cmd: &mut WeissAvcParamCmd,
366 ) -> Result<(), Error> {
367 cmd.numeric_id = Self::PARAM_ID_SPDIF_COAXIAL_OUTPUT_MUTE;
368 cmd.value = if param.0 { 0 } else { 1 };
369 Ok(())
370 }
371
372 fn parse_response_data(
373 param: &mut WeissAvcSpdifCoaxialOutputMute,
374 cmd: &WeissAvcParamCmd,
375 ) -> Result<(), Error> {
376 assert_eq!(cmd.numeric_id, Self::PARAM_ID_SPDIF_COAXIAL_OUTPUT_MUTE);
377 param.0 = cmd.value == 0;
378 Ok(())
379 }
380}
381
382#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
384pub struct WeissAvcAnalogOutputPolarityInversion(pub bool);
385
386impl WeissAvcParamConvert<WeissAvcAnalogOutputPolarityInversion> for WeissMan301Protocol {
387 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
388 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_POLARITY_INVERSION;
389 cmd.value = u32::MAX;
390 Ok(())
391 }
392
393 fn build_control_data(
394 param: &WeissAvcAnalogOutputPolarityInversion,
395 cmd: &mut WeissAvcParamCmd,
396 ) -> Result<(), Error> {
397 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_POLARITY_INVERSION;
398 cmd.value = if param.0 { 1 } else { 0 };
399 Ok(())
400 }
401
402 fn parse_response_data(
403 param: &mut WeissAvcAnalogOutputPolarityInversion,
404 cmd: &WeissAvcParamCmd,
405 ) -> Result<(), Error> {
406 assert_eq!(
407 cmd.numeric_id,
408 Self::PARAM_ID_ANALOG_OUTPUT_POLARITY_INVERSION
409 );
410 param.0 = cmd.value > 0;
411 Ok(())
412 }
413}
414
415#[derive(Debug, Copy, Clone, PartialEq, Eq)]
417pub enum WeissAvcAnalogOutputFilterType {
418 A,
419 B,
420}
421
422impl Default for WeissAvcAnalogOutputFilterType {
423 fn default() -> Self {
424 Self::A
425 }
426}
427
428impl WeissAvcParamConvert<WeissAvcAnalogOutputFilterType> for WeissMan301Protocol {
429 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
430 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_FILTER_TYPE;
431 cmd.value = u32::MAX;
432 Ok(())
433 }
434
435 fn build_control_data(
436 param: &WeissAvcAnalogOutputFilterType,
437 cmd: &mut WeissAvcParamCmd,
438 ) -> Result<(), Error> {
439 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_FILTER_TYPE;
440 cmd.value = if param.eq(&WeissAvcAnalogOutputFilterType::B) {
441 1
442 } else {
443 0
444 };
445 Ok(())
446 }
447
448 fn parse_response_data(
449 param: &mut WeissAvcAnalogOutputFilterType,
450 cmd: &WeissAvcParamCmd,
451 ) -> Result<(), Error> {
452 assert_eq!(cmd.numeric_id, Self::PARAM_ID_ANALOG_OUTPUT_FILTER_TYPE);
453 *param = if cmd.value > 0 {
454 WeissAvcAnalogOutputFilterType::B
455 } else {
456 WeissAvcAnalogOutputFilterType::A
457 };
458 Ok(())
459 }
460}
461
462#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
464pub struct WeissAvcAnalogOutputMute(pub bool);
465
466impl WeissAvcParamConvert<WeissAvcAnalogOutputMute> for WeissMan301Protocol {
467 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
468 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_MUTE;
469 cmd.value = u32::MAX;
470 Ok(())
471 }
472
473 fn build_control_data(
474 param: &WeissAvcAnalogOutputMute,
475 cmd: &mut WeissAvcParamCmd,
476 ) -> Result<(), Error> {
477 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_MUTE;
478 cmd.value = if param.0 { 0 } else { 1 };
479 Ok(())
480 }
481
482 fn parse_response_data(
483 param: &mut WeissAvcAnalogOutputMute,
484 cmd: &WeissAvcParamCmd,
485 ) -> Result<(), Error> {
486 assert_eq!(cmd.numeric_id, Self::PARAM_ID_ANALOG_OUTPUT_MUTE);
487 param.0 = cmd.value == 0;
488 Ok(())
489 }
490}
491
492#[derive(Debug, Copy, Clone, PartialEq, Eq)]
494pub enum WeissAvcAnalogOutputLevel {
495 Zero,
497 NegativeTen,
499 NegativeTwenty,
501 NegativeThirty,
503}
504
505impl Default for WeissAvcAnalogOutputLevel {
506 fn default() -> Self {
507 Self::Zero
508 }
509}
510
511impl WeissAvcParamConvert<WeissAvcAnalogOutputLevel> for WeissMan301Protocol {
512 fn build_status_data(cmd: &mut WeissAvcParamCmd) -> Result<(), Error> {
513 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_LEVEL;
514 cmd.value = u32::MAX;
515 Ok(())
516 }
517
518 fn build_control_data(
519 param: &WeissAvcAnalogOutputLevel,
520 cmd: &mut WeissAvcParamCmd,
521 ) -> Result<(), Error> {
522 cmd.numeric_id = Self::PARAM_ID_ANALOG_OUTPUT_LEVEL;
523 cmd.value = match param {
524 WeissAvcAnalogOutputLevel::NegativeThirty => 3,
525 WeissAvcAnalogOutputLevel::NegativeTwenty => 2,
526 WeissAvcAnalogOutputLevel::NegativeTen => 1,
527 WeissAvcAnalogOutputLevel::Zero => 0,
528 };
529 Ok(())
530 }
531
532 fn parse_response_data(
533 param: &mut WeissAvcAnalogOutputLevel,
534 cmd: &WeissAvcParamCmd,
535 ) -> Result<(), Error> {
536 assert_eq!(cmd.numeric_id, Self::PARAM_ID_ANALOG_OUTPUT_LEVEL);
537 *param = match cmd.value {
538 3 => WeissAvcAnalogOutputLevel::NegativeThirty,
539 2 => WeissAvcAnalogOutputLevel::NegativeTwenty,
540 1 => WeissAvcAnalogOutputLevel::NegativeTen,
541 _ => WeissAvcAnalogOutputLevel::Zero,
542 };
543 Ok(())
544 }
545}
546
547pub trait WeissAvcParamOperation<T>: WeissAvcParamConvert<T> {
549 fn cache_param(fcp: &WeissAvc, param: &mut T, timeout_ms: u32) -> Result<(), Error>;
551 fn update_param(fcp: &WeissAvc, param: &mut T, timeout_ms: u32) -> Result<(), Error>;
553}
554
555impl<T> WeissAvcParamOperation<T> for WeissMan301Protocol
556where
557 WeissMan301Protocol: WeissAvcParamConvert<T>,
558{
559 fn cache_param(fcp: &WeissAvc, param: &mut T, timeout_ms: u32) -> Result<(), Error> {
560 let mut cmd = WeissAvcParamCmd::default();
561 Self::build_status_data(&mut cmd)?;
562 fcp.status(&AvcAddr::Unit, &mut cmd, timeout_ms)?;
563 Self::parse_response_data(param, &cmd)?;
564 Ok(())
565 }
566
567 fn update_param(fcp: &WeissAvc, param: &mut T, timeout_ms: u32) -> Result<(), Error> {
568 let mut cmd = WeissAvcParamCmd::default();
569 Self::build_control_data(param, &mut cmd)?;
570 fcp.control(&AvcAddr::Unit, &mut cmd, timeout_ms)?;
571 Self::parse_response_data(param, &cmd)?;
572 Ok(())
573 }
574}
575
576#[cfg(test)]
577mod test {
578 use super::*;
579
580 #[test]
581 fn weiss_avc_param_command_operands() {
582 let operands = [
583 0x00, 0x1c, 0x6a, 0x01, 0x7f, 0x80, 0x02, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,
584 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
585 0xff, 0xff, 0xff,
586 ];
587 let mut op = WeissAvcParamCmd::default();
588 AvcStatus::parse_operands(&mut op, &AvcAddr::Unit, &operands).unwrap();
589 assert_eq!(op.op.class_id, 0x01);
590 assert_eq!(op.op.sequence_id, 0x7f);
591 assert_eq!(op.op.command_id, 0x8002);
592 assert_eq!(op.op.arguments, &operands[7..]);
593 assert_eq!(op.numeric_id, 0x76543210);
594 assert_eq!(op.value, 0xfedcba98);
595
596 let target = AvcStatus::build_operands(&mut op, &AvcAddr::Unit).unwrap();
597 assert_eq!(&target[..4], &operands[..4]);
598 assert_eq!(&target[5..], &operands[5..]);
600
601 let target = AvcControl::build_operands(&mut op, &AvcAddr::Unit).unwrap();
602 assert_eq!(&target[..4], &operands[..4]);
603 assert_eq!(&target[5..], &operands[5..]);
605
606 let mut op = WeissAvcParamCmd::default();
607 AvcControl::parse_operands(&mut op, &AvcAddr::Unit, &operands).unwrap();
608 assert_eq!(op.op.class_id, 0x01);
609 assert_eq!(op.op.sequence_id, 0x7f);
610 assert_eq!(op.op.command_id, 0x8002);
611 assert_eq!(op.op.arguments, &operands[7..]);
612 assert_eq!(op.numeric_id, 0x76543210);
613 assert_eq!(op.value, 0xfedcba98);
614 }
615}