Buttplug sex toy control library
at dev 5.8 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 ServerDeviceMessageAttributesV3, 10 ServerGenericDeviceMessageAttributesV3, 11 v1::NullDeviceMessageAttributesV1, 12}; 13use buttplug_core::message::{InputType, OutputType}; 14 15use buttplug_server_device_config::ServerDeviceFeature; 16 17use getset::{CopyGetters, Getters, Setters}; 18use serde::{Deserialize, Serialize}; 19 20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Getters, Setters)] 21pub struct ServerDeviceMessageAttributesV2 { 22 // Generic commands 23 #[getset(get = "pub")] 24 #[serde(rename = "VibrateCmd")] 25 #[serde(skip_serializing_if = "Option::is_none")] 26 pub(in crate::message) vibrate_cmd: Option<ServerGenericDeviceMessageAttributesV2>, 27 #[getset(get = "pub")] 28 #[serde(rename = "RotateCmd")] 29 #[serde(skip_serializing_if = "Option::is_none")] 30 pub(in crate::message) rotate_cmd: Option<ServerGenericDeviceMessageAttributesV2>, 31 #[getset(get = "pub")] 32 #[serde(rename = "LinearCmd")] 33 #[serde(skip_serializing_if = "Option::is_none")] 34 pub(in crate::message) linear_cmd: Option<ServerGenericDeviceMessageAttributesV2>, 35 #[getset(get = "pub")] 36 #[serde(rename = "BatteryLevelCmd")] 37 #[serde(skip_serializing_if = "Option::is_none")] 38 pub(in crate::message) battery_level_cmd: Option<ServerSensorDeviceMessageAttributesV2>, 39 40 // RSSILevel is added post-serialization (only for bluetooth devices) 41 #[getset(get = "pub")] 42 #[serde(rename = "RSSILevelCmd")] 43 #[serde(skip_serializing_if = "Option::is_none")] 44 pub(in crate::message) rssi_level_cmd: Option<ServerSensorDeviceMessageAttributesV2>, 45 46 // StopDeviceCmd always exists 47 #[getset(get = "pub")] 48 #[serde(rename = "StopDeviceCmd")] 49 pub(in crate::message) stop_device_cmd: NullDeviceMessageAttributesV1, 50 51 // Needed to load from config for fallback, but unused here. 52 #[getset(get = "pub")] 53 #[serde(rename = "FleshlightLaunchFW12Cmd")] 54 #[serde(skip)] 55 pub(in crate::message) fleshlight_launch_fw12_cmd: Option<NullDeviceMessageAttributesV1>, 56 #[getset(get = "pub")] 57 #[serde(rename = "VorzeA10CycloneCmd")] 58 #[serde(skip)] 59 pub(in crate::message) vorze_a10_cyclone_cmd: Option<NullDeviceMessageAttributesV1>, 60} 61 62#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Getters, CopyGetters, Setters)] 63pub struct ServerGenericDeviceMessageAttributesV2 { 64 #[getset(get_copy = "pub")] 65 #[serde(rename = "FeatureCount")] 66 pub(in crate::message) feature_count: u32, 67 #[getset(get = "pub")] 68 #[serde(rename = "StepCount")] 69 pub(in crate::message) step_count: Vec<u32>, 70 #[getset(get = "pub")] 71 #[serde(skip)] 72 pub(in crate::message) features: Vec<ServerDeviceFeature>, 73} 74 75#[derive(Clone, Debug, PartialEq, Eq, Serialize, Getters, Setters)] 76pub struct ServerSensorDeviceMessageAttributesV2 { 77 #[getset(get = "pub")] 78 #[serde(skip)] 79 feature: ServerDeviceFeature, 80} 81 82impl ServerSensorDeviceMessageAttributesV2 { 83 pub fn new(feature: &ServerDeviceFeature) -> Self { 84 Self { 85 feature: feature.clone(), 86 } 87 } 88} 89 90impl From<Vec<ServerDeviceFeature>> for ServerDeviceMessageAttributesV2 { 91 fn from(value: Vec<ServerDeviceFeature>) -> Self { 92 ServerDeviceMessageAttributesV3::from(value).into() 93 } 94} 95 96pub fn vibrate_cmd_from_scalar_cmd( 97 attributes_vec: &[ServerGenericDeviceMessageAttributesV3], 98) -> ServerGenericDeviceMessageAttributesV2 { 99 let mut feature_count = 0u32; 100 let mut step_count = vec![]; 101 let mut features = vec![]; 102 for attr in attributes_vec { 103 if *attr.actuator_type() == OutputType::Vibrate { 104 feature_count += 1; 105 step_count.push(*attr.step_count()); 106 features.push(attr.feature().clone()); 107 } 108 } 109 ServerGenericDeviceMessageAttributesV2 { 110 feature_count, 111 step_count, 112 features, 113 } 114} 115 116impl From<ServerDeviceMessageAttributesV3> for ServerDeviceMessageAttributesV2 { 117 fn from(other: ServerDeviceMessageAttributesV3) -> Self { 118 Self { 119 vibrate_cmd: other 120 .scalar_cmd() 121 .as_ref() 122 .map(|x| vibrate_cmd_from_scalar_cmd(x)) 123 .filter(|x| x.feature_count() != 0), 124 rotate_cmd: other 125 .rotate_cmd() 126 .as_ref() 127 .map(|x| ServerGenericDeviceMessageAttributesV2::from(x.clone())), 128 linear_cmd: other 129 .linear_cmd() 130 .as_ref() 131 .map(|x| ServerGenericDeviceMessageAttributesV2::from(x.clone())), 132 battery_level_cmd: { 133 if let Some(sensor_info) = other.sensor_read_cmd() { 134 sensor_info 135 .iter() 136 .find(|x| *x.sensor_type() == InputType::Battery) 137 .map(|attr| ServerSensorDeviceMessageAttributesV2::new(attr.feature())) 138 } else { 139 None 140 } 141 }, 142 rssi_level_cmd: { 143 if let Some(sensor_info) = other.sensor_read_cmd() { 144 sensor_info 145 .iter() 146 .find(|x| *x.sensor_type() == InputType::Rssi) 147 .map(|attr| ServerSensorDeviceMessageAttributesV2::new(attr.feature())) 148 } else { 149 None 150 } 151 }, 152 stop_device_cmd: other.stop_device_cmd().clone(), 153 fleshlight_launch_fw12_cmd: other.fleshlight_launch_fw12_cmd().clone(), 154 vorze_a10_cyclone_cmd: other.vorze_a10_cyclone_cmd().clone(), 155 } 156 } 157} 158 159impl From<Vec<ServerGenericDeviceMessageAttributesV3>> for ServerGenericDeviceMessageAttributesV2 { 160 fn from(attributes_vec: Vec<ServerGenericDeviceMessageAttributesV3>) -> Self { 161 Self { 162 feature_count: attributes_vec.len() as u32, 163 step_count: attributes_vec.iter().map(|x| *x.step_count()).collect(), 164 features: attributes_vec.iter().map(|x| x.feature().clone()).collect(), 165 } 166 } 167}