diff --git a/src/devices/cloud_iii_s_wireless.rs b/src/devices/cloud_iii_s_wireless.rs index 231e31c..cc17f9f 100644 --- a/src/devices/cloud_iii_s_wireless.rs +++ b/src/devices/cloud_iii_s_wireless.rs @@ -25,6 +25,14 @@ const AUTO_SHUTDOWN_REPORT_ID: u8 = 0x0c; const AUTO_SHUTDOWN_CMD: [u8; 5] = [0x02, 0x03, 0x00, 0x00, 0x4a]; const AUTO_SHUTDOWN_PACKET_SIZE: usize = 64; +// Equalizer control (via SET_REPORT, report ID 0x0c) +// Packet structure: 0c 02 03 00 00 5f [band] [value_hi] [value_lo] 00... (64 bytes total) +// band: 0-9 (32Hz, 64Hz, 125Hz, 250Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz) +// value: signed 16-bit big-endian, dB * 100 (e.g., +6.0dB = 600, -3.5dB = -350) +const EQ_REPORT_ID: u8 = 0x0c; +const EQ_CMD: [u8; 5] = [0x02, 0x03, 0x00, 0x00, 0x5f]; +const EQ_PACKET_SIZE: usize = 64; + // Button report header (incoming from headset) const CONSUMER_CONTROL_HEADER: u8 = 0x0f; // Consumer control button values @@ -50,6 +58,19 @@ fn make_auto_shutdown_packet(minutes: u64) -> Vec { packet } +fn make_equalizer_band_packet(band_index: u8, db_value: f32) -> Vec { + let mut packet = vec![0u8; EQ_PACKET_SIZE]; + packet[0] = EQ_REPORT_ID; + packet[1..6].copy_from_slice(&EQ_CMD); + packet[6] = band_index; + // Convert dB to device units (dB * 100), clamp to ±12dB range + let value_int = (db_value * 100.0).clamp(-1200.0, 1200.0) as i16; + let value_bytes = value_int.to_be_bytes(); + packet[7] = value_bytes[0]; // High byte + packet[8] = value_bytes[1]; // Low byte + packet +} + pub struct CloudIIISWireless { state: DeviceState, } @@ -162,6 +183,14 @@ impl Device for CloudIIISWireless { None } + // Cloud III S: Equalizer control - CONFIRMED WORKING + fn set_equalizer_band_packet(&self, band_index: u8, db_value: f32) -> Option> { + if band_index > 9 { + return None; + } + Some(make_equalizer_band_packet(band_index, db_value)) + } + fn get_event_from_device_response(&self, response: &[u8]) -> Option> { debug_println!("Read packet: {response:?}"); diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 0a0eb93..3843962 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -90,6 +90,7 @@ pub struct DeviceState { pub can_set_side_tone_volume: bool, pub can_set_voice_prompt: bool, pub can_set_silent_mode: bool, + pub can_set_equalizer: bool, } impl Display for DeviceState { @@ -145,6 +146,7 @@ impl DeviceState { can_set_side_tone_volume: false, can_set_voice_prompt: false, can_set_silent_mode: false, + can_set_equalizer: false, }) } @@ -421,6 +423,11 @@ pub trait Device { fn reset_sirk_packet(&self) -> Option>; fn get_silent_mode_packet(&self) -> Option>; fn set_silent_mode_packet(&self, silence: bool) -> Option>; + /// Set equalizer band (0-9) to dB value (-12.0 to +12.0) + /// Bands: 0=32Hz, 1=64Hz, 2=125Hz, 3=250Hz, 4=500Hz, 5=1kHz, 6=2kHz, 7=4kHz, 8=8kHz, 9=16kHz + fn set_equalizer_band_packet(&self, _band_index: u8, _db_value: f32) -> Option> { + None + } fn get_event_from_device_response(&self, response: &[u8]) -> Option>; fn get_device_state(&self) -> &DeviceState; fn get_device_state_mut(&mut self) -> &mut DeviceState; @@ -451,6 +458,9 @@ pub trait Device { fn can_set_silent_mode(&self) -> bool { self.set_silent_mode_packet(false).is_some() } + fn can_set_equalizer(&self) -> bool { + self.set_equalizer_band_packet(0, 0.0).is_some() + } // Initialize capability flags in device state fn init_capabilities(&mut self) { @@ -462,6 +472,7 @@ pub trait Device { let can_set_side_tone_volume = self.can_set_side_tone_volume(); let can_set_voice_prompt = self.can_set_voice_prompt(); let can_set_silent_mode = self.can_set_silent_mode(); + let can_set_equalizer = self.can_set_equalizer(); // Now set them in device state let state = self.get_device_state_mut(); @@ -472,6 +483,7 @@ pub trait Device { state.can_set_side_tone_volume = can_set_side_tone_volume; state.can_set_voice_prompt = can_set_voice_prompt; state.can_set_silent_mode = can_set_silent_mode; + state.can_set_equalizer = can_set_equalizer; } fn execute_headset_specific_functionality(&mut self) -> Result<(), DeviceError> {