mirror of
https://github.com/4yn/slidershim.git
synced 2026-03-21 17:54:29 -05:00
refactor to 'lights', add diva protocol
This commit is contained in:
parent
287c9c63f6
commit
f356624502
|
|
@ -3,7 +3,7 @@ use serde_json::Value;
|
|||
use std::fs;
|
||||
|
||||
use crate::{
|
||||
input::config::DeviceMode, lighting::config::LedMode, output::config::OutputMode, system,
|
||||
device::config::DeviceMode, lighting::config::LightsMode, output::config::OutputMode, system,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -11,7 +11,7 @@ pub struct Config {
|
|||
pub raw: String,
|
||||
pub device_mode: DeviceMode,
|
||||
pub output_mode: OutputMode,
|
||||
pub led_mode: LedMode,
|
||||
pub lights_mode: LightsMode,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
@ -22,7 +22,7 @@ impl Config {
|
|||
raw: s.to_string(),
|
||||
device_mode: DeviceMode::from_serde_value(&v)?,
|
||||
output_mode: OutputMode::from_serde_value(&v)?,
|
||||
led_mode: LedMode::from_serde_value(&v)?,
|
||||
lights_mode: LightsMode::from_serde_value(&v)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use std::sync::{atomic::Ordering, Arc};
|
|||
|
||||
use crate::{
|
||||
config::Config,
|
||||
input::{brokenithm::BrokenithmJob, config::DeviceMode, device::HidDeviceJob},
|
||||
lighting::{config::LedMode, lighting::LedJob},
|
||||
device::{brokenithm::BrokenithmJob, config::DeviceMode, diva::DivaSliderJob, hid::HidJob},
|
||||
lighting::{config::LightsMode, lighting::LightsJob},
|
||||
output::{config::OutputMode, output::OutputJob},
|
||||
shared::{
|
||||
utils::LoopTimer,
|
||||
|
|
@ -18,10 +18,10 @@ use crate::{
|
|||
pub struct Context {
|
||||
state: SliderState,
|
||||
config: Config,
|
||||
device_worker: Option<ThreadWorker>,
|
||||
brokenithm_worker: Option<AsyncHaltableWorker>,
|
||||
device_thread_worker: Option<ThreadWorker>,
|
||||
device_async_haltable_worker: Option<AsyncHaltableWorker>,
|
||||
output_worker: Option<AsyncWorker>,
|
||||
led_worker: Option<AsyncWorker>,
|
||||
lights_worker: Option<AsyncWorker>,
|
||||
timers: Vec<(&'static str, Arc<AtomicF64>)>,
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ impl Context {
|
|||
info!("Context creating");
|
||||
info!("Device config {:?}", config.device_mode);
|
||||
info!("Output config {:?}", config.output_mode);
|
||||
info!("LED config {:?}", config.led_mode);
|
||||
info!("Lights config {:?}", config.lights_mode);
|
||||
|
||||
let state = SliderState::new();
|
||||
let mut timers = vec![];
|
||||
|
|
@ -39,12 +39,12 @@ impl Context {
|
|||
DeviceMode::None => (None, None),
|
||||
DeviceMode::Brokenithm {
|
||||
ground_only,
|
||||
led_enabled,
|
||||
lights_enabled,
|
||||
} => (
|
||||
None,
|
||||
Some(AsyncHaltableWorker::new(
|
||||
"brokenithm",
|
||||
BrokenithmJob::new(&state, ground_only, led_enabled),
|
||||
BrokenithmJob::new(&state, ground_only, lights_enabled),
|
||||
)),
|
||||
),
|
||||
DeviceMode::Hardware { spec } => (
|
||||
|
|
@ -53,7 +53,19 @@ impl Context {
|
|||
timers.push(("d", timer.fork()));
|
||||
Some(ThreadWorker::new(
|
||||
"device",
|
||||
HidDeviceJob::from_config(&state, spec),
|
||||
HidJob::from_config(&state, spec),
|
||||
timer,
|
||||
))
|
||||
},
|
||||
None,
|
||||
),
|
||||
DeviceMode::DivaSlider { port } => (
|
||||
{
|
||||
let timer = LoopTimer::new();
|
||||
timers.push(("d", timer.fork()));
|
||||
Some(ThreadWorker::new(
|
||||
"diva",
|
||||
DivaSliderJob::new(&state, port),
|
||||
timer,
|
||||
))
|
||||
},
|
||||
|
|
@ -72,14 +84,14 @@ impl Context {
|
|||
))
|
||||
}
|
||||
};
|
||||
let led_worker = match &config.led_mode {
|
||||
LedMode::None => None,
|
||||
let lights_worker = match &config.lights_mode {
|
||||
LightsMode::None => None,
|
||||
_ => {
|
||||
let timer = LoopTimer::new();
|
||||
timers.push(("l", timer.fork()));
|
||||
Some(AsyncWorker::new(
|
||||
"led",
|
||||
LedJob::new(&state, &config.led_mode),
|
||||
"lights",
|
||||
LightsJob::new(&state, &config.lights_mode),
|
||||
timer,
|
||||
))
|
||||
}
|
||||
|
|
@ -88,10 +100,10 @@ impl Context {
|
|||
Self {
|
||||
state,
|
||||
config,
|
||||
device_worker,
|
||||
brokenithm_worker,
|
||||
device_thread_worker: device_worker,
|
||||
device_async_haltable_worker: brokenithm_worker,
|
||||
output_worker,
|
||||
led_worker,
|
||||
lights_worker,
|
||||
timers,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
|
@ -69,7 +69,7 @@ async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
|
|||
async fn handle_brokenithm(
|
||||
ws_stream: WebSocketStream<Upgraded>,
|
||||
state: SliderState,
|
||||
led_enabled: bool,
|
||||
lights_enabled: bool,
|
||||
) {
|
||||
let (mut ws_write, mut ws_read) = ws_stream.split();
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ async fn handle_brokenithm(
|
|||
// info!("Websocket read task done");
|
||||
};
|
||||
|
||||
match led_enabled {
|
||||
match lights_enabled {
|
||||
false => {
|
||||
select! {
|
||||
_ = read_task => {}
|
||||
|
|
@ -163,14 +163,14 @@ async fn handle_brokenithm(
|
|||
true => {
|
||||
let msg_write_handle = msg_write.clone();
|
||||
let state_handle = state.clone();
|
||||
let led_task = async move {
|
||||
let lights_task = async move {
|
||||
loop {
|
||||
let mut led_data = vec![0; 93];
|
||||
let mut lights_data = vec![0; 93];
|
||||
{
|
||||
let lights_handle = state_handle.lights.lock();
|
||||
(&mut led_data).copy_from_slice(&lights_handle.ground);
|
||||
(&mut lights_data).copy_from_slice(&lights_handle.ground);
|
||||
}
|
||||
msg_write_handle.send(Message::Binary(led_data)).ok();
|
||||
msg_write_handle.send(Message::Binary(lights_data)).ok();
|
||||
|
||||
sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
|
|
@ -179,7 +179,7 @@ async fn handle_brokenithm(
|
|||
select! {
|
||||
_ = read_task => {}
|
||||
_ = write_task => {}
|
||||
_ = led_task => {}
|
||||
_ = lights_task => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ async fn handle_brokenithm(
|
|||
async fn handle_websocket(
|
||||
mut request: Request<Body>,
|
||||
state: SliderState,
|
||||
led_enabled: bool,
|
||||
lights_enabled: bool,
|
||||
) -> Result<Response<Body>, Infallible> {
|
||||
let res = match handshake::server::create_response_with_body(&request, || Body::empty()) {
|
||||
Ok(res) => {
|
||||
|
|
@ -202,7 +202,7 @@ async fn handle_websocket(
|
|||
)
|
||||
.await;
|
||||
|
||||
handle_brokenithm(ws_stream, state, led_enabled).await;
|
||||
handle_brokenithm(ws_stream, state, lights_enabled).await;
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
|
|
@ -229,7 +229,7 @@ async fn handle_request(
|
|||
remote_addr: SocketAddr,
|
||||
state: SliderState,
|
||||
ground_only: bool,
|
||||
led_enabled: bool,
|
||||
lights_enabled: bool,
|
||||
) -> Result<Response<Body>, Infallible> {
|
||||
let method = request.method();
|
||||
let path = request.uri().path();
|
||||
|
|
@ -251,7 +251,7 @@ async fn handle_request(
|
|||
true => serve_file("index-go.html").await,
|
||||
},
|
||||
(filename, false) => serve_file(&filename[1..]).await,
|
||||
("/ws", true) => handle_websocket(request, state, led_enabled).await,
|
||||
("/ws", true) => handle_websocket(request, state, lights_enabled).await,
|
||||
_ => error_response().await,
|
||||
}
|
||||
}
|
||||
|
|
@ -259,15 +259,15 @@ async fn handle_request(
|
|||
pub struct BrokenithmJob {
|
||||
state: SliderState,
|
||||
ground_only: bool,
|
||||
led_enabled: bool,
|
||||
lights_enabled: bool,
|
||||
}
|
||||
|
||||
impl BrokenithmJob {
|
||||
pub fn new(state: &SliderState, ground_only: &bool, led_enabled: &bool) -> Self {
|
||||
pub fn new(state: &SliderState, ground_only: &bool, lights_enabled: &bool) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
ground_only: *ground_only,
|
||||
led_enabled: *led_enabled,
|
||||
lights_enabled: *lights_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -277,14 +277,14 @@ impl AsyncHaltableJob for BrokenithmJob {
|
|||
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
||||
let state = self.state.clone();
|
||||
let ground_only = self.ground_only;
|
||||
let led_enabled = self.led_enabled;
|
||||
let lights_enabled = self.lights_enabled;
|
||||
let make_svc = make_service_fn(|conn: &AddrStream| {
|
||||
let remote_addr = conn.remote_addr();
|
||||
let make_svc_state = state.clone();
|
||||
async move {
|
||||
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
|
||||
let svc_state = make_svc_state.clone();
|
||||
handle_request(request, remote_addr, svc_state, ground_only, led_enabled)
|
||||
handle_request(request, remote_addr, svc_state, ground_only, lights_enabled)
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
|
@ -15,7 +15,10 @@ pub enum DeviceMode {
|
|||
},
|
||||
Brokenithm {
|
||||
ground_only: bool,
|
||||
led_enabled: bool,
|
||||
lights_enabled: bool,
|
||||
},
|
||||
DivaSlider {
|
||||
port: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -32,21 +35,24 @@ impl DeviceMode {
|
|||
"yuancon" => DeviceMode::Hardware {
|
||||
spec: HardwareSpec::Yuancon,
|
||||
},
|
||||
"diva" => DeviceMode::DivaSlider {
|
||||
port: v["divaSerialPort"].as_str()?.to_string(),
|
||||
},
|
||||
"brokenithm" => DeviceMode::Brokenithm {
|
||||
ground_only: false,
|
||||
led_enabled: false,
|
||||
lights_enabled: false,
|
||||
},
|
||||
"brokenithm-led" => DeviceMode::Brokenithm {
|
||||
ground_only: false,
|
||||
led_enabled: true,
|
||||
lights_enabled: true,
|
||||
},
|
||||
"brokenithm-ground" => DeviceMode::Brokenithm {
|
||||
ground_only: true,
|
||||
led_enabled: false,
|
||||
lights_enabled: false,
|
||||
},
|
||||
"brokenithm-ground-led" => DeviceMode::Brokenithm {
|
||||
ground_only: true,
|
||||
led_enabled: true,
|
||||
lights_enabled: true,
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
313
src-slider_io/src/device/diva.rs
Normal file
313
src-slider_io/src/device/diva.rs
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
use log::{error, info};
|
||||
use serialport::SerialPort;
|
||||
use std::{collections::VecDeque, num::Wrapping, thread::sleep, time::Duration};
|
||||
|
||||
use crate::{shared::worker::ThreadJob, state::SliderState};
|
||||
|
||||
struct DivaPacket {
|
||||
command: u8,
|
||||
len: u8,
|
||||
data: Vec<u8>,
|
||||
checksum: Wrapping<u8>,
|
||||
raw: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl DivaPacket {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
command: 0,
|
||||
len: 0,
|
||||
data: Vec::with_capacity(256),
|
||||
checksum: Wrapping(0),
|
||||
raw: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_bytes(command: u8, data: &[u8]) -> Self {
|
||||
Self {
|
||||
command,
|
||||
len: data.len() as u8,
|
||||
data: data.iter().copied().collect(),
|
||||
checksum: Wrapping(0),
|
||||
raw: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn push_raw_escaped(byte: u8, raw: &mut Vec<u8>) {
|
||||
match byte {
|
||||
0xfd => {
|
||||
raw.push(0xfd);
|
||||
raw.push(0xfc);
|
||||
}
|
||||
0xff => {
|
||||
raw.push(0xfd);
|
||||
raw.push(0xfe);
|
||||
}
|
||||
_ => {
|
||||
raw.push(byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&mut self) -> &[u8] {
|
||||
let mut raw: Vec<u8> = Vec::with_capacity(512);
|
||||
let mut checksum = Wrapping(0);
|
||||
|
||||
raw.push(0xff);
|
||||
checksum += Wrapping(0xffu8);
|
||||
Self::push_raw_escaped(self.command, &mut raw);
|
||||
checksum += Wrapping(self.command);
|
||||
Self::push_raw_escaped(self.len, &mut raw);
|
||||
checksum += Wrapping(self.len);
|
||||
for i in &self.data {
|
||||
Self::push_raw_escaped(*i, &mut raw);
|
||||
checksum += Wrapping(*i);
|
||||
}
|
||||
|
||||
checksum = -checksum;
|
||||
Self::push_raw_escaped(checksum.0, &mut raw);
|
||||
|
||||
self.raw = Some(raw);
|
||||
return self.raw.as_ref().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
enum DivaDeserializerState {
|
||||
ExpectCommand,
|
||||
ExpectLen,
|
||||
ExpectData,
|
||||
ExpectChecksum,
|
||||
Done,
|
||||
}
|
||||
|
||||
struct DivaDeserializer {
|
||||
state: DivaDeserializerState,
|
||||
escape: u8,
|
||||
len: u8,
|
||||
packet: DivaPacket,
|
||||
}
|
||||
|
||||
impl DivaDeserializer {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
state: DivaDeserializerState::Done,
|
||||
escape: 1,
|
||||
len: 0,
|
||||
packet: DivaPacket::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize(&mut self, data: &[u8], out: &mut VecDeque<DivaPacket>) {
|
||||
for c in data {
|
||||
match c {
|
||||
0xff => {
|
||||
self.packet = DivaPacket::new();
|
||||
self.packet.checksum = Wrapping(0xff);
|
||||
self.state = DivaDeserializerState::ExpectCommand;
|
||||
}
|
||||
0xfd => {
|
||||
self.escape = 1;
|
||||
}
|
||||
c => {
|
||||
let c = c + self.escape;
|
||||
self.escape = 0;
|
||||
|
||||
self.packet.checksum += Wrapping(c);
|
||||
match self.state {
|
||||
DivaDeserializerState::ExpectCommand => {
|
||||
self.packet.command = c;
|
||||
self.state = DivaDeserializerState::ExpectLen;
|
||||
}
|
||||
DivaDeserializerState::ExpectLen => {
|
||||
self.len = c;
|
||||
self.packet.len = c;
|
||||
self.state = match c {
|
||||
0 => DivaDeserializerState::ExpectChecksum,
|
||||
_ => DivaDeserializerState::ExpectData,
|
||||
};
|
||||
}
|
||||
DivaDeserializerState::ExpectData => {
|
||||
self.packet.data.push(c);
|
||||
self.len -= 1;
|
||||
|
||||
if self.len == 0 {
|
||||
self.state = DivaDeserializerState::ExpectChecksum;
|
||||
}
|
||||
}
|
||||
DivaDeserializerState::ExpectChecksum => {
|
||||
debug_assert!(self.packet.checksum == Wrapping(0));
|
||||
if self.packet.checksum == Wrapping(0) {
|
||||
out.push_back(DivaPacket::new());
|
||||
std::mem::swap(&mut self.packet, out.back_mut().unwrap());
|
||||
}
|
||||
self.state = DivaDeserializerState::Done;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum DivaSliderBootstrap {
|
||||
Init,
|
||||
AwaitReset,
|
||||
AwaitInfo,
|
||||
AwaitStart,
|
||||
ReadLoop,
|
||||
}
|
||||
|
||||
pub struct DivaSliderJob {
|
||||
state: SliderState,
|
||||
port: String,
|
||||
packets: VecDeque<DivaPacket>,
|
||||
deserializer: DivaDeserializer,
|
||||
serial_port: Option<Box<dyn SerialPort>>,
|
||||
bootstrap: DivaSliderBootstrap,
|
||||
}
|
||||
|
||||
impl DivaSliderJob {
|
||||
pub fn new(state: &SliderState, port: &String) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
port: port.clone(),
|
||||
packets: VecDeque::with_capacity(100),
|
||||
deserializer: DivaDeserializer::new(),
|
||||
serial_port: None,
|
||||
bootstrap: DivaSliderBootstrap::Init,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ThreadJob for DivaSliderJob {
|
||||
fn setup(&mut self) -> bool {
|
||||
info!(
|
||||
"Serial port for diva slider opening at {} {:?}",
|
||||
self.port.as_str(),
|
||||
115200
|
||||
);
|
||||
match serialport::new(&self.port, 152000).open() {
|
||||
Ok(serial_port_buf) => {
|
||||
info!("Serial port opened");
|
||||
self.serial_port = Some(serial_port_buf);
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Serial port could not open: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self) -> bool {
|
||||
let mut work = false;
|
||||
|
||||
let serial_port = self.serial_port.as_mut().unwrap();
|
||||
|
||||
let bytes_avail = serial_port.bytes_to_read().unwrap_or(0);
|
||||
if bytes_avail > 0 {
|
||||
let mut read_buf = vec![0 as u8; bytes_avail as usize];
|
||||
serial_port.read_exact(&mut read_buf).ok();
|
||||
self.deserializer.deserialize(&read_buf, &mut self.packets);
|
||||
work = true;
|
||||
}
|
||||
|
||||
match self.bootstrap {
|
||||
DivaSliderBootstrap::Init => {
|
||||
let mut reset_packet = DivaPacket::from_bytes(0x10, &[]);
|
||||
serial_port.write(reset_packet.serialize()).ok();
|
||||
|
||||
self.bootstrap = DivaSliderBootstrap::AwaitReset;
|
||||
work = true;
|
||||
}
|
||||
DivaSliderBootstrap::AwaitReset => {
|
||||
if let Some(ack_packet) = self.packets.pop_front() {
|
||||
info!(
|
||||
"Diva slider ack reset {:?} {:?}",
|
||||
ack_packet.command, ack_packet.data
|
||||
);
|
||||
|
||||
let mut info_packet = DivaPacket::from_bytes(0xf0, &[]);
|
||||
serial_port.write(info_packet.serialize()).ok();
|
||||
|
||||
self.bootstrap = DivaSliderBootstrap::AwaitInfo;
|
||||
work = true;
|
||||
}
|
||||
}
|
||||
DivaSliderBootstrap::AwaitInfo => {
|
||||
if let Some(ack_packet) = self.packets.pop_front() {
|
||||
info!(
|
||||
"Diva slider ack info {:?} {:?}",
|
||||
ack_packet.command, ack_packet.data
|
||||
);
|
||||
|
||||
let mut start_packet = DivaPacket::from_bytes(0x03, &[]);
|
||||
serial_port.write(start_packet.serialize()).ok();
|
||||
|
||||
self.bootstrap = DivaSliderBootstrap::AwaitStart;
|
||||
work = true;
|
||||
}
|
||||
}
|
||||
DivaSliderBootstrap::AwaitStart => {
|
||||
if let Some(ack_packet) = self.packets.pop_front() {
|
||||
info!(
|
||||
"Diva slider ack start {:?} {:?}",
|
||||
ack_packet.command, ack_packet.data
|
||||
);
|
||||
|
||||
self.bootstrap = DivaSliderBootstrap::ReadLoop;
|
||||
work = true;
|
||||
}
|
||||
}
|
||||
DivaSliderBootstrap::ReadLoop => {
|
||||
while let Some(data_packet) = self.packets.pop_front() {
|
||||
if data_packet.command == 0x01 && data_packet.len == 32 {
|
||||
let mut input_handle = self.state.input.lock();
|
||||
input_handle
|
||||
.ground
|
||||
.copy_from_slice(&data_packet.data[0..32]);
|
||||
work = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut send_lights = false;
|
||||
let mut lights_buf = [0; 97];
|
||||
{
|
||||
let mut lights_handle = self.state.lights.lock();
|
||||
if lights_handle.dirty {
|
||||
send_lights = true;
|
||||
lights_buf[0] = 0x3f;
|
||||
lights_buf[1..97].copy_from_slice(&lights_handle.ground[0..96]);
|
||||
lights_handle.dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if send_lights {
|
||||
let mut lights_packet = DivaPacket::from_bytes(0x02, &lights_buf);
|
||||
serial_port.write(lights_packet.serialize()).ok();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: async worker?
|
||||
sleep(Duration::from_millis(10));
|
||||
|
||||
work
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DivaSliderJob {
|
||||
fn drop(&mut self) {
|
||||
match self.bootstrap {
|
||||
DivaSliderBootstrap::AwaitStart | DivaSliderBootstrap::ReadLoop => {
|
||||
info!("Diva slider sending stop");
|
||||
|
||||
let serial_port = self.serial_port.as_mut().unwrap();
|
||||
let mut stop_packet = DivaPacket::from_bytes(0x04, &[]);
|
||||
serial_port.write(stop_packet.serialize()).ok();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ enum WriteType {
|
|||
Interrupt,
|
||||
}
|
||||
|
||||
pub struct HidDeviceJob {
|
||||
pub struct HidJob {
|
||||
state: SliderState,
|
||||
|
||||
vid: u16,
|
||||
|
|
@ -44,7 +44,7 @@ pub struct HidDeviceJob {
|
|||
handle: Option<DeviceHandle<GlobalContext>>,
|
||||
}
|
||||
|
||||
impl HidDeviceJob {
|
||||
impl HidJob {
|
||||
fn new(
|
||||
state: SliderState,
|
||||
vid: u16,
|
||||
|
|
@ -212,7 +212,7 @@ impl HidDeviceJob {
|
|||
|
||||
const TIMEOUT: Duration = Duration::from_millis(20);
|
||||
|
||||
impl ThreadJob for HidDeviceJob {
|
||||
impl ThreadJob for HidJob {
|
||||
fn setup(&mut self) -> bool {
|
||||
match self.get_handle() {
|
||||
Ok(_) => {
|
||||
|
|
@ -283,7 +283,7 @@ impl ThreadJob for HidDeviceJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for HidDeviceJob {
|
||||
impl Drop for HidJob {
|
||||
fn drop(&mut self) {
|
||||
if let Some(handle) = self.handle.as_mut() {
|
||||
handle.release_interface(0).ok();
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
pub mod config;
|
||||
|
||||
mod acio;
|
||||
|
||||
pub mod diva;
|
||||
pub mod brokenithm;
|
||||
pub mod device;
|
||||
pub mod hid;
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
// use serialport::SerialPort;
|
||||
// use std::io::{BufRead, BufReader};
|
||||
|
||||
// struct ArcadeSlider {
|
||||
// serial_port: BufReader<Box<dyn SerialPort>>,
|
||||
// }
|
||||
|
||||
// impl ArcadeSlider {
|
||||
// fn new() -> Self {
|
||||
// let serial_port = serialport::new("COM1", 152000).open().unwrap();
|
||||
// let serial_port_buf = BufReader::new(serial_port);
|
||||
// Self {
|
||||
// serial_port: serial_port_buf,
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn recv(&mut self) {
|
||||
// let mut consumed = 0;
|
||||
// {
|
||||
// let d = self.serial_port.fill_buf().unwrap();
|
||||
|
||||
// let mut packets = vec![];
|
||||
// let mut packet = vec![];
|
||||
|
||||
// let mut bytes_taken = 0;
|
||||
// let mut in_escape = 0;
|
||||
// let mut checksum = 0;
|
||||
// for b in d.iter() {
|
||||
// bytes_taken += 1;
|
||||
|
||||
// match b {
|
||||
// 0xff => {
|
||||
// consumed += bytes_taken;
|
||||
// bytes_taken = 0;
|
||||
// in_escape = 0;
|
||||
// }
|
||||
// 0xfd => {
|
||||
// in_escape = 1;
|
||||
// }
|
||||
// _ => {
|
||||
// let b = b + in_escape;
|
||||
// in_escape = 0;
|
||||
// packet.push(b);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// self.serial_port.consume(consumed);
|
||||
// }
|
||||
|
||||
// fn send(&mut self) {}
|
||||
// }
|
||||
|
|
@ -9,7 +9,7 @@ mod config;
|
|||
mod shared;
|
||||
mod state;
|
||||
|
||||
mod input;
|
||||
mod device;
|
||||
mod lighting;
|
||||
mod output;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub enum ReactiveLayout {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LedMode {
|
||||
pub enum LightsMode {
|
||||
None,
|
||||
Reactive {
|
||||
layout: ReactiveLayout,
|
||||
|
|
@ -23,32 +23,32 @@ pub enum LedMode {
|
|||
},
|
||||
}
|
||||
|
||||
impl LedMode {
|
||||
impl LightsMode {
|
||||
pub fn from_serde_value(v: &Value) -> Option<Self> {
|
||||
Some(match v["ledMode"].as_str()? {
|
||||
"none" => LedMode::None,
|
||||
"reactive-4" => LedMode::Reactive {
|
||||
"none" => LightsMode::None,
|
||||
"reactive-4" => LightsMode::Reactive {
|
||||
layout: ReactiveLayout::Even { splits: 4 },
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"reactive-8" => LedMode::Reactive {
|
||||
"reactive-8" => LightsMode::Reactive {
|
||||
layout: ReactiveLayout::Even { splits: 8 },
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"reactive-16" => LedMode::Reactive {
|
||||
"reactive-16" => LightsMode::Reactive {
|
||||
layout: ReactiveLayout::Even { splits: 16 },
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"reactive-voltex" => LedMode::Reactive {
|
||||
"reactive-voltex" => LightsMode::Reactive {
|
||||
layout: ReactiveLayout::Voltex,
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"attract" => LedMode::Attract,
|
||||
"test" => LedMode::Test,
|
||||
"websocket" => LedMode::Websocket {
|
||||
"attract" => LightsMode::Attract,
|
||||
"test" => LightsMode::Test,
|
||||
"websocket" => LightsMode::Websocket {
|
||||
url: v["ledWebsocketUrl"].as_str()?.to_string(),
|
||||
},
|
||||
"serial" => LedMode::Serial {
|
||||
"serial" => LightsMode::Serial {
|
||||
port: v["ledSerialPort"].as_str()?.to_string(),
|
||||
},
|
||||
_ => return None,
|
||||
|
|
|
|||
|
|
@ -13,18 +13,18 @@ use crate::{
|
|||
state::{SliderLights, SliderState},
|
||||
};
|
||||
|
||||
use super::config::{LedMode, ReactiveLayout};
|
||||
use super::config::{LightsMode, ReactiveLayout};
|
||||
|
||||
pub struct LedJob {
|
||||
pub struct LightsJob {
|
||||
state: SliderState,
|
||||
mode: LedMode,
|
||||
mode: LightsMode,
|
||||
serial_port: Option<Box<dyn SerialPort>>,
|
||||
started: Instant,
|
||||
timer: Interval,
|
||||
}
|
||||
|
||||
impl LedJob {
|
||||
pub fn new(state: &SliderState, mode: &LedMode) -> Self {
|
||||
impl LightsJob {
|
||||
pub fn new(state: &SliderState, mode: &LightsMode) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
mode: mode.clone(),
|
||||
|
|
@ -41,7 +41,7 @@ impl LedJob {
|
|||
lights: &mut SliderLights,
|
||||
) {
|
||||
match self.mode {
|
||||
LedMode::Reactive { layout, .. } => {
|
||||
LightsMode::Reactive { layout, .. } => {
|
||||
let flat_input = flat_input.unwrap();
|
||||
|
||||
match layout {
|
||||
|
|
@ -116,7 +116,7 @@ impl LedJob {
|
|||
}
|
||||
}
|
||||
}
|
||||
LedMode::Attract => {
|
||||
LightsMode::Attract => {
|
||||
let theta = self
|
||||
.started
|
||||
.elapsed()
|
||||
|
|
@ -128,7 +128,7 @@ impl LedJob {
|
|||
lights.paint(idx, &[color.red, color.green, color.blue]);
|
||||
}
|
||||
}
|
||||
LedMode::Serial { .. } => {
|
||||
LightsMode::Serial { .. } => {
|
||||
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialProcessor.h
|
||||
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialProcessor.cpp
|
||||
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialLeds.h
|
||||
|
|
@ -155,10 +155,10 @@ impl LedJob {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncJob for LedJob {
|
||||
impl AsyncJob for LightsJob {
|
||||
async fn setup(&mut self) -> bool {
|
||||
match &self.mode {
|
||||
LedMode::Serial { port } => {
|
||||
LightsMode::Serial { port } => {
|
||||
info!(
|
||||
"Serial port for led opening at {} {:?}",
|
||||
port.as_str(),
|
||||
|
|
@ -187,11 +187,11 @@ impl AsyncJob for LedJob {
|
|||
|
||||
// Do the IO here
|
||||
match self.mode {
|
||||
LedMode::Reactive { sensitivity, .. } => {
|
||||
LightsMode::Reactive { sensitivity, .. } => {
|
||||
let input_handle = self.state.input.lock();
|
||||
flat_input = Some(input_handle.to_flat(&sensitivity));
|
||||
}
|
||||
LedMode::Serial { .. } => {
|
||||
LightsMode::Serial { .. } => {
|
||||
if let Some(serial_port) = self.serial_port.as_mut() {
|
||||
let mut serial_data_avail = serial_port.bytes_to_read().unwrap_or(0);
|
||||
if serial_data_avail >= 100 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user