1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Buttplug Rust Source Code File - See https://buttplug.io for more info.
//
// Copyright 2016-2022 Nonpolynomial Labs LLC. All rights reserved.
//
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
// for full license information.

use crate::core::errors::ButtplugDeviceError::ProtocolSpecificError;
use crate::core::message::ActuatorType;
use crate::core::message::ActuatorType::{Rotate, Vibrate};
use crate::{
  core::{errors::ButtplugDeviceError, message::Endpoint},
  server::device::{
    hardware::{HardwareCommand, HardwareWriteCmd},
    protocol::{generic_protocol_setup, ProtocolHandler},
  },
};

generic_protocol_setup!(Cowgirl, "cowgirl");

#[derive(Default)]
pub struct Cowgirl {}

impl ProtocolHandler for Cowgirl {
  fn keepalive_strategy(&self) -> super::ProtocolKeepaliveStrategy {
    super::ProtocolKeepaliveStrategy::RepeatLastPacketStrategy
  }

  fn needs_full_command_set(&self) -> bool {
    true
  }

  fn handle_scalar_cmd(
    &self,
    commands: &[Option<(ActuatorType, u32)>],
  ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> {
    let mut data: Vec<u8> = vec![0x00, 0x01];
    if commands.len() != 2 {
      return Err(ProtocolSpecificError(
        "cowgirl".to_owned(),
        format!("Expected 2 attributes, got {}", commands.len()),
      ));
    }

    if let Some(cmd) = commands[0] {
      if cmd.0 != Vibrate {
        return Err(ProtocolSpecificError(
          "cowgirl".to_owned(),
          format!("Expected Vibrate attribute, got {:?}", cmd.0),
        ));
      }
      data.push(cmd.1 as u8);
    } else {
      return Err(ProtocolSpecificError(
        "cowgirl".to_owned(),
        "Attribute 0 is None".to_owned(),
      ));
    }

    if let Some(cmd) = commands[1] {
      if cmd.0 != Rotate {
        return Err(ProtocolSpecificError(
          "cowgirl".to_owned(),
          format!("Expected Rotate attribute, got {:?}", cmd.0),
        ));
      }
      data.push(cmd.1 as u8);
    } else {
      return Err(ProtocolSpecificError(
        "cowgirl".to_owned(),
        "Attribute 1 is None".to_owned(),
      ));
    }

    Ok(vec![HardwareWriteCmd::new(Endpoint::Tx, data, true).into()])
  }
}