1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-27 23:10:49 +01:00

refactor state structs

This commit is contained in:
4yn 2022-02-13 15:50:03 +08:00
parent 2a0d466cf3
commit ac4933449b
11 changed files with 147 additions and 168 deletions

View File

@ -4,7 +4,6 @@ use std::sync::{atomic::Ordering, Arc};
use crate::{
config::Config,
controller_state::FullState,
device::{brokenithm::BrokenithmJob, config::DeviceMode, device::HidDeviceJob},
lighting::{config::LedMode, led::LedJob},
output::{config::OutputMode, output::OutputJob},
@ -12,11 +11,12 @@ use crate::{
utils::LoopTimer,
worker::{AsyncHaltableWorker, AsyncWorker, ThreadWorker},
},
state::SliderState,
};
#[allow(dead_code)]
pub struct Context {
state: FullState,
state: SliderState,
config: Config,
device_worker: Option<ThreadWorker>,
brokenithm_worker: Option<AsyncHaltableWorker>,
@ -32,7 +32,7 @@ impl Context {
info!("Output config {:?}", config.output_mode);
info!("LED config {:?}", config.led_mode);
let state = FullState::new();
let state = SliderState::new();
let mut timers = vec![];
let (device_worker, brokenithm_worker) = match &config.device_mode {
@ -96,7 +96,7 @@ impl Context {
}
}
pub fn clone_state(&self) -> FullState {
pub fn clone_state(&self) -> SliderState {
self.state.clone()
}

View File

@ -18,7 +18,7 @@ use tokio::{
use tokio_tungstenite::WebSocketStream;
use tungstenite::{handshake, Message};
use crate::{controller_state::FullState, shared::worker::AsyncHaltableJob};
use crate::{shared::worker::AsyncHaltableJob, state::SliderState};
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
@ -68,7 +68,7 @@ async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
async fn handle_brokenithm(
ws_stream: WebSocketStream<Upgraded>,
state: FullState,
state: SliderState,
led_enabled: bool,
) {
let (mut ws_write, mut ws_read) = ws_stream.split();
@ -114,15 +114,15 @@ async fn handle_brokenithm(
}
39 => {
if chars[0] == 'b' {
let mut controller_state_handle = state_handle.controller_state.lock();
let mut input_handle = state_handle.input.lock();
for (idx, c) in chars[0..32].iter().enumerate() {
controller_state_handle.ground_state[idx] = match *c == '1' {
input_handle.ground[idx] = match *c == '1' {
false => 0,
true => 255,
}
}
for (idx, c) in chars[32..38].iter().enumerate() {
controller_state_handle.air_state[idx] = match *c == '1' {
input_handle.air[idx] = match *c == '1' {
false => 0,
true => 1,
}
@ -167,8 +167,8 @@ async fn handle_brokenithm(
loop {
let mut led_data = vec![0; 93];
{
let led_state_handle = state_handle.led_state.lock();
(&mut led_data).copy_from_slice(&led_state_handle.led_state);
let lights_handle = state_handle.lights.lock();
(&mut led_data).copy_from_slice(&lights_handle.ground);
}
msg_write_handle.send(Message::Binary(led_data)).ok();
@ -187,7 +187,7 @@ async fn handle_brokenithm(
async fn handle_websocket(
mut request: Request<Body>,
state: FullState,
state: SliderState,
led_enabled: bool,
) -> Result<Response<Body>, Infallible> {
let res = match handshake::server::create_response_with_body(&request, || Body::empty()) {
@ -227,7 +227,7 @@ async fn handle_websocket(
async fn handle_request(
request: Request<Body>,
remote_addr: SocketAddr,
state: FullState,
state: SliderState,
ground_only: bool,
led_enabled: bool,
) -> Result<Response<Body>, Infallible> {
@ -257,13 +257,13 @@ async fn handle_request(
}
pub struct BrokenithmJob {
state: FullState,
state: SliderState,
ground_only: bool,
led_enabled: bool,
}
impl BrokenithmJob {
pub fn new(state: &FullState, ground_only: &bool, led_enabled: &bool) -> Self {
pub fn new(state: &SliderState, ground_only: &bool, led_enabled: &bool) -> Self {
Self {
state: state.clone(),
ground_only: *ground_only,

View File

@ -8,17 +8,17 @@ use std::{
};
use crate::{
controller_state::{ControllerState, FullState, LedState},
shared::{
utils::{Buffer, ShimError},
worker::ThreadJob,
},
state::{SliderInput, SliderLights, SliderState},
};
use super::config::HardwareSpec;
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
type HidLedCallback = fn(&mut Buffer, &LedState) -> ();
type HidReadCallback = fn(&Buffer, &mut SliderInput) -> ();
type HidLedCallback = fn(&mut Buffer, &SliderLights) -> ();
enum WriteType {
Bulk,
@ -26,7 +26,7 @@ enum WriteType {
}
pub struct HidDeviceJob {
state: FullState,
state: SliderState,
vid: u16,
pid: u16,
@ -46,7 +46,7 @@ pub struct HidDeviceJob {
impl HidDeviceJob {
fn new(
state: FullState,
state: SliderState,
vid: u16,
pid: u16,
read_endpoint: u8,
@ -71,7 +71,7 @@ impl HidDeviceJob {
}
}
pub fn from_config(state: &FullState, spec: &HardwareSpec) -> Self {
pub fn from_config(state: &SliderState, spec: &HardwareSpec) -> Self {
match spec {
HardwareSpec::TasollerOne => Self::new(
state.clone(),
@ -79,7 +79,7 @@ impl HidDeviceJob {
0x2333,
0x84,
0x03,
|buf, controller_state| {
|buf, input| {
if buf.len != 11 {
return;
}
@ -90,15 +90,15 @@ impl HidDeviceJob {
.flat_map(|x| (0..8).map(move |i| ((x) >> i) & 1))
.collect();
for i in 0..32 {
controller_state.ground_state[i] = bits[34 + i] * 255;
input.ground[i] = bits[34 + i] * 255;
}
controller_state.flip_vert();
input.flip_vert();
controller_state.air_state.copy_from_slice(&bits[28..34]);
controller_state.extra_state[0..2].copy_from_slice(&bits[26..28]);
input.air.copy_from_slice(&bits[28..34]);
input.extra[0..2].copy_from_slice(&bits[26..28]);
},
WriteType::Bulk,
|buf, led_state| {
|buf, lights| {
buf.len = 240;
buf.data[0] = 'B' as u8;
buf.data[1] = 'L' as u8;
@ -106,7 +106,7 @@ impl HidDeviceJob {
for (buf_chunk, state_chunk) in buf.data[3..96]
.chunks_mut(3)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
.zip(lights.ground.chunks(3).rev())
{
buf_chunk[0] = state_chunk[1];
buf_chunk[1] = state_chunk[0];
@ -121,22 +121,20 @@ impl HidDeviceJob {
0x2333,
0x84,
0x03,
|buf, controller_state| {
|buf, input| {
if buf.len != 36 {
return;
}
controller_state
.ground_state
.copy_from_slice(&buf.data[4..36]);
controller_state.flip_vert();
input.ground.copy_from_slice(&buf.data[4..36]);
input.flip_vert();
let bits: Vec<u8> = (0..8).map(|x| (buf.data[3] >> x) & 1).collect();
controller_state.air_state.copy_from_slice(&bits[0..6]);
controller_state.extra_state[0..2].copy_from_slice(&bits[6..8]);
input.air.copy_from_slice(&bits[0..6]);
input.extra[0..2].copy_from_slice(&bits[6..8]);
},
WriteType::Bulk,
|buf, led_state| {
|buf, lights| {
buf.len = 240;
buf.data[0] = 'B' as u8;
buf.data[1] = 'L' as u8;
@ -144,7 +142,7 @@ impl HidDeviceJob {
for (buf_chunk, state_chunk) in buf.data[3..96]
.chunks_mut(3)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
.zip(lights.ground.chunks(3).rev())
{
buf_chunk[0] = state_chunk[1];
buf_chunk[1] = state_chunk[0];
@ -159,29 +157,27 @@ impl HidDeviceJob {
0x2001,
0x81,
0x02,
|buf, controller_state| {
|buf, input| {
if buf.len != 34 {
return;
}
controller_state
.ground_state
.copy_from_slice(&buf.data[2..34]);
input.ground.copy_from_slice(&buf.data[2..34]);
for i in 0..6 {
controller_state.air_state[i ^ 1] = (buf.data[0] >> i) & 1;
input.air[i ^ 1] = (buf.data[0] >> i) & 1;
}
for i in 0..3 {
controller_state.extra_state[2 - i] = (buf.data[1] >> i) & 1;
input.extra[2 - i] = (buf.data[1] >> i) & 1;
}
},
WriteType::Interrupt,
|buf, led_state| {
|buf, lights| {
buf.len = 31 * 2;
for (buf_chunk, state_chunk) in buf
.data
.chunks_mut(2)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
.zip(lights.ground.chunks(3).rev())
{
buf_chunk[0] = (state_chunk[0] << 3 & 0xe0) | (state_chunk[2] >> 3);
buf_chunk[1] = (state_chunk[1] & 0xf8) | (state_chunk[0] >> 5);
@ -248,8 +244,8 @@ impl ThreadJob for HidDeviceJob {
// if self.read_buf.len != 0 {
if (self.read_buf.len != 0) && (self.read_buf.slice() != self.last_read_buf.slice()) {
work = true;
let mut controller_state_handle = self.state.controller_state.lock();
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
let mut input_handle = self.state.input.lock();
(self.read_callback)(&self.read_buf, input_handle.deref_mut());
swap(&mut self.read_buf, &mut self.last_read_buf);
}
}
@ -257,10 +253,10 @@ impl ThreadJob for HidDeviceJob {
// Led loop
{
{
let mut led_state_handle = self.state.led_state.lock();
if led_state_handle.dirty {
(self.led_callback)(&mut self.led_buf, led_state_handle.deref());
led_state_handle.dirty = false;
let mut lights_handle = self.state.lights.lock();
if lights_handle.dirty {
(self.led_callback)(&mut self.led_buf, lights_handle.deref());
lights_handle.dirty = false;
}
}

View File

@ -6,8 +6,8 @@
#![feature(more_qualified_paths)]
mod config;
mod controller_state;
mod shared;
mod state;
mod device;
mod lighting;

View File

@ -9,14 +9,14 @@ use std::{
use tokio::time::{interval, Interval};
use crate::{
controller_state::{FullState, LedState},
shared::{utils::Buffer, voltex::VoltexState, worker::AsyncJob},
state::{SliderLights, SliderState},
};
use super::config::{LedMode, ReactiveLayout};
pub struct LedJob {
state: FullState,
state: SliderState,
mode: LedMode,
serial_port: Option<Box<dyn SerialPort>>,
started: Instant,
@ -24,7 +24,7 @@ pub struct LedJob {
}
impl LedJob {
pub fn new(state: &FullState, mode: &LedMode) -> Self {
pub fn new(state: &SliderState, mode: &LedMode) -> Self {
Self {
state: state.clone(),
mode: mode.clone(),
@ -36,26 +36,26 @@ impl LedJob {
fn calc_lights(
&self,
flat_controller_state: Option<&Vec<bool>>,
flat_input: Option<&Vec<bool>>,
serial_buffer: Option<&Buffer>,
led_state: &mut LedState,
lights: &mut SliderLights,
) {
match self.mode {
LedMode::Reactive { layout, .. } => {
let flat_controller_state = flat_controller_state.unwrap();
let flat_input = flat_input.unwrap();
match layout {
ReactiveLayout::Even { splits } => {
let buttons_per_split = 32 / splits;
let banks: Vec<bool> = flat_controller_state
let banks: Vec<bool> = flat_input
.chunks(32 / splits)
.take(splits)
.map(|x| x.contains(&true))
.collect();
for idx in 0..31 {
led_state.paint(
lights.paint(
idx,
match (idx + 1) % buttons_per_split {
0 => &[255, 0, 255],
@ -68,49 +68,49 @@ impl LedJob {
}
}
ReactiveLayout::Voltex => {
led_state.led_state.fill(0);
lights.ground.fill(0);
// Fixed
led_state.paint(3, &[10, 100, 180]);
lights.paint(3, &[10, 100, 180]);
for idx in 0..5 {
led_state.paint(7 + idx * 4, &[64, 64, 64]);
lights.paint(7 + idx * 4, &[64, 64, 64]);
}
led_state.paint(27, &[180, 10, 110]);
lights.paint(27, &[180, 10, 110]);
let voltex_state = VoltexState::from_flat(flat_controller_state);
let voltex_input = VoltexState::from_flat(flat_input);
// Left laser
for (idx, state) in voltex_state.laser[0..2].iter().enumerate() {
for (idx, state) in voltex_input.laser[0..2].iter().enumerate() {
if *state {
led_state.paint(0 + idx * 4, &[70, 230, 250]);
led_state.paint(1 + idx * 4, &[70, 230, 250]);
led_state.paint(2 + idx * 4, &[70, 230, 250]);
lights.paint(0 + idx * 4, &[70, 230, 250]);
lights.paint(1 + idx * 4, &[70, 230, 250]);
lights.paint(2 + idx * 4, &[70, 230, 250]);
}
}
// Right laser
for (idx, state) in voltex_state.laser[2..4].iter().enumerate() {
for (idx, state) in voltex_input.laser[2..4].iter().enumerate() {
if *state {
led_state.paint(24 + idx * 4, &[250, 60, 200]);
led_state.paint(25 + idx * 4, &[255, 60, 200]);
led_state.paint(26 + idx * 4, &[255, 60, 200]);
lights.paint(24 + idx * 4, &[250, 60, 200]);
lights.paint(25 + idx * 4, &[255, 60, 200]);
lights.paint(26 + idx * 4, &[255, 60, 200]);
}
}
// Buttons
for (idx, state) in voltex_state.bt.iter().enumerate() {
for (idx, state) in voltex_input.bt.iter().enumerate() {
if *state {
led_state.paint(8 + idx * 4, &[255, 255, 255]);
led_state.paint(10 + idx * 4, &[255, 255, 255]);
lights.paint(8 + idx * 4, &[255, 255, 255]);
lights.paint(10 + idx * 4, &[255, 255, 255]);
}
}
// Fx
for (idx, state) in voltex_state.fx.iter().enumerate() {
for (idx, state) in voltex_input.fx.iter().enumerate() {
if *state {
led_state.paint(9 + idx * 8, &[250, 100, 30]);
led_state.paint(11 + idx * 8, &[250, 100, 30]);
led_state.paint(13 + idx * 8, &[250, 100, 30]);
lights.paint(9 + idx * 8, &[250, 100, 30]);
lights.paint(11 + idx * 8, &[250, 100, 30]);
lights.paint(13 + idx * 8, &[250, 100, 30]);
}
}
}
@ -125,7 +125,7 @@ impl LedJob {
for idx in 0..31 {
let slice_theta = (&theta + (idx as f64) / 32.0) % 1.0;
let color = Srgb::from_color(Hsv::new(slice_theta * 360.0, 1.0, 1.0)).into_format::<u8>();
led_state.paint(idx, &[color.red, color.green, color.blue]);
lights.paint(idx, &[color.red, color.green, color.blue]);
}
}
LedMode::Serial { .. } => {
@ -142,16 +142,15 @@ impl LedJob {
.rev()
.enumerate()
{
led_state.paint(idx, &[(*buf_chunk)[1], (*buf_chunk)[2], (*buf_chunk)[0]]);
lights.paint(idx, &[(*buf_chunk)[1], (*buf_chunk)[2], (*buf_chunk)[0]]);
}
// println!("leds {:?}", led_state.led_state);
}
}
}
_ => panic!("Not implemented"),
}
led_state.dirty = true;
lights.dirty = true;
}
}
@ -183,14 +182,14 @@ impl AsyncJob for LedJob {
}
async fn tick(&mut self) -> bool {
let mut flat_controller_state: Option<Vec<bool>> = None;
let mut flat_input: Option<Vec<bool>> = None;
let mut serial_buffer: Option<Buffer> = None;
// Do the IO here
match self.mode {
LedMode::Reactive { sensitivity, .. } => {
let controller_state_handle = self.state.controller_state.lock();
flat_controller_state = Some(controller_state_handle.to_flat(&sensitivity));
let input_handle = self.state.input.lock();
flat_input = Some(input_handle.to_flat(&sensitivity));
}
LedMode::Serial { .. } => {
if let Some(serial_port) = self.serial_port.as_mut() {
@ -218,15 +217,13 @@ impl AsyncJob for LedJob {
// Then calculate and transfer
{
let mut led_state_handle = self.state.led_state.lock();
let mut lights_handle = self.state.lights.lock();
self.calc_lights(
flat_controller_state.as_ref(),
flat_input.as_ref(),
serial_buffer.as_ref(),
led_state_handle.deref_mut(),
lights_handle.deref_mut(),
);
}
// thread::sleep(Duration::from_millis(30));
// spin_sleep::sleep(Duration::from_micros(33333));
self.timer.tick().await;
true

View File

@ -9,10 +9,10 @@ use tokio::{
sync::{mpsc, oneshot},
};
use crate::{config::Config, context::Context, controller_state::FullState};
use crate::{config::Config, context::Context, state::SliderState};
pub struct Manager {
state: Arc<Mutex<Option<FullState>>>,
state: Arc<Mutex<Option<SliderState>>>,
context: Arc<Mutex<Option<Context>>>,
join_handle: Option<JoinHandle<()>>,
tx_config: mpsc::UnboundedSender<Config>,
@ -81,7 +81,7 @@ impl Manager {
self.tx_config.send(config).unwrap();
}
pub fn try_get_state(&self) -> Option<FullState> {
pub fn try_get_state(&self) -> Option<SliderState> {
let state_handle = self.state.lock();
state_handle.as_ref().map(|x| x.clone())
}

View File

@ -95,8 +95,8 @@ impl GamepadOutput {
}
impl OutputHandler for GamepadOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
let voltex_state = VoltexState::from_flat(flat_controller_state);
fn tick(&mut self, flat_input: &Vec<bool>) -> bool {
let voltex_state = VoltexState::from_flat(flat_input);
let buttons = voltex_state
.bt
@ -123,15 +123,13 @@ impl OutputHandler for GamepadOutput {
});
let lx = self.left_wind.update(
voltex_state.laser[0] || (self.use_air && flat_controller_state[32]),
voltex_state.laser[1]
|| (self.use_air && (flat_controller_state[33] || flat_controller_state[34])),
voltex_state.laser[0] || (self.use_air && flat_input[32]),
voltex_state.laser[1] || (self.use_air && (flat_input[33] || flat_input[34])),
) * 20000;
let rx = self.right_wind.update(
voltex_state.laser[2]
|| (self.use_air && (flat_controller_state[35] || flat_controller_state[36])),
voltex_state.laser[3] || (self.use_air && flat_controller_state[37]),
voltex_state.laser[2] || (self.use_air && (flat_input[35] || flat_input[36])),
voltex_state.laser[3] || (self.use_air && flat_input[37]),
) * 20000;
let mut dirty = false;

View File

@ -187,9 +187,9 @@ impl KeyboardOutput {
}
impl OutputHandler for KeyboardOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
fn tick(&mut self, flat_input: &Vec<bool>) -> bool {
self.next_keys.fill(false);
for (idx, x) in flat_controller_state.iter().enumerate() {
for (idx, x) in flat_input.iter().enumerate() {
if *x {
self.next_keys[self.ground_to_idx[idx]] = true;
}

View File

@ -3,22 +3,17 @@ use log::error;
use std::time::Duration;
use tokio::time::{interval, Interval};
// use crate::slider_io::{
// config::OutputMode, controller_state::FullState, gamepad::GamepadOutput,
// keyboard::KeyboardOutput, worker::AsyncJob,
// };
use crate::{controller_state::FullState, shared::worker::AsyncJob};
use crate::{shared::worker::AsyncJob, state::SliderState};
use super::{config::OutputMode, gamepad::GamepadOutput, keyboard::KeyboardOutput};
pub trait OutputHandler: Send {
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool;
fn tick(&mut self, flat_input: &Vec<bool>) -> bool;
fn reset(&mut self);
}
pub struct OutputJob {
state: FullState,
state: SliderState,
mode: OutputMode,
sensitivity: u8,
handler: Option<Box<dyn OutputHandler>>,
@ -26,7 +21,7 @@ pub struct OutputJob {
}
impl OutputJob {
pub fn new(state: &FullState, mode: &OutputMode) -> Self {
pub fn new(state: &SliderState, mode: &OutputMode) -> Self {
Self {
state: state.clone(),
mode: mode.clone(),
@ -77,14 +72,13 @@ impl AsyncJob for OutputJob {
}
async fn tick(&mut self) -> bool {
let flat_controller_state: Vec<bool>;
{
let controller_state_handle = self.state.controller_state.lock();
flat_controller_state = controller_state_handle.to_flat(&self.sensitivity);
}
let flat_input = {
let input_handle = self.state.input.lock();
input_handle.to_flat(&self.sensitivity)
};
if let Some(handler) = self.handler.as_mut() {
handler.tick(&flat_controller_state);
handler.tick(&flat_input);
}
self.timer.tick().await;

View File

@ -6,7 +6,7 @@ pub struct VoltexState {
}
impl VoltexState {
pub fn from_flat(flat_controller_state: &Vec<bool>) -> Self {
pub fn from_flat(flat_input: &Vec<bool>) -> Self {
let mut voltex_state = Self {
laser: [false; 4],
bt: [false; 4],
@ -14,24 +14,24 @@ impl VoltexState {
extra: [false; 3],
};
voltex_state.laser[0] = flat_controller_state[0..4].contains(&true);
voltex_state.laser[1] = flat_controller_state[4..8].contains(&true);
voltex_state.laser[2] = flat_controller_state[24..28].contains(&true);
voltex_state.laser[3] = flat_controller_state[28..32].contains(&true);
voltex_state.laser[0] = flat_input[0..4].contains(&true);
voltex_state.laser[1] = flat_input[4..8].contains(&true);
voltex_state.laser[2] = flat_input[24..28].contains(&true);
voltex_state.laser[3] = flat_input[28..32].contains(&true);
for i in 0..4 {
voltex_state.bt[i] = flat_controller_state[9 + i * 4] || flat_controller_state[11 + i * 4];
voltex_state.bt[i] = flat_input[9 + i * 4] || flat_input[11 + i * 4];
}
for i in 0..2 {
voltex_state.fx[i] = flat_controller_state[8 + i * 8]
|| flat_controller_state[10 + i * 8]
|| flat_controller_state[12 + i * 8]
|| flat_controller_state[14 + i * 8];
voltex_state.fx[i] = flat_input[8 + i * 8]
|| flat_input[10 + i * 8]
|| flat_input[12 + i * 8]
|| flat_input[14 + i * 8];
}
for i in 0..3 {
voltex_state.extra[i] = flat_controller_state[38 + i];
voltex_state.extra[i] = flat_input[38 + i];
}
voltex_state

View File

@ -3,28 +3,28 @@ use std::{sync::Arc, time::Instant};
/// Stores the input state of a slider controller, including ground touch pads,
/// air strings and extra buttons.
pub struct ControllerState {
pub struct SliderInput {
/// Represents touch pressure in 32 touch pads in a 2 tall and 16 wide grid.
/// Each pressur is in a `u8` from 0 to 255. Pads are represented in order of
/// bottom left, then top left, then flows from left to right.
pub ground_state: [u8; 32],
pub ground: [u8; 32],
/// Represents air string state in 6 pads starting from bottom to top. 0 means
/// uninterrupted, 1 means interrupted.
pub air_state: [u8; 6],
pub air: [u8; 6],
/// Represents extra button state, usually used for coin/test/card entry
/// functions.
pub extra_state: [u8; 3],
pub extra: [u8; 3],
}
impl ControllerState {
impl SliderInput {
/// Make a blank input state.
pub fn new() -> Self {
Self {
ground_state: [0; 32],
air_state: [0; 6],
extra_state: [0; 3],
ground: [0; 32],
air: [0; 6],
extra: [0; 3],
}
}
@ -32,16 +32,10 @@ impl ControllerState {
/// visualisation.
pub fn to_flat(&self, sensitivity: &u8) -> Vec<bool> {
self
.ground_state
.ground
.iter()
.map(|x| x >= sensitivity)
.chain(
self
.air_state
.iter()
.chain(self.extra_state.iter())
.map(|x| x > &0),
)
.chain(self.air.iter().chain(self.extra.iter()).map(|x| x > &0))
.collect()
}
@ -50,16 +44,16 @@ impl ControllerState {
/// botton left that is used internally).
pub fn flip_vert(&mut self) {
for i in 0..16 {
self.ground_state.swap(i * 2, i * 2 + 1);
self.ground.swap(i * 2, i * 2 + 1);
}
}
}
// Stores the lighting state of a slider controller.
pub struct LedState {
pub struct SliderLights {
/// Represents the RGB pixel values of the slider controller from left to
/// right. Alternates between 16 touch pad pixels and 15 divider pixels.
pub led_state: [u8; 3 * 31],
pub ground: [u8; 3 * 31],
/// Internal dirty flag used to indicate that new lighting data is available.
pub dirty: bool,
@ -68,11 +62,11 @@ pub struct LedState {
pub start: Instant,
}
impl LedState {
impl SliderLights {
/// Make a blank lighting state.
pub fn new() -> Self {
Self {
led_state: [0; 3 * 31],
ground: [0; 3 * 31],
dirty: false,
start: Instant::now(),
}
@ -80,27 +74,27 @@ impl LedState {
/// Apply a RGB color to some pixel in the lighting state.
pub fn paint(&mut self, idx: usize, color: &[u8; 3]) {
self.led_state[3 * idx..3 * (idx + 1)].copy_from_slice(color);
self.ground[3 * idx..3 * (idx + 1)].copy_from_slice(color);
}
}
/// Stores data required for a single slider controller. Data and lighting
/// states are stored seperately in their own `Arc<Mutex<T>>` so that they can
/// be locked independently.
pub struct FullState {
pub struct SliderState {
/// Input data for the slider controller.
pub controller_state: Arc<Mutex<ControllerState>>,
pub input: Arc<Mutex<SliderInput>>,
/// Lighting data for the slider controller.
pub led_state: Arc<Mutex<LedState>>,
pub lights: Arc<Mutex<SliderLights>>,
}
impl FullState {
impl SliderState {
/// Creates a blank slider controller state
pub fn new() -> Self {
Self {
controller_state: Arc::new(Mutex::new(ControllerState::new())),
led_state: Arc::new(Mutex::new(LedState::new())),
input: Arc::new(Mutex::new(SliderInput::new())),
lights: Arc::new(Mutex::new(SliderLights::new())),
}
}
@ -109,25 +103,25 @@ impl FullState {
pub fn snapshot(&self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![];
{
let controller_state_handle = self.controller_state.lock();
buf.extend(controller_state_handle.ground_state);
buf.extend(controller_state_handle.air_state);
buf.extend(controller_state_handle.extra_state);
let input_handle = self.input.lock();
buf.extend(input_handle.ground);
buf.extend(input_handle.air);
buf.extend(input_handle.extra);
};
{
let led_state_handle = self.led_state.lock();
buf.extend(led_state_handle.led_state);
let lights_handle = self.lights.lock();
buf.extend(lights_handle.ground);
};
buf
}
}
impl Clone for FullState {
impl Clone for SliderState {
fn clone(&self) -> Self {
Self {
controller_state: Arc::clone(&self.controller_state),
led_state: Arc::clone(&self.led_state),
input: Arc::clone(&self.input),
lights: Arc::clone(&self.lights),
}
}
}