Skip to content

Commit

Permalink
merge: prepare for coin/bill hardware
Browse files Browse the repository at this point in the history
  • Loading branch information
LiteHell committed Jun 10, 2024
2 parents fb50f95 + 088fdfe commit 737a0d8
Show file tree
Hide file tree
Showing 27 changed files with 639 additions and 178 deletions.
13 changes: 11 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
members = [
"game",
"data-struct-lib",
"chart-recorder"
"chart-recorder",
"controller-lib"
]

[profile.dev.package.kira]
Expand Down
11 changes: 11 additions & 0 deletions controller-lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "bidrum-controller-lib"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bidrum-data-struct-lib = { path = "../data-struct-lib" }
serialport = "4.3.0"
device_query = "2.0.0"
2 changes: 2 additions & 0 deletions controller-lib/src/keyboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod coin_device;
pub mod janggu_device;
70 changes: 70 additions & 0 deletions controller-lib/src/keyboard/coin_device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::{
sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc,
},
time::Duration,
};

use device_query::{DeviceQuery, DeviceState, Keycode};

use crate::CoinInputDevice;

/// United bidrum controller of Janggu and Coin/Bill acceptor
pub struct KeyboardCoinDevice {
unconsumed_coins: Arc<AtomicU32>,
stopping: Arc<AtomicBool>,
}

impl Drop for KeyboardCoinDevice {
fn drop(&mut self) {
self.stopping.store(true, Ordering::Relaxed);
}
}

impl CoinInputDevice for KeyboardCoinDevice {
fn get_unconsumed_coins(&self) -> u32 {
self.unconsumed_coins.load(Ordering::Relaxed)
}

fn consume_coins(&mut self, coins: u32) {
self.unconsumed_coins.fetch_sub(coins, Ordering::Relaxed);
}
}

impl KeyboardCoinDevice {
pub fn new() -> KeyboardCoinDevice {
let unconsumed_coins = Arc::new(AtomicU32::new(0));
let stopping = Arc::new(AtomicBool::new(false));

{
let unconsumed_coins = unconsumed_coins.clone();

let _stopping = stopping.clone();

std::thread::spawn(move || {
let mut pressed = false;
let device_state = DeviceState::new();
loop {
let new_pressed = device_state.get_keys().contains(&Keycode::C);
if new_pressed && !pressed {
// increase one on keydown
unconsumed_coins.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}

pressed = new_pressed;
std::thread::sleep(Duration::from_millis(10));
}
});
}

KeyboardCoinDevice {
unconsumed_coins: unconsumed_coins,
stopping: stopping,
}
}
}

fn has_coin_bit(bits: u8) -> bool {
bits & 16 != 0
}
94 changes: 94 additions & 0 deletions controller-lib/src/keyboard/janggu_device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use std::{
sync::{
atomic::{AtomicBool, AtomicU8, Ordering},
Arc, RwLock,
},
thread,
};

use bidrum_data_struct_lib::janggu::{JangguFace, JangguInputState};
use device_query::{DeviceQuery, DeviceState, Keycode};

use crate::JangguDevice;

pub struct KeyboardJangguDevice {
stopping: Arc<AtomicBool>,
// Using RwLock<JangguInputState> is too slow
state: Arc<AtomicU8>,
}

impl KeyboardJangguDevice {
pub fn new() -> KeyboardJangguDevice {
let stopping = Arc::new(AtomicBool::new(false));
let state = Arc::new(AtomicU8::new(0));

{
let stopping = stopping.clone();
let state = state.clone();

thread::spawn(move || {
let mut device_states = DeviceState::new();
loop {
if stopping.load(Ordering::Relaxed) {
break;
}

state.store(keyboard_to_bits(&mut device_states), Ordering::Relaxed);
}
});
}

KeyboardJangguDevice {
state: state,
stopping: stopping,
}
}
}

impl Drop for KeyboardJangguDevice {
fn drop(&mut self) {
self.stopping.store(true, Ordering::Relaxed);
}
}

impl JangguDevice for KeyboardJangguDevice {
fn read_janggu_input_state(&self) -> JangguInputState {
bits_to_janggu_input_state(self.state.load(Ordering::Relaxed))
}
}

fn bits_to_janggu_input_state(bits: u8) -> JangguInputState {
JangguInputState {
궁채: if bits & 1 != 0 {
Some(JangguFace::궁편)
} else if bits & 2 != 0 {
Some(JangguFace::열편)
} else {
None
},
열채: if bits & 4 != 0 {
Some(JangguFace::궁편)
} else if bits & 8 != 0 {
Some(JangguFace::열편)
} else {
None
},
}
}

fn keyboard_to_bits(device_states: &mut DeviceState) -> u8 {
let keys = device_states.get_keys();
let mut bits = 0;
if keys.contains(&Keycode::D) {
bits |= 1;
} else if keys.contains(&Keycode::F) {
bits |= 2;
}
if keys.contains(&Keycode::J) {
bits |= 4;
} else if keys.contains(&Keycode::K) {
bits |= 8;
}

return bits;
}
17 changes: 17 additions & 0 deletions controller-lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pub mod keyboard;
pub mod serial;

use bidrum_data_struct_lib::janggu::JangguInputState;

/// Bidrum Janggu Controller
pub trait JangguDevice {
/// Reads janggu controller input state
fn read_janggu_input_state(&self) -> JangguInputState;
}

/// Bidrum Coin/Bill Acceptor
pub trait CoinInputDevice {
/// Reads unconsumed coin count
fn get_unconsumed_coins(&self) -> u32;
fn consume_coins(&mut self, coins: u32);
}
15 changes: 15 additions & 0 deletions controller-lib/src/serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mod coin_device;
mod janggu_device;
mod serial_reader;

use coin_device::SerialCoinDevice;
use janggu_device::SerialJangguDevice;
use serial_reader::BidrumSerialReader;

pub fn new(serial_port: String) -> (SerialJangguDevice, SerialCoinDevice) {
let serial_reader = BidrumSerialReader::new(serial_port);
return (
SerialJangguDevice::new(serial_reader.clone()),
SerialCoinDevice::new(serial_reader.clone()),
);
}
72 changes: 72 additions & 0 deletions controller-lib/src/serial/coin_device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::{
sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc,
},
thread::{self},
};

use crate::CoinInputDevice;

use super::serial_reader::BidrumSerialReader;

/// United bidrum controller of Janggu and Coin/Bill acceptor
pub struct SerialCoinDevice {
serial_reader: BidrumSerialReader,
unconsumed_coins: Arc<AtomicU32>,
stopping: Arc<AtomicBool>,
}

impl Drop for SerialCoinDevice {
fn drop(&mut self) {
self.stopping.store(true, Ordering::Relaxed);
}
}

impl CoinInputDevice for SerialCoinDevice {
fn get_unconsumed_coins(&self) -> u32 {
self.unconsumed_coins.load(Ordering::Relaxed)
}

fn consume_coins(&mut self, coins: u32) {
self.unconsumed_coins.fetch_sub(coins, Ordering::Relaxed);
}
}

impl SerialCoinDevice {
pub(super) fn new(serial_reader: BidrumSerialReader) -> SerialCoinDevice {
let unconsumed_coins = Arc::new(AtomicU32::new(0));
let stopping = Arc::new(AtomicBool::new(false));

{
let unconsumed_coins = unconsumed_coins.clone();
let bits = serial_reader.bits.clone();
let stopping = stopping.clone();
thread::spawn(move || {
let mut prev = false;
loop {
if stopping.load(Ordering::Relaxed) {
break;
}

let current = has_coin_bit(bits.load(Ordering::Relaxed));
if !prev && current {
unconsumed_coins.fetch_add(1, Ordering::Relaxed);
}

prev = current;
}
});
}

SerialCoinDevice {
serial_reader: serial_reader,
unconsumed_coins: unconsumed_coins,
stopping: stopping,
}
}
}

fn has_coin_bit(bits: u8) -> bool {
bits & 16 != 0
}
44 changes: 44 additions & 0 deletions controller-lib/src/serial/janggu_device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::sync::atomic::Ordering;

use bidrum_data_struct_lib::janggu::{JangguFace, JangguInputState};

use crate::JangguDevice;

use super::serial_reader::BidrumSerialReader;

pub struct SerialJangguDevice {
serial_reader: BidrumSerialReader,
}

impl SerialJangguDevice {
pub(super) fn new(serial_reader: BidrumSerialReader) -> SerialJangguDevice {
SerialJangguDevice {
serial_reader: serial_reader,
}
}
}

impl JangguDevice for SerialJangguDevice {
fn read_janggu_input_state(&self) -> JangguInputState {
return parse_janggu_bits(self.serial_reader.bits.load(Ordering::Relaxed));
}
}

fn parse_janggu_bits(bits: u8) -> JangguInputState {
return JangguInputState {
궁채: if bits & 1 != 0 {
Some(JangguFace::궁편)
} else if bits & 2 != 0 {
Some(JangguFace::열편)
} else {
None
},
열채: if bits & 4 != 0 {
Some(JangguFace::궁편)
} else if bits & 8 != 0 {
Some(JangguFace::열편)
} else {
None
},
};
}
Loading

0 comments on commit 737a0d8

Please sign in to comment.