Buttplug sex toy control library
at master 380 lines 14 kB view raw
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved. 4// 5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6// for full license information. 7 8use crate::message::{ 9 v1::NullDeviceMessageAttributesV1, 10 v2::{ClientDeviceMessageAttributesV2, GenericDeviceMessageAttributesV2}, 11}; 12use buttplug_core::message::{ 13 DeviceFeature, 14 DeviceFeatureOutputValueProperties, 15 InputCommandType, 16 InputType, 17 OutputType, 18}; 19use getset::{Getters, MutGetters, Setters}; 20use serde::{Deserialize, Serialize, Serializer, ser::SerializeSeq}; 21use std::ops::RangeInclusive; 22 23// This will look almost exactly like ServerDeviceMessageAttributes. However, it will only contain 24// information we want the client to know, i.e. step counts versus specific step ranges. This is 25// what will be sent to the client as part of DeviceAdded/DeviceList messages. It should not be used 26// for outside configuration/serialization, rather it should be a subset of that information. 27// 28// For many messages, client and server configurations may be exactly the same. If they are not, 29// then we denote this by prefixing the type with Client/Server. Server attributes will usually be 30// hosted in the server/device/configuration module. 31#[derive(Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)] 32pub struct ClientDeviceMessageAttributesV3 { 33 // Generic commands 34 #[getset(get = "pub", get_mut = "pub(super)")] 35 #[serde(rename = "ScalarCmd")] 36 #[serde(skip_serializing_if = "Option::is_none")] 37 pub(in crate::message) scalar_cmd: Option<Vec<ClientGenericDeviceMessageAttributesV3>>, 38 #[getset(get = "pub", get_mut = "pub(super)")] 39 #[serde(rename = "RotateCmd")] 40 #[serde(skip_serializing_if = "Option::is_none")] 41 pub(in crate::message) rotate_cmd: Option<Vec<ClientGenericDeviceMessageAttributesV3>>, 42 #[getset(get = "pub", get_mut = "pub(super)")] 43 #[serde(rename = "LinearCmd")] 44 #[serde(skip_serializing_if = "Option::is_none")] 45 pub(in crate::message) linear_cmd: Option<Vec<ClientGenericDeviceMessageAttributesV3>>, 46 47 // Sensor Messages 48 #[getset(get = "pub")] 49 #[serde(rename = "SensorReadCmd")] 50 #[serde(skip_serializing_if = "Option::is_none")] 51 pub(in crate::message) sensor_read_cmd: Option<Vec<SensorDeviceMessageAttributesV3>>, 52 #[getset(get = "pub")] 53 #[serde(rename = "SensorSubscribeCmd")] 54 #[serde(skip_serializing_if = "Option::is_none")] 55 pub(in crate::message) sensor_subscribe_cmd: Option<Vec<SensorDeviceMessageAttributesV3>>, 56 57 // StopDeviceCmd always exists 58 #[getset(get = "pub")] 59 #[serde(rename = "StopDeviceCmd")] 60 #[serde(skip_deserializing)] 61 pub(in crate::message) stop_device_cmd: NullDeviceMessageAttributesV1, 62 63 // Needed to load from config for fallback, but unused here. 64 #[getset(get = "pub")] 65 #[serde(rename = "FleshlightLaunchFW12Cmd")] 66 #[serde(skip_serializing)] 67 pub(in crate::message) fleshlight_launch_fw12_cmd: Option<NullDeviceMessageAttributesV1>, 68 #[getset(get = "pub")] 69 #[serde(rename = "VorzeA10CycloneCmd")] 70 #[serde(skip_serializing)] 71 pub(in crate::message) vorze_a10_cyclone_cmd: Option<NullDeviceMessageAttributesV1>, 72} 73 74pub fn vibrate_cmd_from_scalar_cmd( 75 attributes_vec: &[ClientGenericDeviceMessageAttributesV3], 76) -> GenericDeviceMessageAttributesV2 { 77 let mut feature_count = 0u32; 78 let mut step_count = vec![]; 79 for attr in attributes_vec { 80 if *attr.actuator_type() == OutputType::Vibrate { 81 feature_count += 1; 82 step_count.push(*attr.step_count()); 83 } 84 } 85 GenericDeviceMessageAttributesV2 { 86 feature_count, 87 step_count, 88 } 89} 90 91impl From<ClientDeviceMessageAttributesV3> for ClientDeviceMessageAttributesV2 { 92 fn from(other: ClientDeviceMessageAttributesV3) -> Self { 93 Self { 94 vibrate_cmd: other 95 .scalar_cmd() 96 .as_ref() 97 .map(|x| vibrate_cmd_from_scalar_cmd(x)) 98 .filter(|x| x.feature_count() != 0), 99 rotate_cmd: other 100 .rotate_cmd() 101 .as_ref() 102 .map(|x| GenericDeviceMessageAttributesV2::from(x.clone())), 103 linear_cmd: other 104 .linear_cmd() 105 .as_ref() 106 .map(|x| GenericDeviceMessageAttributesV2::from(x.clone())), 107 battery_level_cmd: { 108 if let Some(sensor_info) = other.sensor_read_cmd() { 109 if sensor_info 110 .iter() 111 .any(|x| *x.sensor_type() == InputType::Battery) 112 { 113 Some(NullDeviceMessageAttributesV1::default()) 114 } else { 115 None 116 } 117 } else { 118 None 119 } 120 }, 121 rssi_level_cmd: { 122 if let Some(sensor_info) = other.sensor_read_cmd() { 123 if sensor_info 124 .iter() 125 .any(|x| *x.sensor_type() == InputType::Rssi) 126 { 127 Some(NullDeviceMessageAttributesV1::default()) 128 } else { 129 None 130 } 131 } else { 132 None 133 } 134 }, 135 stop_device_cmd: other.stop_device_cmd().clone(), 136 fleshlight_launch_fw12_cmd: other.fleshlight_launch_fw12_cmd().clone(), 137 vorze_a10_cyclone_cmd: other.vorze_a10_cyclone_cmd().clone(), 138 } 139 } 140} 141 142impl ClientDeviceMessageAttributesV3 { 143 pub fn finalize(&mut self) { 144 if let Some(scalar_attrs) = &mut self.scalar_cmd { 145 for (i, attr) in scalar_attrs.iter_mut().enumerate() { 146 attr.index = i as u32; 147 } 148 } 149 if let Some(sensor_read_attrs) = &mut self.sensor_read_cmd { 150 for (i, attr) in sensor_read_attrs.iter_mut().enumerate() { 151 attr.index = i as u32; 152 } 153 } 154 if let Some(sensor_subscribe_attrs) = &mut self.sensor_subscribe_cmd { 155 for (i, attr) in sensor_subscribe_attrs.iter_mut().enumerate() { 156 attr.index = i as u32; 157 } 158 } 159 } 160} 161 162fn unspecified_feature() -> String { 163 "N/A".to_string() 164} 165 166#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Getters, Setters)] 167pub struct ClientGenericDeviceMessageAttributesV3 { 168 #[getset(get = "pub")] 169 #[serde(rename = "FeatureDescriptor")] 170 #[serde(default = "unspecified_feature")] 171 pub(in crate::message) feature_descriptor: String, 172 #[getset(get = "pub")] 173 #[serde(rename = "ActuatorType")] 174 pub(in crate::message) actuator_type: OutputType, 175 #[serde(rename = "StepCount")] 176 #[getset(get = "pub")] 177 pub(in crate::message) step_count: u32, 178 // TODO This needs to actually be part of the device info relayed to the client in spec v4. 179 #[getset(get = "pub")] 180 #[serde(skip, default)] 181 pub(in crate::message) index: u32, 182} 183 184impl From<Vec<ClientGenericDeviceMessageAttributesV3>> for GenericDeviceMessageAttributesV2 { 185 fn from(attributes_vec: Vec<ClientGenericDeviceMessageAttributesV3>) -> Self { 186 Self { 187 feature_count: attributes_vec.len() as u32, 188 step_count: attributes_vec.iter().map(|x| *x.step_count()).collect(), 189 } 190 } 191} 192 193impl ClientGenericDeviceMessageAttributesV3 { 194 pub fn new(feature_descriptor: &str, step_count: u32, actuator_type: OutputType) -> Self { 195 Self { 196 feature_descriptor: feature_descriptor.to_owned(), 197 actuator_type, 198 step_count, 199 index: 0, 200 } 201 } 202} 203 204fn range_sequence_serialize<S>( 205 range_vec: &Vec<RangeInclusive<i32>>, 206 serializer: S, 207) -> Result<S::Ok, S::Error> 208where 209 S: Serializer, 210{ 211 let mut seq = serializer.serialize_seq(Some(range_vec.len()))?; 212 for range in range_vec { 213 seq.serialize_element(&vec![*range.start(), *range.end()])?; 214 } 215 seq.end() 216} 217 218#[derive(Clone, Debug, Serialize, Deserialize, Getters, Setters)] 219pub struct SensorDeviceMessageAttributesV3 { 220 #[getset(get = "pub")] 221 #[serde(rename = "FeatureDescriptor")] 222 pub(in crate::message) feature_descriptor: String, 223 #[getset(get = "pub")] 224 #[serde(rename = "SensorType")] 225 pub(in crate::message) sensor_type: InputType, 226 #[getset(get = "pub")] 227 #[serde(rename = "SensorRange", serialize_with = "range_sequence_serialize")] 228 pub(in crate::message) sensor_range: Vec<RangeInclusive<i32>>, 229 // TODO This needs to actually be part of the device info relayed to the client in spec v4. 230 #[getset(get = "pub")] 231 #[serde(skip, default)] 232 pub(in crate::message) index: u32, 233 // Matching device feature for this attribute. Do not serialize or deserialize this, it's not part 234 // of this version of the protocol, only use it for comparison when doing message conversion. 235 #[getset(get = "pub")] 236 #[serde(skip)] 237 pub(in crate::message) feature: DeviceFeature, 238} 239 240// This is an almost exact copy of the conversion we do for ServerDeviceFeature -> 241// ServerDeviceMessageAttributesV3, but there's enough differences in the members that it's just 242// easiest to mostly repeat here. 243impl From<Vec<DeviceFeature>> for ClientDeviceMessageAttributesV3 { 244 fn from(features: Vec<DeviceFeature>) -> Self { 245 let scalar_attrs: Vec<ClientGenericDeviceMessageAttributesV3> = features 246 .iter() 247 .flat_map(|feature| { 248 let mut actuator_vec = vec![]; 249 if let Some(output_map) = feature.output() { 250 let mut create_actuator = 251 |actuator_type, actuator: &DeviceFeatureOutputValueProperties| { 252 let attrs = ClientGenericDeviceMessageAttributesV3 { 253 feature_descriptor: feature.description().to_owned(), 254 actuator_type, 255 step_count: actuator.step_count(), 256 index: 0, 257 }; 258 actuator_vec.push(attrs) 259 }; 260 if let Some(x) = output_map.constrict().as_ref() { 261 create_actuator(OutputType::Constrict, x) 262 } 263 if let Some(x) = output_map.temperature().as_ref() { 264 create_actuator(OutputType::Temperature, x) 265 } 266 if let Some(x) = output_map.led().as_ref() { 267 create_actuator(OutputType::Led, x) 268 } 269 if let Some(x) = output_map.oscillate().as_ref() { 270 create_actuator(OutputType::Oscillate, x) 271 } 272 if let Some(x) = output_map.position().as_ref() { 273 create_actuator(OutputType::Position, x) 274 } 275 if let Some(x) = output_map.rotate().as_ref() { 276 create_actuator(OutputType::Rotate, x) 277 } 278 if let Some(x) = output_map.spray().as_ref() { 279 create_actuator(OutputType::Spray, x) 280 } 281 if let Some(x) = output_map.vibrate().as_ref() { 282 create_actuator(OutputType::Vibrate, x) 283 } 284 } 285 actuator_vec 286 }) 287 .collect(); 288 289 // We have to calculate rotation attributes seperately, since they're a combination of 290 // feature type and message in >= v4. 291 let rotate_attrs: Vec<ClientGenericDeviceMessageAttributesV3> = features 292 .iter() 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() 297 && *actuator.value().start() < 0 298 { 299 let actuator_type = OutputType::Rotate; 300 let attrs = ClientGenericDeviceMessageAttributesV3 { 301 feature_descriptor: feature.description().to_owned(), 302 actuator_type, 303 step_count: actuator.step_count(), 304 index: 0, 305 }; 306 actuator_vec.push(attrs) 307 } 308 actuator_vec 309 }) 310 .collect(); 311 312 let linear_attrs: Vec<ClientGenericDeviceMessageAttributesV3> = features 313 .iter() 314 .flat_map(|feature| { 315 let mut actuator_vec = vec![]; 316 if let Some(output_map) = feature.output() 317 && let Some(actuator) = output_map.position_with_duration() 318 { 319 let actuator_type = OutputType::Position; 320 let attrs = ClientGenericDeviceMessageAttributesV3 { 321 feature_descriptor: feature.description().to_owned(), 322 actuator_type, 323 step_count: actuator.step_count(), 324 index: 0, 325 }; 326 actuator_vec.push(attrs) 327 } 328 actuator_vec 329 }) 330 .collect(); 331 332 let sensor_filter = { 333 let attrs: Vec<SensorDeviceMessageAttributesV3> = features 334 .iter() 335 .map(|feature| { 336 let mut sensor_vec = vec![]; 337 if let Some(sensor_map) = feature.input() { 338 // Only convert Battery backwards. Other sensors weren't really built for v3 and we 339 // never recommended using them or implemented much for them. 340 if let Some(battery) = sensor_map.battery() 341 && battery.input_commands().contains(&InputCommandType::Read) 342 { 343 sensor_vec.push(SensorDeviceMessageAttributesV3 { 344 feature_descriptor: feature.description().to_owned(), 345 sensor_type: InputType::Battery, 346 sensor_range: battery.value_range().clone(), 347 feature: feature.clone(), 348 index: 0, 349 }); 350 } 351 } 352 sensor_vec 353 }) 354 .flatten() 355 .collect(); 356 if !attrs.is_empty() { Some(attrs) } else { None } 357 }; 358 359 Self { 360 scalar_cmd: if scalar_attrs.is_empty() { 361 None 362 } else { 363 Some(scalar_attrs) 364 }, 365 rotate_cmd: if rotate_attrs.is_empty() { 366 None 367 } else { 368 Some(rotate_attrs) 369 }, 370 linear_cmd: if linear_attrs.is_empty() { 371 None 372 } else { 373 Some(linear_attrs) 374 }, 375 sensor_read_cmd: sensor_filter, 376 sensor_subscribe_cmd: None, 377 ..Default::default() 378 } 379 } 380}