···23232424/// Notification that a device has been found and connected to the server.
2525#[derive(
2626- ButtplugMessage, PartialEq, Clone, Debug, Getters, CopyGetters, Serialize, Deserialize,
2626+ ButtplugMessage, Clone, Debug, Getters, CopyGetters, Serialize, Deserialize,
2727)]
2828pub struct DeviceAddedV3 {
2929 #[serde(rename = "Id")]
···1515 ButtplugMessageValidator,
1616 OutputCmdV4,
1717 OutputCommand,
1818- OutputType,
1918 },
2019};
2120···107106 // Check to make sure the feature has an actuator that handles the data we've been passed
108107 if let Some(output_map) = feature.output() {
109108 let output_type = cmd.command().as_output_type();
110110- if let Some(actuator) = output_map.get(&output_type) {
111111- let value = cmd.command().value();
112112- let step_count = actuator.step_count();
113113- if value > step_count {
114114- Err(ButtplugError::from(
115115- ButtplugDeviceError::DeviceStepRangeError(step_count, value),
116116- ))
117117- } else {
118118- // Only set adjusted value if we haven't gotten zero, otherwise assume stop.
119119- let new_value = if [OutputType::Position, OutputType::PositionWithDuration]
120120- .contains(&output_type)
121121- && actuator.reverse_position()
122122- {
123123- actuator.step_limit().end() - value
124124- } else if step_count != 0 && value != 0 {
125125- actuator.step_limit().start() + value
126126- } else {
127127- 0
128128- };
129129- let mut new_command = cmd.command();
130130- new_command.set_value(new_value);
131131- // We can't make a private trait impl to turn a ValueCmd into a CheckedValueCmd, and this
132132- // is all about security, so we just copy. Silly, but it works for our needs in terms of
133133- // making this a barrier.
134134- Ok(Self {
135135- id: cmd.id(),
136136- feature_id: feature.id(),
137137- device_index: cmd.device_index(),
138138- feature_index: cmd.feature_index(),
139139- output_command: new_command,
140140- })
141141- }
142142- } else {
143143- Err(ButtplugError::from(
144144- ButtplugDeviceError::MessageNotSupported(
145145- ButtplugDeviceMessageNameV4::OutputCmd.to_string(),
146146- ),
147147- ))
148148- }
109109+ let value = cmd.command().value();
110110+ let new_value = output_map.calculate_from_value(output_type, value as i32).map_err(|_| ButtplugDeviceError::DeviceStepRangeError(0, value))?;
111111+ let mut new_command = cmd.command();
112112+ new_command.set_value(new_value as u32);
113113+ // We can't make a private trait impl to turn a ValueCmd into a CheckedValueCmd, and this
114114+ // is all about security, so we just copy. Silly, but it works for our needs in terms of
115115+ // making this a barrier.
116116+ Ok(Self {
117117+ id: cmd.id(),
118118+ feature_id: feature.id(),
119119+ device_index: cmd.device_index(),
120120+ feature_index: cmd.feature_index(),
121121+ output_command: new_command,
122122+ })
149123 } else {
150124 Err(ButtplugError::from(
151125 ButtplugDeviceError::MessageNotSupported(
···141141extern crate log;
142142143143mod device_config_file;
144144+145145+use buttplug_core::message::OutputType;
144146pub use device_config_file::{load_protocol_configs}; //, save_user_config};
145147mod device_config_manager;
146148pub use device_config_manager::*;
···150152pub use identifiers::*;
151153mod device_definitions;
152154pub use device_definitions::*;
153153-mod device_feature;
154154-pub use device_feature::*;
155155+mod server_device_feature;
156156+pub use server_device_feature::*;
155157mod endpoint;
156158pub use endpoint::*;
157159use uuid::Uuid;
···174176 #[error("Device definition with base id {0} not found")]
175177 BaseIdNotFound(Uuid),
176178 #[error("Feature vectors between base and user device definitions do not match")]
177177- UserFeatureMismatch
179179+ UserFeatureMismatch,
180180+ #[error("Output value {0} not in range {1}")]
181181+ InvalidOutputValue(i32, String),
182182+ #[error("Output type {0} not available on device")]
183183+ InvalidOutput(OutputType),
184184+ #[error("Float value {0} is not 0 < x < 1")]
185185+ InvalidFloatConversion(f64)
178186}