fix: refactor to avoid circular dependencies

This commit is contained in:
2026-07-20 23:14:26 +02:00
parent 455585eeb6
commit 605d23f529
20 changed files with 603 additions and 522 deletions
+29 -386
View File
@@ -1,16 +1,30 @@
use std::{
collections::HashMap, io::{Read, Write}, net::{IpAddr, SocketAddr, TcpStream}, sync::{Mutex, OnceLock}, time::Duration, fmt,
collections::HashMap,
fmt,
io::{Read, Write},
net::{IpAddr, SocketAddr, TcpStream},
sync::{Mutex, OnceLock},
time::Duration,
};
use strum::{EnumCount, IntoEnumIterator};
use strum::IntoEnumIterator;
use crate::common::errors::{DSPError, ValidationError};
use crate::dsp408::client::types;
use crate::dsp408::client::constants;
use crate::dsp408::protocol::frame::extract_frame;
use crate::dsp408::protocol::commands;
use crate::dsp408::mapper::response::map_response;
use crate::dsp408::mapper;
use crate::{
common::errors::{DSPError, ValidationError},
dsp408::{
mapper::{
self,
constants::{PRESET_INDEX_MAX, CONFIG_CHUNK_INDEX_MAX},
response::map_response,
},
protocol::{
commands,
config::decode_config,
frame::extract_frame,
},
types,
},
};
pub const SOCKET_TIMEOUT: Duration = Duration::from_secs(20);
pub const RECV_BUFSIZE: usize = 4096;
@@ -231,9 +245,9 @@ impl DSP408 {
let flags = self.get_device_flags()?;
let current_preset = self.get_current_preset()?;
let modified = self.get_preset_modification_status()?;
let mut preset_names = Vec::with_capacity(constants::PRESET_INDEX_MAX);
let mut preset_names = Vec::with_capacity(PRESET_INDEX_MAX);
for i in 0..constants::PRESET_INDEX_MAX {
for i in 0..PRESET_INDEX_MAX {
preset_names.push(
self.get_preset_name(i + 1)?
);
@@ -805,6 +819,7 @@ impl DSP408 {
}
// Command `0x33` (Set PEQ Band)
#[allow(clippy::too_many_arguments)]
pub fn set_peq_band(
&mut self,
channel: types::Channel,
@@ -847,7 +862,7 @@ impl DSP408 {
gain: gain_db,
frequency: freq_hz,
q,
filter_type: filter_type,
filter_type,
bypass,
};
@@ -1607,12 +1622,12 @@ impl DSP408 {
fn read_config_state(&mut self) -> Result<types::DSPConfigState, DSPError> {
let mut raw = Vec::new();
for i in 0..=constants::CONFIG_CHUNK_INDEX_MAX {
for i in 0..=CONFIG_CHUNK_INDEX_MAX {
let chunk = self.get_config_chunk(i)?;
raw.extend_from_slice(&chunk.data);
}
let config = build_config_from_chunk(&raw)?;
let config = decode_config(&raw)?;
if !self.request_acknowledgement()? {
return Err(DSPError::OperationFailed(
@@ -1641,375 +1656,3 @@ impl fmt::Debug for DSP408 {
.finish()
}
}
struct BinaryReader<'a> {
data: &'a [u8],
}
impl<'a> BinaryReader<'a> {
fn new(data: &'a [u8]) -> Self {
Self { data }
}
fn pop(&mut self, n: usize) -> Result<&'a [u8], DSPError> {
if self.data.len() < n {
return Err(DSPError::InvalidRequest(
"buffer underflow".into()
));
}
let (value, rest) = self.data.split_at(n);
self.data = rest;
Ok(value)
}
fn read_u8(&mut self) -> Result<u8, DSPError> {
Ok(self.pop(1)?[0])
}
fn read_u16(&mut self) -> Result<u16, DSPError> {
Ok(u16::from_le_bytes(
self.pop(2)?.try_into().unwrap()
))
}
fn skip(&mut self, n: usize) -> Result<(), DSPError> {
self.pop(n)?;
Ok(())
}
}
fn apply_flag<T>(
r: &mut BinaryReader,
targets: &mut [T],
setter: impl Fn(&mut T, bool),
) -> Result<(), DSPError> {
let bitmap = r.read_u16()?;
for (index, target) in targets.iter_mut().enumerate() {
setter(target, bitmap & (1 << index) != 0);
}
Ok(())
}
fn read_gate(r: &mut BinaryReader) -> Result<types::Gate, DSPError> {
Ok(types::Gate {
attack: mapper::raw_to_attack_ms(r.read_u16()?)?,
release: mapper::raw_to_release_ms(r.read_u16()?)?,
hold: mapper::raw_to_hold_ms(r.read_u16()?)?,
threshold: mapper::raw_to_gate_threshold_db(r.read_u16()?)?,
})
}
fn read_geq(
r: &mut BinaryReader,
) -> Result<types::GraphicEQ, DSPError> {
let gains = types::DiscreteFrequency::iter()
.map(|_| {
let raw = r.read_u16()?;
Ok(mapper::raw_to_eq_gain(raw)?)
})
.collect::<Result<Vec<_>, DSPError>>()?;
Ok(types::GraphicEQ {
gains,
bypass: false,
})
}
fn read_peq_chain(
r: &mut BinaryReader,
band_count: usize,
) -> Result<types::PEQChain, DSPError> {
let bands = (0..band_count)
.map(|_| {
Ok(types::PEQ {
gain: mapper::raw_to_eq_gain(r.read_u16()?)?,
frequency: mapper::raw_to_frequency_hz(r.read_u16()?)?,
q: mapper::raw_to_peq_q(r.read_u8()?)?,
filter_type: mapper::raw_to_peq_filter(r.read_u8()?)?,
bypass: false,
})
})
.collect::<Result<Vec<_>, DSPError>>()?;
Ok(types::PEQChain {
bands,
bypass: false,
})
}
fn read_crossover(
r: &mut BinaryReader,
) -> Result<types::CrossoverFilters, DSPError> {
let hp_freq = r.read_u16()?;
let lp_freq = r.read_u16()?;
let hp_filter = r.read_u8()?;
let lp_filter = r.read_u8()?;
Ok(types::CrossoverFilters {
high_pass: types::Crossover {
frequency: mapper::raw_to_frequency_hz(hp_freq)?,
slope: mapper::raw_to_crossover_filter(hp_filter)?,
},
low_pass: types::Crossover {
frequency: mapper::raw_to_frequency_hz(lp_freq)?,
slope: mapper::raw_to_crossover_filter(lp_filter)?,
},
})
}
fn read_compressor(
r: &mut BinaryReader,
) -> Result<types::Compressor, DSPError> {
Ok(types::Compressor {
ratio: mapper::raw_to_ratio(r.read_u16()?)?,
attack: mapper::raw_to_attack_ms(r.read_u16()?)?,
release: mapper::raw_to_release_ms(r.read_u16()?)?,
knee: mapper::raw_to_knee_db(r.read_u16()?)?,
threshold: mapper::raw_to_threshold_db(r.read_u16()?)?,
})
}
fn read_limiter(
r: &mut BinaryReader,
) -> Result<types::Limiter, DSPError> {
let attack = mapper::raw_to_attack_ms(r.read_u16()?)?;
let release = mapper::raw_to_release_ms(r.read_u16()?)?;
r.skip(2)?;
let threshold = mapper::raw_to_threshold_db(r.read_u16()?)?;
Ok(types::Limiter {
attack,
release,
threshold,
})
}
fn build_config_from_chunk(payload: &[u8]) -> Result<types::DSPConfigState, DSPError> {
let mut r = BinaryReader::new(payload);
r.skip(2)?; // flags (unused)
let _preset_name = mapper::raw_to_preset_name(r.pop(constants::PRESET_NAME_LENGTH)?)?;
let mut input_channels = vec![types::InputChannelState::default(); types::InputChannel::COUNT];
let mut output_channels = vec![types::OutputChannelState::default(); types::OutputChannel::COUNT];
let mut input_delays_raw: Vec<u8> = Vec::new();
let mut output_delays_raw: Vec<u8> = Vec::new();
// ============================
// INPUT CHANNELS
// ============================
for (channel, inp) in types::InputChannel::iter().zip(input_channels.iter_mut()) {
inp.name = mapper::raw_to_channel_name(r.pop(constants::CHANNEL_NAME_LENGTH)?)?;
inp.gate = read_gate(&mut r)?;
inp.geq = read_geq(&mut r)?;
inp.peq_chain = read_peq_chain(&mut r, constants::PEQ_INPUT_BAND_COUNT)?;
inp.crossover = read_crossover(&mut r)?;
inp.gain = mapper::raw_to_gain(r.read_u16()?)?;
inp.phase_inverted = r.read_u8()? != 0;
r.skip(2)?; // reserved
input_delays_raw.push(r.read_u8()?);
r.skip(1)?;
inp.linked_channels = mapper::raw_to_link_channels(mapper::channel_to_raw(types::Channel::Input(channel))?, r.read_u8()?)?;
}
// ============================
// OUTPUT CHANNELS
// ============================
for (channel, out) in types::OutputChannel::iter().zip(output_channels.iter_mut()) {
out.name = mapper::raw_to_channel_name(r.pop(constants::CHANNEL_NAME_LENGTH)?)?;
r.skip(1)?;
out.matrix_routes = types::MatrixRoutes {
connected:
mapper::raw_to_matrix(
r.read_u8()?
)?,
gains: (0..4)
.map(|_| {
let raw = r.read_u16()?;
Ok::<f32, DSPError>(mapper::raw_to_matrix_gain(raw)?)
})
.collect::<Result<Vec<_>, _>>()?,
};
out.crossover = read_crossover(&mut r)?;
out.peq_chain = read_peq_chain(&mut r, constants::PEQ_OUTPUT_BAND_COUNT)?;
out.compressor = read_compressor(&mut r)?;
out.limiter = read_limiter(&mut r)?;
out.gain = mapper::raw_to_gain(r.read_u16()?)?;
out.phase_inverted = r.read_u8()? != 0;
r.skip(2)?; // reserved
output_delays_raw.push(r.read_u8()?);
r.skip(1)?;
out.linked_channels = mapper::raw_to_link_channels(mapper::channel_to_raw(types::Channel::Output(channel))?, r.read_u8()?)?;
}
// ============================
// MUTE FLAGS
// ============================
apply_flag(
&mut r,
&mut input_channels,
|ch, value| ch.mute = value,
)?;
apply_flag(
&mut r,
&mut output_channels,
|ch, value| ch.mute = value,
)?;
// ============================
// PEQ BYPASS FLAGS
// ============================
for inp in &mut input_channels {
apply_flag(
&mut r,
inp.peq_chain.bands.as_mut_slice(),
|band, value| band.bypass = value,
)?;
}
for out in &mut output_channels {
apply_flag(
&mut r,
out.peq_chain.bands.as_mut_slice(),
|band, value| band.bypass = value,
)?;
}
// ============================
// INPUT SOURCE
// ============================
let input_source = types::InputSource {
r#type: mapper::raw_to_input_source(
r.read_u16()? as u8,
)?,
frequency: mapper::raw_to_frequency_value(
r.read_u16()? as u8,
)?,
};
// ============================
// DELAY UNIT
// ============================
let delay_unit = mapper::raw_to_delay_unit(
r.read_u16()? as u8,
)?;
// ============================
// APPLY DELAYS
// ============================
for (inp, raw_delay) in input_channels.iter_mut().zip(input_delays_raw)
{
inp.delay = mapper::raw_to_delay(
raw_delay,
delay_unit,
)?;
}
for (out, raw_delay) in output_channels.iter_mut().zip(output_delays_raw)
{
out.delay = mapper::raw_to_delay(
raw_delay,
delay_unit,
)?;
}
// ============================
// PEQ / GEQ BYPASS
// ============================
let input_peq_bitmap = r.read_u16()?;
for (index, inp) in input_channels.iter_mut().enumerate() {
let bypass = input_peq_bitmap & (1 << index) != 0;
for peq in inp.peq_chain.bands.iter_mut() {
peq.bypass = bypass;
}
}
let output_peq_bitmap = r.read_u16()?;
for (index, out) in output_channels.iter_mut().enumerate() {
let bypass = output_peq_bitmap & (1 << index) != 0;
for peq in out.peq_chain.bands.iter_mut() {
peq.bypass = bypass;
}
}
let bitmap = r.read_u16()?;
for (index, inp) in input_channels.iter_mut().enumerate() {
inp.geq.bypass = bitmap & (1 << index) != 0;
}
// ============================
// BUILD CHANNEL MAP
// ============================
let mut input_states = HashMap::new();
for (channel, state) in types::InputChannel::iter().zip(input_channels) {
input_states.insert(
channel,
state,
);
}
let mut output_states = HashMap::new();
for (channel, state) in types::OutputChannel::iter().zip(output_channels) {
output_states.insert(
channel,
state,
);
}
Ok(types::DSPConfigState {
input_states,
output_states,
delay_unit: delay_unit,
input_source: input_source,
})
}