mirror of
https://github.com/nekename/OpenDeck.git
synced 2026-10-28 18:02:23 +00:00
Implement communication with ProntoKey devices
This commit is contained in:
1 parent
3b648014a0
commit
4e7be5f1d9
5 files changed
+234
-3
No files matched your search
Generated
+1
@@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "opendeck",
|
||||
"version": "2.0.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^2.0.3",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
|
||||
Generated
+78
@@ -2,6 +2,27 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "CoreFoundation-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mach",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "IOKit-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a"
|
||||
dependencies = [
|
||||
"CoreFoundation-sys",
|
||||
"libc",
|
||||
"mach",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
@@ -1823,6 +1844,26 @@ dependencies = [
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libudev"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libudev-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.1.1"
|
||||
@@ -1894,6 +1935,24 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@@ -2221,6 +2280,7 @@ version = "2.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serialport",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
]
|
||||
@@ -3140,6 +3200,24 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serialport"
|
||||
version = "4.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c32634e2bd4311420caa504404a55fad2131292c485c97014cbed89a5899885f"
|
||||
dependencies = [
|
||||
"CoreFoundation-sys",
|
||||
"IOKit-sys",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libudev",
|
||||
"mach2",
|
||||
"nix",
|
||||
"regex",
|
||||
"scopeguard",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
|
||||
@@ -16,6 +16,7 @@ tauri-build = { version = "1.5.0", features = [] }
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
tauri = { version = "1.5.2", features = [ "system-tray", "api-all" ] }
|
||||
serialport = "4.2.2"
|
||||
|
||||
[features]
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
@@ -0,0 +1,146 @@
|
||||
use std::thread;
|
||||
|
||||
use std::time::Duration;
|
||||
use serde_json::Value;
|
||||
|
||||
/// Implemented by all supported devices.
|
||||
trait BaseDevice {
|
||||
fn num_keys(&self) -> u8;
|
||||
fn num_dials(&self) -> u8;
|
||||
|
||||
fn key_down(&self, key: u8);
|
||||
fn key_up(&self, key: u8);
|
||||
fn dial_rotate(&self, dial: u8, ticks: i16);
|
||||
}
|
||||
|
||||
/// A representation of a ProntoKey device.
|
||||
struct ProntoKeyDevice {
|
||||
address: String
|
||||
}
|
||||
impl BaseDevice for ProntoKeyDevice {
|
||||
fn num_keys(&self) -> u8 { 9 }
|
||||
fn num_dials(&self) -> u8 { 2 }
|
||||
|
||||
fn key_down(&self, key: u8) {
|
||||
println!("{} down {}", &self.address, key);
|
||||
}
|
||||
fn key_up(&self, key: u8) {
|
||||
println!("{} up {}", &self.address, key);
|
||||
}
|
||||
fn dial_rotate(&self, dial: u8, ticks: i16) {
|
||||
println!("{} rotate {} by {}", &self.address, dial, ticks);
|
||||
}
|
||||
}
|
||||
impl ProntoKeyDevice {
|
||||
/// Attempt to open a serial connection with the device and handle incoming data.
|
||||
fn init(port: String) {
|
||||
thread::spawn(|| {
|
||||
let mut device: Option<ProntoKeyDevice> = Option::None;
|
||||
let mut last_key: u8 = 0;
|
||||
let mut last_sliders: Vec<i16> = vec![0; 2];
|
||||
|
||||
let mut port = match
|
||||
serialport::new(port, 57600)
|
||||
.timeout(Duration::from_millis(10))
|
||||
.open()
|
||||
{
|
||||
Ok(p) => p,
|
||||
Err(e) => panic!("Failed to open serial port: {}", e.description)
|
||||
};
|
||||
let _ = port.write("register".as_bytes());
|
||||
|
||||
let mut serial_buf: Vec<u8> = vec![0; 1024];
|
||||
let mut holding_string: String = "".to_owned();
|
||||
|
||||
loop {
|
||||
match port.read(serial_buf.as_mut_slice()) {
|
||||
Ok(t) => {
|
||||
match std::str::from_utf8(&serial_buf[..t]) {
|
||||
Ok(data) => holding_string += data,
|
||||
Err(_) => break
|
||||
}
|
||||
// Iterate through JSON objects received from device that are being held in the buffer.
|
||||
while holding_string.contains("}") {
|
||||
let index = holding_string.find("}").unwrap_or_default();
|
||||
let chunk = holding_string[..=index].trim();
|
||||
let j: Value = match serde_json::from_str(chunk) {
|
||||
Ok(data) => data,
|
||||
Err(_) => continue
|
||||
};
|
||||
holding_string = holding_string[(index + 1)..].to_owned();
|
||||
|
||||
// If the device is uninitialised, attempt to read its MAC address and initialise.
|
||||
if device.is_none() {
|
||||
match &j["address"] {
|
||||
Value::String(address) => {
|
||||
device = Some(ProntoKeyDevice { address: address.clone() });
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let device = device.as_ref().unwrap();
|
||||
|
||||
// Handle key presses and releases.
|
||||
match &j["key"] {
|
||||
Value::Number(num) => {
|
||||
match num.as_u64().unwrap_or_default() as u8 {
|
||||
0 => device.key_up(last_key),
|
||||
val => {
|
||||
device.key_down(val);
|
||||
last_key = val;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Handle slider value changes.
|
||||
match &j["slider0"] {
|
||||
Value::Number(val) => {
|
||||
let val: i16 = match val.as_i64() {
|
||||
Some(v) => v as i16,
|
||||
_ => last_sliders[0]
|
||||
};
|
||||
device.dial_rotate(0, val - last_sliders[0]);
|
||||
last_sliders[0] = val;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
match &j["slider1"] {
|
||||
Value::Number(val) => {
|
||||
let val: i16 = match val.as_i64() {
|
||||
Some(v) => v as i16,
|
||||
_ => last_sliders[1]
|
||||
};
|
||||
device.dial_rotate(1, val - last_sliders[1]);
|
||||
last_sliders[1] = val;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => (),
|
||||
Err(e) => eprintln!("{:?}", e)
|
||||
}
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to initialise all connected devices.
|
||||
pub fn initialise_devices() {
|
||||
// Iterate through available serial ports and attempt to register them as ProntoKey devices.
|
||||
for port in serialport::available_ports().unwrap_or_default() {
|
||||
match port.port_type {
|
||||
serialport::SerialPortType::UsbPort(info) => {
|
||||
if info.vid == 0x10c4 && info.pid == 0xea60 {
|
||||
ProntoKeyDevice::init(port.port_name);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
// Prevents additional console window on Windows in release
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
mod devices;
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
devices::initialise_devices();
|
||||
|
||||
match tauri::Builder::default().run(tauri::generate_context!()) {
|
||||
Err(e) => panic!("Error while running Tauri application: {}", e.to_string()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user