use super::ControllerInput;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PowerPadState {
pub strobe: bool,
pub bit_index: u8,
pub button_states: u16,
}
pub struct PowerPad {
strobe: bool,
bit_index: u8,
button_states: u16,
}
impl Default for PowerPad {
fn default() -> Self {
Self::new()
}
}
impl PowerPad {
const D3_ORDER: [crate::nes::input::PowerPadButton; 8] = [
crate::nes::input::PowerPadButton::Two,
crate::nes::input::PowerPadButton::One,
crate::nes::input::PowerPadButton::Five,
crate::nes::input::PowerPadButton::Nine,
crate::nes::input::PowerPadButton::Six,
crate::nes::input::PowerPadButton::Ten,
crate::nes::input::PowerPadButton::Eleven,
crate::nes::input::PowerPadButton::Seven,
];
const D4_ORDER: [Option<crate::nes::input::PowerPadButton>; 8] = [
Some(crate::nes::input::PowerPadButton::Four),
Some(crate::nes::input::PowerPadButton::Three),
Some(crate::nes::input::PowerPadButton::Twelve),
Some(crate::nes::input::PowerPadButton::Eight),
None,
None,
None,
None,
];
pub fn new() -> Self {
Self {
strobe: false,
bit_index: 0,
button_states: 0,
}
}
pub fn write_strobe(&mut self, value: u8) {
let new_strobe = value & 0x01 != 0;
if self.strobe && !new_strobe {
self.bit_index = 0;
}
self.strobe = new_strobe;
}
pub fn read(&mut self, is_dummy_read: bool) -> u8 {
let index = self.bit_index as usize;
let d3 = if index < 8 {
self.button_is_pressed(Self::D3_ORDER[index])
} else {
true
};
let d4 = if index < 8 {
match Self::D4_ORDER[index] {
Some(button) => self.button_is_pressed(button),
None => true,
}
} else {
true
};
if !self.strobe && !is_dummy_read {
self.bit_index = self.bit_index.saturating_add(1);
}
((d3 as u8) << 3) | ((d4 as u8) << 4)
}
pub fn set_button(&mut self, button: crate::nes::input::PowerPadButton, pressed: bool) {
let bit = button as u8;
if pressed {
self.button_states |= 1 << bit;
} else {
self.button_states &= !(1 << bit);
}
}
fn button_is_pressed(&self, button: crate::nes::input::PowerPadButton) -> bool {
(self.button_states & (1 << (button as u8))) != 0
}
pub fn capture_state(&self) -> PowerPadState {
PowerPadState {
strobe: self.strobe,
bit_index: self.bit_index,
button_states: self.button_states,
}
}
pub fn restore_state(&mut self, state: &PowerPadState) {
self.strobe = state.strobe;
self.bit_index = state.bit_index;
self.button_states = state.button_states;
}
}
impl crate::nes::input::Controller for PowerPad {
fn write_strobe(&mut self, value: u8) {
self.write_strobe(value);
}
fn read(&mut self, is_dummy_read: bool) -> u8 {
self.read(is_dummy_read)
}
fn capture_state(&self) -> crate::nes::input::ControllerState {
crate::nes::input::ControllerState::PowerPad(self.capture_state())
}
fn restore_state(&mut self, state: &crate::nes::input::ControllerState) {
if let crate::nes::input::ControllerState::PowerPad(power_pad_state) = state {
self.restore_state(power_pad_state);
}
}
fn set_button(&mut self, _button: crate::nes::input::Button, _pressed: bool) -> bool {
false
}
fn set_power_pad_button(
&mut self,
button: crate::nes::input::PowerPadButton,
pressed: bool,
) -> bool {
self.set_button(button, pressed);
true
}
fn set_mouse_x_position(&mut self, _position: u8) -> bool {
false
}
fn set_mouse_y_position(&mut self, _position: u8) -> bool {
false
}
fn set_mouse_left_button(&mut self, _pressed: bool) -> bool {
false
}
fn input_type(&self) -> ControllerInput {
crate::nes::input::controller_input_type(crate::nes::input::ControllerType::PowerPad)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nes::input::PowerPadButton;
#[test]
fn test_power_pad_shifts_buttons_in_protocol_order() {
let mut power_pad = PowerPad::new();
power_pad.set_button(PowerPadButton::One, true);
power_pad.set_button(PowerPadButton::Four, true);
power_pad.set_button(PowerPadButton::Twelve, true);
power_pad.write_strobe(1);
power_pad.write_strobe(0);
let expected = [
0x10, 0x08, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, ];
for expected_value in expected {
assert_eq!(power_pad.read(false) & 0x18, expected_value);
}
}
#[test]
fn test_power_pad_capture_restore_state_roundtrip() {
let mut power_pad = PowerPad::new();
power_pad.set_button(PowerPadButton::Two, true);
power_pad.set_button(PowerPadButton::Eight, true);
power_pad.write_strobe(1);
power_pad.write_strobe(0);
power_pad.read(false);
power_pad.read(false);
let state = power_pad.capture_state();
let mut restored = PowerPad::new();
restored.restore_state(&state);
assert_eq!(restored.capture_state().button_states, state.button_states);
assert_eq!(restored.capture_state().bit_index, state.bit_index);
assert_eq!(restored.capture_state().strobe, state.strobe);
}
#[test]
fn test_power_pad_does_not_support_standard_joypad_buttons() {
let mut power_pad = PowerPad::new();
assert!(!crate::nes::input::Controller::set_button(
&mut power_pad,
crate::nes::input::Button::A,
true
));
}
}