use super::*;
const CATEGORY_HWCTL: u32 = 3;
const CMD_SET_CLOCK: u32 = 0;
const CMD_GET_CLOCK: u32 = 1;
const CMD_SET_FLAGS: u32 = 3;
const CMD_GET_FLAGS: u32 = 4;
const CMD_BLINK_LED: u32 = 5;
const CMD_RECONNECT: u32 = 6;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct EfwSamplingClockParameters {
pub rate: u32,
pub source: ClkSrc,
}
impl<O, P> EfwWhollyCachableParamsOperation<P, EfwSamplingClockParameters> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn cache_wholly(
proto: &mut P,
states: &mut EfwSamplingClockParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let args = Vec::new();
let mut params = vec![0; 3];
proto
.transaction(
CATEGORY_HWCTL,
CMD_GET_CLOCK,
&args,
&mut params,
timeout_ms,
)
.map(|_| {
deserialize_clock_source(&mut states.source, params[0]);
states.rate = params[1];
})
}
}
impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwSamplingClockParameters> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn update_wholly(
proto: &mut P,
states: &EfwSamplingClockParameters,
timeout_ms: u32,
) -> Result<(), Error> {
let args = [serialize_clock_source(&states.source), states.rate, 0];
let mut params = vec![0; 3];
proto.transaction(
CATEGORY_HWCTL,
CMD_SET_CLOCK,
&args,
&mut params,
timeout_ms,
)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum HwCtlFlag {
MixerEnabled,
SpdifPro,
SpdifNoneAudio,
CtlRoomSelect,
OutputLevelBypass,
MeterInMode,
MeterOutMode,
SoftClip,
GuitarHexInput,
GuitarAutoCharging,
PhantomPowering,
Reserved(usize),
}
impl Default for HwCtlFlag {
fn default() -> Self {
Self::Reserved(usize::MAX)
}
}
fn serialize_hw_ctl_flag(flag: &HwCtlFlag) -> usize {
match flag {
HwCtlFlag::MixerEnabled => 0,
HwCtlFlag::SpdifPro => 1,
HwCtlFlag::SpdifNoneAudio => 2,
HwCtlFlag::CtlRoomSelect => 8, HwCtlFlag::OutputLevelBypass => 9,
HwCtlFlag::MeterInMode => 12,
HwCtlFlag::MeterOutMode => 13,
HwCtlFlag::SoftClip => 18,
HwCtlFlag::GuitarHexInput => 29,
HwCtlFlag::GuitarAutoCharging => 30,
HwCtlFlag::PhantomPowering => 31,
HwCtlFlag::Reserved(pos) => *pos,
}
}
fn deserialize_hw_ctl_flag(flag: &mut HwCtlFlag, pos: usize) {
*flag = match pos {
0 => HwCtlFlag::MixerEnabled,
1 => HwCtlFlag::SpdifPro,
2 => HwCtlFlag::SpdifNoneAudio,
8 => HwCtlFlag::CtlRoomSelect,
9 => HwCtlFlag::OutputLevelBypass,
12 => HwCtlFlag::MeterInMode,
13 => HwCtlFlag::MeterOutMode,
18 => HwCtlFlag::SoftClip,
29 => HwCtlFlag::GuitarHexInput,
30 => HwCtlFlag::GuitarAutoCharging,
31 => HwCtlFlag::PhantomPowering,
_ => HwCtlFlag::Reserved(pos),
};
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct EfwHwCtlFlags(pub Vec<HwCtlFlag>);
impl<O, P> EfwWhollyCachableParamsOperation<P, EfwHwCtlFlags> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn cache_wholly(
proto: &mut P,
states: &mut EfwHwCtlFlags,
timeout_ms: u32,
) -> Result<(), Error> {
let args = Vec::new();
let mut params = vec![0];
proto.transaction(
CATEGORY_HWCTL,
CMD_GET_FLAGS,
&args,
&mut params,
timeout_ms,
)?;
(0..32).filter(|i| params[0] & (1 << i) > 0).for_each(|i| {
let mut flag = HwCtlFlag::default();
deserialize_hw_ctl_flag(&mut flag, i);
if states.0.iter().find(|f| flag.eq(f)).is_none() {
states.0.push(flag);
}
});
Ok(())
}
}
impl<O, P> EfwPartiallyUpdatableParamsOperation<P, EfwHwCtlFlags> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn update_partially(
proto: &mut P,
states: &mut EfwHwCtlFlags,
updates: EfwHwCtlFlags,
timeout_ms: u32,
) -> Result<(), Error> {
let mut args = [0; 2];
let mut params = Vec::new();
updates
.0
.iter()
.for_each(|flag| args[0] |= 1 << serialize_hw_ctl_flag(flag));
states.0.iter().for_each(|flag| {
if updates.0.iter().find(|f| flag.eq(f)).is_none() {
args[1] = 1 << serialize_hw_ctl_flag(flag);
}
});
proto.transaction(
CATEGORY_HWCTL,
CMD_SET_FLAGS,
&args,
&mut params,
timeout_ms,
)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct EfwLedBlink;
impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwLedBlink> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn update_wholly(proto: &mut P, _: &EfwLedBlink, timeout_ms: u32) -> Result<(), Error> {
let args = Vec::new();
let mut params = Vec::new();
proto.transaction(
CATEGORY_HWCTL,
CMD_BLINK_LED,
&args,
&mut params,
timeout_ms,
)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct EfwReconnectPhy;
impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwReconnectPhy> for O
where
O: EfwHardwareSpecification,
P: EfwProtocolExtManual,
{
fn update_wholly(proto: &mut P, _: &EfwReconnectPhy, timeout_ms: u32) -> Result<(), Error> {
let args = Vec::new();
let mut params = Vec::new();
proto.transaction(
CATEGORY_HWCTL,
CMD_RECONNECT,
&args,
&mut params,
timeout_ms,
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn hw_ctl_flag_serdes() {
[
HwCtlFlag::MixerEnabled,
HwCtlFlag::SpdifPro,
HwCtlFlag::SpdifNoneAudio,
HwCtlFlag::CtlRoomSelect,
HwCtlFlag::OutputLevelBypass,
HwCtlFlag::MeterInMode,
HwCtlFlag::MeterOutMode,
HwCtlFlag::SoftClip,
HwCtlFlag::GuitarHexInput,
HwCtlFlag::GuitarAutoCharging,
HwCtlFlag::PhantomPowering,
HwCtlFlag::default(),
]
.iter()
.for_each(|flag| {
let val = serialize_hw_ctl_flag(&flag);
let mut f = HwCtlFlag::default();
deserialize_hw_ctl_flag(&mut f, val);
assert_eq!(*flag, f);
});
}
}