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