From 4f83151b96885979536d28d94e5dbb32750120f4 Mon Sep 17 00:00:00 2001 From: BlackDragon-B Date: Sun, 19 May 2024 17:14:28 +0200 Subject: [PATCH] i have severe brain damage --- .gitignore | 15 +-- Cargo.lock | 251 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- WACCA_Touch_Protocol.md | 22 ++-- src/bridge.rs | 126 ++++++++++++++++++++ src/game.rs | 46 ++++++++ src/lib.rs | 6 + src/main.rs | 203 +++----------------------------- src/unit.rs | 165 ++++++++++++++++++++++++++ src/utils.rs | 13 +++ src/wacca.rs | 215 ---------------------------------- 11 files changed, 637 insertions(+), 427 deletions(-) create mode 100644 Cargo.lock create mode 100644 src/bridge.rs create mode 100644 src/game.rs create mode 100644 src/lib.rs create mode 100644 src/unit.rs create mode 100644 src/utils.rs delete mode 100644 src/wacca.rs diff --git a/.gitignore b/.gitignore index ada8be9..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb \ No newline at end of file +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..20c7fa7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,251 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" +dependencies = [ + "core-foundation-sys", + "mach2", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[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 = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serialport" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "core-foundation-sys", + "io-kit-sys", + "libudev", + "mach2", + "nix", + "regex", + "scopeguard", + "unescaper", + "winapi", +] + +[[package]] +name = "syn" +version = "2.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unescaper" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adf6ad32eb5b3cadff915f7b770faaac8f7ff0476633aa29eb0d9584d889d34" +dependencies = [ + "thiserror", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wabri" +version = "0.1.0" +dependencies = [ + "serialport", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 35c38e0..563f868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -serial2 = "0.2.20" +serialport = "4.3.0" diff --git a/WACCA_Touch_Protocol.md b/WACCA_Touch_Protocol.md index adc5bb1..dd05b99 100644 --- a/WACCA_Touch_Protocol.md +++ b/WACCA_Touch_Protocol.md @@ -10,11 +10,12 @@ For the address the following values are used: - Sync Board -> Unit Boards: 0xE0 + Unit Board ID #### Command ID The following Command ID's are known: -- 0xA8: Get the Unit Board Version -- 0xA0: -- 0x94: -- 0x90: "Initialize" Touch -- 0xA1: Poll board for touch data +- 0xA8: Get Unit Board Version +- 0xA0: Get Unit Board Version 2? +- 0x94: Set Thresholds +- 0x90: "Initialize" unit board +- 0xA1: Poll touch state +- 0xA3: Poll touch state (Analogue) (Not tested yed) #### Variable Data This contains data, it has a variable length. #### Checksum @@ -74,7 +75,14 @@ The sync board sends: The unit boards respond with: `0xD1 0xA1 0x80 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x75 0xF0` - - +#### 0xA3 - Poll touch state (Analogue) +This command retrieves the touch state from the unit boards. +The sync board sends: + +`0xE1 0xA3 0x42 0xF0` + +The unit boards respond with: + +`0xD1 0xA3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x72 0xF0` diff --git a/src/bridge.rs b/src/bridge.rs new file mode 100644 index 0000000..c7604a4 --- /dev/null +++ b/src/bridge.rs @@ -0,0 +1,126 @@ +use std::{env, io::{self, BufReader, Read}, str, sync::{ mpsc::{self, Receiver, Sender}, Arc}, thread, time::{Duration, Instant}}; +use serialport; +use crate::{game::{self, fix_touch}, utils::{self, calc_checksum}, unit}; + +pub fn start(side: bool, wedge_port: &str, game_port: &str) { + let args: Vec = env::args().collect(); + let mut left = unit::WedgePort {hardware_port: serialport::new(wedge_port, 921600).timeout(Duration::from_micros(1000)).open().expect("Unable to open serialport")}; + let mut game = serialport::new(game_port, 115200).timeout(Duration::from_millis(1)).open().expect("Unable to open serialport"); + // for i in 1..100 { + // let mut x: Vec<(u8, String)> = left.get_version(); + // //println!("{:?}",x); + // } + left.set_thresholds(0x11, 0x0C); + left.init(); + thread::sleep(Duration::from_millis(200)); + + let (gametx, gamerx): (Sender>, Receiver>) = mpsc::channel(); + + let mut c = game.try_clone().unwrap(); + thread::spawn(move || { + let mut serialbuffer: Vec = vec![0; 1000]; + loop { + match c.read(serialbuffer.as_mut_slice()) { + Ok(t) => { println!("{:?}", serialbuffer[..t].to_vec()); let _ = &gametx.send(serialbuffer[..t].to_vec()); }, + Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (), + Err(e) => eprintln!("{:?}", e), + } + } + }); + + let mut active: bool = false; + let mut touchbuffer: Vec = vec![0; 36]; + let params = game::SyncBoardParams::get(); + loop { + let x = Instant::now(); + + //game logic + match gamerx.try_recv() { + Ok(m) => { + println!(" a{:?}",m); + let res: Option> = match m[0] { + 0xa0 => { + active = false; + Some([vec![m[0]], "190523".as_bytes().to_vec(), vec![44]].concat().to_vec()) + }, + 0x77 => { + None + }, + 0x20 => { + active = false; + None + }, + 0xa2 => { + active = false; + //Some(vec![ 162, 63, 29, 0, 0, 0, 0 ]) + Some(vec![ 162, 63, 29 ]) + }, + 0x94 => { + active = false; + //Some(vec![ 148, 0, 20, 0, 0, 0, 0 ]) + Some(vec![ 148, 0, 20 ]) + }, + 0xc9 => { + active = true; + //Some(vec![ 201, 0, 73, 0, 0, 0, 0 ]) + Some(vec![ 201, 0, 73 ]) + }, + 0xa8 => { + let mut versions = vec!["190523", "190523", "190523", "190523", "190523", "190523"]; + Some(game::UnitBoardVersionPacket { + sync_board_version: "190523", + unit_board_version: versions, + side: side, + }.serialize()) + }, + 0x72 => { + active = false; + let param: &str = match m[3] { + 0x30 => {params.param0000} + 0x31 => {params.param0016} + 0x33 => {params.param0032} + _ => {""} + }; + Some([param.as_bytes(), &vec![utils::calc_checksum(¶m.as_bytes().to_vec())]].concat()) + }, + 0x9a => { + active = false; + None + }, + _ => { + None + }, + }; + match res { + Some(x) => { let _ = game.write(&x); }, + None => () + } + } + Err(_) => () + + } + if active { + let e = left.get_touch(); + utils::copy_into(&mut touchbuffer, 1, &[0; 24]); + for l in e { + let r = 7-l.0; + touchbuffer[r as usize] = touchbuffer[r as usize] | fix_touch(l.1[0], side); + touchbuffer[(r+6) as usize] = touchbuffer[(r+6) as usize] | fix_touch(l.1[1], side); + touchbuffer[(r+12) as usize] = touchbuffer[(r+12) as usize] | fix_touch(l.1[2], side); + touchbuffer[(r+18) as usize] = touchbuffer[(r+18) as usize] | fix_touch(l.1[3], side); + } + touchbuffer[0] = 129; + touchbuffer[34] = touchbuffer[34]+1; + touchbuffer[35] = 128; + touchbuffer[35] = calc_checksum(&touchbuffer); + if touchbuffer[34] == 127 {touchbuffer[34] = 0}; + println!("write"); + let _ = game.write(&touchbuffer); + } else { + thread::sleep(Duration::from_millis(1)); + } + //reader.read(serial_buf.as_mut_slice()); + println!("{:?}",x.elapsed()); + } + +} diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..db883be --- /dev/null +++ b/src/game.rs @@ -0,0 +1,46 @@ +use crate::utils::calc_checksum; + +pub struct SyncBoardParams<'a> { + pub param0000: &'a str, + pub param0016: &'a str, + pub param0032: &'a str, +} + +impl SyncBoardParams<'static> { + pub fn get() -> SyncBoardParams<'static> { + SyncBoardParams { + param0000: " 0 0 1 2 3 4 5 15 15 15 15 15 15 11 11 11", + param0016: " 11 11 11 128 103 103 115 138 127 103 105 111 126 113 95 100", + param0032: " 101 115 98 86 76 67 68 48 117 0 82 154 0 6 35 4", + } + } +} + +pub struct UnitBoardVersionPacket<'a> { + pub sync_board_version: &'a str, + pub unit_board_version: Vec<&'a str>, + pub side: bool, +} + +impl UnitBoardVersionPacket<'_> { + pub fn serialize(&self) -> Vec { + let mut s: Vec = vec![0xA8]; + s.append(&mut self.sync_board_version.as_bytes().to_vec()); + if self.side {s.push(0x4C)} else {s.push(0x52)}; + for v in &self.unit_board_version { + s.append(&mut v.as_bytes().to_vec()); + } + s.push(calc_checksum(&[s.as_slice(),vec![0x80].as_slice()].concat())); + //if self.side {s.push(104)} else {s.push(118)}; + s + } +} + +pub fn fix_touch(byte: u8, side: bool) -> u8 { + let side = side.clone(); + if side { + byte.reverse_bits() >> 3 + } else { + byte & 0x7f + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..26db842 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +#![feature(exclusive_range_pattern)] + +mod unit; +mod utils; +mod game; +mod bridge; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2285ca3..ddc9ba6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,196 +1,19 @@ #![feature(exclusive_range_pattern)] -use std::{io, sync::{atomic::{AtomicBool, Ordering}, mpsc::{self, Receiver, Sender}, Arc, Mutex}, thread, time::{Duration, Instant}}; -use serial2::SerialPort; -use wacca::{calc_checksum, SyncBoardParams, TouchBinding, CommandPacket}; - -use crate::wacca::fix_touch; - -mod wacca; +use std::env; +mod unit; +mod utils; +mod game; +mod bridge; fn main() { - let game_left = Arc::new(SerialPort::open("/dev/tnt0", 115200).expect("Unable to open serialport")); - - let game_right = Arc::new(SerialPort::open("/dev/tnt2", 115200).expect("Unable to open serialport")); - - let wedge_left = Arc::new(Mutex::new(SerialPort::open("/dev/ttyUSB0", 921600).expect("Unable to open serialport"))); - - let wedge_right = Arc::new(Mutex::new(SerialPort::open("/dev/ttyUSB1", 921600).expect("Unable to open serialport"))); - - let bindings = vec![ - TouchBinding { - game_serial: game_left, - wedge_serial: wedge_left, - side: false, - }, - TouchBinding { - game_serial: game_right, - wedge_serial: wedge_right, - side: true, + let args: Vec = env::args().collect(); + if args.len() > 1 { + match args[1].as_ref() { + "selftest" => { println!("Selftest"); }, + "bridge" | _ => { bridge::start(false, "COM20", "COM5"); } } - ]; - - for binding in bindings.into_iter() { - println!("loading thread"); - - //let we need some params - let params = Arc::new(SyncBoardParams::get(&binding.side)); - - //Sync board -> Game writer thread logic - let (writer_tx, writer_rx): (Sender>, Receiver>) = mpsc::channel(); - let command_tx = writer_tx.clone(); - - let game_serial_1 = binding.game_serial.clone(); - let wedge_serial_1 = binding.wedge_serial.clone(); - thread::spawn(move || { - loop { - match writer_rx.recv() { - Ok(data) => { - let _ = SerialPort::write(&game_serial_1,&data); - }, - Err(e) => {println!("{:?}",e)} - }; - } - }); - //AtomicBool to check if touch should be active - let touch_active = Arc::new(AtomicBool::new(false)); - - //command handler for handshake between game and sync board - let touch_active_1 = touch_active.clone(); - let touch_active_2 = touch_active.clone(); - let game_serial_2 = binding.game_serial.clone(); - let wedge_serial_1 = &binding.wedge_serial.clone(); - let wedge_serial_2 = &binding.wedge_serial.clone(); - let params_1 = params.clone(); - - thread::spawn(move || { - let wedge = &binding.wedge_serial.clone(); - let mut serialbuffer: Vec = vec![0; 1000]; - loop { - let data = loop { - match SerialPort::read(&game_serial_2, serialbuffer.as_mut_slice()) { - Ok(t) => {break serialbuffer[..t].to_vec()}, - Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (), - Err(e) => eprintln!("{:?}", e), - } - }; - let mut wedge = loop { - match wedge.lock() { - Ok(g) => {break g}, - Err(e) => () - } - }; - match wacca::handle_data(&data, ¶ms, touch_active_2.clone(), wedge) { - Some(d) => command_tx.send(d).expect("Something has gone wrong!"), - None => (), - }; - }; - }); - - //Send touch packet - let wedge: Arc> = wedge_serial_2.clone(); - - thread::spawn(move || { - loop { - for i in 0..127 { - if touch_active_1.load(Ordering::Relaxed) { - let now = Instant::now(); - let mut wedge = loop { - match wedge.lock() { - Ok(g) => {break g}, - Err(e) => () - } - }; - let mut touchbuffer: Vec = vec![0; 36]; - for x in 1..7 { - //bottleneck under here - let r: usize = 7-x; - let touch = match wacca::issue_command(&wedge, &CommandPacket { out: true, wedge_id: x as u8, command_id: 0xA1, data: Vec::new() }) { - Ok(data) => data, - Err(_) => continue, - }; - if touch.data.len() >= 4 { - touchbuffer[r as usize] = touchbuffer[r as usize] | fix_touch(touch.data[0], params_1.side); - touchbuffer[(r+6) as usize] = touchbuffer[(r+6) as usize] | fix_touch(touch.data[1], params_1.side); - touchbuffer[(r+12) as usize] = touchbuffer[(r+12) as usize] | fix_touch(touch.data[2], params_1.side); - touchbuffer[(r+18) as usize] = touchbuffer[(r+18) as usize] | fix_touch(touch.data[3], params_1.side); - } - } - touchbuffer[0] = 129; - touchbuffer[34] = i; - touchbuffer[35] = 128; - touchbuffer[35] = calc_checksum(&touchbuffer); - if touchbuffer[34] == 127 {touchbuffer[34] = 0}; - let _ = writer_tx.send(touchbuffer); - io::Write::flush(&mut io::stdout()).unwrap(); - thread::sleep(Duration::from_millis(4)); - } else { - thread::sleep(Duration::from_millis(4)); - } - } - } - }); - - //wedge stuff - //let (wedge_tx, wedge_rx): (Sender>, Receiver>) = mpsc::channel(); //channel pair for the wedge commands (unit board -> sync board) - //let (touch_tx, touch_rx): (Sender, Receiver) = mpsc::channel(); //channel pair for the touch commands (unit boards -> sync board) - -/* //thread for submitting commands to the unit boards - let wedge_serial_1 = binding.wedge_serial.clone(); - thread::spawn(move || { - loop { - match wedge_cmd_rx.recv() { - Ok(data) => { - let _ = SerialPort::write(&wedge_serial_1,&data.serialize()); - }, - Err(e) => {println!("{:?}",e)} - }; - } - }); - - //thread for receiving data from the unit boards - let wedge_serial_2 = binding.wedge_serial.clone(); - thread::spawn(move || { - let mut serialbuffer: Vec = vec![0; 1000]; - loop { - let data = loop { - match SerialPort::read(&wedge_serial_2, serialbuffer.as_mut_slice()) { - Ok(t) => {break serialbuffer[..t].to_vec()}, - Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (), - Err(e) => eprintln!("{:?}", e), - } - }; - let packet = match CommandPacket::new(data) { - Ok(d) => Some(d), - Err(e) => {println!("{:?}", e); None} - }; - match packet { - Some(d) => { - match d.command_id { - 0xA0 | 0xA2 | 0x94 | 0xC9 => { - println!("hfddfi"); - let _ = &wedge_cmd_recv_tx.send(d); - } - _ => {} - } - }, - None => {thread::sleep(Duration::from_millis(10))} - } - // match wacca::handle_data(&data, ¶ms, touch_active_2.clone()) { - // Some(d) => command_tx.send(d).expect("Something has gone wrong!"), - // None => (), - // }; - }; - }); */ - - thread::spawn(move || { - println!("hi"); - thread::sleep(Duration::from_millis(100)); - }); + } else { + bridge::start(true, "COM18", "COM6"); } - - loop { - thread::sleep(Duration::from_secs(1)); - } - -} +} \ No newline at end of file diff --git a/src/unit.rs b/src/unit.rs new file mode 100644 index 0000000..53d64f3 --- /dev/null +++ b/src/unit.rs @@ -0,0 +1,165 @@ +use serialport::SerialPort; +use std::{io::{self, Read, Write}, ops::Range, str, thread, time::{Duration, Instant}}; +use crate::utils::calc_checksum; + +#[derive(Debug)] +struct CommandPacket { + out: bool, + wedge_id: u8, + command_id: u8, + data: Vec +} + +impl CommandPacket { + fn serialize(&self) -> Vec { + let dir: u8 = if self.out { 0xE0 } else { 0xD0 }; + let mut packet: Vec = vec![self.wedge_id+dir, self.command_id]; + packet.extend(&self.data); + let tail: Vec = vec![calc_checksum(&packet),240]; + return [packet, tail].concat(); + } + + fn bulk(&self, r: Range) -> Vec { + let mut commands: Vec = Vec::new(); + for i in r { + commands.push(CommandPacket { out: self.out, wedge_id: i, command_id: self.command_id, data: self.data.clone()}) + } + commands + } + + fn dissect(data: Vec) -> Vec { + let mut commands: Vec = Vec::new(); + + let pieces: Vec<_> = data + .split(|&e| e == 0xf0) + .filter(|v| v.len() > 1 ) + .collect(); + + for command in pieces.iter() { + match CommandPacket::new(command.to_vec()) { + Ok(c) => commands.push(c), + Err(e) => println!("ERR: {:?}", e) + }; + } + commands + } + fn new(mut data: Vec) -> Result { + if data.len() < 4 { + println!("LEN {:X?}",data); + return Err("Invalid Size".to_string()) + } + match data[data.len()-1] { + 0 => data = data[..data.len()-1].to_vec(), + 0xF0 => (), + _ => data = [data, [0xF0].to_vec()].concat() + } + match data[0] { + 209..215 => (), + 225..231 => (), + _ => data = data[1..data.len()].to_vec(), + } + + let c = calc_checksum(&data[0..data.len()-2].to_vec()); + let checksum: u8 = data[data.len()-2]; + if c != checksum { + if calc_checksum(&[data[0..data.len()-2].to_vec(), vec![0x80]].concat()) != checksum { + println!("CHECK {:X?}",data); + return Err("Invalid Checksum".to_string()); + } + }; + let a: (bool, u8) = match data[0] { + 209..215 => (false, data[0]-208), + 225..231 => (true, data[0]-224), + _ => (false,0) + }; + if a.1 == 0 {return Err("Wedge ID out of bounds".to_string())} + + let datalen: usize = if data.len() > 4 { + data.len()-3 + } else { + 2 + }; + return Ok(CommandPacket { + out: a.0, + wedge_id: a.1, + command_id: data[1], + data: data[2..datalen].to_vec() + }) + } +} + +pub struct WedgePort { + pub hardware_port: Box, +} +impl WedgePort { + fn issue_command(&mut self, data: &CommandPacket) -> Result { + self.hardware_port.write(&data.serialize()).expect("Write failed!"); + let _ = self.hardware_port.flush(); + let mut serialbuffer: Vec = vec![0; 32]; + let data = loop { + match self.hardware_port.read(serialbuffer.as_mut_slice()) { + Ok(t) => {break serialbuffer[..t].to_vec()}, + Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {}, + Err(e) => eprintln!("{:?}", e), + }; + }; + //let x = self.hardware_port.read(serialbuffer.as_mut_slice()).expect("Found no data!"); + //println!("{:?}",x); + CommandPacket::new(data) + } + + fn issue_commandblk(&mut self, data: Vec) -> Vec { + for i in data { + let _ = self.hardware_port.write(&i.serialize()); + let _ = self.hardware_port.flush(); + thread::sleep(Duration::from_micros(1000)); + } + //println!("poopy {:?}",start.elapsed()); + let mut serialbuffer: Vec = vec![0; 256]; + let data = loop { + match self.hardware_port.read(serialbuffer.as_mut_slice()) { + Ok(t) => {break serialbuffer[..t].to_vec()}, + Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {}, + Err(e) => eprintln!("{:?}", e), + }; + }; + //let x = self.hardware_port.read(serialbuffer.as_mut_slice()).expect("Found no data!"); + //println!("{:?}",x); + //let pieces: Vec<_> = it.split(|v| v == 0xf0 && it.peek() == 0x00).filter(|v| !v.is_empty()).collect(); + CommandPacket::dissect(data) + } + + pub fn get_version(&mut self) -> Vec<(u8, String)> { + let mut versions: Vec<(u8, String)> = Vec::new(); + // for i in 1..7 { + // match self.issue_command(&CommandPacket { out: true, wedge_id: i, command_id: 0xA8, data: Vec::new() }) { + // Ok(t) => {versions.push((i, str::from_utf8(&t.data).unwrap()[..6].to_string()))} + // Err(e) => println!("ERROR: {:?}", e), + // }; + // } + let p = self.issue_commandblk(CommandPacket { out: true, wedge_id: 1, command_id: 0xA8, data: Vec::new() }.bulk(1..7)); + for x in p { + versions.push((x.wedge_id, str::from_utf8(&x.data).unwrap()[..6].to_string())) + }; + versions + } + + pub fn set_thresholds(&mut self, on: u8, off: u8) { + let p = self.issue_commandblk(CommandPacket { out: true, wedge_id: 1, command_id: 0x94, data: vec![on, off] }.bulk(1..7)); + } + + pub fn init(&mut self) { + let p: Vec = self.issue_commandblk(CommandPacket { out: true, wedge_id: 1, command_id: 0x90, data: vec![0x14, 0x07, 0x7F, 0x3F, 0x44] }.bulk(1..7)); + } + + pub fn get_touch(&mut self) -> Vec<(u8, Vec)> { + let mut s: Vec<(u8, Vec)> = Vec::new(); + let p = self.issue_commandblk(CommandPacket { out: true, wedge_id: 1, command_id: 0xA1, data: Vec::new() }.bulk(1..7)); + for i in p { + s.push((i.wedge_id, i.data[..4].to_vec())) + } + s + } + + +} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..7c04af0 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,13 @@ +pub fn calc_checksum(data: &Vec) -> u8 { + let mut checksum: u8 = 0; + for byte in data.iter() { + checksum ^= byte; + } + checksum +} + +pub fn copy_into(v: &mut Vec, position: usize, data: &[u8]) { + let buf = &mut v[position..]; + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); +} \ No newline at end of file diff --git a/src/wacca.rs b/src/wacca.rs deleted file mode 100644 index f26ee4d..0000000 --- a/src/wacca.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::{io::{self, Read, Write}, str, sync::{atomic::{AtomicBool, Ordering}, mpsc::{Receiver, Sender}, Arc, Mutex}, thread, time::{Duration, Instant}}; - -use serial2::SerialPort; - -pub struct SyncBoardParams<'a> { - pub param0000: &'a str, - pub param0016: &'a str, - pub param0032: &'a str, - pub sync_board_version: &'a str, - pub side: bool, -} - -impl SyncBoardParams<'static> { - pub fn get(side: &bool) -> SyncBoardParams<'static> { - SyncBoardParams { - param0000: " 0 0 1 2 3 4 5 15 15 15 15 15 15 11 11 11", - param0016: " 11 11 11 128 103 103 115 138 127 103 105 111 126 113 95 100", - param0032: " 101 115 98 86 76 67 68 48 117 0 82 154 0 6 35 4", - sync_board_version: "190523", - side: *side, - } - } -} - -pub struct TouchBinding { - pub game_serial: Arc, - pub wedge_serial: Arc>, - pub side: bool, -} - -#[derive(Debug)] -pub struct CommandPacket { - pub out: bool, - pub wedge_id: u8, - pub command_id: u8, - pub data: Vec -} - -pub struct UnitBoardVersionPacket { - pub sync_board_version: String, - pub unit_board_version: Vec, - pub side: bool, -} - -impl UnitBoardVersionPacket { - pub fn serialize(&self) -> Vec { - let mut s: Vec = vec![0xA8]; - s.append(&mut self.sync_board_version.as_bytes().to_vec()); - if self.side {s.push(0x4C)} else {s.push(0x52)}; - for v in &self.unit_board_version { - s.append(&mut v.as_bytes().to_vec()); - } - s.push(calc_checksum(&[s.as_slice(),vec![0x80].as_slice()].concat())); - //if self.side {s.push(104)} else {s.push(118)}; - s - } -} - -impl CommandPacket { - pub fn serialize(&self) -> Vec { - let dir: u8 = if self.out { 0xE0 } else { 0xD0 }; - let mut packet: Vec = vec![self.wedge_id+dir, self.command_id]; - packet.extend(&self.data); - let tail: Vec = vec![calc_checksum(&packet),240]; - return [packet, tail].concat(); - } - - pub fn new(mut data: Vec) -> Result { //TODO: Rewrite this parser to be more lenient with incoming data (trailing zero's etc) - if data.len() < 4 { - return Err("Invalid Size") - } - if data[data.len()-1] == 0 { - data = data[..data.len()-1].to_vec(); - } - //let c: u8 = if data[1] == 0xA1 { - // calc_checksum(&[data[0..data.len()-2].to_vec(), vec![0x80]].concat()) - //} else { - let c = calc_checksum(&data[0..data.len()-2].to_vec()); - - let checksum: u8 = data[data.len()-2]; - if c != checksum { - if calc_checksum(&[data[0..data.len()-2].to_vec(), vec![0x80]].concat()) != checksum { - println!("check"); - println!("{:X?}",data); - return Err("Invalid Checksum"); - } - }; - let a: (bool, u8) = match data[0] { - 209..215 => (false, data[0]-208), - 225..231 => (true, data[0]-224), - _ => (false,0) - }; - if a.1 == 0 {return Err("Wedge ID out of bounds")} - - let datalen: usize = if data.len() > 4 { - data.len()-3 - } else { - 2 - }; - return Ok(CommandPacket { - out: a.0, - wedge_id: a.1, - command_id: data[1], - data: data[2..datalen].to_vec() - }) - } -} - -pub fn calc_checksum(data: &Vec) -> u8 { - let mut checksum: u8 = 0; - for byte in data.iter() { - checksum ^= byte; - } - checksum -} - -pub fn handle_data(buffer: &Vec, params: &SyncBoardParams, mut scan_active: Arc, mut wedge: std::sync::MutexGuard<'_, SerialPort>) -> Option> { - println!("aaaa {:?}",buffer[0]); - match buffer[0] { - 0xa0 => { - scan_active.store(false, Ordering::Relaxed); - return Some([vec![buffer[0]], params.sync_board_version.as_bytes().to_vec(), vec![44]].concat().to_vec()); - }, - 0x77 => { - return None; - }, - 0x20 => { - scan_active.store(false, Ordering::Relaxed); - return None; - }, - 0xa2 => { - scan_active.store(false, Ordering::Relaxed); - for i in 1..7 { - let packet = issue_command(&wedge,&CommandPacket { out: true, wedge_id: i, command_id: 0xA0, data: Vec::new()}); - } - return Some(vec![ 162, 63, 29, 0, 0, 0, 0 ]); - }, - 0x94 => { - scan_active.store(false, Ordering::Relaxed); - for i in 1..7 { - let packet = issue_command(&wedge,&CommandPacket { out: true, wedge_id: i, command_id: 0x94, data: Vec::new() }); - } - return Some(vec![ 148, 0, 20, 0, 0, 0, 0 ]); - }, - 0xc9 => { - scan_active.store(true, Ordering::Relaxed); - for i in 1..7 { - let packet = issue_command(&wedge,&CommandPacket { out: true, wedge_id: i, command_id: 0x90, data: vec![0x14, 0x07, 0x7F, 0x3F,]}); - } - return Some(vec![ 201, 0, 73, 0, 0, 0, 0 ]); - }, - 0xa8 => { - let mut versions: Vec = Vec::new(); - for i in 1..7 { - let packet = issue_command(&wedge,&CommandPacket { out: true, wedge_id: i, command_id: 0xA0, data: Vec::new() }); - //thread::sleep(Duration::from_secs(1)); - let data = packet.expect("veri bad"); - let version = str::from_utf8(&data.data).expect("Error").to_string(); - versions.push(version[..6].to_string()); - println!("{:?}", data) - - } - //let mut versions = vec!["190523".to_string(), "190523".to_string(), "190523".to_string(), "190523".to_string(), "190523".to_string(), "190523".to_string()]; - return Some(UnitBoardVersionPacket { - sync_board_version: params.sync_board_version.to_string(), - unit_board_version: versions, - side: params.side, - }.serialize()); - }, - 0x72 => { - scan_active.store(false, Ordering::Relaxed); - let param: &str = match buffer[3] { - 0x30 => {params.param0000} - 0x31 => {params.param0016} - 0x33 => {params.param0032} - _ => {""} - }; - return Some([param.as_bytes(), &vec![calc_checksum(¶m.as_bytes().to_vec())]].concat()) - }, - 0x9a => { - scan_active.store(false, Ordering::Relaxed); - return None; - }, - _ => { - return None; - }, - } -} - -pub(crate) fn issue_command(port: &SerialPort, data: &CommandPacket) -> Result { - let now = Instant::now(); - let _ = port.write(&data.serialize()); - //thread::sleep(Duration::from_secs(1)); - let mut serialbuffer: Vec = vec![0; 32]; - println!("afw {:?}",now.elapsed()); - let data = loop { - //println!("hi"); - match port.read(serialbuffer.as_mut_slice()) { //slow poopy function - Ok(t) => {break serialbuffer[..t].to_vec()}, - Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (), - Err(e) => eprintln!("{:?}", e), - }; - }; - println!("x {:?}",now.elapsed()); - CommandPacket::new(data) -} - -pub fn fix_touch(byte: u8, side: bool) -> u8 { - let side = side.clone(); - if side { - byte.reverse_bits() >> 3 - } else { - byte & 0x7f - } -} \ No newline at end of file