Add support for old cloud 2
This commit is contained in:
@@ -21,7 +21,7 @@ fn main() {
|
|||||||
Arg::new("mute")
|
Arg::new("mute")
|
||||||
.long("mute")
|
.long("mute")
|
||||||
.required(false)
|
.required(false)
|
||||||
.help("Mute or un mute the headset.")
|
.help("Mute or unmute the headset.")
|
||||||
.value_parser(clap::value_parser!(bool)),
|
.value_parser(clap::value_parser!(bool)),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -45,6 +45,13 @@ fn main() {
|
|||||||
.help("Enable voice prompt. This may not be supported on your device.")
|
.help("Enable voice prompt. This may not be supported on your device.")
|
||||||
.value_parser(clap::value_parser!(bool)),
|
.value_parser(clap::value_parser!(bool)),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("surround_sound")
|
||||||
|
.long("surround_sound")
|
||||||
|
.required(false)
|
||||||
|
.help("Enables surround sound. This may be on by default and cannot be changed on your device.")
|
||||||
|
.value_parser(clap::value_parser!(bool)),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let mut device = match connect_compatible_device() {
|
let mut device = match connect_compatible_device() {
|
||||||
@@ -108,6 +115,16 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(surround_sound) = matches.get_one::<bool>("surround_sound") {
|
||||||
|
if let Some(packet) = device.set_surround_sound_packet(*surround_sound) {
|
||||||
|
if let Err(err) = device.get_device_state().hid_device.write(&packet) {
|
||||||
|
println!("Failed to set surround sound with error: {:?}", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Can't change surround sound on this device")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_secs_f64(0.5));
|
std::thread::sleep(Duration::from_secs_f64(0.5));
|
||||||
|
|
||||||
if let Err(error) = device.active_refresh_state() {
|
if let Err(error) = device.active_refresh_state() {
|
||||||
@@ -116,11 +133,3 @@ fn main() {
|
|||||||
};
|
};
|
||||||
println!("{}", device.get_device_state());
|
println!("{}", device.get_device_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_basic_device_access() {
|
|
||||||
let _ = match CloudIIWirelessDTS::new() {
|
|
||||||
Ok(device) => device,
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
195
src/devices/cloud_ii_wireless.rs
Normal file
195
src/devices/cloud_ii_wireless.rs
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
use crate::devices::{ChargingStatus, Device, DeviceError, DeviceEvent, DeviceState};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const HYPERX: u16 = 0x0951;
|
||||||
|
pub const VENDOR_IDS: [u16; 1] = [HYPERX];
|
||||||
|
// Possible Cloud II Wireless product IDs
|
||||||
|
pub const PRODUCT_IDS: [u16; 3] = [0x1718, 0x018B, 0x0b92];
|
||||||
|
|
||||||
|
const BASE_PACKET: [u8; 62] = {
|
||||||
|
let mut tmp = [0u8; 62];
|
||||||
|
tmp[0] = 0x06;
|
||||||
|
tmp[1] = 0x00;
|
||||||
|
tmp[2] = 0x02;
|
||||||
|
tmp[3] = 0x00;
|
||||||
|
tmp[4] = 0x9A;
|
||||||
|
tmp[5] = 0x00;
|
||||||
|
tmp[6] = 0x00;
|
||||||
|
tmp[7] = 0x68;
|
||||||
|
tmp[8] = 0x4A;
|
||||||
|
tmp[9] = 0x8E;
|
||||||
|
tmp[10] = 0x0A;
|
||||||
|
tmp[11] = 0x00;
|
||||||
|
tmp[12] = 0x00;
|
||||||
|
tmp[13] = 0x00;
|
||||||
|
tmp[14] = 0xBB;
|
||||||
|
tmp[15] = 0x01;
|
||||||
|
tmp
|
||||||
|
};
|
||||||
|
|
||||||
|
// I am unsure about all the other command ids
|
||||||
|
|
||||||
|
const GET_CHARGING_CMD_ID: u8 = 3;
|
||||||
|
// const GET_MIC_CONNECTED_CMD_ID: u8 = 8;
|
||||||
|
const GET_BATTERY_CMD_ID: u8 = 2;
|
||||||
|
const GET_AUTO_SHUTDOWN_CMD_ID: u8 = 26;
|
||||||
|
const SET_AUTO_SHUTDOWN_CMD_ID: u8 = 24;
|
||||||
|
// includes also some other information such as side tone and surround sound
|
||||||
|
const GET_MUTE_CMD_ID: u8 = 1;
|
||||||
|
// const SET_MUTE_CMD_ID: u8 = 32;
|
||||||
|
// const GET_PAIRING_CMD_ID: u8 = 9;
|
||||||
|
// const GET_PRODUCT_COLOR_CMD_ID: u8 = 14;
|
||||||
|
// const GET_SIDE_TONE_ON_CMD_ID: u8 = 6;
|
||||||
|
const SET_SIDE_TONE_ON_CMD_ID: u8 = 25;
|
||||||
|
// const GET_SIDE_TONE_VOLUME_CMD_ID: u8 = 11;
|
||||||
|
// const SET_SIDE_TONE_VOLUME_CMD_ID: u8 = 35;
|
||||||
|
// const GET_VOICE_PROMPT_CMD_ID: u8 = 9;
|
||||||
|
// const SET_VOICE_PROMPT_CMD_ID: u8 = 19;
|
||||||
|
// const GET_WIRELESS_STATUS_CMD_ID: u8 = 1;
|
||||||
|
|
||||||
|
pub struct CloudIIWireless {
|
||||||
|
state: DeviceState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CloudIIWireless {
|
||||||
|
pub fn new_from_state(state: DeviceState) -> Self {
|
||||||
|
CloudIIWireless { state }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Result<Self, DeviceError> {
|
||||||
|
let state = DeviceState::new(&PRODUCT_IDS, &VENDOR_IDS)?;
|
||||||
|
Ok(CloudIIWireless { state })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for CloudIIWireless {
|
||||||
|
fn get_charging_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = GET_CHARGING_CMD_ID;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_battery_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = GET_BATTERY_CMD_ID;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_automatic_shut_down_packet(&self, shutdown_after: Duration) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = SET_AUTO_SHUTDOWN_CMD_ID;
|
||||||
|
tmp[16] = (shutdown_after.as_secs() / 60) as u8;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_automatic_shut_down_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = GET_AUTO_SHUTDOWN_CMD_ID;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mute_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = GET_MUTE_CMD_ID;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_mute_packet(&self, _mute: bool) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mic_connected_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pairing_info_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_product_color_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_side_tone_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_side_tone_packet(&self, side_tone_on: bool) -> Option<Vec<u8>> {
|
||||||
|
let mut tmp = BASE_PACKET.to_vec();
|
||||||
|
tmp[15] = SET_SIDE_TONE_ON_CMD_ID;
|
||||||
|
tmp[16] = side_tone_on as u8;
|
||||||
|
Some(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_side_tone_volume_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_side_tone_volume_packet(&self, _volume: u8) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_voice_prompt_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_voice_prompt_packet(&self, _enable: bool) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_wireless_connected_status_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_surround_sound_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_surround_sound_packet(&self, _surround_sound: bool) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_event_from_device_response(&self, response: &[u8]) -> Option<Vec<DeviceEvent>> {
|
||||||
|
if response.len() < 7 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
println!("Received packet: {:?}", response);
|
||||||
|
match (response[3], response[7], response[12], response[14]) {
|
||||||
|
(GET_BATTERY_CMD_ID, level, _, _) => Some(vec![DeviceEvent::BatterLevel(level)]),
|
||||||
|
(GET_CHARGING_CMD_ID, status, _, _) => {
|
||||||
|
Some(vec![DeviceEvent::Charging(ChargingStatus::from(status))])
|
||||||
|
}
|
||||||
|
(GET_AUTO_SHUTDOWN_CMD_ID, shutdown, _, _) => {
|
||||||
|
Some(vec![DeviceEvent::AutomaticShutdownAfter(
|
||||||
|
Duration::from_secs(shutdown as u64 * 60),
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
(GET_MUTE_CMD_ID, _, surround, other) => Some(vec![
|
||||||
|
DeviceEvent::SideToneOn((other & 16) != 0),
|
||||||
|
DeviceEvent::Muted((other & 2) != 0),
|
||||||
|
DeviceEvent::SurroundSound((surround & 2) != 0),
|
||||||
|
]),
|
||||||
|
_ => {
|
||||||
|
println!("Unknown device event: {:?}", response);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device_state(&self) -> &DeviceState {
|
||||||
|
&self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device_state_mut(&mut self) -> &mut DeviceState {
|
||||||
|
&mut self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_write(&mut self) {
|
||||||
|
let mut input_report_buffer = [0u8; 64];
|
||||||
|
input_report_buffer[0] = 6;
|
||||||
|
self.state
|
||||||
|
.hid_device
|
||||||
|
.get_input_report(&mut input_report_buffer)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -159,35 +159,51 @@ impl Device for CloudIIWirelessDTS {
|
|||||||
Some(tmp)
|
Some(tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_event_from_device_response(&self, response: &[u8]) -> Option<DeviceEvent> {
|
fn get_surround_sound_packet(&self) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_surround_sound_packet(&self, _surround_sound: bool) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_event_from_device_response(&self, response: &[u8]) -> Option<Vec<DeviceEvent>> {
|
||||||
if response.len() < 7 {
|
if response.len() < 7 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match (response[2], response[3], response[4], response[7]) {
|
match (response[2], response[3], response[4], response[7]) {
|
||||||
(_, GET_CHARGING_CMD_ID, status, _) => {
|
(_, GET_CHARGING_CMD_ID, status, _) => {
|
||||||
Some(DeviceEvent::Charging(ChargingStatus::from(status)))
|
Some(vec![DeviceEvent::Charging(ChargingStatus::from(status))])
|
||||||
}
|
}
|
||||||
(_, GET_MIC_CONNECTED_CMD_ID, status, _) => {
|
(_, GET_MIC_CONNECTED_CMD_ID, status, _) => {
|
||||||
Some(DeviceEvent::MicConnected(status == 1))
|
Some(vec![DeviceEvent::MicConnected(status == 1)])
|
||||||
|
}
|
||||||
|
(_, GET_BATTERY_CMD_ID, _, level) => Some(vec![DeviceEvent::BatterLevel(level)]),
|
||||||
|
(_, GET_AUTO_SHUTDOWN_CMD_ID, time, _) => {
|
||||||
|
Some(vec![DeviceEvent::AutomaticShutdownAfter(
|
||||||
|
Duration::from_secs(time as u64 * 60),
|
||||||
|
)])
|
||||||
}
|
}
|
||||||
(_, GET_BATTERY_CMD_ID, _, level) => Some(DeviceEvent::BatterLevel(level)),
|
|
||||||
(_, GET_AUTO_SHUTDOWN_CMD_ID, time, _) => Some(DeviceEvent::AutomaticShutdownAfter(
|
|
||||||
Duration::from_secs(time as u64 * 60),
|
|
||||||
)),
|
|
||||||
(_, SET_MUTE_CMD_ID, status, _) | (_, GET_MUTE_CMD_ID, status, _) => {
|
(_, SET_MUTE_CMD_ID, status, _) | (_, GET_MUTE_CMD_ID, status, _) => {
|
||||||
Some(DeviceEvent::Muted(status == 1))
|
Some(vec![DeviceEvent::Muted(status == 1)])
|
||||||
|
}
|
||||||
|
(_, GET_PAIRING_CMD_ID, status, _) => Some(vec![DeviceEvent::PairingInfo(status)]),
|
||||||
|
(_, GET_SIDE_TONE_ON_CMD_ID, status, _) => {
|
||||||
|
Some(vec![DeviceEvent::SideToneOn(status == 1)])
|
||||||
}
|
}
|
||||||
(_, GET_PAIRING_CMD_ID, status, _) => Some(DeviceEvent::PairingInfo(status)),
|
|
||||||
(_, GET_SIDE_TONE_ON_CMD_ID, status, _) => Some(DeviceEvent::SideToneOn(status == 1)),
|
|
||||||
(_, GET_SIDE_TONE_VOLUME_CMD_ID, status, _) => {
|
(_, GET_SIDE_TONE_VOLUME_CMD_ID, status, _) => {
|
||||||
Some(DeviceEvent::SideToneVolume(status))
|
Some(vec![DeviceEvent::SideToneVolume(status)])
|
||||||
}
|
}
|
||||||
(_, GET_WIRELESS_STATUS_CMD_ID, status, _) => {
|
(_, GET_WIRELESS_STATUS_CMD_ID, status, _) => {
|
||||||
Some(DeviceEvent::WirelessConnected(status == 1 || status == 4))
|
Some(vec![DeviceEvent::WirelessConnected(
|
||||||
|
status == 1 || status == 4,
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
(GET_VOICE_PROMPT_CMD_ID, status, _, _) => {
|
||||||
|
Some(vec![DeviceEvent::VoicePrompt(status == 1)])
|
||||||
}
|
}
|
||||||
(GET_VOICE_PROMPT_CMD_ID, status, _, _) => Some(DeviceEvent::VoicePrompt(status == 1)),
|
|
||||||
(GET_PRODUCT_COLOR_CMD_ID, status, _, _) => {
|
(GET_PRODUCT_COLOR_CMD_ID, status, _, _) => {
|
||||||
Some(DeviceEvent::ProductColor(Color::from(status)))
|
Some(vec![DeviceEvent::ProductColor(Color::from(status))])
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown device event: {:?}", response);
|
println!("Unknown device event: {:?}", response);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ pub struct DeviceState {
|
|||||||
pub product_color: Option<Color>,
|
pub product_color: Option<Color>,
|
||||||
pub side_tone_on: Option<bool>,
|
pub side_tone_on: Option<bool>,
|
||||||
pub side_tone_volume: Option<u8>,
|
pub side_tone_volume: Option<u8>,
|
||||||
|
pub surround_sound: Option<bool>,
|
||||||
pub voice_prompt_on: Option<bool>,
|
pub voice_prompt_on: Option<bool>,
|
||||||
pub connected: Option<bool>,
|
pub connected: Option<bool>,
|
||||||
}
|
}
|
||||||
@@ -71,6 +72,7 @@ Pairing info: {}
|
|||||||
Product color: {}
|
Product color: {}
|
||||||
Side tone on: {}
|
Side tone on: {}
|
||||||
Side tone volume: {}
|
Side tone volume: {}
|
||||||
|
Surround sound: {}
|
||||||
Voice prompt on: {}
|
Voice prompt on: {}
|
||||||
Connected: {}",
|
Connected: {}",
|
||||||
self.device_name.clone().unwrap_or("Unknown".to_string()),
|
self.device_name.clone().unwrap_or("Unknown".to_string()),
|
||||||
@@ -88,6 +90,8 @@ Connected: {}",
|
|||||||
self.side_tone_on.map_or(unknown.clone(), |s| s.to_string()),
|
self.side_tone_on.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
self.side_tone_volume
|
self.side_tone_volume
|
||||||
.map_or(unknown.clone(), |s| s.to_string()),
|
.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
|
self.surround_sound
|
||||||
|
.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
self.voice_prompt_on
|
self.voice_prompt_on
|
||||||
.map_or(unknown.clone(), |v| v.to_string()),
|
.map_or(unknown.clone(), |v| v.to_string()),
|
||||||
self.connected.map_or(unknown.clone(), |c| c.to_string()),
|
self.connected.map_or(unknown.clone(), |c| c.to_string()),
|
||||||
@@ -124,6 +128,7 @@ impl DeviceState {
|
|||||||
charging: None,
|
charging: None,
|
||||||
battery_level: None,
|
battery_level: None,
|
||||||
muted: None,
|
muted: None,
|
||||||
|
surround_sound: None,
|
||||||
mic_connected: None,
|
mic_connected: None,
|
||||||
automatic_shutdown_after: None,
|
automatic_shutdown_after: None,
|
||||||
pairing_info: None,
|
pairing_info: None,
|
||||||
@@ -147,6 +152,7 @@ Pairing info: {}
|
|||||||
Product color: {}
|
Product color: {}
|
||||||
Side tone on: {}
|
Side tone on: {}
|
||||||
Side tone volume: {}
|
Side tone volume: {}
|
||||||
|
Surround sound: {}
|
||||||
Voice prompt on: {}
|
Voice prompt on: {}
|
||||||
Connected: {}",
|
Connected: {}",
|
||||||
self.battery_level
|
self.battery_level
|
||||||
@@ -163,6 +169,8 @@ Connected: {}",
|
|||||||
self.side_tone_on.map_or(unknown.clone(), |s| s.to_string()),
|
self.side_tone_on.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
self.side_tone_volume
|
self.side_tone_volume
|
||||||
.map_or(unknown.clone(), |s| s.to_string()),
|
.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
|
self.surround_sound
|
||||||
|
.map_or(unknown.clone(), |s| s.to_string()),
|
||||||
self.voice_prompt_on
|
self.voice_prompt_on
|
||||||
.map_or(unknown.clone(), |v| v.to_string()),
|
.map_or(unknown.clone(), |v| v.to_string()),
|
||||||
self.connected.map_or(unknown.clone(), |c| c.to_string()),
|
self.connected.map_or(unknown.clone(), |c| c.to_string()),
|
||||||
@@ -182,6 +190,7 @@ Connected: {}",
|
|||||||
DeviceEvent::ProductColor(color) => self.product_color = Some(*color),
|
DeviceEvent::ProductColor(color) => self.product_color = Some(*color),
|
||||||
DeviceEvent::SideToneOn(side) => self.side_tone_on = Some(*side),
|
DeviceEvent::SideToneOn(side) => self.side_tone_on = Some(*side),
|
||||||
DeviceEvent::SideToneVolume(volume) => self.side_tone_volume = Some(*volume),
|
DeviceEvent::SideToneVolume(volume) => self.side_tone_volume = Some(*volume),
|
||||||
|
DeviceEvent::SurroundSound(status) => self.surround_sound = Some(*status),
|
||||||
DeviceEvent::VoicePrompt(on) => self.voice_prompt_on = Some(*on),
|
DeviceEvent::VoicePrompt(on) => self.voice_prompt_on = Some(*on),
|
||||||
DeviceEvent::WirelessConnected(connected) => self.connected = Some(*connected),
|
DeviceEvent::WirelessConnected(connected) => self.connected = Some(*connected),
|
||||||
};
|
};
|
||||||
@@ -191,7 +200,15 @@ Connected: {}",
|
|||||||
self.charging = None;
|
self.charging = None;
|
||||||
self.battery_level = None;
|
self.battery_level = None;
|
||||||
self.muted = None;
|
self.muted = None;
|
||||||
|
self.surround_sound = None;
|
||||||
self.mic_connected = None;
|
self.mic_connected = None;
|
||||||
|
self.automatic_shutdown_after = None;
|
||||||
|
self.pairing_info = None;
|
||||||
|
self.product_color = None;
|
||||||
|
self.side_tone_on = None;
|
||||||
|
self.side_tone_volume = None;
|
||||||
|
self.voice_prompt_on = None;
|
||||||
|
self.connected = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +239,7 @@ pub enum DeviceEvent {
|
|||||||
SideToneVolume(u8),
|
SideToneVolume(u8),
|
||||||
VoicePrompt(bool),
|
VoicePrompt(bool),
|
||||||
WirelessConnected(bool),
|
WirelessConnected(bool),
|
||||||
|
SurroundSound(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
@@ -293,6 +311,8 @@ pub trait Device {
|
|||||||
fn get_automatic_shut_down_packet(&self) -> Option<Vec<u8>>;
|
fn get_automatic_shut_down_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn get_mute_packet(&self) -> Option<Vec<u8>>;
|
fn get_mute_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn set_mute_packet(&self, mute: bool) -> Option<Vec<u8>>;
|
fn set_mute_packet(&self, mute: bool) -> Option<Vec<u8>>;
|
||||||
|
fn get_surround_sound_packet(&self) -> Option<Vec<u8>>;
|
||||||
|
fn set_surround_sound_packet(&self, surround_sound: bool) -> Option<Vec<u8>>;
|
||||||
fn get_mic_connected_packet(&self) -> Option<Vec<u8>>;
|
fn get_mic_connected_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn get_pairing_info_packet(&self) -> Option<Vec<u8>>;
|
fn get_pairing_info_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn get_product_color_packet(&self) -> Option<Vec<u8>>;
|
fn get_product_color_packet(&self) -> Option<Vec<u8>>;
|
||||||
@@ -303,11 +323,11 @@ pub trait Device {
|
|||||||
fn get_voice_prompt_packet(&self) -> Option<Vec<u8>>;
|
fn get_voice_prompt_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn set_voice_prompt_packet(&self, enable: bool) -> Option<Vec<u8>>;
|
fn set_voice_prompt_packet(&self, enable: bool) -> Option<Vec<u8>>;
|
||||||
fn get_wireless_connected_status_packet(&self) -> Option<Vec<u8>>;
|
fn get_wireless_connected_status_packet(&self) -> Option<Vec<u8>>;
|
||||||
fn get_event_from_device_response(&self, response: &[u8]) -> Option<DeviceEvent>;
|
fn get_event_from_device_response(&self, response: &[u8]) -> Option<Vec<DeviceEvent>>;
|
||||||
fn get_device_state(&self) -> &DeviceState;
|
fn get_device_state(&self) -> &DeviceState;
|
||||||
fn get_device_state_mut(&mut self) -> &mut DeviceState;
|
fn get_device_state_mut(&mut self) -> &mut DeviceState;
|
||||||
fn prepare_write(&mut self) {}
|
fn prepare_write(&mut self) {}
|
||||||
fn wait_for_updates(&mut self, duration: Duration) -> Option<DeviceEvent> {
|
fn wait_for_updates(&mut self, duration: Duration) -> Option<Vec<DeviceEvent>> {
|
||||||
let mut buf = [0u8; 8];
|
let mut buf = [0u8; 8];
|
||||||
let res = self
|
let res = self
|
||||||
.get_device_state()
|
.get_device_state()
|
||||||
@@ -330,6 +350,7 @@ pub trait Device {
|
|||||||
self.get_battery_packet(),
|
self.get_battery_packet(),
|
||||||
self.get_automatic_shut_down_packet(),
|
self.get_automatic_shut_down_packet(),
|
||||||
self.get_mute_packet(),
|
self.get_mute_packet(),
|
||||||
|
self.get_surround_sound_packet(),
|
||||||
self.get_mic_connected_packet(),
|
self.get_mic_connected_packet(),
|
||||||
self.get_pairing_info_packet(),
|
self.get_pairing_info_packet(),
|
||||||
self.get_product_color_packet(),
|
self.get_product_color_packet(),
|
||||||
@@ -342,8 +363,10 @@ pub trait Device {
|
|||||||
for packet in packets.into_iter().flatten() {
|
for packet in packets.into_iter().flatten() {
|
||||||
self.prepare_write();
|
self.prepare_write();
|
||||||
self.get_device_state().hid_device.write(&packet)?;
|
self.get_device_state().hid_device.write(&packet)?;
|
||||||
if let Some(event) = self.wait_for_updates(Duration::from_secs(1)) {
|
if let Some(events) = self.wait_for_updates(Duration::from_secs(1)) {
|
||||||
self.get_device_state_mut().update_self_with_event(&event);
|
for event in events {
|
||||||
|
self.get_device_state_mut().update_self_with_event(&event);
|
||||||
|
}
|
||||||
responded = true;
|
responded = true;
|
||||||
}
|
}
|
||||||
if !self.get_device_state().connected.map_or(true, |c| c) {
|
if !self.get_device_state().connected.map_or(true, |c| c) {
|
||||||
@@ -361,13 +384,17 @@ pub trait Device {
|
|||||||
/// Refreshes the state by listening for events
|
/// Refreshes the state by listening for events
|
||||||
/// Only the battery level is actively queried because it is not communicated by the device on its own
|
/// Only the battery level is actively queried because it is not communicated by the device on its own
|
||||||
fn passive_refresh_state(&mut self) -> Result<(), DeviceError> {
|
fn passive_refresh_state(&mut self) -> Result<(), DeviceError> {
|
||||||
if let Some(event) = self.wait_for_updates(Duration::from_secs(1)) {
|
if let Some(events) = self.wait_for_updates(Duration::from_secs(1)) {
|
||||||
self.get_device_state_mut().update_self_with_event(&event);
|
for event in events {
|
||||||
|
self.get_device_state_mut().update_self_with_event(&event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(batter_packet) = self.get_battery_packet() {
|
if let Some(batter_packet) = self.get_battery_packet() {
|
||||||
self.get_device_state().hid_device.write(&batter_packet)?;
|
self.get_device_state().hid_device.write(&batter_packet)?;
|
||||||
if let Some(event) = self.wait_for_updates(Duration::from_secs(1)) {
|
if let Some(events) = self.wait_for_updates(Duration::from_secs(1)) {
|
||||||
self.get_device_state_mut().update_self_with_event(&event);
|
for event in events {
|
||||||
|
self.get_device_state_mut().update_self_with_event(&event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ fn main() {
|
|||||||
loop {
|
loop {
|
||||||
std::thread::sleep(refresh_interval);
|
std::thread::sleep(refresh_interval);
|
||||||
// with the default refresh_interval the state is only actively queried every 3min
|
// with the default refresh_interval the state is only actively queried every 3min
|
||||||
// quiting the device to frequently can lead to instability
|
// querying the device to frequently can lead to instability
|
||||||
match if run_counter % 60 == 0 {
|
match if run_counter % 60 == 0 {
|
||||||
device.active_refresh_state()
|
device.active_refresh_state()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user