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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//! Namco's JogCon Controller
//! ============================
//! This controller has a jog wheel in the center which is controlled by a
//! motor to provide force feedback. Only three games support the controller
//! but it is featureful enough that it can be treated as a servo motor with
//! little effort.

use classic::GamepadButtons;
use byteorder::{
    ByteOrder,
    LittleEndian
};
use super::{
    HasStandardButtons,
    PollCommand,
};

/// What we want the JogCon's wheel to do after we
/// poll it
#[derive(Clone)]
pub enum JogControl {
    /// Stop the motor
    Stop = 0x00,
    /// Hold the wheel in position (and return it if it moves)
    Hold = 0x30,
    /// Start turning the wheel left
    Left = 0x20,
    /// Start turning the wheel right
    Right = 0x10,
    /// Drop how many revolutions were turned and keep track of
    /// only the distance to return to the original angle
    DropRevolutions = 0x80,
    /// Drop how many revolutions were turned and return back
    /// to the starting angle
    DropAndHold = 0xb0,
    /// Set a new hold position
    NewHold = 0xc0,
}

/// What state the JogCon's wheel was in last poll
pub enum JogState {
    /// The wheel was turned left
    TurnedLeft,
    /// The wheel was turned right
    TurnedRight,
    /// The wheel met its maximum recordable distance
    AtMaximum
}

#[repr(C)]
/// Represents the Namco JogCon controller
pub struct JogCon {
    // TODO: Implement an endian-safe accessor for jog_position
    // TODO: Implement an enum accessor for jog_state

    /// Standard buttons (Cross, Circle, L3, Start, etc)
    pub buttons: GamepadButtons,

    /// The absolute position of the jog wheel
    jog_position: [u8; 2],

    /// What state is the jog wheel in
    pub jog_state: u8,
}

impl JogCon {
    /// The absolute position of the jog wheel
    pub fn jog_position(&self) -> i16 {
        LittleEndian::read_i16(&self.jog_position)
    }
}

impl HasStandardButtons for JogCon {
    fn buttons(&self) -> GamepadButtons {
        self.buttons.clone()
    }
}

/// Command for controlling the wheel on the JogCon
pub struct ControlJC {
    /// The mode the wheel should be in (move left, move right, etc)
	pub mode: JogControl,
    /// How strong the motor should be working
	pub strength: u8,
}

impl ControlJC {
    /// Create a new one of thes newfangled control commands
    pub fn new(mode: JogControl, strength: u8) -> Self {
        Self {
            mode: mode,
            strength: strength,
        }
    }
}

/// Implement the needed functions to control the motor on the JogCon
impl PollCommand for ControlJC {
    /// Sets the command for the wheel on the JogCon
    fn set_command(&self, command: &mut [u8]) {
        command[0] = self.mode.clone() as u8;
        command[0] |= self.strength & 0x0f;
    }
}