1
0
mirror of https://github.com/4yn/slidershim.git synced 2025-02-02 04:27:58 +01:00

wip serial

This commit is contained in:
4yn 2022-02-17 01:40:48 +08:00
parent 5865cd9d21
commit 2782d406dd
10 changed files with 358 additions and 108 deletions

View File

@ -4,7 +4,10 @@ use std::io;
use slider_io::{ use slider_io::{
device::diva, device::diva,
shared::{utils::LoopTimer, worker::ThreadWorker}, shared::{
utils::LoopTimer,
worker::{ThreadJob, ThreadWorker},
},
state::SliderState, state::SliderState,
}; };
@ -14,14 +17,23 @@ fn main() {
.init(); .init();
let state = SliderState::new(); let state = SliderState::new();
let mut job = diva::DivaSliderJob::new(&state, &"COM4".to_string(), 0x3f);
let timer = LoopTimer::new(); let ok = job.setup();
let _worker = ThreadWorker::new( while ok {
"d", job.tick();
diva::DivaSliderJob::new(&state, &"COM5".to_string()), }
timer,
);
// let state = SliderState::new();
// let timer = LoopTimer::new();
// let _worker = ThreadWorker::new(
// "d",
// diva::DivaSliderJob::new(&state, &"COM4".to_string(), 0x3f),
// timer,
// );
println!("Press enter to quit");
let mut input = String::new(); let mut input = String::new();
io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -0,0 +1,47 @@
use std::{mem, ptr};
use winapi::um::{commapi::*, fileapi::*, minwinbase::*, synchapi::*, winbase::*, winnt::*};
fn main() {
unsafe {
let mut port: Vec<u16> = vec![];
port.extend("COM4".encode_utf16());
port.push(0);
let handle = CreateFileW(
port.as_ptr(),
GENERIC_READ | GENERIC_WRITE,
0,
ptr::null_mut(),
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0 as HANDLE,
);
let mut overlapped_read: OVERLAPPED = mem::zeroed();
overlapped_read.hEvent = CreateEventW(ptr::null_mut(), 1, 0, ptr::null_mut());
let mut overlapped_write: OVERLAPPED = mem::zeroed();
overlapped_write.hEvent = CreateEventW(ptr::null_mut(), 0, 0, ptr::null_mut());
SetupComm(handle, 4096, 4096);
let mut timeouts: COMMTIMEOUTS = mem::zeroed();
GetCommTimeouts(handle, &mut timeouts);
SetCommMask(handle, 0x80); // EV_ERR
let mut dcb: DCB = mem::zeroed();
GetCommState(handle, &mut dcb);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.set_fParity(0);
dcb.StopBits = ONESTOPBIT;
dcb.set_fBinary(1);
PurgeComm(
handle,
PURGE_TXCLEAR | PURGE_TXABORT | PURGE_RXCLEAR | PURGE_RXABORT,
);
}
}

View File

@ -0,0 +1,102 @@
extern crate slider_io;
use std::{thread::sleep, time::Duration};
fn main() {
let mut sp = serialport::new("COM4", 115200).open().unwrap();
sp.write_request_to_send(true).unwrap();
sp.write_data_terminal_ready(true).unwrap();
sleep(Duration::from_millis(100));
println!("tx");
let res = sp.write(&[0xff, 0x01, 0x00, 0xf1]).unwrap();
println!("tx {}", res);
loop {
sleep(Duration::from_millis(100));
println!("rx");
let mut buf = [0u8; 4];
let res = sp.read(&mut buf).unwrap();
println!("rx {} {:?}", res, buf);
}
}
// use serial2::SerialPort;
// fn main() {
// let sp = SerialPort::open("COM4", 115200).unwrap();
// println!("Tx");
// let res = sp.write("data".as_bytes()).unwrap();
// println!("Tx {}", res);
// loop {
// println!("Rx");
// let mut buf = [0u8; 5];
// let res = sp.read(&mut buf).unwrap();
// // let res = sp.read(&mut buf).unwrap_or_else(|e| {
// // println!("Err {}", e);
// // 0
// // });
// println!("Rx {} {:?}", res, buf);
// }
// let mut sp = serialport::new("COM4", 115200).open().unwrap();
// println!("Tx");
// let res = sp.write("data".as_bytes()).unwrap();
// println!("Tx {}", res);
// loop {
// println!("Rx");
// let mut buf = [0u8; 5];
// let res = sp.read(&mut buf).unwrap();
// println!("Rx {} {:?}", res, buf);
// }
// }
// use serialport::SerialPort;
// use std::time::Duration;
// use tokio::{
// io::{self, AsyncReadExt, AsyncWriteExt},
// time::sleep,
// };
// use tokio_serial::SerialPortBuilderExt;
// #[tokio::main]
// async fn main() -> io::Result<()> {
// let mut sp = tokio_serial::new("COM4", 115200)
// .open_native_async()
// .unwrap();
// sp.write_request_to_send(true).unwrap();
// sp.write_data_terminal_ready(true).unwrap();
// // sp.set_timeout(Duration::from_millis(1000))?;
// let (mut rx_port, mut tx_port) = tokio::io::split(sp);
// // tx_port.write(&[41, 42, 43, 44]).await?;
// // let mut buf = [0u8; 10];
// // let res = rx_port.read(&mut buf).await?;
// // println!("{}, {:?}", res, buf);
// loop {
// let mut buf = [0u8; 10];
// let res = rx_port.read(&mut buf).await?;
// println!("{}, {:?}", res, buf);
// }
// // let mut serial_reader =
// // tokio_util::codec::FramedRead::new(rx_port,
// // tokio_util::codec::BytesCodec::new()); let serial_sink =
// // tokio_util::codec::FramedWrite::new(tx_port,
// // tokio_util::codec::BytesCodec::new());
// // println!("Tx");
// // let res = tx.write("data".as_bytes()).await?;
// // println!("Sent {}", res);
// // sleep(Duration::from_millis(1000)).await;
// // loop {
// // let mut buffer = [0u8; 1];
// // println!("Rx");
// // let res = rx.read(&mut buffer).await;
// // println!("{:?} {:?}", res, buffer);
// // }
// Ok(())
// }

View File

@ -63,13 +63,13 @@ impl Context {
None, None,
None, None,
), ),
DeviceMode::DivaSlider { port } => ( DeviceMode::DivaSlider { port, brightness } => (
{ {
let timer = LoopTimer::new(); let timer = LoopTimer::new();
timers.push(("d", timer.fork())); timers.push(("d", timer.fork()));
Some(ThreadWorker::new( Some(ThreadWorker::new(
"diva", "diva",
DivaSliderJob::new(&state, port), DivaSliderJob::new(&state, port, *brightness),
timer, timer,
)) ))
}, },

View File

@ -19,6 +19,7 @@ pub enum DeviceMode {
}, },
DivaSlider { DivaSlider {
port: String, port: String,
brightness: u8,
}, },
} }
@ -37,6 +38,7 @@ impl DeviceMode {
}, },
"diva" => DeviceMode::DivaSlider { "diva" => DeviceMode::DivaSlider {
port: v["divaSerialPort"].as_str()?.to_string(), port: v["divaSerialPort"].as_str()?.to_string(),
brightness: u8::try_from(v["divaBrightness"].as_i64()?).ok()?,
}, },
"brokenithm" => DeviceMode::Brokenithm { "brokenithm" => DeviceMode::Brokenithm {
ground_only: false, ground_only: false,

View File

@ -1,9 +1,8 @@
use log::{error, info}; use log::{debug, error, info, warn};
use serialport::{COMPort, SerialPort}; use serialport::{COMPort, SerialPort};
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
io::{Read, Write}, io::{Read, Write},
num::Wrapping,
thread::sleep, thread::sleep,
time::Duration, time::Duration,
}; };
@ -13,11 +12,23 @@ use crate::{
state::SliderState, state::SliderState,
}; };
/*
Init packet
0xff 0x10 0x00 0xf1
Report of all touch sliders at 16 pressure
0xff 0x01 0x20 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0xe0
Report of all touch sliders at 0-31 pressure
0xff 0x01 0x20 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x0f
*/
#[derive(Debug)]
struct DivaPacket { struct DivaPacket {
command: u8, command: u8,
len: u8, len: u8,
data: Vec<u8>, data: Vec<u8>,
checksum: Wrapping<u8>, checksum: u8,
raw: Option<Vec<u8>>, raw: Option<Vec<u8>>,
} }
@ -27,17 +38,23 @@ impl DivaPacket {
command: 0, command: 0,
len: 0, len: 0,
data: Vec::with_capacity(256), data: Vec::with_capacity(256),
checksum: Wrapping(0), checksum: 0,
raw: None, raw: None,
} }
} }
fn from_bytes(command: u8, data: &[u8]) -> Self { fn from_bytes(command: u8, data: &[u8]) -> Self {
let checksum = 0xffu64
+ (command as u64)
+ (data.len() as u64)
+ data.iter().map(|x| (*x) as u64).sum::<u64>();
let checksum = ((0x100 - (checksum & 0xff)) & 0xff) as u8;
Self { Self {
command, command,
len: data.len() as u8, len: data.len() as u8,
data: data.iter().copied().collect(), data: data.iter().copied().collect(),
checksum: Wrapping(0), checksum: checksum,
raw: None, raw: None,
} }
} }
@ -60,23 +77,21 @@ impl DivaPacket {
fn serialize(&mut self) -> &[u8] { fn serialize(&mut self) -> &[u8] {
let mut raw: Vec<u8> = Vec::with_capacity(512); let mut raw: Vec<u8> = Vec::with_capacity(512);
let mut checksum = Wrapping(0);
raw.push(0xff); raw.push(0xff);
checksum += Wrapping(0xffu8);
Self::push_raw_escaped(self.command, &mut raw); Self::push_raw_escaped(self.command, &mut raw);
checksum += Wrapping(self.command);
Self::push_raw_escaped(self.len, &mut raw); Self::push_raw_escaped(self.len, &mut raw);
checksum += Wrapping(self.len);
for i in &self.data { for i in &self.data {
Self::push_raw_escaped(*i, &mut raw); Self::push_raw_escaped(*i, &mut raw);
checksum += Wrapping(*i);
} }
Self::push_raw_escaped(self.checksum, &mut raw);
checksum = -checksum; // null pad?
Self::push_raw_escaped(checksum.0, &mut raw); // raw.push(0);
debug!("Diva serializing {}", raw.len());
self.raw = Some(raw); self.raw = Some(raw);
// debug!("Diva serializing {:?}", &self.raw);
return self.raw.as_ref().unwrap(); return self.raw.as_ref().unwrap();
} }
} }
@ -91,6 +106,7 @@ enum DivaDeserializerState {
struct DivaDeserializer { struct DivaDeserializer {
state: DivaDeserializerState, state: DivaDeserializerState,
checksum: u64,
escape: u8, escape: u8,
len: u8, len: u8,
packet: DivaPacket, packet: DivaPacket,
@ -100,7 +116,8 @@ impl DivaDeserializer {
fn new() -> Self { fn new() -> Self {
Self { Self {
state: DivaDeserializerState::Done, state: DivaDeserializerState::Done,
escape: 1, checksum: 0,
escape: 0,
len: 0, len: 0,
packet: DivaPacket::new(), packet: DivaPacket::new(),
} }
@ -108,11 +125,13 @@ impl DivaDeserializer {
fn deserialize(&mut self, data: &[u8], out: &mut VecDeque<DivaPacket>) { fn deserialize(&mut self, data: &[u8], out: &mut VecDeque<DivaPacket>) {
// println!("Found data"); // println!("Found data");
// debug!("Diva deserializing {:?}", data);
debug!("Diva deserializing {}", data.len());
for c in data { for c in data {
match c { match c {
0xff => { 0xff => {
self.packet = DivaPacket::new(); self.packet = DivaPacket::new();
self.packet.checksum = Wrapping(0xff); self.checksum = 0xff;
self.state = DivaDeserializerState::ExpectCommand; self.state = DivaDeserializerState::ExpectCommand;
self.escape = 0; self.escape = 0;
@ -126,7 +145,7 @@ impl DivaDeserializer {
let c = c + self.escape; let c = c + self.escape;
self.escape = 0; self.escape = 0;
self.packet.checksum += Wrapping(c); self.checksum += c as u64;
match self.state { match self.state {
DivaDeserializerState::ExpectCommand => { DivaDeserializerState::ExpectCommand => {
self.packet.command = c; self.packet.command = c;
@ -154,9 +173,11 @@ impl DivaDeserializer {
// println!("data {}", c); // println!("data {}", c);
} }
DivaDeserializerState::ExpectChecksum => { DivaDeserializerState::ExpectChecksum => {
// println!("checksum {} {:?}", c, self.packet.checksum); self.packet.checksum = c;
debug_assert!(self.packet.checksum == Wrapping(0)); debug_assert!(self.checksum & 0xff == 0);
if self.packet.checksum == Wrapping(0) { // println!("Packet complete {} {}", self.checksum, c);
if self.checksum & 0xff == 0 {
// println!("Feeding packet");
out.push_back(DivaPacket::new()); out.push_back(DivaPacket::new());
std::mem::swap(&mut self.packet, out.back_mut().unwrap()); std::mem::swap(&mut self.packet, out.back_mut().unwrap());
} }
@ -174,25 +195,31 @@ enum DivaSliderBootstrap {
Init, Init,
AwaitReset, AwaitReset,
AwaitInfo, AwaitInfo,
AwaitStart,
ReadLoop, ReadLoop,
Halt,
} }
pub struct DivaSliderJob { pub struct DivaSliderJob {
state: SliderState, state: SliderState,
port: String, port: String,
packets: VecDeque<DivaPacket>, brightness: u8,
// read_buf: Vec<u8>,
in_packets: VecDeque<DivaPacket>,
out_packets: VecDeque<DivaPacket>,
deserializer: DivaDeserializer, deserializer: DivaDeserializer,
serial_port: Option<COMPort>, serial_port: Option<COMPort>,
bootstrap: DivaSliderBootstrap, bootstrap: DivaSliderBootstrap,
} }
impl DivaSliderJob { impl DivaSliderJob {
pub fn new(state: &SliderState, port: &String) -> Self { pub fn new(state: &SliderState, port: &String, brightness: u8) -> Self {
Self { Self {
state: state.clone(), state: state.clone(),
port: port.clone(), port: port.clone(),
packets: VecDeque::with_capacity(100), brightness,
// read_buf: vec![0u8; 1024],
in_packets: VecDeque::with_capacity(100),
out_packets: VecDeque::with_capacity(100),
deserializer: DivaDeserializer::new(), deserializer: DivaDeserializer::new(),
serial_port: None, serial_port: None,
bootstrap: DivaSliderBootstrap::Init, bootstrap: DivaSliderBootstrap::Init,
@ -207,11 +234,24 @@ impl ThreadJob for DivaSliderJob {
self.port.as_str(), self.port.as_str(),
115200 115200
); );
match serialport::new(&self.port, 152000).open_native() { match serialport::new(&self.port, 152000)
.flow_control(serialport::FlowControl::Hardware)
.open_native()
{
Ok(serial_port) => { Ok(serial_port) => {
info!("Serial port opened"); info!("Serial port opened");
// serial_port.write_request_to_send(true).unwrap_or_else(|e| {
// error!("Serial request to send failed {}", e);
// });
// serial_port
// .write_data_terminal_ready(true)
// .unwrap_or_else(|e| {
// error!("Serial data terminal ready failed {}", e);
// });
// serial_port.set_timeout(Duration::from_millis(10)).ok();
serial_port.clear(serialport::ClearBuffer::All).ok();
serial_port serial_port
.set_read_write_timeout(Duration::from_millis(3)) .set_read_write_timeout(Duration::from_millis(100))
.ok(); .ok();
self.serial_port = Some(serial_port); self.serial_port = Some(serial_port);
true true
@ -228,93 +268,74 @@ impl ThreadJob for DivaSliderJob {
let serial_port = self.serial_port.as_mut().unwrap(); let serial_port = self.serial_port.as_mut().unwrap();
let bytes_avail = serial_port.bytes_to_read().unwrap_or(0); let bytes_avail = serial_port.bytes_to_read().unwrap_or_else(|e| {
error!("Diva serial read error {}", e);
0
});
// debug!("Serial read {} bytes", bytes_avail);
if bytes_avail > 0 { if bytes_avail > 0 {
let mut read_buf = vec![0 as u8; bytes_avail as usize]; let mut read_buf = vec![0 as u8; bytes_avail as usize];
serial_port.read(&mut read_buf).ok(); serial_port.read_exact(&mut read_buf).unwrap();
self.deserializer.deserialize(&read_buf, &mut self.packets); self
.deserializer
.deserialize(&read_buf, &mut self.in_packets);
work = true; work = true;
} }
// let read_amount = serial_port.read(&mut self.read_buf).unwrap_or_else(|e| {
// error!("Read error {}", e);
// 0
// });
// debug!("Serial read {} bytes", read_amount);
// if read_amount > 0 {
// self
// .deserializer
// .deserialize(&self.read_buf[0..read_amount], &mut self.packets);
// }
match self.bootstrap { match self.bootstrap {
DivaSliderBootstrap::Init => { DivaSliderBootstrap::Init => {
info!("Diva sending init"); info!("Diva sending init");
let mut reset_packet = DivaPacket::from_bytes(0x10, &[]); let reset_packet = DivaPacket::from_bytes(0x10, &[]);
match serial_port.write(reset_packet.serialize()) { self.out_packets.push_back(reset_packet);
Ok(_) => {
info!("Diva sent init");
self.bootstrap = DivaSliderBootstrap::AwaitReset; self.bootstrap = DivaSliderBootstrap::AwaitReset;
work = true;
}
Err(e) => {
error!("Diva send init error {}", e);
}
}
// Wait for flush
sleep(Duration::from_millis(100));
} }
DivaSliderBootstrap::AwaitReset => { DivaSliderBootstrap::AwaitReset => {
while self.packets.len() > 1 { while let Some(ack_packet) = self.in_packets.pop_front() {
self.packets.pop_front(); if ack_packet.command == 0x10 && ack_packet.len == 0x00 && ack_packet.checksum == 0xf1 {
}
if let Some(ack_packet) = self.packets.pop_front() {
info!( info!(
"Diva ack reset {:?} {:?}", "Diva ack reset {:#4x} {:?}",
ack_packet.command, ack_packet.data ack_packet.command, ack_packet.data
); );
let mut info_packet = DivaPacket::from_bytes(0xf0, &[]); info!("Diva sending info");
let info_packet = DivaPacket::from_bytes(0xf0, &[]);
match serial_port.write(info_packet.serialize()) { self.out_packets.push_back(info_packet);
Ok(_) => {
info!("Diva sent info");
self.bootstrap = DivaSliderBootstrap::AwaitInfo; self.bootstrap = DivaSliderBootstrap::AwaitInfo;
work = true; break;
} } else {
Err(e) => { warn!(
error!("Diva send info error {}", e); "Unexpected packet {:#4x} {:?}",
} ack_packet.command, ack_packet.data
);
} }
} }
} }
DivaSliderBootstrap::AwaitInfo => { DivaSliderBootstrap::AwaitInfo => {
if let Some(ack_packet) = self.packets.pop_front() { if let Some(ack_packet) = self.in_packets.pop_front() {
info!( info!(
"Diva ack info {:?} {:?}", "Diva ack info {:#4x} {:?}",
ack_packet.command, ack_packet.data
);
let mut start_packet = DivaPacket::from_bytes(0x03, &[]);
match serial_port.write(start_packet.serialize()) {
Ok(_) => {
info!("Diva sent start");
self.bootstrap = DivaSliderBootstrap::AwaitStart;
work = true;
}
Err(e) => {
error!("Diva send start error {}", e);
}
}
}
}
DivaSliderBootstrap::AwaitStart => {
if let Some(ack_packet) = self.packets.pop_front() {
info!(
"Diva ack start {:?} {:?}",
ack_packet.command, ack_packet.data ack_packet.command, ack_packet.data
); );
info!("Diva sending start");
let start_packet = DivaPacket::from_bytes(0x03, &[]);
self.out_packets.push_back(start_packet);
self.bootstrap = DivaSliderBootstrap::ReadLoop; self.bootstrap = DivaSliderBootstrap::ReadLoop;
work = true;
} }
} }
DivaSliderBootstrap::ReadLoop => { DivaSliderBootstrap::ReadLoop => {
while let Some(data_packet) = self.packets.pop_front() { while let Some(data_packet) = self.in_packets.pop_front() {
if data_packet.command == 0x01 && data_packet.len == 32 { if data_packet.command == 0x01 && data_packet.len == 32 {
let mut input_handle = self.state.input.lock(); let mut input_handle = self.state.input.lock();
input_handle input_handle
@ -325,24 +346,62 @@ impl ThreadJob for DivaSliderJob {
} }
let mut send_lights = false; let mut send_lights = false;
let mut lights_buf = [0; 97]; let mut lights_buf = [0; 94];
{ {
let mut lights_handle = self.state.lights.lock(); let mut lights_handle = self.state.lights.lock();
if lights_handle.dirty { if lights_handle.dirty {
send_lights = true; send_lights = true;
lights_buf[0] = 0x3f; lights_buf[0] = self.brightness;
lights_buf[1..97].copy_from_slice(&lights_handle.ground[0..96]); lights_buf[1..94].copy_from_slice(&lights_handle.ground[0..93]);
lights_handle.dirty = false; lights_handle.dirty = false;
} }
} }
if send_lights { if send_lights {
let mut lights_packet = DivaPacket::from_bytes(0x02, &lights_buf); let lights_packet = DivaPacket::from_bytes(0x02, &lights_buf);
serial_port.write(lights_packet.serialize()).ok(); self.out_packets.push_back(lights_packet);
} }
} }
DivaSliderBootstrap::Halt => {}
}; };
let mut sent = false;
while let Some(mut packet) = self.out_packets.pop_front() {
println!("Sending packet {:?}", packet);
sent = true;
serial_port
.write(packet.serialize())
.map_err(|e| {
error!("Send packet err {}", e);
e
})
.ok();
}
if sent {
println!("Flushing");
serial_port
.flush()
.map_err(|e| {
error!("Flush err {}", e);
e
})
.ok();
serial_port
.write(&[0])
.map_err(|e| {
error!("Send null packet err {}", e);
e
})
.ok();
serial_port
.flush()
.map_err(|e| {
error!("Flush null packet err {}", e);
e
})
.ok();
}
// TODO: async worker? // TODO: async worker?
sleep(Duration::from_millis(10)); sleep(Duration::from_millis(10));
@ -353,7 +412,7 @@ impl ThreadJob for DivaSliderJob {
impl Drop for DivaSliderJob { impl Drop for DivaSliderJob {
fn drop(&mut self) { fn drop(&mut self) {
match self.bootstrap { match self.bootstrap {
DivaSliderBootstrap::AwaitStart | DivaSliderBootstrap::ReadLoop => { DivaSliderBootstrap::ReadLoop => {
let serial_port = self.serial_port.as_mut().unwrap(); let serial_port = self.serial_port.as_mut().unwrap();
let mut stop_packet = DivaPacket::from_bytes(0x04, &[]); let mut stop_packet = DivaPacket::from_bytes(0x04, &[]);
serial_port.write(stop_packet.serialize()).ok(); serial_port.write(stop_packet.serialize()).ok();
@ -361,6 +420,5 @@ impl Drop for DivaSliderJob {
_ => {} _ => {}
}; };
info!("Diva serial port closed"); info!("Diva serial port closed");
// println!("Diva slider dropped");
} }
} }

View File

@ -52,7 +52,7 @@ impl LoopTimer {
Self { Self {
cap: 100, cap: 100,
cur: 0, cur: 0,
buf: vec![Instant::now() - Duration::from_secs(10); 100], buf: vec![Instant::now() - Duration::from_secs(10_000); 100],
freq: Arc::new(AtomicF64::new(0.0)), freq: Arc::new(AtomicF64::new(0.0)),
} }
} }

View File

@ -40,7 +40,7 @@ fn main() {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
{ {
let log_file_path = slider_io::Config::get_log_file_path().unwrap(); let log_file_path = slider_io::system::get_log_file_path().unwrap();
simple_logging::log_to_file(log_file_path.as_path(), log::LevelFilter::Debug).unwrap(); simple_logging::log_to_file(log_file_path.as_path(), log::LevelFilter::Debug).unwrap();
} }

View File

@ -1,7 +1,7 @@
{ {
"package": { "package": {
"productName": "slidershim", "productName": "slidershim",
"version": "0.1.4" "version": "0.2.0"
}, },
"build": { "build": {
"distDir": "../public", "distDir": "../public",

View File

@ -11,6 +11,7 @@
let ledMode = "none"; let ledMode = "none";
let divaSerialPort = "COM1"; let divaSerialPort = "COM1";
let divaBrightness = 63;
let keyboardSensitivity = 20; let keyboardSensitivity = 20;
let outputPolling = "100"; let outputPolling = "100";
let outputWebsocketUrl = "http://localhost:3000"; let outputWebsocketUrl = "http://localhost:3000";
@ -58,6 +59,7 @@
ledMode = payload.ledMode || "none"; ledMode = payload.ledMode || "none";
divaSerialPort = payload.divaSerialPort || "COM1"; divaSerialPort = payload.divaSerialPort || "COM1";
divaBrightness = payload.divaBrightness || 63;
keyboardSensitivity = payload.keyboardSensitivity || 20; keyboardSensitivity = payload.keyboardSensitivity || 20;
outputPolling = payload.outputPolling || "100"; outputPolling = payload.outputPolling || "100";
outputWebsocketUrl = outputWebsocketUrl =
@ -106,6 +108,7 @@
outputMode, outputMode,
ledMode, ledMode,
divaSerialPort, divaSerialPort,
divaBrightness,
keyboardSensitivity, keyboardSensitivity,
outputPolling, outputPolling,
outputWebsocketUrl, outputWebsocketUrl,
@ -137,7 +140,7 @@
<div class="titlebar"> <div class="titlebar">
<div class="header-icon"> <div class="header-icon">
<img src="/icon.png" /> <img src="/icon.png" alt="logo" />
</div> </div>
<div class="header"> <div class="header">
&nbsp;slidershim{versionString} &nbsp;slidershim{versionString}
@ -200,6 +203,32 @@
</select> </select>
</div> </div>
</div> </div>
<div class="row">
<div class="label">Brightness</div>
<div class="input">
<input
type="number"
min="1"
max="255"
step="1"
bind:value={divaBrightness}
on:change={markDirty}
/>
</div>
</div>
<div class="row">
<div class="label" />
<div class="input">
<input
type="range"
min="1"
max="255"
step="1"
bind:value={divaBrightness}
on:change={markDirty}
/>
</div>
</div>
{/if} {/if}
<div class="row"> <div class="row">