firewire_bebob_protocols/presonus/
inspire1394.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for Inspire 1394.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by PreSonus for Inspire 1394.
8//!
9//! ## Diagram of internal signal flow
10//!
11//! ```text
12//! analog-input-1/2 ---------+--------> stream-output-1/2
13//! analog-input-3/4 ---------|-+------> stream-output-3/4
14//!                           | |
15//!                           v v
16//!                       ++=======++
17//! stream-input-1/2 -+-> ||  6x2  ||
18//!                   |   || mixer ||
19//!                   |   ++=======++
20//!                   |        |
21//!                   v        v
22//!               (one source only)
23//!               analog-output-1/2
24//!                 headphone-1/2
25//! ```
26//!
27//! The protocol implementation for PreSonus Inspire 1394 was written with firmware version below:
28//!
29//! ```sh
30//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
31//! protocol:
32//!   version: 1
33//! bootloader:
34//!   timestamp: 2005-09-02T05:43:21+0000
35//!   version: 0.0.0
36//! hardware:
37//!   GUID: 0xe6120493000a9200
38//!   model ID: 0x00009c
39//!   revision: 0.0.1
40//! software:
41//!   timestamp: 2005-09-02T06:23:23+0000
42//!   ID: 0x00010001
43//!   revision: 0.255.65535
44//! image:
45//!   base address: 0x20080000
46//!   maximum size: 0x180000
47//! ```
48
49use super::*;
50
51/// The protocol implementation of clock operation.
52#[derive(Default, Debug)]
53pub struct Inspire1394ClkProtocol;
54
55impl MediaClockFrequencyOperation for Inspire1394ClkProtocol {
56    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000];
57}
58
59impl SamplingClockSourceOperation for Inspire1394ClkProtocol {
60    const DST: SignalAddr = SignalAddr::Subunit(SignalSubunitAddr {
61        subunit: MUSIC_SUBUNIT_0,
62        plug_id: 0x03,
63    });
64
65    const SRC_LIST: &'static [SignalAddr] = &[
66        // Internal.
67        SignalAddr::Subunit(SignalSubunitAddr {
68            subunit: MUSIC_SUBUNIT_0,
69            plug_id: 0x02,
70        }),
71    ];
72}
73
74/// The protocol implementation of physical input.
75#[derive(Default, Debug)]
76pub struct Inspire1394PhysInputProtocol;
77
78impl AvcAudioFeatureSpecification for Inspire1394PhysInputProtocol {
79    const ENTRIES: &'static [(u8, AudioCh)] = &[
80        (0x1, AudioCh::Each(0)),
81        (0x1, AudioCh::Each(1)),
82        (0x2, AudioCh::Each(0)),
83        (0x2, AudioCh::Each(1)),
84    ];
85}
86
87impl AvcLevelOperation for Inspire1394PhysInputProtocol {}
88
89impl AvcMuteOperation for Inspire1394PhysInputProtocol {}
90
91/// The protocol implementation of physical output.
92#[derive(Default, Debug)]
93pub struct Inspire1394PhysOutputProtocol;
94
95impl AvcAudioFeatureSpecification for Inspire1394PhysOutputProtocol {
96    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x06, AudioCh::Each(0)), (0x06, AudioCh::Each(1))];
97}
98
99impl AvcLevelOperation for Inspire1394PhysOutputProtocol {}
100
101impl AvcMuteOperation for Inspire1394PhysOutputProtocol {}
102
103impl AvcSelectorOperation for Inspire1394PhysOutputProtocol {
104    const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x01];
105    // NOTE: "mixer-output-1/2", "stream-input-1/2"
106    const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01];
107}
108
109/// The protocol implementation of headphone.
110#[derive(Default, Debug)]
111pub struct Inspire1394HeadphoneProtocol;
112
113impl AvcAudioFeatureSpecification for Inspire1394HeadphoneProtocol {
114    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x07, AudioCh::Each(0)), (0x07, AudioCh::Each(1))];
115}
116
117impl AvcLevelOperation for Inspire1394HeadphoneProtocol {}
118
119impl AvcMuteOperation for Inspire1394HeadphoneProtocol {}
120
121/// The protocol implementation of analog source for mixer.
122#[derive(Default, Debug)]
123pub struct Inspire1394MixerAnalogSourceProtocol;
124
125impl AvcAudioFeatureSpecification for Inspire1394MixerAnalogSourceProtocol {
126    const ENTRIES: &'static [(u8, AudioCh)] = &[
127        (0x03, AudioCh::Each(0)),
128        (0x03, AudioCh::Each(1)),
129        (0x04, AudioCh::Each(0)),
130        (0x04, AudioCh::Each(1)),
131    ];
132}
133
134impl AvcLevelOperation for Inspire1394MixerAnalogSourceProtocol {}
135
136impl AvcLrBalanceOperation for Inspire1394MixerAnalogSourceProtocol {}
137
138impl AvcMuteOperation for Inspire1394MixerAnalogSourceProtocol {}
139
140/// The protocol implementation of stream source for mixer.
141#[derive(Default, Debug)]
142pub struct Inspire1394MixerStreamSourceProtocol;
143
144impl AvcAudioFeatureSpecification for Inspire1394MixerStreamSourceProtocol {
145    const ENTRIES: &'static [(u8, AudioCh)] = &[(0x05, AudioCh::Master)];
146}
147
148impl AvcLevelOperation for Inspire1394MixerStreamSourceProtocol {}
149
150impl AvcMuteOperation for Inspire1394MixerStreamSourceProtocol {}
151
152const METER_FRAME_SIZE: usize = 32;
153
154/// The structure of meter information for Inspire 1394.
155#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
156pub struct Inspire1394Meter {
157    pub phys_inputs: [i32; 4],
158    pub stream_inputs: [i32; 2],
159    pub phys_outputs: [i32; 2],
160    frame: [u8; METER_FRAME_SIZE],
161}
162
163/// The protocol implementation of meter information.
164#[derive(Default, Debug)]
165pub struct Inspire1394MeterProtocol;
166
167impl Inspire1394MeterProtocol {
168    /// The minimum value of detected signal level.
169    pub const LEVEL_MIN: i32 = 0;
170    /// The maximum value of detected signal level.
171    pub const LEVEL_MAX: i32 = 0x07ffffff;
172    /// The step value of detected signal level.
173    pub const LEVEL_STEP: i32 = 0x100;
174
175    /// Cache state of hardware to the parameters.
176    pub fn cache(
177        req: &FwReq,
178        node: &FwNode,
179        meter: &mut Inspire1394Meter,
180        timeout_ms: u32,
181    ) -> Result<(), Error> {
182        let frame = &mut meter.frame;
183        req.transaction_sync(
184            node,
185            FwTcode::ReadBlockRequest,
186            DM_APPL_METER_OFFSET,
187            METER_FRAME_SIZE,
188            frame,
189            timeout_ms,
190        )?;
191
192        let mut quadlet = [0u8; 4];
193        meter
194            .phys_inputs
195            .iter_mut()
196            .chain(&mut meter.stream_inputs)
197            .chain(&mut meter.phys_outputs)
198            .enumerate()
199            .for_each(|(i, m)| {
200                let pos = i * 4;
201                quadlet.copy_from_slice(&frame[pos..(pos + 4)]);
202                *m = i32::from_be_bytes(quadlet);
203            });
204
205        Ok(())
206    }
207}
208
209/// The parameters of input switches.
210#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
211pub struct Inspire1394SwitchParameters {
212    /// Phono mode in 2nd input pair (lines).
213    pub pair1_phono: bool,
214    /// Phantom powering in 1st input pair (microphones).
215    pub pair0_phantom: [bool; 2],
216    /// Signal boost in 1st input pair (microphones).
217    pub pair0_boost: [bool; 2],
218    /// Signal limit in 1st input pair (microphones).
219    pub pair0_limit: [bool; 2],
220}
221
222/// Protocol implementation to operate input switches.
223#[derive(Default, Debug)]
224pub struct Inspire1394SwitchProtocol;
225
226impl Inspire1394SwitchProtocol {
227    pub fn cache(
228        avc: &BebobAvc,
229        params: &mut Inspire1394SwitchParameters,
230        timeout_ms: u32,
231    ) -> Result<(), Error> {
232        [
233            InputSwitch::Analog34Phono(Default::default()),
234            InputSwitch::Analog12Phantom(0, Default::default()),
235            InputSwitch::Analog12Phantom(1, Default::default()),
236            InputSwitch::Analog12Boost(0, Default::default()),
237            InputSwitch::Analog12Boost(1, Default::default()),
238            InputSwitch::Analog12Limit(0, Default::default()),
239            InputSwitch::Analog12Limit(1, Default::default()),
240        ]
241        .iter()
242        .try_for_each(|switch| {
243            let mut op = InputSwitchOperation::new(switch);
244            avc.status(&AvcAddr::Subunit(MUSIC_SUBUNIT_0), &mut op, timeout_ms)?;
245            match op.switch {
246                InputSwitch::Analog34Phono(val) => params.pair1_phono = val,
247                InputSwitch::Analog12Phantom(idx, val) => params.pair0_phantom[idx] = val,
248                InputSwitch::Analog12Boost(idx, val) => params.pair0_boost[idx] = val,
249                InputSwitch::Analog12Limit(idx, val) => params.pair0_limit[idx] = val,
250                _ => (),
251            }
252            Ok(())
253        })
254    }
255
256    pub fn update(
257        avc: &BebobAvc,
258        params: &Inspire1394SwitchParameters,
259        prev: &mut Inspire1394SwitchParameters,
260        timeout_ms: u32,
261    ) -> Result<(), Error> {
262        Self::build_switches(prev)
263            .iter()
264            .zip(Self::build_switches(params).iter())
265            .filter(|(o, n)| !n.eq(o))
266            .try_for_each(|(_, new)| {
267                let mut op = InputSwitchOperation::new(new);
268                avc.control(&AvcAddr::Subunit(MUSIC_SUBUNIT_0), &mut op, timeout_ms)
269            })
270            .map(|_| *prev = *params)
271    }
272
273    fn build_switches(params: &Inspire1394SwitchParameters) -> Vec<InputSwitch> {
274        vec![
275            InputSwitch::Analog34Phono(params.pair1_phono),
276            InputSwitch::Analog12Phantom(0, params.pair0_phantom[0]),
277            InputSwitch::Analog12Phantom(1, params.pair0_phantom[1]),
278            InputSwitch::Analog12Boost(0, params.pair0_boost[0]),
279            InputSwitch::Analog12Boost(1, params.pair0_boost[1]),
280            InputSwitch::Analog12Limit(0, params.pair0_limit[0]),
281            InputSwitch::Analog12Limit(1, params.pair0_limit[1]),
282        ]
283    }
284}
285
286/// The switch related to inputs.
287#[derive(Debug, Copy, Clone, PartialEq, Eq)]
288pub enum InputSwitch {
289    /// Phono mode for 2nd pair of inputs (line).
290    Analog34Phono(bool),
291    /// Phantom powering for 1st pair of inputs (microphones).
292    Analog12Phantom(usize, bool),
293    /// Boost for 1st pair of inputs (microphones).
294    Analog12Boost(usize, bool),
295    /// Limitter for 1st pair of inputs (microphones).
296    Analog12Limit(usize, bool),
297    /// Link stereo pairs.
298    #[allow(dead_code)]
299    AnalogStereoLink(usize, bool),
300}
301
302const CMD_PHONO: u8 = 0x00;
303const CMD_MIC_PHANTOM: u8 = 0x01;
304const CMD_MIC_BOOST: u8 = 0x02;
305const CMD_MIC_LIMIT: u8 = 0x03;
306const CMD_STEREO_LINK: u8 = 0x05;
307
308impl Default for InputSwitch {
309    fn default() -> Self {
310        Self::Analog34Phono(false)
311    }
312}
313
314/// The AV/C operation for input switch.
315#[derive(Debug)]
316pub struct InputSwitchOperation {
317    /// The switch for input.
318    pub switch: InputSwitch,
319    op: VendorDependent,
320}
321
322impl Default for InputSwitchOperation {
323    fn default() -> Self {
324        Self {
325            switch: Default::default(),
326            op: VendorDependent {
327                company_id: PRESONUS_OUI,
328                data: vec![0; 3],
329            },
330        }
331    }
332}
333
334impl InputSwitchOperation {
335    fn new(switch: &InputSwitch) -> Self {
336        let mut op = Self::default();
337        op.switch = *switch;
338        op
339    }
340}
341
342impl AvcOp for InputSwitchOperation {
343    const OPCODE: u8 = VendorDependent::OPCODE;
344}
345
346impl AvcControl for InputSwitchOperation {
347    fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
348        match self.switch {
349            InputSwitch::Analog34Phono(state) => {
350                self.op.data[0] = CMD_PHONO;
351                self.op.data[1] = 0x00;
352                self.op.data[2] = state as u8;
353            }
354            InputSwitch::Analog12Phantom(ch, state) => {
355                self.op.data[0] = CMD_MIC_PHANTOM;
356                self.op.data[1] = 1 + ch as u8;
357                self.op.data[2] = state as u8;
358            }
359            InputSwitch::Analog12Boost(ch, state) => {
360                self.op.data[0] = CMD_MIC_BOOST;
361                self.op.data[1] = 1 + ch as u8;
362                self.op.data[2] = state as u8;
363            }
364            InputSwitch::Analog12Limit(ch, state) => {
365                self.op.data[0] = CMD_MIC_LIMIT;
366                self.op.data[1] = 1 + ch as u8;
367                self.op.data[2] = state as u8;
368            }
369            InputSwitch::AnalogStereoLink(ch, state) => {
370                self.op.data[0] = CMD_STEREO_LINK;
371                self.op.data[1] = 1 + ch as u8;
372                self.op.data[2] = state as u8;
373            }
374        }
375        AvcControl::build_operands(&mut self.op, addr)
376    }
377
378    fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
379        AvcControl::parse_operands(&mut self.op, addr, operands)
380    }
381}
382
383impl AvcStatus for InputSwitchOperation {
384    fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
385        match self.switch {
386            InputSwitch::Analog34Phono(_) => {
387                self.op.data[0] = CMD_PHONO;
388                self.op.data[1] = 0x00;
389            }
390            InputSwitch::Analog12Phantom(ch, _) => {
391                self.op.data[0] = CMD_PHONO;
392                self.op.data[1] = 1 + ch as u8;
393            }
394            InputSwitch::Analog12Boost(ch, _) => {
395                self.op.data[0] = CMD_PHONO;
396                self.op.data[1] = 1 + ch as u8;
397            }
398            InputSwitch::Analog12Limit(ch, _) => {
399                self.op.data[0] = CMD_PHONO;
400                self.op.data[1] = 1 + ch as u8;
401            }
402            InputSwitch::AnalogStereoLink(ch, _) => {
403                self.op.data[0] = CMD_STEREO_LINK;
404                self.op.data[1] = 1 + ch as u8;
405            }
406        }
407        self.op.data[2] = 0xff;
408        AvcControl::build_operands(&mut self.op, addr)
409    }
410
411    fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
412        AvcControl::parse_operands(&mut self.op, addr, operands).map(|_| match &mut self.switch {
413            InputSwitch::Analog34Phono(state) => {
414                *state = self.op.data[2] > 0;
415            }
416            InputSwitch::Analog12Phantom(_, state) => {
417                *state = self.op.data[2] > 0;
418            }
419            InputSwitch::Analog12Boost(_, state) => {
420                *state = self.op.data[2] > 0;
421            }
422            InputSwitch::Analog12Limit(_, state) => {
423                *state = self.op.data[2] > 0;
424            }
425            InputSwitch::AnalogStereoLink(_, state) => {
426                *state = self.op.data[2] > 0;
427            }
428        })
429    }
430}