Buttplug sex toy control library

chore: Make rest of svakom protocols compile

They may not be right but they're done.

Affects #709

+166 -463
+16 -16
crates/buttplug_server/src/device/protocol_impl/mod.rs
··· 425 425 sexverse_lg389::setup::SexverseLG389IdentifierFactory::default(), 426 426 ); 427 427 add_to_protocol_map(&mut map, serveu::setup::ServeUIdentifierFactory::default()); 428 - //add_to_protocol_map( 429 - // &mut map, 430 - // svakom::svakom_avaneo::setup::SvakomAvaNeoIdentifierFactory::default(), 431 - //); 428 + add_to_protocol_map( 429 + &mut map, 430 + svakom::svakom_avaneo::setup::SvakomAvaNeoIdentifierFactory::default(), 431 + ); 432 432 add_to_protocol_map( 433 433 &mut map, 434 434 svakom::svakom_alex::setup::SvakomAlexIdentifierFactory::default(), ··· 449 449 &mut map, 450 450 svakom::svakom_dice::setup::SvakomDiceIdentifierFactory::default(), 451 451 ); 452 - //add_to_protocol_map( 453 - // &mut map, 454 - // svakom::svakom_dt250a::setup::SvakomDT250AIdentifierFactory::default(), 455 - //); 452 + add_to_protocol_map( 453 + &mut map, 454 + svakom::svakom_dt250a::setup::SvakomDT250AIdentifierFactory::default(), 455 + ); 456 456 add_to_protocol_map( 457 457 &mut map, 458 458 svakom::svakom_iker::setup::SvakomIkerIdentifierFactory::default(), ··· 473 473 &mut map, 474 474 svakom::svakom_sam2::setup::SvakomSam2IdentifierFactory::default(), 475 475 ); 476 - //add_to_protocol_map( 477 - // &mut map, 478 - // svakom::svakom_suitcase::setup::SvakomSuitcaseIdentifierFactory::default(), 479 - //); 480 - //add_to_protocol_map( 481 - // &mut map, 482 - // svakom::svakom_tarax::setup::SvakomTaraXIdentifierFactory::default(), 483 - //); 476 + add_to_protocol_map( 477 + &mut map, 478 + svakom::svakom_suitcase::setup::SvakomSuitcaseIdentifierFactory::default(), 479 + ); 480 + add_to_protocol_map( 481 + &mut map, 482 + svakom::svakom_tarax::setup::SvakomTaraXIdentifierFactory::default(), 483 + ); 484 484 add_to_protocol_map( 485 485 &mut map, 486 486 svakom::svakom_v1::setup::SvakomV1IdentifierFactory::default(),
+4 -4
crates/buttplug_server/src/device/protocol_impl/svakom/mod.rs
··· 1 1 pub mod svakom_alex; 2 2 pub mod svakom_alex_v2; 3 - //pub mod svakom_avaneo; 3 + pub mod svakom_avaneo; 4 4 pub mod svakom_barnard; 5 5 pub mod svakom_barney; 6 6 pub mod svakom_dice; 7 - //pub mod svakom_dt250a; 7 + pub mod svakom_dt250a; 8 8 pub mod svakom_iker; 9 9 pub mod svakom_jordan; 10 10 pub mod svakom_pulse; 11 11 pub mod svakom_sam; 12 12 pub mod svakom_sam2; 13 - //pub mod svakom_suitcase; 14 - //pub mod svakom_tarax; 13 + pub mod svakom_suitcase; 14 + pub mod svakom_tarax; 15 15 pub mod svakom_v1; 16 16 pub mod svakom_v2; 17 17 pub mod svakom_v3;
+45 -105
crates/buttplug_server/src/device/protocol_impl/svakom/svakom_avaneo.rs
··· 5 5 // Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6 6 // for full license information. 7 7 8 - use crate::{ 9 - core::{ 10 - errors::ButtplugDeviceError, 11 - , 12 - }, 8 + use buttplug_core::errors::ButtplugDeviceError; 9 + use buttplug_server_device_config::Endpoint; 10 + use uuid::Uuid; 11 + 13 12 use crate::device::{ 14 - configuration::{ProtocolCommunicationSpecifier, UserDeviceDefinition, UserDeviceIdentifier}, 15 - hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 16 - protocol::{ 17 - generic_protocol_initializer_setup, 18 - ProtocolHandler, 19 - ProtocolIdentifier, 20 - ProtocolInitializer, 21 - }, 22 - }, 23 - util::{async_manager, sleep}, 13 + hardware::{HardwareCommand, HardwareWriteCmd}, 14 + protocol::{generic_protocol_setup, ProtocolHandler}, 24 15 }; 25 - use async_trait::async_trait; 26 - use std::{sync::Arc, time::Duration}; 27 16 28 - generic_protocol_initializer_setup!(SvakomAvaNeo, "svakom-avaneo"); 17 + 18 + generic_protocol_setup!(SvakomAvaNeo, "svakom-avaneo"); 29 19 30 20 #[derive(Default)] 31 - pub struct SvakomAvaNeoInitializer {} 21 + pub struct SvakomAvaNeo {} 32 22 33 - #[async_trait] 34 - impl ProtocolInitializer for SvakomAvaNeoInitializer { 35 - async fn initialize( 36 - &mut self, 37 - hardware: Arc<Hardware>, 38 - _: &UserDeviceDefinition, 39 - ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 40 - Ok(Arc::new(SvakomAvaNeo::new(hardware))) 41 - } 42 - } 43 - 44 - async fn delayed_update_handler(device: Arc<Hardware>, mode: u8, scalar: u8) { 45 - sleep(Duration::from_millis(35)).await; 46 - let res = device 47 - .write_value(&HardwareWriteCmd::new( 23 + impl SvakomAvaNeo { 24 + fn form_hardware_command( 25 + &self, 26 + feature_id: Uuid, 27 + speed: u32, 28 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 29 + Ok(vec![HardwareWriteCmd::new( 30 + &[feature_id], 48 31 Endpoint::Tx, 49 - [0x55, mode, 0x00, 0x00, scalar, 0xff].to_vec(), 32 + [ 33 + 0x55, 34 + 0x03, 35 + 0x00, 36 + 0x00, 37 + if speed == 0 { 0x00 } else { 0x01 }, 38 + speed as u8, 39 + ] 40 + .to_vec(), 50 41 false, 51 - )) 52 - .await; 53 - if res.is_err() { 54 - error!("Delayed Svakom Tara X command error: {:?}", res.err()); 55 - } 56 - } 57 - 58 - pub struct SvakomAvaNeo { 59 - device: Arc<Hardware>, 60 - } 61 - impl SvakomAvaNeo { 62 - fn new(device: Arc<Hardware>) -> Self { 63 - Self { device } 42 + ) 43 + .into()]) 64 44 } 65 45 } 66 46 67 47 impl ProtocolHandler for SvakomAvaNeo { 68 - fn handle_value_cmd( 48 + // Note: This protocol used to have a mode byte that was set in cases where multiple commands were 49 + // sent at the same time. This has been removed in the v10 line, but may cause issues. If we get 50 + // bug reports on that, we may need to revisit this implementation. 51 + 52 + fn handle_output_vibrate_cmd( 69 53 &self, 70 - cmds: &[Option<(ActuatorType, i32)>], 54 + _feature_index: u32, 55 + feature_id: uuid::Uuid, 56 + speed: u32, 71 57 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 72 - if cmds.is_empty() { 73 - return Ok(vec![]); 74 - } 58 + self.form_hardware_command(feature_id, speed) 59 + } 75 60 76 - let mut hcmd = None; 77 - if let Some(cmd) = cmds[0] { 78 - let scalar = cmd.1; 79 - hcmd = Some(HardwareWriteCmd::new( 80 - Endpoint::Tx, 81 - [ 82 - 0x55, 83 - 0x03, 84 - 0x00, 85 - 0x00, 86 - if scalar == 0 { 0x00 } else { 0x01 }, 87 - scalar as u8, 88 - ] 89 - .to_vec(), 90 - false, 91 - )); 92 - } 93 - 94 - if cmds.len() < 2 { 95 - return if hcmd.is_some() { 96 - Ok(vec![hcmd.unwrap().into()]) 97 - } else { 98 - Ok(vec![]) 99 - }; 100 - } 101 - 102 - if let Some(cmd) = cmds[1] { 103 - let scalar = cmd.1; 104 - let mode = if cmd.0 == ActuatorType::Vibrate { 105 - 0x09 106 - } else { 107 - 0x08 108 - }; 109 - if hcmd.is_none() { 110 - return Ok(vec![HardwareWriteCmd::new( 111 - Endpoint::Tx, 112 - [0x55, mode, 0x00, 0x00, scalar as u8, 0xff].to_vec(), 113 - false, 114 - ) 115 - .into()]); 116 - } else { 117 - // Sending both commands in quick succession blots the earlier command 118 - let dev = self.device.clone(); 119 - async_manager::spawn(async move { delayed_update_handler(dev, mode, scalar as u8).await }); 120 - } 121 - } 122 - 123 - if hcmd.is_some() { 124 - Ok(vec![hcmd.unwrap().into()]) 125 - } else { 126 - Ok(vec![]) 127 - } 61 + fn handle_output_oscillate_cmd( 62 + &self, 63 + _feature_index: u32, 64 + feature_id: uuid::Uuid, 65 + speed: u32, 66 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 67 + self.form_hardware_command(feature_id, speed) 128 68 } 129 69 }
+45 -126
crates/buttplug_server/src/device/protocol_impl/svakom/svakom_dt250a.rs
··· 5 5 // Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6 6 // for full license information. 7 7 8 - use crate::{ 9 - core::{ 10 - errors::ButtplugDeviceError, 11 - , 12 - }, 8 + use buttplug_core::errors::ButtplugDeviceError; 9 + use buttplug_server_device_config::Endpoint; 10 + use uuid::Uuid; 11 + 13 12 use crate::device::{ 14 - configuration::{ProtocolCommunicationSpecifier, UserDeviceDefinition, UserDeviceIdentifier}, 15 - hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 16 - protocol::{ 17 - generic_protocol_initializer_setup, 18 - ProtocolHandler, 19 - ProtocolIdentifier, 20 - ProtocolInitializer, 21 - }, 22 - }, 23 - util::{async_manager, sleep}, 13 + hardware::{HardwareCommand, HardwareWriteCmd}, 14 + protocol::{generic_protocol_setup, ProtocolHandler}, 24 15 }; 25 - use async_trait::async_trait; 26 - use std::{sync::Arc, time::Duration}; 27 16 28 - generic_protocol_initializer_setup!(SvakomDT250A, "svakom-dt250a"); 29 17 30 - #[derive(Default)] 31 - pub struct SvakomDT250AInitializer {} 18 + generic_protocol_setup!(SvakomDT250A, "svakom-dt250a"); 32 19 33 - #[async_trait] 34 - impl ProtocolInitializer for SvakomDT250AInitializer { 35 - async fn initialize( 36 - &mut self, 37 - hardware: Arc<Hardware>, 38 - _: &UserDeviceDefinition, 39 - ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 40 - Ok(Arc::new(SvakomDT250A::new(hardware))) 41 - } 42 - } 43 - 44 - async fn delayed_update_handler(device: Arc<Hardware>, cmd: Vec<u8>, delay: u64) { 45 - sleep(Duration::from_millis(delay)).await; 46 - let res = device 47 - .write_value(&HardwareWriteCmd::new(Endpoint::Tx, cmd, false)) 48 - .await; 49 - if res.is_err() { 50 - error!("Delayed Svakom DT250A command error: {:?}", res.err()); 51 - } 52 - } 20 + #[derive(Default)] 21 + pub struct SvakomDT250A {} 53 22 54 - pub struct SvakomDT250A { 55 - device: Arc<Hardware>, 56 - } 57 23 impl SvakomDT250A { 58 - fn new(device: Arc<Hardware>) -> Self { 59 - Self { device } 60 - } 61 - } 24 + // Note: This protocol used to have a mode byte that was set in cases where multiple commands were 25 + // sent at the same time. This has been removed in the v10 line, but may cause issues. If we get 26 + // bug reports on that, we may need to revisit this implementation. 62 27 63 - impl ProtocolHandler for SvakomDT250A { 64 - fn handle_value_cmd( 28 + fn form_hardware_command( 65 29 &self, 66 - cmds: &[Option<(ActuatorType, i32)>], 30 + mode: u8, 31 + feature_id: Uuid, 32 + speed: u32, 67 33 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 68 - if cmds.is_empty() { 69 - return Ok(vec![]); 70 - } 71 - 72 - let mut delay = 30; 73 - let mut hcmd = None; 74 - if let Some(cmd) = cmds[0] { 75 - let scalar = cmd.1; 76 - 77 - hcmd = Some(HardwareWriteCmd::new( 78 - Endpoint::Tx, 79 - [ 80 - 0x55, 81 - 0x03, 82 - 0x00, 83 - 0x00, 84 - scalar as u8, 85 - if scalar == 0 { 0x00 } else { 0x01 }, 86 - ] 87 - .to_vec(), 88 - false, 89 - )); 90 - } 91 - 92 - if cmds.len() < 2 { 93 - return if hcmd.is_some() { 94 - Ok(vec![hcmd.unwrap().into()]) 95 - } else { 96 - Ok(vec![]) 97 - }; 98 - } 99 - 100 - if let Some(cmd) = cmds[1] { 101 - let scalar = cmd.1; 102 - let data = [ 34 + Ok(vec![HardwareWriteCmd::new( 35 + &[feature_id], 36 + Endpoint::Tx, 37 + [ 103 38 0x55, 104 - 0x08, 39 + mode, 105 40 0x00, 106 41 0x00, 107 - scalar as u8, 108 - if scalar == 0 { 0x00 } else { 0x01 }, 42 + if speed == 0 { 0x00 } else { 0x01 }, 43 + speed as u8, 109 44 ] 110 - .to_vec(); 45 + .to_vec(), 46 + false, 47 + ) 48 + .into()]) 49 + } 50 + } 111 51 112 - if hcmd.is_none() { 113 - return Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()]); 114 - } else { 115 - // Sending both commands in quick succession blots the earlier command 116 - let dev = self.device.clone(); 117 - async_manager::spawn(async move { delayed_update_handler(dev, data, delay).await }); 118 - 119 - // This is the minimum time between the 2nd and 3rd command that doesn't seem to just get dropped... 120 - delay += 250; 121 - } 122 - } 123 - 124 - if cmds.len() < 3 { 125 - return if hcmd.is_some() { 126 - Ok(vec![hcmd.unwrap().into()]) 127 - } else { 128 - Ok(vec![]) 129 - }; 130 - } 131 - 132 - if let Some(cmd) = cmds[2] { 133 - let scalar = cmd.1; 134 - let data = [0x55, 0x09, 0x00, 0x00, scalar as u8, 0x00].to_vec(); 52 + impl ProtocolHandler for SvakomDT250A { 53 + fn handle_output_vibrate_cmd( 54 + &self, 55 + _feature_index: u32, 56 + feature_id: uuid::Uuid, 57 + speed: u32, 58 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 59 + self.form_hardware_command(0x03, feature_id, speed) 60 + } 135 61 136 - if hcmd.is_none() { 137 - return Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, false).into()]); 138 - } else { 139 - // Sending both commands in quick succession blots the earlier command 140 - let dev = self.device.clone(); 141 - async_manager::spawn(async move { delayed_update_handler(dev, data, delay).await }); 142 - } 143 - } 144 - 145 - if hcmd.is_some() { 146 - Ok(vec![hcmd.unwrap().into()]) 147 - } else { 148 - Ok(vec![]) 149 - } 62 + fn handle_output_constrict_cmd( 63 + &self, 64 + _feature_index: u32, 65 + feature_id: uuid::Uuid, 66 + level: u32, 67 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 68 + self.form_hardware_command(0x08, feature_id, level) 150 69 } 151 70 }
+34 -111
crates/buttplug_server/src/device/protocol_impl/svakom/svakom_suitcase.rs
··· 5 5 // Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6 6 // for full license information. 7 7 8 - use crate::{ 9 - core::{ 10 - errors::ButtplugDeviceError, 11 - message::{ActuatorType, Endpoint}, 12 - }, 8 + use buttplug_core::errors::ButtplugDeviceError; 9 + use buttplug_server_device_config::Endpoint; 10 + use uuid::Uuid; 11 + 13 12 use crate::device::{ 14 - configuration::{ProtocolCommunicationSpecifier, UserDeviceDefinition, UserDeviceIdentifier}, 15 - hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 16 - protocol::{ 17 - generic_protocol_initializer_setup, 18 - ProtocolHandler, 19 - ProtocolIdentifier, 20 - ProtocolInitializer, 21 - }, 22 - }, 23 - util::{async_manager, sleep}, 13 + hardware::{HardwareCommand, HardwareWriteCmd}, 14 + protocol::{generic_protocol_setup, ProtocolHandler}, 24 15 }; 25 - use async_trait::async_trait; 26 - use std::{sync::Arc, time::Duration}; 16 + 27 17 28 - generic_protocol_initializer_setup!(SvakomSuitcase, "svakom-suitcase"); 18 + generic_protocol_setup!(SvakomSuitcase, "svakom-suitcase"); 29 19 30 20 #[derive(Default)] 31 - pub struct SvakomSuitcaseInitializer {} 32 - 33 - #[async_trait] 34 - impl ProtocolInitializer for SvakomSuitcaseInitializer { 35 - async fn initialize( 36 - &mut self, 37 - hardware: Arc<Hardware>, 38 - _: &UserDeviceDefinition, 39 - ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 40 - Ok(Arc::new(SvakomSuitcase::new(hardware))) 41 - } 42 - } 43 - 44 - async fn delayed_update_handler(device: Arc<Hardware>, scalar: u8) { 45 - sleep(Duration::from_millis(50)).await; 46 - let res = device 47 - .write_value(&HardwareWriteCmd::new( 48 - Endpoint::Tx, 49 - [0x55, 0x09, 0x00, 0x00, scalar, 0x00].to_vec(), 50 - false, 51 - )) 52 - .await; 53 - if res.is_err() { 54 - error!("Delayed Svakom Suitcase command error: {:?}", res.err()); 55 - } 56 - } 57 - 58 - pub struct SvakomSuitcase { 59 - device: Arc<Hardware>, 60 - } 61 - impl SvakomSuitcase { 62 - fn new(device: Arc<Hardware>) -> Self { 63 - Self { device } 64 - } 65 - } 21 + pub struct SvakomSuitcase {} 66 22 67 23 impl ProtocolHandler for SvakomSuitcase { 68 - fn handle_value_cmd( 69 - &self, 70 - cmds: &[Option<(ActuatorType, i32)>], 71 - ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 72 - if cmds.is_empty() { 73 - return Ok(vec![]); 74 - } 75 - 76 - let mut hcmd = None; 77 - if let Some(cmd) = cmds[0] { 78 - let scalar = cmd.1; 79 - let mut speed = (scalar % 10) as u8; 80 - let mut intensity = if scalar == 0 { 81 - 0u8 82 - } else { 83 - (scalar as f32 / 10.0).floor() as u8 + 1 84 - }; 85 - if speed == 0 && intensity != 0 { 86 - // 10 -> 2,0 -> 1,A 87 - speed = 10; 88 - intensity -= 1; 89 - } 90 - 91 - hcmd = Some(HardwareWriteCmd::new( 92 - Endpoint::Tx, 93 - [0x55, 0x03, 0x00, 0x00, intensity, speed].to_vec(), 94 - false, 95 - )); 96 - } 97 - 98 - if cmds.len() < 2 { 99 - return if hcmd.is_some() { 100 - Ok(vec![hcmd.unwrap().into()]) 101 - } else { 102 - Ok(vec![]) 103 - }; 104 - } 105 - 106 - if let Some(cmd) = cmds[1] { 107 - let scalar = cmd.1; 108 - 109 - if hcmd.is_none() { 110 - return Ok(vec![HardwareWriteCmd::new( 111 - Endpoint::Tx, 112 - [0x55, 0x09, 0x00, 0x00, scalar as u8, 0x00].to_vec(), 113 - false, 114 - ) 115 - .into()]); 116 - } else { 117 - // Sending both commands in quick succession blots the earlier command 118 - let dev = self.device.clone(); 119 - async_manager::spawn(async move { delayed_update_handler(dev, scalar as u8).await }); 120 - } 121 - } 122 - 123 - if hcmd.is_some() { 124 - Ok(vec![hcmd.unwrap().into()]) 24 + // I am like 90% sure this is wrong since this device has two vibrators, but the original 25 + // implementation made no sense in terms of knowing which command addressed which index. Putting 26 + // in a best effort here and we'll see if anyone complains. 27 + fn handle_output_vibrate_cmd( 28 + &self, 29 + _feature_index: u32, 30 + feature_id: Uuid, 31 + speed: u32, 32 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 33 + let scalar = speed; 34 + let mut speed = (scalar % 10) as u8; 35 + let mut intensity = if scalar == 0 { 36 + 0u8 125 37 } else { 126 - Ok(vec![]) 38 + (scalar as f32 / 10.0).floor() as u8 + 1 39 + }; 40 + if speed == 0 && intensity != 0 { 41 + // 10 -> 2,0 -> 1,A 42 + speed = 10; 43 + intensity -= 1; 127 44 } 45 + Ok(vec![HardwareWriteCmd::new( 46 + &[feature_id], 47 + Endpoint::Tx, 48 + [0x55, 0x03, 0x00, 0x00, intensity, speed].to_vec(), 49 + false, 50 + ).into()]) 128 51 } 129 52 }
+22 -101
crates/buttplug_server/src/device/protocol_impl/svakom/svakom_tarax.rs
··· 5 5 // Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6 6 // for full license information. 7 7 8 - use crate::device::configuration::ProtocolCommunicationSpecifier; 9 - use crate::{ 10 - core::{ 11 - errors::ButtplugDeviceError, 12 - message::{ActuatorType, Endpoint}, 13 - }, 8 + use buttplug_core::errors::ButtplugDeviceError; 9 + use buttplug_server_device_config::Endpoint; 10 + use uuid::Uuid; 11 + 14 12 use crate::device::{ 15 - configuration::{UserDeviceDefinition, UserDeviceIdentifier}, 16 - hardware::{Hardware, HardwareCommand, HardwareWriteCmd}, 17 - protocol::{ 18 - generic_protocol_initializer_setup, 19 - ProtocolHandler, 20 - ProtocolIdentifier, 21 - ProtocolInitializer, 22 - }, 23 - }, 24 - util::{async_manager, sleep}, 13 + hardware::{HardwareCommand, HardwareWriteCmd}, 14 + protocol::{generic_protocol_setup, ProtocolHandler}, 25 15 }; 26 - use async_trait::async_trait; 27 - use std::{sync::Arc, time::Duration}; 28 16 29 - generic_protocol_initializer_setup!(SvakomTaraX, "svakom-tarax"); 17 + generic_protocol_setup!(SvakomTaraX, "svakom-tarax"); 30 18 31 19 #[derive(Default)] 32 - pub struct SvakomTaraXInitializer {} 33 - 34 - #[async_trait] 35 - impl ProtocolInitializer for SvakomTaraXInitializer { 36 - async fn initialize( 37 - &mut self, 38 - hardware: Arc<Hardware>, 39 - _: &UserDeviceDefinition, 40 - ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 41 - Ok(Arc::new(SvakomTaraX::new(hardware))) 42 - } 43 - } 44 - 45 - async fn delayed_update_handler(device: Arc<Hardware>, scalar: u8) { 46 - sleep(Duration::from_millis(25)).await; 47 - let res = device 48 - .write_value(&HardwareWriteCmd::new( 49 - Endpoint::Tx, 50 - [0x55, 0x09, 0x00, 0x00, scalar, 0x00].to_vec(), 51 - false, 52 - )) 53 - .await; 54 - if res.is_err() { 55 - error!("Delayed Svakom Tara X command error: {:?}", res.err()); 56 - } 57 - } 58 - 59 - pub struct SvakomTaraX { 60 - device: Arc<Hardware>, 61 - } 62 - impl SvakomTaraX { 63 - fn new(device: Arc<Hardware>) -> Self { 64 - Self { device } 65 - } 66 - } 20 + pub struct SvakomTaraX {} 67 21 68 22 impl ProtocolHandler for SvakomTaraX { 69 - fn handle_value_cmd( 70 - &self, 71 - cmds: &[Option<(ActuatorType, i32)>], 72 - ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 73 - if cmds.is_empty() { 74 - return Ok(vec![]); 75 - } 76 - 77 - let mut hcmd = None; 78 - if let Some(cmd) = cmds[0] { 79 - let scalar = cmd.1; 80 - hcmd = Some(HardwareWriteCmd::new( 23 + // I am like 90% sure this is wrong since this device has two vibrators, but the original 24 + // implementation made no sense in terms of knowing which command addressed which index. Putting 25 + // in a best effort here and we'll see if anyone complains. 26 + fn handle_output_vibrate_cmd( 27 + &self, 28 + _feature_index: u32, 29 + feature_id: Uuid, 30 + speed: u32, 31 + ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 32 + Ok(vec!(HardwareWriteCmd::new( 33 + &[feature_id], 81 34 Endpoint::Tx, 82 35 [ 83 36 0x55, 84 37 0x03, 85 38 0x00, 86 39 0x00, 87 - if scalar == 0 { 0x01 } else { scalar as u8 }, 88 - if scalar == 0 { 0x01 } else { 0x02 }, 40 + if speed == 0 { 0x01 } else { speed as u8 }, 41 + if speed == 0 { 0x01 } else { 0x02 }, 89 42 ] 90 43 .to_vec(), 91 44 false, 92 - )); 93 - } 94 - 95 - if cmds.len() < 2 { 96 - return if hcmd.is_some() { 97 - Ok(vec![hcmd.unwrap().into()]) 98 - } else { 99 - Ok(vec![]) 100 - }; 101 - } 102 - 103 - if let Some(cmd) = cmds[1] { 104 - let scalar = cmd.1; 105 - 106 - if hcmd.is_none() { 107 - return Ok(vec![HardwareWriteCmd::new( 108 - Endpoint::Tx, 109 - [0x55, 0x09, 0x00, 0x00, scalar as u8, 0x00].to_vec(), 110 - false, 111 - ) 112 - .into()]); 113 - } else { 114 - // Sending both commands in quick succession blots the earlier command 115 - let dev = self.device.clone(); 116 - async_manager::spawn(async move { delayed_update_handler(dev, scalar as u8).await }); 117 - } 118 - } 119 - 120 - if hcmd.is_some() { 121 - Ok(vec![hcmd.unwrap().into()]) 122 - } else { 123 - Ok(vec![]) 124 - } 45 + ).into())) 125 46 } 126 47 }