Navigation Menu

Skip to content

Commit

Permalink
feat: Adding Lovehoney Desire protocol
Browse files Browse the repository at this point in the history
Fixes #56
  • Loading branch information
blackspherefollower authored and qdot committed Feb 8, 2020
1 parent 913d624 commit ac56b2c
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
7 changes: 7 additions & 0 deletions buttplug/src/device/configuration_manager.rs
Expand Up @@ -30,6 +30,7 @@ use crate::device::protocol::kiiroo_gen2vibe::KiirooGen2VibeProtocolCreator;
use crate::device::protocol::kiiroo_gen21::KiirooGen21ProtocolCreator;
use crate::device::protocol::aneros::AnerosProtocolCreator;
use crate::device::protocol::lelo_f1s::LeloF1sProtocolCreator;
use crate::device::protocol::lovehoney_desire::LovehoneyDesireProtocolCreator;

static DEVICE_CONFIGURATION_JSON: &str =
include_str!("../../dependencies/buttplug-device-config/buttplug-device-config.json");
Expand Down Expand Up @@ -336,6 +337,12 @@ impl DeviceConfigurationManager {
Box::new(LiboVibesProtocolCreator::new(config))
}),
);
protocols.insert(
"lovehoney-desire".to_owned(),
Box::new(|config: DeviceProtocolConfiguration| {
Box::new(LovehoneyDesireProtocolCreator::new(config))
}),
);
protocols.insert(
"lovense".to_owned(),
Box::new(|config: DeviceProtocolConfiguration| {
Expand Down
168 changes: 168 additions & 0 deletions buttplug/src/device/protocol/lovehoney_desire.rs
@@ -0,0 +1,168 @@
use super::{ButtplugProtocol, ButtplugProtocolCreator};
use crate::{
core::{
errors::{ButtplugDeviceError, ButtplugError},
messages::{
self, ButtplugDeviceCommandMessageUnion, ButtplugMessageUnion, MessageAttributesMap,
StopDeviceCmd, VibrateCmd, VibrateSubcommand,
},
},
device::{
configuration_manager::DeviceProtocolConfiguration,
device::{DeviceImpl, DeviceWriteCmd},
Endpoint,
},
};
use async_trait::async_trait;

pub struct LovehoneyDesireProtocolCreator {
config: DeviceProtocolConfiguration,
}

impl LovehoneyDesireProtocolCreator {
pub fn new(config: DeviceProtocolConfiguration) -> Self {
Self { config }
}
}

#[async_trait]
impl ButtplugProtocolCreator for LovehoneyDesireProtocolCreator {
async fn try_create_protocol(
&self,
device_impl: &Box<dyn DeviceImpl>,
) -> Result<Box<dyn ButtplugProtocol>, ButtplugError> {
let (names, attrs) = self.config.get_attributes(device_impl.name()).unwrap();
let name = names.get("en-us").unwrap();
Ok(Box::new(LovehoneyDesireProtocol::new(name, attrs)))
}
}

#[derive(Clone)]
pub struct LovehoneyDesireProtocol {
name: String,
attributes: MessageAttributesMap,
sent_vibration: bool,
vibrations: Vec<u8>,
}

impl LovehoneyDesireProtocol {
pub fn new(name: &str, attributes: MessageAttributesMap) -> Self {
let mut vibrations: Vec<u8> = vec![];
if let Some(attr) = attributes.get("VibrateCmd") {
if let Some(count) = attr.feature_count {
vibrations = vec![0; count as usize];
}
}
LovehoneyDesireProtocol {
name: name.to_owned(),
attributes,
sent_vibration: false,
vibrations,
}
}
}

#[async_trait]
impl ButtplugProtocol for LovehoneyDesireProtocol {
fn name(&self) -> &str {
&self.name
}

fn message_attributes(&self) -> MessageAttributesMap {
self.attributes.clone()
}

fn box_clone(&self) -> Box<dyn ButtplugProtocol> {
Box::new((*self).clone())
}

async fn parse_message(
&mut self,
device: &Box<dyn DeviceImpl>,
message: &ButtplugDeviceCommandMessageUnion,
) -> Result<ButtplugMessageUnion, ButtplugError> {
match message {
ButtplugDeviceCommandMessageUnion::StopDeviceCmd(msg) => {
self.handle_stop_device_cmd(device, msg).await
}
ButtplugDeviceCommandMessageUnion::VibrateCmd(msg) => {
self.handle_vibrate_cmd(device, msg).await
}
_ => Err(ButtplugError::ButtplugDeviceError(
ButtplugDeviceError::new("LovehoneyDesireProtocol does not accept this message type."),
)),
}
}
}

impl LovehoneyDesireProtocol {
async fn handle_stop_device_cmd(
&mut self,
device: &Box<dyn DeviceImpl>,
_: &StopDeviceCmd,
) -> Result<ButtplugMessageUnion, ButtplugError> {
self.handle_vibrate_cmd(
device,
&VibrateCmd::new(
0,
vec![VibrateSubcommand::new(0, 0.0); self.vibrations.len()],
),
)
.await
}

async fn handle_vibrate_cmd(
&mut self,
device: &Box<dyn DeviceImpl>,
msg: &VibrateCmd,
) -> Result<ButtplugMessageUnion, ButtplugError> {
let mut new_speeds = self.vibrations.clone();
let mut changed: Vec<bool> = vec![];
for _ in 0..new_speeds.len() {
changed.push(!self.sent_vibration);
}

if new_speeds.len() == 0 || new_speeds.len() > 2 {
// Should probably be an error
return Ok(ButtplugMessageUnion::Ok(messages::Ok::default()));
}

// ToDo: Per-feature step count support?
let max_value: u8 = 0x7F;

for i in 0..msg.speeds.len() {
//ToDo: Need safeguards
let index = msg.speeds[i].index as usize;
new_speeds[index] = (msg.speeds[i].speed * max_value as f64) as u8;
if new_speeds[index] != self.vibrations[index] {
changed[index] = true;
}
}

self.sent_vibration = true;
self.vibrations = new_speeds;

if !changed.contains(&true) {
return Ok(ButtplugMessageUnion::Ok(messages::Ok::default()));
}

// Both values are the same, something changed
if self.vibrations.len() >= 2 && self.vibrations[0] == self.vibrations[1] {
let msg = DeviceWriteCmd::new(Endpoint::Tx, vec![0xF3, 0, self.vibrations[0]], false);
device.write_value(msg.into()).await?;
return Ok(ButtplugMessageUnion::Ok(messages::Ok::default()));
}

if changed[0] {
let msg = DeviceWriteCmd::new(Endpoint::Tx, vec![0xF3, 1, self.vibrations[0]], false);
device.write_value(msg.into()).await?;
}

if self.vibrations.len() >= 2 && changed[1] {
let msg = DeviceWriteCmd::new(Endpoint::Tx, vec![0xF3, 2, self.vibrations[1]], false);
device.write_value(msg.into()).await?;
}

Ok(ButtplugMessageUnion::Ok(messages::Ok::default()))
}
}
1 change: 1 addition & 0 deletions buttplug/src/device/protocol/mod.rs
Expand Up @@ -7,6 +7,7 @@ pub mod libo_elle;
pub mod libo_kegel;
pub mod libo_shark;
pub mod libo_vibes;
pub mod lovehoney_desire;
pub mod lovense;
pub mod maxpro;
pub mod picobong;
Expand Down

0 comments on commit ac56b2c

Please sign in to comment.