Buttplug sex toy control library

chore: Start removing RotateWithDirection

+154 -208
+51
buttplug-user-device-config-v4.json
···
··· 1 + { 2 + "version": { 3 + "major": 4, 4 + "minor": 0 5 + }, 6 + "user_configs": { 7 + "protocols": {}, 8 + "devices": [ 9 + { 10 + "identifier": { 11 + "protocol": "lovense", 12 + "identifier": "EL", 13 + "address": "PeripheralId(81b8f016-ba95-e1ae-3a71-a2e6b1d83b21)" 14 + }, 15 + "config": { 16 + "id": "5d434198-4697-4b00-985e-33788fc955d1", 17 + "base_id": "bbfd764c-b419-4c13-aeb0-e753a86318ed", 18 + "features": [ 19 + { 20 + "id": "16099312-8bf8-45f7-9a37-9c56ffd972ae", 21 + "base_id": "0627be5e-8553-4f20-b4cf-15f5e1896e5f", 22 + "output": { 23 + "vibrate": { 24 + "disabled": false 25 + } 26 + } 27 + }, 28 + { 29 + "id": "c82ea967-3014-49ef-8189-e7e065c4bdbf", 30 + "base_id": "360d81e7-5126-4dbb-b72d-7bb60eb67400", 31 + "output": { 32 + "rotate": { 33 + "disabled": false 34 + } 35 + } 36 + }, 37 + { 38 + "id": "3ad9adee-8c32-408f-8e8c-4a275bb9421c", 39 + "base_id": "50b9b31f-c2a8-459a-81fd-c54604f5184e" 40 + } 41 + ], 42 + "user_config": { 43 + "allow": false, 44 + "deny": false, 45 + "index": 0 46 + } 47 + } 48 + } 49 + ] 50 + } 51 + }
+1 -7
crates/buttplug_client/src/device/command.rs
··· 29 Led(u32), 30 Spray(u32), 31 Position(u32), 32 - RotateWithDirection(u32, bool), 33 PositionWithDuration(u32, u32), 34 // f64 types are old style float, will need to convert before sending 35 VibrateFloat(f64), ··· 40 LedFloat(f64), 41 SprayFloat(f64), 42 PositionFloat(f64), 43 - RotateWithDirectionFloat(f64, bool), 44 PositionWithDurationFloat(f64, u32), 45 } 46 ··· 55 OutputType::Led => Ok(ClientDeviceOutputCommand::LedFloat(value)), 56 OutputType::Spray => Ok(ClientDeviceOutputCommand::SprayFloat(value)), 57 OutputType::Position => Ok(ClientDeviceOutputCommand::PositionFloat(value)), 58 - _ => Err(ButtplugClientError::ButtplugOutputCommandConversionError("Cannot use PositionWithDuration or RotateWithDirection with this method".to_owned())) 59 } 60 } 61 } ··· 78 ClientDeviceOutputCommand::PositionWithDuration(_, _) 79 | ClientDeviceOutputCommand::PositionWithDurationFloat(_, _) => { 80 OutputType::PositionWithDuration 81 - } 82 - ClientDeviceOutputCommand::RotateWithDirection(_, _) 83 - | ClientDeviceOutputCommand::RotateWithDirectionFloat(_, _) => { 84 - OutputType::RotateWithDirection 85 } 86 } 87 }
··· 29 Led(u32), 30 Spray(u32), 31 Position(u32), 32 PositionWithDuration(u32, u32), 33 // f64 types are old style float, will need to convert before sending 34 VibrateFloat(f64), ··· 39 LedFloat(f64), 40 SprayFloat(f64), 41 PositionFloat(f64), 42 PositionWithDurationFloat(f64, u32), 43 } 44 ··· 53 OutputType::Led => Ok(ClientDeviceOutputCommand::LedFloat(value)), 54 OutputType::Spray => Ok(ClientDeviceOutputCommand::SprayFloat(value)), 55 OutputType::Position => Ok(ClientDeviceOutputCommand::PositionFloat(value)), 56 + _ => Err(ButtplugClientError::ButtplugOutputCommandConversionError("Cannot use PositionWithDuration with this method".to_owned())) 57 } 58 } 59 } ··· 76 ClientDeviceOutputCommand::PositionWithDuration(_, _) 77 | ClientDeviceOutputCommand::PositionWithDurationFloat(_, _) => { 78 OutputType::PositionWithDuration 79 } 80 } 81 }
+15 -41
crates/buttplug_client/src/device/feature.rs
··· 15 OutputCmdV4, 16 OutputCommand, 17 OutputPositionWithDuration, 18 - OutputRotateWithDirection, 19 OutputType, 20 OutputValue, 21 }, ··· 64 fn check_step_value( 65 &self, 66 feature_output: &dyn DeviceFeatureOutputLimits, 67 - steps: u32, 68 - ) -> Result<u32, ButtplugClientError> { 69 - if feature_output.step_limit().contains(&(steps as i32)) { 70 Ok(steps) 71 } else { 72 Err(ButtplugClientError::ButtplugOutputCommandConversionError( ··· 83 &self, 84 feature_output: &dyn DeviceFeatureOutputLimits, 85 float_amt: f64, 86 - ) -> Result<u32, ButtplugClientError> { 87 if !(0.0f64..=1.0f64).contains(&float_amt) { 88 Err(ButtplugClientError::ButtplugOutputCommandConversionError( 89 "Float values must be between 0.0 and 1.0".to_owned(), 90 )) 91 } else { 92 - Ok((float_amt * feature_output.step_count() as f64).ceil() as u32) 93 } 94 } 95 ··· 144 } 145 ClientDeviceOutputCommand::PositionWithDurationFloat(v, d) => { 146 OutputCommand::PositionWithDuration(OutputPositionWithDuration::new( 147 - self.convert_float_value(output, *v)?, 148 - *d, 149 - )) 150 - } 151 - ClientDeviceOutputCommand::RotateWithDirectionFloat(v, d) => { 152 - OutputCommand::RotateWithDirection(OutputRotateWithDirection::new( 153 - self.convert_float_value(output, *v)?, 154 *d, 155 )) 156 } 157 ClientDeviceOutputCommand::Vibrate(v) => { 158 - OutputCommand::Vibrate(OutputValue::new(self.check_step_value(output, *v)?)) 159 } 160 ClientDeviceOutputCommand::Oscillate(v) => { 161 - OutputCommand::Oscillate(OutputValue::new(self.check_step_value(output, *v)?)) 162 } 163 ClientDeviceOutputCommand::Rotate(v) => { 164 - OutputCommand::Rotate(OutputValue::new(self.check_step_value(output, *v)?)) 165 } 166 ClientDeviceOutputCommand::Constrict(v) => { 167 - OutputCommand::Constrict(OutputValue::new(self.check_step_value(output, *v)?)) 168 } 169 ClientDeviceOutputCommand::Heater(v) => { 170 - OutputCommand::Heater(OutputValue::new(self.check_step_value(output, *v)?)) 171 } 172 ClientDeviceOutputCommand::Led(v) => { 173 - OutputCommand::Led(OutputValue::new(self.check_step_value(output, *v)?)) 174 } 175 ClientDeviceOutputCommand::Spray(v) => { 176 - OutputCommand::Spray(OutputValue::new(self.check_step_value(output, *v)?)) 177 } 178 ClientDeviceOutputCommand::Position(v) => { 179 - OutputCommand::Position(OutputValue::new(self.check_step_value(output, *v)?)) 180 } 181 ClientDeviceOutputCommand::PositionWithDuration(v, d) => OutputCommand::PositionWithDuration( 182 - OutputPositionWithDuration::new(self.check_step_value(output, *v)?, *d), 183 - ), 184 - ClientDeviceOutputCommand::RotateWithDirection(v, d) => OutputCommand::RotateWithDirection( 185 - OutputRotateWithDirection::new(self.check_step_value(output, *v)?, *d), 186 ), 187 }; 188 Ok(OutputCmdV4::new( ··· 268 } 269 ClientDeviceCommandValue::Float(f) => { 270 ClientDeviceOutputCommand::PositionWithDurationFloat(f, duration_in_ms) 271 - } 272 - }) 273 - } 274 - 275 - pub fn rotate_with_direction( 276 - &self, 277 - level: impl Into<ClientDeviceCommandValue>, 278 - clockwise: bool, 279 - ) -> ButtplugClientResultFuture { 280 - let val = level.into(); 281 - self.send_command(&match val { 282 - ClientDeviceCommandValue::Int(v) => { 283 - ClientDeviceOutputCommand::RotateWithDirection(v, clockwise) 284 - } 285 - ClientDeviceCommandValue::Float(f) => { 286 - ClientDeviceOutputCommand::RotateWithDirectionFloat(f, clockwise) 287 } 288 }) 289 }
··· 15 OutputCmdV4, 16 OutputCommand, 17 OutputPositionWithDuration, 18 OutputType, 19 OutputValue, 20 }, ··· 63 fn check_step_value( 64 &self, 65 feature_output: &dyn DeviceFeatureOutputLimits, 66 + steps: i32, 67 + ) -> Result<i32, ButtplugClientError> { 68 + if feature_output.step_limit().contains(&(steps)) { 69 Ok(steps) 70 } else { 71 Err(ButtplugClientError::ButtplugOutputCommandConversionError( ··· 82 &self, 83 feature_output: &dyn DeviceFeatureOutputLimits, 84 float_amt: f64, 85 + ) -> Result<i32, ButtplugClientError> { 86 if !(0.0f64..=1.0f64).contains(&float_amt) { 87 Err(ButtplugClientError::ButtplugOutputCommandConversionError( 88 "Float values must be between 0.0 and 1.0".to_owned(), 89 )) 90 } else { 91 + Ok((float_amt * feature_output.step_count() as f64).ceil() as i32) 92 } 93 } 94 ··· 143 } 144 ClientDeviceOutputCommand::PositionWithDurationFloat(v, d) => { 145 OutputCommand::PositionWithDuration(OutputPositionWithDuration::new( 146 + self.convert_float_value(output, *v)? as u32, 147 *d, 148 )) 149 } 150 ClientDeviceOutputCommand::Vibrate(v) => { 151 + OutputCommand::Vibrate(OutputValue::new(self.check_step_value(output, *v as i32)?)) 152 } 153 ClientDeviceOutputCommand::Oscillate(v) => { 154 + OutputCommand::Oscillate(OutputValue::new(self.check_step_value(output, *v as i32)?)) 155 } 156 ClientDeviceOutputCommand::Rotate(v) => { 157 + OutputCommand::Rotate(OutputValue::new(self.check_step_value(output, *v as i32)?)) 158 } 159 ClientDeviceOutputCommand::Constrict(v) => { 160 + OutputCommand::Constrict(OutputValue::new(self.check_step_value(output, *v as i32)?)) 161 } 162 ClientDeviceOutputCommand::Heater(v) => { 163 + OutputCommand::Heater(OutputValue::new(self.check_step_value(output, *v as i32)?)) 164 } 165 ClientDeviceOutputCommand::Led(v) => { 166 + OutputCommand::Led(OutputValue::new(self.check_step_value(output, *v as i32)?)) 167 } 168 ClientDeviceOutputCommand::Spray(v) => { 169 + OutputCommand::Spray(OutputValue::new(self.check_step_value(output, *v as i32)?)) 170 } 171 ClientDeviceOutputCommand::Position(v) => { 172 + OutputCommand::Position(OutputValue::new(self.check_step_value(output, *v as i32)?)) 173 } 174 ClientDeviceOutputCommand::PositionWithDuration(v, d) => OutputCommand::PositionWithDuration( 175 + OutputPositionWithDuration::new(self.check_step_value(output, *v as i32)? as u32, *d), 176 ), 177 }; 178 Ok(OutputCmdV4::new( ··· 258 } 259 ClientDeviceCommandValue::Float(f) => { 260 ClientDeviceOutputCommand::PositionWithDurationFloat(f, duration_in_ms) 261 } 262 }) 263 }
+2
crates/buttplug_core/src/errors.rs
··· 157 DeviceScanningAlreadyStopped, 158 /// Device permission error: {0} 159 DevicePermissionError(String), 160 /// {0} 161 ProtocolAttributesNotFound(String), 162 /// Protocol {0} not implemented in library
··· 157 DeviceScanningAlreadyStopped, 158 /// Device permission error: {0} 159 DevicePermissionError(String), 160 + /// Device command does not take negative numbers 161 + DeviceCommandSignError, 162 /// {0} 163 ProtocolAttributesNotFound(String), 164 /// Protocol {0} not implemented in library
-11
crates/buttplug_core/src/message/device_feature.rs
··· 16 Unknown, 17 #[serde(alias = "vibrate")] 18 Vibrate, 19 - // Single Direction Rotation Speed 20 #[serde(alias = "rotate")] 21 Rotate, 22 - // Two Direction Rotation Speed 23 - #[serde(alias = "rotate_with_direction")] 24 - RotateWithDirection, 25 #[serde(alias = "oscillate")] 26 Oscillate, 27 #[serde(alias = "constrict")] ··· 196 #[serde(skip_serializing_if = "Option::is_none")] 197 rotate: Option<DeviceFeatureOutputValueProperties>, 198 #[serde(skip_serializing_if = "Option::is_none")] 199 - rotate_with_direction: Option<DeviceFeatureOutputValueProperties>, 200 - #[serde(skip_serializing_if = "Option::is_none")] 201 oscillate: Option<DeviceFeatureOutputValueProperties>, 202 #[serde(skip_serializing_if = "Option::is_none")] 203 constrict: Option<DeviceFeatureOutputValueProperties>, ··· 223 OutputType::Position => self.position.is_some(), 224 OutputType::PositionWithDuration => self.position_with_duration.is_some(), 225 OutputType::Rotate => self.rotate.is_some(), 226 - OutputType::RotateWithDirection => self.rotate_with_direction.is_some(), 227 OutputType::Spray => self.spray.is_some(), 228 OutputType::Unknown => false, 229 OutputType::Vibrate => self.vibrate.is_some(), ··· 258 .map(|x| x as &dyn DeviceFeatureOutputLimits), 259 OutputType::Rotate => self 260 .rotate() 261 - .as_ref() 262 - .map(|x| x as &dyn DeviceFeatureOutputLimits), 263 - OutputType::RotateWithDirection => self 264 - .rotate_with_direction() 265 .as_ref() 266 .map(|x| x as &dyn DeviceFeatureOutputLimits), 267 OutputType::Spray => self
··· 16 Unknown, 17 #[serde(alias = "vibrate")] 18 Vibrate, 19 #[serde(alias = "rotate")] 20 Rotate, 21 #[serde(alias = "oscillate")] 22 Oscillate, 23 #[serde(alias = "constrict")] ··· 192 #[serde(skip_serializing_if = "Option::is_none")] 193 rotate: Option<DeviceFeatureOutputValueProperties>, 194 #[serde(skip_serializing_if = "Option::is_none")] 195 oscillate: Option<DeviceFeatureOutputValueProperties>, 196 #[serde(skip_serializing_if = "Option::is_none")] 197 constrict: Option<DeviceFeatureOutputValueProperties>, ··· 217 OutputType::Position => self.position.is_some(), 218 OutputType::PositionWithDuration => self.position_with_duration.is_some(), 219 OutputType::Rotate => self.rotate.is_some(), 220 OutputType::Spray => self.spray.is_some(), 221 OutputType::Unknown => false, 222 OutputType::Vibrate => self.vibrate.is_some(), ··· 251 .map(|x| x as &dyn DeviceFeatureOutputLimits), 252 OutputType::Rotate => self 253 .rotate() 254 .as_ref() 255 .map(|x| x as &dyn DeviceFeatureOutputLimits), 256 OutputType::Spray => self
-1
crates/buttplug_core/src/message/v4/mod.rs
··· 23 OutputCmdV4, 24 OutputCommand, 25 OutputPositionWithDuration, 26 - OutputRotateWithDirection, 27 OutputValue, 28 }, 29 request_server_info::RequestServerInfoV4,
··· 23 OutputCmdV4, 24 OutputCommand, 25 OutputPositionWithDuration, 26 OutputValue, 27 }, 28 request_server_info::RequestServerInfoV4,
+7 -27
crates/buttplug_core/src/message/v4/output_cmd.rs
··· 23 #[getset(get_copy = "pub")] 24 pub struct OutputValue { 25 #[serde(rename = "Value")] 26 - value: u32, 27 } 28 29 impl OutputValue { 30 - pub fn new(value: u32) -> Self { 31 Self { value } 32 } 33 } ··· 47 } 48 } 49 50 - #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, CopyGetters)] 51 - #[getset(get_copy = "pub")] 52 - pub struct OutputRotateWithDirection { 53 - #[serde(rename = "Speed")] 54 - speed: u32, 55 - #[serde(rename = "Clockwise")] 56 - clockwise: bool, 57 - } 58 - 59 - impl OutputRotateWithDirection { 60 - pub fn new(speed: u32, clockwise: bool) -> Self { 61 - Self { speed, clockwise } 62 - } 63 - } 64 - 65 #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] 66 pub enum OutputCommand { 67 Vibrate(OutputValue), 68 // Single Direction Rotation Speed 69 Rotate(OutputValue), 70 - // Two Direction Rotation Speed 71 - RotateWithDirection(OutputRotateWithDirection), 72 Oscillate(OutputValue), 73 Constrict(OutputValue), 74 Spray(OutputValue), ··· 81 } 82 83 impl OutputCommand { 84 - pub fn value(&self) -> u32 { 85 match self { 86 OutputCommand::Constrict(x) 87 | OutputCommand::Spray(x) ··· 91 | OutputCommand::Position(x) 92 | OutputCommand::Rotate(x) 93 | OutputCommand::Vibrate(x) => x.value(), 94 - OutputCommand::RotateWithDirection(x) => x.speed(), 95 - OutputCommand::PositionWithDuration(x) => x.position(), 96 } 97 } 98 99 - pub fn set_value(&mut self, value: u32) { 100 match self { 101 OutputCommand::Constrict(x) 102 | OutputCommand::Spray(x) ··· 106 | OutputCommand::Position(x) 107 | OutputCommand::Rotate(x) 108 | OutputCommand::Vibrate(x) => x.value = value, 109 - OutputCommand::RotateWithDirection(x) => x.speed = value, 110 - OutputCommand::PositionWithDuration(x) => x.position = value, 111 } 112 } 113 ··· 115 match self { 116 Self::Vibrate(_) => OutputType::Vibrate, 117 Self::Rotate(_) => OutputType::Rotate, 118 - Self::RotateWithDirection(_) => OutputType::RotateWithDirection, 119 Self::Oscillate(_) => OutputType::Oscillate, 120 Self::Constrict(_) => OutputType::Constrict, 121 Self::Spray(_) => OutputType::Spray, ··· 126 } 127 } 128 129 - pub fn from_output_type(output_type: OutputType, value: u32) -> Result<Self, ButtplugError> { 130 match output_type { 131 OutputType::Constrict => Ok(Self::Constrict(OutputValue::new(value))), 132 OutputType::Heater => Ok(Self::Heater(OutputValue::new(value))),
··· 23 #[getset(get_copy = "pub")] 24 pub struct OutputValue { 25 #[serde(rename = "Value")] 26 + value: i32, 27 } 28 29 impl OutputValue { 30 + pub fn new(value: i32) -> Self { 31 Self { value } 32 } 33 } ··· 47 } 48 } 49 50 #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] 51 pub enum OutputCommand { 52 Vibrate(OutputValue), 53 // Single Direction Rotation Speed 54 Rotate(OutputValue), 55 Oscillate(OutputValue), 56 Constrict(OutputValue), 57 Spray(OutputValue), ··· 64 } 65 66 impl OutputCommand { 67 + pub fn value(&self) -> i32 { 68 match self { 69 OutputCommand::Constrict(x) 70 | OutputCommand::Spray(x) ··· 74 | OutputCommand::Position(x) 75 | OutputCommand::Rotate(x) 76 | OutputCommand::Vibrate(x) => x.value(), 77 + OutputCommand::PositionWithDuration(x) => x.position() as i32, 78 } 79 } 80 81 + pub fn set_value(&mut self, value: i32) { 82 match self { 83 OutputCommand::Constrict(x) 84 | OutputCommand::Spray(x) ··· 88 | OutputCommand::Position(x) 89 | OutputCommand::Rotate(x) 90 | OutputCommand::Vibrate(x) => x.value = value, 91 + OutputCommand::PositionWithDuration(x) => x.position = value as u32, 92 } 93 } 94 ··· 96 match self { 97 Self::Vibrate(_) => OutputType::Vibrate, 98 Self::Rotate(_) => OutputType::Rotate, 99 Self::Oscillate(_) => OutputType::Oscillate, 100 Self::Constrict(_) => OutputType::Constrict, 101 Self::Spray(_) => OutputType::Spray, ··· 106 } 107 } 108 109 + pub fn from_output_type(output_type: OutputType, value: i32) -> Result<Self, ButtplugError> { 110 match output_type { 111 OutputType::Constrict => Ok(Self::Constrict(OutputValue::new(value))), 112 OutputType::Heater => Ok(Self::Heater(OutputValue::new(value))),
+8 -14
crates/buttplug_server/src/device/protocol.rs
··· 227 let output_command = cmd.output_command(); 228 match output_command { 229 OutputCommand::Constrict(x) => { 230 - self.handle_output_constrict_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 231 } 232 OutputCommand::Spray(x) => { 233 - self.handle_output_spray_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 234 } 235 OutputCommand::Oscillate(x) => { 236 - self.handle_output_oscillate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 237 } 238 OutputCommand::Rotate(x) => { 239 self.handle_output_rotate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 240 } 241 OutputCommand::Vibrate(x) => { 242 - self.handle_output_vibrate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 243 } 244 OutputCommand::Position(x) => { 245 - self.handle_output_position_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 246 } 247 OutputCommand::Heater(x) => { 248 - self.handle_output_heater_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 249 } 250 OutputCommand::Led(x) => { 251 - self.handle_output_led_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 252 } 253 OutputCommand::PositionWithDuration(x) => self.handle_position_with_duration_cmd( 254 cmd.feature_index(), 255 cmd.feature_id(), 256 x.position(), 257 x.duration(), 258 - ), 259 - OutputCommand::RotateWithDirection(x) => self.handle_rotation_with_direction_cmd( 260 - cmd.feature_index(), 261 - cmd.feature_id(), 262 - x.speed(), 263 - x.clockwise(), 264 ), 265 } 266 } ··· 278 &self, 279 _feature_index: u32, 280 _feature_id: Uuid, 281 - _speed: u32, 282 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 283 self.command_unimplemented("OutputCmd (Rotate Actuator)") 284 }
··· 227 let output_command = cmd.output_command(); 228 match output_command { 229 OutputCommand::Constrict(x) => { 230 + self.handle_output_constrict_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 231 } 232 OutputCommand::Spray(x) => { 233 + self.handle_output_spray_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 234 } 235 OutputCommand::Oscillate(x) => { 236 + self.handle_output_oscillate_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 237 } 238 OutputCommand::Rotate(x) => { 239 self.handle_output_rotate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 240 } 241 OutputCommand::Vibrate(x) => { 242 + self.handle_output_vibrate_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 243 } 244 OutputCommand::Position(x) => { 245 + self.handle_output_position_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 246 } 247 OutputCommand::Heater(x) => { 248 + self.handle_output_heater_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 249 } 250 OutputCommand::Led(x) => { 251 + self.handle_output_led_cmd(cmd.feature_index(), cmd.feature_id(), x.value().try_into().map_err(|e| ButtplugDeviceError::DeviceCommandSignError)?) 252 } 253 OutputCommand::PositionWithDuration(x) => self.handle_position_with_duration_cmd( 254 cmd.feature_index(), 255 cmd.feature_id(), 256 x.position(), 257 x.duration(), 258 ), 259 } 260 } ··· 272 &self, 273 _feature_index: u32, 274 _feature_id: Uuid, 275 + _speed: i32, 276 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 277 self.command_unimplemented("OutputCmd (Rotate Actuator)") 278 }
+1 -1
crates/buttplug_server/src/device/protocol_impl/cowgirl.rs
··· 65 &self, 66 _feature_index: u32, 67 _feature_id: Uuid, 68 - speed: u32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 self.speeds[1].store(speed as u8, Ordering::Relaxed); 71 Ok(self.hardware_commands())
··· 65 &self, 66 _feature_index: u32, 67 _feature_id: Uuid, 68 + speed: i32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 self.speeds[1].store(speed as u8, Ordering::Relaxed); 71 Ok(self.hardware_commands())
+2 -2
crates/buttplug_server/src/device/protocol_impl/joyhub/joyhub.rs
··· 66 &self, 67 feature_index: u32, 68 _feature_id: Uuid, 69 - speed: u32, 70 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 71 - self.form_hardware_command(feature_index, speed) 72 } 73 74 fn handle_output_oscillate_cmd(
··· 66 &self, 67 feature_index: u32, 68 _feature_id: Uuid, 69 + speed: i32, 70 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 71 + self.form_hardware_command(feature_index, speed as u32) 72 } 73 74 fn handle_output_oscillate_cmd(
+2 -2
crates/buttplug_server/src/device/protocol_impl/joyhub/joyhub_v2.rs
··· 66 &self, 67 feature_index: u32, 68 _feature_id: Uuid, 69 - speed: u32, 70 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 71 - self.form_hardware_command(feature_index, speed) 72 } 73 74 fn handle_output_oscillate_cmd(
··· 66 &self, 67 feature_index: u32, 68 _feature_id: Uuid, 69 + speed: i32, 70 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 71 + self.form_hardware_command(feature_index, speed as u32) 72 } 73 74 fn handle_output_oscillate_cmd(
+2 -2
crates/buttplug_server/src/device/protocol_impl/joyhub/joyhub_v4.rs
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 - speed: u32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 - self.form_hardware_command(feature_index, speed) 71 } 72 73 fn handle_output_oscillate_cmd(
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 + speed: i32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 + self.form_hardware_command(feature_index, speed as u32) 71 } 72 73 fn handle_output_oscillate_cmd(
+2 -2
crates/buttplug_server/src/device/protocol_impl/joyhub/joyhub_v5.rs
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 - speed: u32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 - self.form_hardware_command(feature_index, speed) 71 } 72 73 fn handle_output_oscillate_cmd(
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 + speed: i32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 + self.form_hardware_command(feature_index, speed as u32) 71 } 72 73 fn handle_output_oscillate_cmd(
+2 -2
crates/buttplug_server/src/device/protocol_impl/joyhub/joyhub_v6.rs
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 - speed: u32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 - self.form_hardware_command(feature_index, speed) 71 } 72 73 fn handle_output_oscillate_cmd(
··· 65 &self, 66 feature_index: u32, 67 _feature_id: Uuid, 68 + speed: i32, 69 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 70 + self.form_hardware_command(feature_index, speed as u32) 71 } 72 73 fn handle_output_oscillate_cmd(
+1 -1
crates/buttplug_server/src/device/protocol_impl/kizuna.rs
··· 24 &self, 25 _feature_index: u32, 26 feature_id: Uuid, 27 - speed: u32, 28 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 29 Ok(vec![ 30 HardwareWriteCmd::new(
··· 24 &self, 25 _feature_index: u32, 26 feature_id: Uuid, 27 + speed: i32, 28 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 29 Ok(vec![ 30 HardwareWriteCmd::new(
+2 -2
crates/buttplug_server/src/device/protocol_impl/lelo_harmony.rs
··· 147 &self, 148 feature_index: u32, 149 feature_id: Uuid, 150 - speed: u32, 151 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 152 - self.handle_input_cmd(feature_index, feature_id, speed) 153 } 154 155 fn handle_output_vibrate_cmd(
··· 147 &self, 148 feature_index: u32, 149 feature_id: Uuid, 150 + speed: i32, 151 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 152 + self.handle_input_cmd(feature_index, feature_id, speed as u32) 153 } 154 155 fn handle_output_vibrate_cmd(
+1
crates/buttplug_server/src/device/protocol_impl/lovense/lovense_multi_actuator.rs
··· 42 feature_id: Uuid, 43 speed: u32, 44 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 45 let lovense_cmd = format!("Vibrate{}:{};", feature_index + 1, speed) 46 .as_bytes() 47 .to_vec();
··· 42 feature_id: Uuid, 43 speed: u32, 44 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 45 + debug!("Lovense multi-actuator command: {}", format!("Vibrate{}:{};", feature_index + 1, speed)); 46 let lovense_cmd = format!("Vibrate{}:{};", feature_index + 1, speed) 47 .as_bytes() 48 .to_vec();
+2 -2
crates/buttplug_server/src/device/protocol_impl/lovense/lovense_rotate_vibrator.rs
··· 42 &self, 43 _feature_index: u32, 44 _feature_id: Uuid, 45 - speed: u32, 46 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 47 - form_rotate_with_direction_command(speed, false) 48 } 49 50 fn handle_rotation_with_direction_cmd(
··· 42 &self, 43 _feature_index: u32, 44 _feature_id: Uuid, 45 + speed: i32, 46 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 47 + form_rotate_with_direction_command(speed.abs() as u32, speed < 0) 48 } 49 50 fn handle_rotation_with_direction_cmd(
+1 -1
crates/buttplug_server/src/device/protocol_impl/lovense/mod.rs
··· 200 .filter(|x| { 201 x.output() 202 .as_ref() 203 - .is_some_and(|x| x.contains(OutputType::RotateWithDirection)) 204 }) 205 .count() 206 == 1;
··· 200 .filter(|x| { 201 x.output() 202 .as_ref() 203 + .is_some_and(|x| x.contains(OutputType::Rotate)) 204 }) 205 .count() 206 == 1;
+1 -1
crates/buttplug_server/src/device/protocol_impl/luvmazer.rs
··· 41 &self, 42 _feature_index: u32, 43 feature_id: Uuid, 44 - speed: u32, 45 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 46 Ok(vec![ 47 HardwareWriteCmd::new(
··· 41 &self, 42 _feature_index: u32, 43 feature_id: Uuid, 44 + speed: i32, 45 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 46 Ok(vec![ 47 HardwareWriteCmd::new(
+2 -2
crates/buttplug_server/src/device/protocol_impl/metaxsire.rs
··· 126 &self, 127 feature_index: u32, 128 _feature_id: Uuid, 129 - speed: u32, 130 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 131 - self.form_command(feature_index, speed) 132 } 133 134 fn handle_output_constrict_cmd(
··· 126 &self, 127 feature_index: u32, 128 _feature_id: Uuid, 129 + speed: i32, 130 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 131 + self.form_command(feature_index, speed as u32) 132 } 133 134 fn handle_output_constrict_cmd(
+2 -2
crates/buttplug_server/src/device/protocol_impl/metaxsire_v3.rs
··· 60 &self, 61 feature_index: u32, 62 feature_id: uuid::Uuid, 63 - speed: u32, 64 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 65 - self.form_command(feature_index, feature_id, speed) 66 } 67 }
··· 60 &self, 61 feature_index: u32, 62 feature_id: uuid::Uuid, 63 + speed: i32, 64 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 65 + self.form_command(feature_index, feature_id, speed as u32) 66 } 67 }
+1 -1
crates/buttplug_server/src/device/protocol_impl/sakuraneko.rs
··· 54 &self, 55 _feature_index: u32, 56 feature_id: Uuid, 57 - speed: u32, 58 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 59 Ok(vec![ 60 HardwareWriteCmd::new(
··· 54 &self, 55 _feature_index: u32, 56 feature_id: Uuid, 57 + speed: i32, 58 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 59 Ok(vec![ 60 HardwareWriteCmd::new(
+1 -1
crates/buttplug_server/src/device/protocol_impl/svakom/svakom_v3.rs
··· 53 &self, 54 _feature_index: u32, 55 feature_id: Uuid, 56 - speed: u32, 57 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 58 Ok(vec![ 59 HardwareWriteCmd::new(
··· 53 &self, 54 _feature_index: u32, 55 feature_id: Uuid, 56 + speed: i32, 57 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 58 Ok(vec![ 59 HardwareWriteCmd::new(
+1 -1
crates/buttplug_server/src/device/protocol_impl/tryfun.rs
··· 44 &self, 45 _feature_index: u32, 46 feature_id: uuid::Uuid, 47 - speed: u32, 48 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 49 let mut sum: u8 = 0xff; 50 let mut data = vec![0xAA, 0x02, 0x08, speed as u8];
··· 44 &self, 45 _feature_index: u32, 46 feature_id: uuid::Uuid, 47 + speed: i32, 48 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 49 let mut sum: u8 = 0xff; 50 let mut data = vec![0xAA, 0x02, 0x08, speed as u8];
-7
crates/buttplug_server/src/device/server_device.rs
··· 53 DeviceMessageInfoV4, 54 InputCommandType, 55 InputType, 56 - OutputRotateWithDirection, 57 OutputType, 58 OutputValue, 59 }, ··· 438 } 439 OutputType::Rotate => { 440 stop_cmd(message::OutputCommand::Rotate(OutputValue::new(0))); 441 - break; 442 - } 443 - OutputType::RotateWithDirection => { 444 - stop_cmd(message::OutputCommand::RotateWithDirection( 445 - OutputRotateWithDirection::new(0, true), 446 - )); 447 break; 448 } 449 OutputType::Vibrate => {
··· 53 DeviceMessageInfoV4, 54 InputCommandType, 55 InputType, 56 OutputType, 57 OutputValue, 58 }, ··· 437 } 438 OutputType::Rotate => { 439 stop_cmd(message::OutputCommand::Rotate(OutputValue::new(0))); 440 break; 441 } 442 OutputType::Vibrate => {
+3 -6
crates/buttplug_server/src/message/v3/client_device_message_attributes.rs
··· 10 v2::{ClientDeviceMessageAttributesV2, GenericDeviceMessageAttributesV2}, 11 }; 12 use buttplug_core::message::{ 13 - DeviceFeature, 14 - DeviceFeatureOutputValueProperties, 15 - InputCommandType, 16 - InputType, 17 - OutputType, 18 }; 19 use getset::{Getters, MutGetters, Setters}; 20 use serde::{Deserialize, Serialize, Serializer, ser::SerializeSeq}; ··· 293 .flat_map(|feature| { 294 let mut actuator_vec = vec![]; 295 if let Some(output_map) = feature.output() 296 - && let Some(actuator) = output_map.rotate_with_direction() { 297 let actuator_type = OutputType::Rotate; 298 let attrs = ClientGenericDeviceMessageAttributesV3 { 299 feature_descriptor: feature.description().to_owned(),
··· 10 v2::{ClientDeviceMessageAttributesV2, GenericDeviceMessageAttributesV2}, 11 }; 12 use buttplug_core::message::{ 13 + DeviceFeature, DeviceFeatureOutputLimits, DeviceFeatureOutputValueProperties, InputCommandType, InputType, OutputType 14 }; 15 use getset::{Getters, MutGetters, Setters}; 16 use serde::{Deserialize, Serialize, Serializer, ser::SerializeSeq}; ··· 289 .flat_map(|feature| { 290 let mut actuator_vec = vec![]; 291 if let Some(output_map) = feature.output() 292 + && let Some(actuator) = output_map.rotate() 293 + && *actuator.value().start() < 0 { 294 let actuator_type = OutputType::Rotate; 295 let attrs = ClientGenericDeviceMessageAttributesV3 { 296 feature_descriptor: feature.description().to_owned(),
+2 -1
crates/buttplug_server/src/message/v3/server_device_message_attributes.rs
··· 108 .flat_map(|feature| { 109 let mut actuator_vec = vec![]; 110 if let Some(output_map) = feature.output() 111 - && let Some(actuator) = output_map.rotate_with_direction() { 112 let actuator_type = OutputType::Rotate; 113 let step_count = actuator.value().step_count(); 114 let attrs = ServerGenericDeviceMessageAttributesV3 {
··· 108 .flat_map(|feature| { 109 let mut actuator_vec = vec![]; 110 if let Some(output_map) = feature.output() 111 + && let Some(actuator) = output_map.rotate() 112 + && *actuator.value().base().start() < 0 { 113 let actuator_type = OutputType::Rotate; 114 let step_count = actuator.value().step_count(); 115 let attrs = ServerGenericDeviceMessageAttributesV3 {
+2 -2
crates/buttplug_server/src/message/v4/checked_output_cmd.rs
··· 109 let value = cmd.command().value(); 110 let new_value = output_map 111 .calculate_from_value(output_type, value as i32) 112 - .map_err(|_| ButtplugDeviceError::DeviceStepRangeError(0, value))?; 113 let mut new_command = cmd.command(); 114 - new_command.set_value(new_value as u32); 115 // We can't make a private trait impl to turn a ValueCmd into a CheckedValueCmd, and this 116 // is all about security, so we just copy. Silly, but it works for our needs in terms of 117 // making this a barrier.
··· 109 let value = cmd.command().value(); 110 let new_value = output_map 111 .calculate_from_value(output_type, value as i32) 112 + .map_err(|_| ButtplugDeviceError::DeviceStepRangeError(0, value.abs() as u32))?; 113 let mut new_command = cmd.command(); 114 + new_command.set_value(new_value); 115 // We can't make a private trait impl to turn a ValueCmd into a CheckedValueCmd, and this 116 // is all about security, so we just copy. Silly, but it works for our needs in terms of 117 // making this a barrier.
+6 -9
crates/buttplug_server/src/message/v4/checked_output_vec_cmd.rs
··· 24 ButtplugMessageValidator, 25 OutputCommand, 26 OutputPositionWithDuration, 27 - OutputRotateWithDirection, 28 OutputType, 29 OutputValue, 30 }, ··· 122 |e: buttplug_server_device_config::ButtplugDeviceConfigError| { 123 ButtplugMessageError::InvalidMessageContents(e.to_string()) 124 }, 125 - )? as u32, 126 )), 127 )) 128 } ··· 192 OutputCommand::Vibrate(OutputValue::new( 193 actuator 194 .calculate_scaled_float(vibrate_cmd.speed()) 195 - .map_err(|e| ButtplugMessageError::InvalidMessageContents(e.to_string()))? 196 - as u32, 197 )), 198 )) 199 } ··· 257 msg.device_index(), 258 idx, 259 feature.feature.id(), 260 - OutputCommand::from_output_type(cmd.actuator_type(), output_value as u32).unwrap(), 261 )); 262 } 263 ··· 374 .ok_or(ButtplugError::from( 375 ButtplugDeviceError::DeviceNoActuatorError("RotateCmdV1".to_owned()), 376 ))? 377 - .rotate_with_direction() 378 .as_ref() 379 .ok_or(ButtplugError::from( 380 ButtplugDeviceError::DeviceNoActuatorError("RotateCmdV1".to_owned()), ··· 384 msg.device_index(), 385 idx, 386 feature.feature.id(), 387 - OutputCommand::RotateWithDirection(OutputRotateWithDirection::new( 388 actuator.calculate_scaled_float(cmd.speed()).map_err(|_| { 389 ButtplugError::from(ButtplugMessageError::InvalidMessageContents( 390 "Position should be 0.0 < x < 1.0".to_owned(), 391 )) 392 - })? as u32, 393 - cmd.clockwise(), 394 )), 395 )); 396 }
··· 24 ButtplugMessageValidator, 25 OutputCommand, 26 OutputPositionWithDuration, 27 OutputType, 28 OutputValue, 29 }, ··· 121 |e: buttplug_server_device_config::ButtplugDeviceConfigError| { 122 ButtplugMessageError::InvalidMessageContents(e.to_string()) 123 }, 124 + )?, 125 )), 126 )) 127 } ··· 191 OutputCommand::Vibrate(OutputValue::new( 192 actuator 193 .calculate_scaled_float(vibrate_cmd.speed()) 194 + .map_err(|e| ButtplugMessageError::InvalidMessageContents(e.to_string()))?, 195 )), 196 )) 197 } ··· 255 msg.device_index(), 256 idx, 257 feature.feature.id(), 258 + OutputCommand::from_output_type(cmd.actuator_type(), output_value).unwrap(), 259 )); 260 } 261 ··· 372 .ok_or(ButtplugError::from( 373 ButtplugDeviceError::DeviceNoActuatorError("RotateCmdV1".to_owned()), 374 ))? 375 + .rotate() 376 .as_ref() 377 .ok_or(ButtplugError::from( 378 ButtplugDeviceError::DeviceNoActuatorError("RotateCmdV1".to_owned()), ··· 382 msg.device_index(), 383 idx, 384 feature.feature.id(), 385 + OutputCommand::Rotate(OutputValue::new( 386 actuator.calculate_scaled_float(cmd.speed()).map_err(|_| { 387 ButtplugError::from(ButtplugMessageError::InvalidMessageContents( 388 "Position should be 0.0 < x < 1.0".to_owned(), 389 )) 390 + })? as i32 * (if cmd.clockwise() { 1 } else { -1 }) 391 )), 392 )); 393 }
+14 -14
crates/buttplug_server_device_config/build-config/buttplug-device-config-v4.json
··· 1 { 2 "version": { 3 "major": 4, 4 - "minor": 67 5 }, 6 "protocols": { 7 "activejoy": { ··· 10040 { 10041 "id": "515e07e2-a6e6-4ac0-a4b0-512504311260", 10042 "output": { 10043 - "rotate_with_direction": { 10044 "value": [ 10045 -20, 10046 20 ··· 10572 { 10573 "id": "360d81e7-5126-4dbb-b72d-7bb60eb67400", 10574 "output": { 10575 - "rotate_with_direction": { 10576 "value": [ 10577 -20, 10578 20 ··· 10918 { 10919 "id": "af885c72-ce2b-47d5-87be-3847f24d18a5", 10920 "output": { 10921 - "rotate_with_direction": { 10922 "value": [ 10923 -20, 10924 20 ··· 11323 { 11324 "id": "d49001e8-5f6b-43ac-9cc7-7e68fab7c323", 11325 "output": { 11326 - "rotate_with_direction": { 11327 "value": [ 11328 -20, 11329 20 ··· 13295 { 13296 "id": "683b450d-bb1a-4fca-b61a-83f8b56086fa", 13297 "output": { 13298 - "rotate_with_direction": { 13299 "value": [ 13300 -255, 13301 255 ··· 13914 { 13915 "id": "fabe3961-dc17-4f32-856f-13880c0a29a3", 13916 "output": { 13917 - "rotate_with_direction": { 13918 "value": [ 13919 -2, 13920 2 ··· 18224 { 18225 "id": "b7495351-9101-448a-94c4-4598cf541dca", 18226 "output": { 18227 - "rotate_with_direction": { 18228 "value": [ 18229 -6, 18230 6 ··· 18461 { 18462 "id": "26402ebe-7ee0-4c7d-ae40-205ec4f3a1b0", 18463 "output": { 18464 - "rotate_with_direction": { 18465 "value": [ 18466 -100, 18467 100 ··· 18776 { 18777 "id": "1d1b4dea-ab29-4426-a9f4-dda2c594eefb", 18778 "output": { 18779 - "rotate_with_direction": { 18780 "value": [ 18781 -10, 18782 10 ··· 18857 { 18858 "id": "8e249d53-8d80-4f42-bc40-e6edb7779e92", 18859 "output": { 18860 - "rotate_with_direction": { 18861 "value": [ 18862 -99, 18863 99 ··· 18878 { 18879 "id": "2d8d1443-c394-4df4-b9bb-1659d8323b45", 18880 "output": { 18881 - "rotate_with_direction": { 18882 "value": [ 18883 -99, 18884 99 ··· 18899 { 18900 "id": "a1632ce4-314f-481d-9ae2-2a11a0c4caa4", 18901 "output": { 18902 - "rotate_with_direction": { 18903 "value": [ 18904 -99, 18905 99 ··· 18910 { 18911 "id": "4b09a02d-9a4a-4c8b-8340-8e6ca3cecfc2", 18912 "output": { 18913 - "rotate_with_direction": { 18914 "value": [ 18915 -99, 18916 99
··· 1 { 2 "version": { 3 "major": 4, 4 + "minor": 69 5 }, 6 "protocols": { 7 "activejoy": { ··· 10040 { 10041 "id": "515e07e2-a6e6-4ac0-a4b0-512504311260", 10042 "output": { 10043 + "rotate": { 10044 "value": [ 10045 -20, 10046 20 ··· 10572 { 10573 "id": "360d81e7-5126-4dbb-b72d-7bb60eb67400", 10574 "output": { 10575 + "rotate": { 10576 "value": [ 10577 -20, 10578 20 ··· 10918 { 10919 "id": "af885c72-ce2b-47d5-87be-3847f24d18a5", 10920 "output": { 10921 + "rotate": { 10922 "value": [ 10923 -20, 10924 20 ··· 11323 { 11324 "id": "d49001e8-5f6b-43ac-9cc7-7e68fab7c323", 11325 "output": { 11326 + "rotate": { 11327 "value": [ 11328 -20, 11329 20 ··· 13295 { 13296 "id": "683b450d-bb1a-4fca-b61a-83f8b56086fa", 13297 "output": { 13298 + "rotate": { 13299 "value": [ 13300 -255, 13301 255 ··· 13914 { 13915 "id": "fabe3961-dc17-4f32-856f-13880c0a29a3", 13916 "output": { 13917 + "rotate": { 13918 "value": [ 13919 -2, 13920 2 ··· 18224 { 18225 "id": "b7495351-9101-448a-94c4-4598cf541dca", 18226 "output": { 18227 + "rotate": { 18228 "value": [ 18229 -6, 18230 6 ··· 18461 { 18462 "id": "26402ebe-7ee0-4c7d-ae40-205ec4f3a1b0", 18463 "output": { 18464 + "rotate": { 18465 "value": [ 18466 -100, 18467 100 ··· 18776 { 18777 "id": "1d1b4dea-ab29-4426-a9f4-dda2c594eefb", 18778 "output": { 18779 + "rotate": { 18780 "value": [ 18781 -10, 18782 10 ··· 18857 { 18858 "id": "8e249d53-8d80-4f42-bc40-e6edb7779e92", 18859 "output": { 18860 + "rotate": { 18861 "value": [ 18862 -99, 18863 99 ··· 18878 { 18879 "id": "2d8d1443-c394-4df4-b9bb-1659d8323b45", 18880 "output": { 18881 + "rotate": { 18882 "value": [ 18883 -99, 18884 99 ··· 18899 { 18900 "id": "a1632ce4-314f-481d-9ae2-2a11a0c4caa4", 18901 "output": { 18902 + "rotate": { 18903 "value": [ 18904 -99, 18905 99 ··· 18910 { 18911 "id": "4b09a02d-9a4a-4c8b-8340-8e6ca3cecfc2", 18912 "output": { 18913 + "rotate": { 18914 "value": [ 18915 -99, 18916 99
+2 -2
crates/buttplug_server_device_config/device-config-v4/buttplug-device-config-schema-v4.json
··· 186 "output": { 187 "type": "object", 188 "patternProperties": { 189 - "^(vibrate|rotate|oscillate|constrict|spray|position|rotate_with_direction|heater|led)$": { 190 "type": "object", 191 "properties": { 192 "value": { ··· 276 "output": { 277 "type": "object", 278 "patternProperties": { 279 - "^(vibrate|rotate|oscillate|constrict|spray|rotate_with_direction|heater|led)$": { 280 "type": "object", 281 "properties": { 282 "value": {
··· 186 "output": { 187 "type": "object", 188 "patternProperties": { 189 + "^(vibrate|rotate|oscillate|constrict|spray|position|heater|led)$": { 190 "type": "object", 191 "properties": { 192 "value": { ··· 276 "output": { 277 "type": "object", 278 "patternProperties": { 279 + "^(vibrate|rotate|oscillate|constrict|spray|heater|led)$": { 280 "type": "object", 281 "properties": { 282 "value": {
+2 -2
crates/buttplug_server_device_config/device-config-v4/protocols/lovense-connect-service.yml
··· 84 - 20 85 - id: af885c72-ce2b-47d5-87be-3847f24d18a5 86 output: 87 - rotate_with_direction: 88 value: 89 - -20 90 - 20 ··· 307 - 20 308 - id: d49001e8-5f6b-43ac-9cc7-7e68fab7c323 309 output: 310 - rotate_with_direction: 311 value: 312 - -20 313 - 20
··· 84 - 20 85 - id: af885c72-ce2b-47d5-87be-3847f24d18a5 86 output: 87 + rotate: 88 value: 89 - -20 90 - 20 ··· 307 - 20 308 - id: d49001e8-5f6b-43ac-9cc7-7e68fab7c323 309 output: 310 + rotate: 311 value: 312 - -20 313 - 20
+2 -2
crates/buttplug_server_device_config/device-config-v4/protocols/lovense.yml
··· 85 - 20 86 - id: 515e07e2-a6e6-4ac0-a4b0-512504311260 87 output: 88 - rotate_with_direction: 89 value: 90 - -20 91 - 20 ··· 378 - 20 379 - id: 360d81e7-5126-4dbb-b72d-7bb60eb67400 380 output: 381 - rotate_with_direction: 382 value: 383 - -20 384 - 20
··· 85 - 20 86 - id: 515e07e2-a6e6-4ac0-a4b0-512504311260 87 output: 88 + rotate: 89 value: 90 - -20 91 - 20 ··· 378 - 20 379 - id: 360d81e7-5126-4dbb-b72d-7bb60eb67400 380 output: 381 + rotate: 382 value: 383 - -20 384 - 20
+1 -1
crates/buttplug_server_device_config/device-config-v4/protocols/motorbunny.yml
··· 9 - 255 10 - id: 683b450d-bb1a-4fca-b61a-83f8b56086fa 11 output: 12 - rotate_with_direction: 13 value: 14 - -255 15 - 255
··· 9 - 255 10 - id: 683b450d-bb1a-4fca-b61a-83f8b56086fa 11 output: 12 + rotate: 13 value: 14 - -255 15 - 255
+1 -1
crates/buttplug_server_device_config/device-config-v4/protocols/nexus-revo.yml
··· 9 - 10 10 - id: fabe3961-dc17-4f32-856f-13880c0a29a3 11 output: 12 - rotate_with_direction: 13 value: 14 - -2 15 - 2
··· 9 - 10 10 - id: fabe3961-dc17-4f32-856f-13880c0a29a3 11 output: 12 + rotate: 13 value: 14 - -2 15 - 2
+1 -1
crates/buttplug_server_device_config/device-config-v4/protocols/synchro.yml
··· 3 features: 4 - id: b7495351-9101-448a-94c4-4598cf541dca 5 output: 6 - rotate_with_direction: 7 value: 8 - -6 9 - 6
··· 3 features: 4 - id: b7495351-9101-448a-94c4-4598cf541dca 5 output: 6 + rotate: 7 value: 8 - -6 9 - 6
+1 -1
crates/buttplug_server_device_config/device-config-v4/protocols/tryfun-meta2.yml
··· 15 - 100 16 - id: 26402ebe-7ee0-4c7d-ae40-205ec4f3a1b0 17 output: 18 - rotate_with_direction: 19 value: 20 - -100 21 - 100
··· 15 - 100 16 - id: 26402ebe-7ee0-4c7d-ae40-205ec4f3a1b0 17 output: 18 + rotate: 19 value: 20 - -100 21 - 100
+1 -1
crates/buttplug_server_device_config/device-config-v4/protocols/vorze-cyclone-x.yml
··· 3 features: 4 - id: 1d1b4dea-ab29-4426-a9f4-dda2c594eefb 5 output: 6 - rotate_with_direction: 7 value: 8 - -10 9 - 10
··· 3 features: 4 - id: 1d1b4dea-ab29-4426-a9f4-dda2c594eefb 5 output: 6 + rotate: 7 value: 8 - -10 9 - 10
+4 -4
crates/buttplug_server_device_config/device-config-v4/protocols/vorze-sa.yml
··· 34 features: 35 - id: 8e249d53-8d80-4f42-bc40-e6edb7779e92 36 output: 37 - rotate_with_direction: 38 value: 39 - -99 40 - 99 ··· 46 features: 47 - id: 2d8d1443-c394-4df4-b9bb-1659d8323b45 48 output: 49 - rotate_with_direction: 50 value: 51 - -99 52 - 99 ··· 58 features: 59 - id: a1632ce4-314f-481d-9ae2-2a11a0c4caa4 60 output: 61 - rotate_with_direction: 62 value: 63 - -99 64 - 99 65 - id: 4b09a02d-9a4a-4c8b-8340-8e6ca3cecfc2 66 output: 67 - rotate_with_direction: 68 value: 69 - -99 70 - 99
··· 34 features: 35 - id: 8e249d53-8d80-4f42-bc40-e6edb7779e92 36 output: 37 + rotate: 38 value: 39 - -99 40 - 99 ··· 46 features: 47 - id: 2d8d1443-c394-4df4-b9bb-1659d8323b45 48 output: 49 + rotate: 50 value: 51 - -99 52 - 99 ··· 58 features: 59 - id: a1632ce4-314f-481d-9ae2-2a11a0c4caa4 60 output: 61 + rotate: 62 value: 63 - -99 64 - 99 65 - id: 4b09a02d-9a4a-4c8b-8340-8e6ca3cecfc2 66 output: 67 + rotate: 68 value: 69 - -99 70 - 99
+1 -1
crates/buttplug_server_device_config/device-config-v4/version.yaml
··· 1 version: 2 major: 4 3 - minor: 67
··· 1 version: 2 major: 4 3 + minor: 69
+1 -8
crates/buttplug_server_device_config/src/device_config_file/feature.rs
··· 83 #[serde(skip_serializing_if = "Option::is_none")] 84 rotate: Option<BaseDeviceFeatureOutputValueProperties>, 85 #[serde(skip_serializing_if = "Option::is_none")] 86 - rotate_with_direction: Option<BaseDeviceFeatureOutputValueProperties>, 87 - #[serde(skip_serializing_if = "Option::is_none")] 88 oscillate: Option<BaseDeviceFeatureOutputValueProperties>, 89 #[serde(skip_serializing_if = "Option::is_none")] 90 constrict: Option<BaseDeviceFeatureOutputValueProperties>, ··· 108 } 109 if let Some(rotate) = val.rotate { 110 output.set_rotate(Some(rotate.into())); 111 - } 112 - if let Some(rotate_with_direction) = val.rotate_with_direction { 113 - output.set_rotate_with_direction(Some(rotate_with_direction.into())); 114 } 115 if let Some(oscillate) = val.oscillate { 116 output.set_oscillate(Some(oscillate.into())); ··· 254 #[serde(skip_serializing_if = "Option::is_none")] 255 rotate: Option<UserDeviceFeatureOutputValueProperties>, 256 #[serde(skip_serializing_if = "Option::is_none")] 257 - rotate_with_direction: Option<UserDeviceFeatureOutputValueProperties>, 258 - #[serde(skip_serializing_if = "Option::is_none")] 259 oscillate: Option<UserDeviceFeatureOutputValueProperties>, 260 #[serde(skip_serializing_if = "Option::is_none")] 261 constrict: Option<UserDeviceFeatureOutputValueProperties>, ··· 277 base_output: &ServerDeviceFeatureOutput, 278 ) -> Result<ServerDeviceFeatureOutput, ButtplugDeviceConfigError> { 279 let mut output = ServerDeviceFeatureOutput::default(); 280 if let Some(base_vibrate) = base_output.vibrate() { 281 if let Some(user_vibrate) = &self.vibrate { 282 output.set_vibrate(Some(user_vibrate.with_base_properties(base_vibrate)?)); ··· 349 Self { 350 vibrate: value.vibrate().as_ref().map(|x| x.into()), 351 rotate: value.rotate().as_ref().map(|x| x.into()), 352 - rotate_with_direction: value.rotate_with_direction().as_ref().map(|x| x.into()), 353 oscillate: value.oscillate().as_ref().map(|x| x.into()), 354 constrict: value.constrict().as_ref().map(|x| x.into()), 355 heater: value.heater().as_ref().map(|x| x.into()),
··· 83 #[serde(skip_serializing_if = "Option::is_none")] 84 rotate: Option<BaseDeviceFeatureOutputValueProperties>, 85 #[serde(skip_serializing_if = "Option::is_none")] 86 oscillate: Option<BaseDeviceFeatureOutputValueProperties>, 87 #[serde(skip_serializing_if = "Option::is_none")] 88 constrict: Option<BaseDeviceFeatureOutputValueProperties>, ··· 106 } 107 if let Some(rotate) = val.rotate { 108 output.set_rotate(Some(rotate.into())); 109 } 110 if let Some(oscillate) = val.oscillate { 111 output.set_oscillate(Some(oscillate.into())); ··· 249 #[serde(skip_serializing_if = "Option::is_none")] 250 rotate: Option<UserDeviceFeatureOutputValueProperties>, 251 #[serde(skip_serializing_if = "Option::is_none")] 252 oscillate: Option<UserDeviceFeatureOutputValueProperties>, 253 #[serde(skip_serializing_if = "Option::is_none")] 254 constrict: Option<UserDeviceFeatureOutputValueProperties>, ··· 270 base_output: &ServerDeviceFeatureOutput, 271 ) -> Result<ServerDeviceFeatureOutput, ButtplugDeviceConfigError> { 272 let mut output = ServerDeviceFeatureOutput::default(); 273 + // TODO Flip logic and output errors if user has something base doesn't, or vice versa. 274 if let Some(base_vibrate) = base_output.vibrate() { 275 if let Some(user_vibrate) = &self.vibrate { 276 output.set_vibrate(Some(user_vibrate.with_base_properties(base_vibrate)?)); ··· 343 Self { 344 vibrate: value.vibrate().as_ref().map(|x| x.into()), 345 rotate: value.rotate().as_ref().map(|x| x.into()), 346 oscillate: value.oscillate().as_ref().map(|x| x.into()), 347 constrict: value.constrict().as_ref().map(|x| x.into()), 348 heater: value.heater().as_ref().map(|x| x.into()),
-18
crates/buttplug_server_device_config/src/server_device_feature.rs
··· 292 pub struct ServerDeviceFeatureOutput { 293 vibrate: Option<ServerDeviceFeatureOutputValueProperties>, 294 rotate: Option<ServerDeviceFeatureOutputValueProperties>, 295 - rotate_with_direction: Option<ServerDeviceFeatureOutputValueProperties>, 296 oscillate: Option<ServerDeviceFeatureOutputValueProperties>, 297 constrict: Option<ServerDeviceFeatureOutputValueProperties>, 298 heater: Option<ServerDeviceFeatureOutputValueProperties>, ··· 312 OutputType::Position => self.position.is_some(), 313 OutputType::PositionWithDuration => self.position_with_duration.is_some(), 314 OutputType::Rotate => self.rotate.is_some(), 315 - OutputType::RotateWithDirection => self.rotate.is_some(), 316 OutputType::Spray => self.spray.is_some(), 317 OutputType::Unknown => false, 318 OutputType::Vibrate => self.vibrate.is_some(), ··· 346 .rotate 347 .is_some() 348 .then(|| types.push(OutputType::Rotate)); 349 - self 350 - .rotate_with_direction 351 - .is_some() 352 - .then(|| types.push(OutputType::RotateWithDirection)); 353 self.spray.is_some().then(|| types.push(OutputType::Spray)); 354 self 355 .vibrate ··· 393 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 394 |x| x.calculate_scaled_value(value), 395 ), 396 - OutputType::RotateWithDirection => self.rotate_with_direction.as_ref().map_or( 397 - Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 398 - |x| x.calculate_scaled_value(value), 399 - ), 400 OutputType::Spray => self.spray.as_ref().map_or( 401 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 402 |x| x.calculate_scaled_value(value), ··· 443 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 444 |x| x.calculate_scaled_float(value), 445 ), 446 - OutputType::RotateWithDirection => self.rotate_with_direction.as_ref().map_or( 447 - Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 448 - |x| x.calculate_scaled_float(value), 449 - ), 450 OutputType::Spray => self.spray.as_ref().map_or( 451 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 452 |x| x.calculate_scaled_float(value), ··· 465 let mut builder = DeviceFeatureOutputBuilder::default(); 466 val.vibrate.as_ref().map(|x| builder.vibrate(x.into())); 467 val.rotate.as_ref().map(|x| builder.rotate(x.into())); 468 - val 469 - .rotate_with_direction 470 - .as_ref() 471 - .map(|x| builder.rotate_with_direction(x.into())); 472 val.oscillate.as_ref().map(|x| builder.oscillate(x.into())); 473 val.constrict.as_ref().map(|x| builder.constrict(x.into())); 474 val.heater.as_ref().map(|x| builder.heater(x.into()));
··· 292 pub struct ServerDeviceFeatureOutput { 293 vibrate: Option<ServerDeviceFeatureOutputValueProperties>, 294 rotate: Option<ServerDeviceFeatureOutputValueProperties>, 295 oscillate: Option<ServerDeviceFeatureOutputValueProperties>, 296 constrict: Option<ServerDeviceFeatureOutputValueProperties>, 297 heater: Option<ServerDeviceFeatureOutputValueProperties>, ··· 311 OutputType::Position => self.position.is_some(), 312 OutputType::PositionWithDuration => self.position_with_duration.is_some(), 313 OutputType::Rotate => self.rotate.is_some(), 314 OutputType::Spray => self.spray.is_some(), 315 OutputType::Unknown => false, 316 OutputType::Vibrate => self.vibrate.is_some(), ··· 344 .rotate 345 .is_some() 346 .then(|| types.push(OutputType::Rotate)); 347 self.spray.is_some().then(|| types.push(OutputType::Spray)); 348 self 349 .vibrate ··· 387 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 388 |x| x.calculate_scaled_value(value), 389 ), 390 OutputType::Spray => self.spray.as_ref().map_or( 391 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 392 |x| x.calculate_scaled_value(value), ··· 433 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 434 |x| x.calculate_scaled_float(value), 435 ), 436 OutputType::Spray => self.spray.as_ref().map_or( 437 Err(ButtplugDeviceConfigError::InvalidOutput(output_type)), 438 |x| x.calculate_scaled_float(value), ··· 451 let mut builder = DeviceFeatureOutputBuilder::default(); 452 val.vibrate.as_ref().map(|x| builder.vibrate(x.into())); 453 val.rotate.as_ref().map(|x| builder.rotate(x.into())); 454 val.oscillate.as_ref().map(|x| builder.oscillate(x.into())); 455 val.constrict.as_ref().map(|x| builder.constrict(x.into())); 456 val.heater.as_ref().map(|x| builder.heater(x.into()));
-1
crates/examples/src/bin/device_tester.rs
··· 17 DeviceFeature, 18 DeviceFeatureOutput, 19 OutputCommand, 20 - OutputRotateWithDirection, 21 OutputType, 22 OutputValue, 23 };
··· 17 DeviceFeature, 18 DeviceFeatureOutput, 19 OutputCommand, 20 OutputType, 21 OutputValue, 22 };