Compare commits
13 commits
9e43e6a943
...
17f484acd5
Author | SHA1 | Date | |
---|---|---|---|
17f484acd5 | |||
9a68f43e5d | |||
1e1a82830b | |||
311427b0a5 | |||
b956c543fc | |||
a2b629beab | |||
c0daf3f64c | |||
9f4b2e57a2 | |||
b63986711d | |||
321ece84bc | |||
474841212d | |||
d90011d921 | |||
9c61d88fe4 |
14 changed files with 592 additions and 312 deletions
117
auto/Cargo.lock
generated
117
auto/Cargo.lock
generated
|
@ -38,7 +38,7 @@ dependencies = [
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"atspi-common",
|
"atspi-common",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459"
|
checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"immutable-chunkmap",
|
"immutable-chunkmap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
@ -93,7 +93,7 @@ checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"paste",
|
"paste",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"windows 0.58.0",
|
"windows 0.58.0",
|
||||||
|
@ -198,7 +198,7 @@ dependencies = [
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys 0.6.0+11769913",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -747,7 +747,7 @@ dependencies = [
|
||||||
"polling",
|
"polling",
|
||||||
"rustix 0.38.44",
|
"rustix 0.38.44",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1088,6 +1088,21 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
"lock_api",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot_core",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dasp_sample"
|
name = "dasp_sample"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1104,6 +1119,27 @@ dependencies = [
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "directories"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1240,7 +1276,7 @@ dependencies = [
|
||||||
"epaint",
|
"epaint",
|
||||||
"log",
|
"log",
|
||||||
"profiling",
|
"profiling",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"type-map",
|
"type-map",
|
||||||
"web-time",
|
"web-time",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
@ -1801,7 +1837,7 @@ checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"gpu-descriptor-types",
|
"gpu-descriptor-types",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1832,6 +1868,12 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
@ -2123,7 +2165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2135,6 +2177,8 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"common",
|
"common",
|
||||||
"cpal",
|
"cpal",
|
||||||
|
"dashmap",
|
||||||
|
"directories",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui-toast",
|
"egui-toast",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
|
@ -2190,7 +2234,7 @@ dependencies = [
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
@ -2468,7 +2512,7 @@ dependencies = [
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv",
|
"spirv",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2498,7 +2542,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys 0.5.0+25.2.9519653",
|
"ndk-sys 0.5.0+25.2.9519653",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2513,7 +2557,7 @@ dependencies = [
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys 0.6.0+11769913",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2912,6 +2956,12 @@ version = "1.20.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orbclient"
|
name = "orbclient"
|
||||||
version = "0.3.48"
|
version = "0.3.48"
|
||||||
|
@ -3238,7 +3288,7 @@ dependencies = [
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"simd_helpers",
|
"simd_helpers",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"v_frame",
|
"v_frame",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
@ -3302,6 +3352,17 @@ dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"libredox",
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
@ -3606,7 +3667,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"rustix 0.38.44",
|
"rustix 0.38.44",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"wayland-csd-frame",
|
"wayland-csd-frame",
|
||||||
|
@ -3803,7 +3864,16 @@ version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3817,6 +3887,17 @@ dependencies = [
|
||||||
"syn 2.0.99",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.99",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
@ -4374,7 +4455,7 @@ dependencies = [
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
]
|
]
|
||||||
|
@ -4412,7 +4493,7 @@ dependencies = [
|
||||||
"renderdoc-sys",
|
"renderdoc-sys",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub enum ControlPacket {
|
||||||
EStop,
|
EStop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct SensorData {
|
pub struct SensorData {
|
||||||
/// left distance, mm
|
/// left distance, mm
|
||||||
pub tof_l: Option<u16>,
|
pub tof_l: Option<u16>,
|
||||||
|
@ -45,6 +45,12 @@ pub struct TelemetryPacket {
|
||||||
pub cam_state: CamState,
|
pub cam_state: CamState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for TelemetryPacket {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { sensors: Default::default(), cam_state: CamState::Idle }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub enum CamState {
|
pub enum CamState {
|
||||||
Firing,
|
Firing,
|
||||||
|
|
|
@ -89,7 +89,7 @@ async fn main(spawner: Spawner) {
|
||||||
spawner.spawn(logger_task(driver)).unwrap();
|
spawner.spawn(logger_task(driver)).unwrap();
|
||||||
|
|
||||||
let limit_switch = Input::new(p.PIN_16, Pull::Up);
|
let limit_switch = Input::new(p.PIN_16, Pull::Up);
|
||||||
let mut auto_status = Output::new(p.PIN_2, Level::Low);
|
let mut auto_status = Output::new(p.PIN_2, Level::High);
|
||||||
|
|
||||||
let mut d: pwm::Config = Default::default();
|
let mut d: pwm::Config = Default::default();
|
||||||
d.divider = 40.into();
|
d.divider = 40.into();
|
||||||
|
|
117
interface/Cargo.lock
generated
117
interface/Cargo.lock
generated
|
@ -38,7 +38,7 @@ dependencies = [
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"atspi-common",
|
"atspi-common",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459"
|
checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"immutable-chunkmap",
|
"immutable-chunkmap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
@ -93,7 +93,7 @@ checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"paste",
|
"paste",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"windows 0.58.0",
|
"windows 0.58.0",
|
||||||
|
@ -198,7 +198,7 @@ dependencies = [
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys 0.6.0+11769913",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -739,7 +739,7 @@ dependencies = [
|
||||||
"polling",
|
"polling",
|
||||||
"rustix",
|
"rustix",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1080,6 +1080,21 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
"lock_api",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot_core",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dasp_sample"
|
name = "dasp_sample"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1096,6 +1111,27 @@ dependencies = [
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "directories"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1232,7 +1268,7 @@ dependencies = [
|
||||||
"epaint",
|
"epaint",
|
||||||
"log",
|
"log",
|
||||||
"profiling",
|
"profiling",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"type-map",
|
"type-map",
|
||||||
"web-time",
|
"web-time",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
@ -1793,7 +1829,7 @@ checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"gpu-descriptor-types",
|
"gpu-descriptor-types",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1824,6 +1860,12 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
@ -2115,7 +2157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2127,6 +2169,8 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"common",
|
"common",
|
||||||
"cpal",
|
"cpal",
|
||||||
|
"dashmap",
|
||||||
|
"directories",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui-toast",
|
"egui-toast",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
|
@ -2182,7 +2226,7 @@ dependencies = [
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
@ -2454,7 +2498,7 @@ dependencies = [
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv",
|
"spirv",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2484,7 +2528,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys 0.5.0+25.2.9519653",
|
"ndk-sys 0.5.0+25.2.9519653",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2499,7 +2543,7 @@ dependencies = [
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys 0.6.0+11769913",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2898,6 +2942,12 @@ version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orbclient"
|
name = "orbclient"
|
||||||
version = "0.3.48"
|
version = "0.3.48"
|
||||||
|
@ -3224,7 +3274,7 @@ dependencies = [
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"simd_helpers",
|
"simd_helpers",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"v_frame",
|
"v_frame",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
@ -3288,6 +3338,17 @@ dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"libredox",
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
@ -3579,7 +3640,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"rustix",
|
"rustix",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"wayland-csd-frame",
|
"wayland-csd-frame",
|
||||||
|
@ -3776,7 +3837,16 @@ version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3790,6 +3860,17 @@ dependencies = [
|
||||||
"syn 2.0.96",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.96",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
@ -4347,7 +4428,7 @@ dependencies = [
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
]
|
]
|
||||||
|
@ -4385,7 +4466,7 @@ dependencies = [
|
||||||
"renderdoc-sys",
|
"renderdoc-sys",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
|
|
|
@ -23,3 +23,5 @@ chrono = "0.4.40"
|
||||||
image = "0.25.5"
|
image = "0.25.5"
|
||||||
libloading = "0.8.6"
|
libloading = "0.8.6"
|
||||||
emath = "0.31.1"
|
emath = "0.31.1"
|
||||||
|
dashmap = { version = "6.1.0", features = ["serde"] }
|
||||||
|
directories = "6.0.0"
|
||||||
|
|
|
@ -1,28 +1,47 @@
|
||||||
use std::{collections::VecDeque, ops::{Deref, Div, Index, Range, Sub}, sync::Arc};
|
use std::{future::Future, ops::{Deref, Range}, pin::Pin, sync::{atomic::{AtomicBool, Ordering}, Arc}, thread::sleep, time::Duration};
|
||||||
|
|
||||||
use common::{CamState, ControlPacket, SensorData, TelemetryPacket};
|
use common::{CamState, ControlPacket, SensorData, TelemetryPacket};
|
||||||
use anyhow::{Context, Ok, Result};
|
use anyhow::{anyhow, Ok, Result};
|
||||||
use eframe::Storage;
|
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use tokio::sync::{self, broadcast, mpsc, watch};
|
use tokio::{sync::watch, task::JoinHandle};
|
||||||
|
|
||||||
pub struct AutoConfig {
|
use crate::storage::StorageManager;
|
||||||
turn_gain: f32,
|
|
||||||
auto_fire_distance: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AutoInterface {
|
pub struct AutoInterface {
|
||||||
command_sender: Option<mpsc::Sender<ControlPacket>>,
|
command_sender: watch::Sender<ControlPacket>,
|
||||||
data_receiver: watch::Receiver<TelemetryPacket>,
|
data_receiver: watch::Receiver<TelemetryPacket>,
|
||||||
config: &'static dyn Storage,
|
config: StorageManager,
|
||||||
enabled: bool,
|
enabled: Arc<AtomicBool>,
|
||||||
|
enable_permission: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AutoInterface {
|
impl AutoInterface {
|
||||||
|
/// new
|
||||||
|
///
|
||||||
|
/// returns command channel from auto, enable status
|
||||||
|
pub fn new(data: watch::Receiver<TelemetryPacket>, config: StorageManager, enable_permission: Arc<AtomicBool>) -> (Self, watch::Receiver<ControlPacket>, Arc<AtomicBool>) {
|
||||||
|
let (commands, receiver) = watch::channel(ControlPacket::Fire);
|
||||||
|
|
||||||
|
let enabled = Arc::new(AtomicBool::new(false));
|
||||||
|
let interface = Self {
|
||||||
|
command_sender: commands,
|
||||||
|
data_receiver: data,
|
||||||
|
config,
|
||||||
|
enabled: enabled.clone(),
|
||||||
|
enable_permission,
|
||||||
|
};
|
||||||
|
|
||||||
|
(interface, receiver, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&self) -> watch::Receiver<ControlPacket> {
|
||||||
|
self.command_sender.subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
/// change active command, fails if not in control
|
/// change active command, fails if not in control
|
||||||
pub async fn run_command(&self, command: ControlPacket) -> Result<()> {
|
pub fn run_command(&self, command: ControlPacket) -> Result<()> {
|
||||||
self.command_sender.as_ref().context("no sender")?.send(command).await?;
|
self.command_sender.send(command)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn sensor_data(&mut self) -> SensorData {
|
pub fn sensor_data(&mut self) -> SensorData {
|
||||||
|
@ -34,22 +53,33 @@ impl AutoInterface {
|
||||||
pub async fn sensor_update(&mut self) -> SensorData {
|
pub async fn sensor_update(&mut self) -> SensorData {
|
||||||
self.data_receiver.changed().await.unwrap();
|
self.data_receiver.changed().await.unwrap();
|
||||||
self.data_receiver.borrow().sensors.clone()
|
self.data_receiver.borrow().sensors.clone()
|
||||||
|
}
|
||||||
|
pub fn sensor_update_blocking(&mut self) -> SensorData {
|
||||||
|
loop {
|
||||||
|
if self.data_receiver.has_changed().unwrap() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(Duration::from_millis(10)); // TODO: exponential or condvars
|
||||||
|
}
|
||||||
|
self.data_receiver.borrow_and_update().sensors.clone()
|
||||||
}
|
}
|
||||||
/// disable auto
|
/// disable auto
|
||||||
pub fn disable(&self) {unimplemented!()}
|
pub fn disable(&mut self) {
|
||||||
|
self.enabled.store(false, Ordering::Release);
|
||||||
|
}
|
||||||
/// request auto enable, fails if the driver does not grant it
|
/// request auto enable, fails if the driver does not grant it
|
||||||
pub fn enable(&mut self) -> Result<()> {
|
pub fn enable(&mut self) -> Result<()> {
|
||||||
self.enabled = self.command_sender.is_some();
|
if self.enable_permission.load(Ordering::Acquire) {
|
||||||
Ok(())
|
self.enabled.store(true, Ordering::Release);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("no enable"))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn enabled(&self) -> bool { self.enabled}
|
pub fn enabled(&self) -> bool { self.enabled.load(Ordering::Acquire) }
|
||||||
pub fn conf(&self, key: &'static Configurable) -> f32 {
|
pub fn conf(&self, key: &'static Configurable) -> f32 {
|
||||||
self.config.get_string(&key.name)
|
self.config.load(key)
|
||||||
.map(|s| s.parse().ok())
|
|
||||||
.flatten().unwrap_or(key.default)
|
|
||||||
}
|
}
|
||||||
fn send_message(&self, message: String) {unimplemented!()}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Configurable {
|
pub struct Configurable {
|
||||||
|
@ -93,13 +123,45 @@ impl Default for Configurable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A fake trait in the sense that these methods are exposed as symbols, not trait methods
|
pub struct Auto {
|
||||||
pub trait Auto {
|
library: Arc<Library>,
|
||||||
|
// these aren't actually static, they have the same lifetime as the library xP
|
||||||
|
configs: &'static [Configurable],
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Auto {
|
||||||
|
pub fn new(path: &str) -> Result<Self> {
|
||||||
|
let lib = unsafe {Library::new(path)?};
|
||||||
|
let lib = Arc::new(lib);
|
||||||
|
|
||||||
|
let configurations: Symbol<&&[Configurable]> = unsafe {lib.get(b"CONFIGS").unwrap()};
|
||||||
|
|
||||||
|
let name: Symbol<&&'static str> = unsafe {lib.get(b"NAME").unwrap()};
|
||||||
|
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
configs: *configurations,
|
||||||
|
name: *name,
|
||||||
|
library: lib,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
/// entrypoint
|
/// entrypoint
|
||||||
async fn run(interface: &AutoInterface);
|
pub fn run(&self, interface: AutoInterface) -> Result<()> {
|
||||||
/// register
|
let func: Symbol<unsafe extern "C" fn(AutoInterface) -> ()> = unsafe {self.library.get(b"entry")?};
|
||||||
fn default_configs() -> [Configurable];
|
|
||||||
fn name() -> &'static str;
|
unsafe { func(interface.clone()) };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configs(&self) -> &'static [Configurable] {
|
||||||
|
self.configs
|
||||||
|
}
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,4 +180,3 @@ pub fn get_confs() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
146
interface/src/auto_impl.rs
Normal file
146
interface/src/auto_impl.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
|
||||||
|
use std::{collections::VecDeque, future::Future, ops::Sub, pin::Pin};
|
||||||
|
|
||||||
|
use common::CamState;
|
||||||
|
use crate::auto::{AutoInterface, Configurable};
|
||||||
|
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub fn entry(interface: AutoInterface) -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||||||
|
Box::pin(auto(interface))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub static NAME: &'static str = "scanseek v1";
|
||||||
|
|
||||||
|
const AUTO_GAP: Configurable = Configurable::new("auto minimum gap").range(0. .. 300.).default(140.)
|
||||||
|
.description("distance (mm) distance measurements must instantaneously drop to indicate a detection. This should line up with the size of the smallest robot you compete against");
|
||||||
|
const AUTO_SELF_OCCLUSION: Configurable = Configurable::new("auto self occlusion").range(0. .. 200.).default(143.)
|
||||||
|
.description("distance (mm) below which measurements are considered noise in the scan phase");
|
||||||
|
const AUTO_CONVERGENCE_POINT: Configurable = Configurable::new("auto convergence").range(100. .. 300.).default(190.)
|
||||||
|
.description("distance (mm) where the tof beams intersect");
|
||||||
|
const AUTO_SEEK_RANGE: Configurable = Configurable::new("auto seek range").range(200. .. 8000.).default(500.);
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub static CONFIGS: &[Configurable] = &[
|
||||||
|
AUTO_GAP,
|
||||||
|
AUTO_SELF_OCCLUSION,
|
||||||
|
AUTO_CONVERGENCE_POINT,
|
||||||
|
AUTO_SEEK_RANGE,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub async fn auto(mut interface: AutoInterface) {
|
||||||
|
let mut tof_l = Stats::new();
|
||||||
|
let mut tof_r = Stats::new();
|
||||||
|
loop {
|
||||||
|
let data = interface.sensor_update().await;
|
||||||
|
println!("auto got on data");
|
||||||
|
let cam = interface.cam_state();
|
||||||
|
let CamState::Charged = cam else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(latest_tof_l) = data.tof_l else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
tof_l.update(latest_tof_l as i16);
|
||||||
|
let Some(latest_tof_r) = data.tof_r else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
tof_r.update(latest_tof_r as i16);
|
||||||
|
|
||||||
|
let auto_gap = interface.conf(&AUTO_GAP);
|
||||||
|
let auto_self_occlusion = interface.conf(&AUTO_SELF_OCCLUSION);
|
||||||
|
|
||||||
|
let detection = |latest: u16, delta: i16| {
|
||||||
|
delta < auto_gap as i16 && latest > auto_self_occlusion as u16
|
||||||
|
};
|
||||||
|
|
||||||
|
if detection(latest_tof_l, tof_l.delta()) || detection(latest_tof_l, tof_l.delta()) {
|
||||||
|
if let Ok(()) = interface.enable() {
|
||||||
|
println!("found, now seek");
|
||||||
|
seek(interface.clone(), &mut tof_l, &mut tof_r).await;
|
||||||
|
} else {
|
||||||
|
println!("requested enable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn seek(mut interface: AutoInterface, tof_l: &mut Stats<i16>, tof_r: &mut Stats<i16>) {
|
||||||
|
let crossover = interface.conf(&AUTO_CONVERGENCE_POINT) as i16;
|
||||||
|
let range = interface.conf(&AUTO_SEEK_RANGE) as i16;
|
||||||
|
loop {
|
||||||
|
let data = interface.sensor_data();
|
||||||
|
data.tof_l.map(|d| tof_l.update(d as i16));
|
||||||
|
data.tof_r.map(|d| tof_r.update(d as i16));
|
||||||
|
|
||||||
|
let left_near = tof_l.latest() < crossover && tof_l.delta() < 70;
|
||||||
|
let right_near = tof_r.latest() < crossover && tof_r.delta() < 70;
|
||||||
|
|
||||||
|
let left_far = tof_l.latest() > crossover && tof_l.latest() < range && tof_l.delta() < 70;
|
||||||
|
let right_far = tof_r.latest() > crossover && tof_r.latest() < range && tof_r.delta() < 70;
|
||||||
|
|
||||||
|
let near = left_near || right_near;
|
||||||
|
|
||||||
|
let far = !near && (left_far || right_far);
|
||||||
|
|
||||||
|
let mut twist = 0.0;
|
||||||
|
if near {
|
||||||
|
if tof_l.max() > tof_r.max() {
|
||||||
|
twist = 1.0; // right
|
||||||
|
} else {
|
||||||
|
twist = -1.0; // left
|
||||||
|
}
|
||||||
|
} else if far {
|
||||||
|
if tof_l.max() > tof_r.max() {
|
||||||
|
twist = -1.0; // left
|
||||||
|
} else {
|
||||||
|
twist = 1.0; // right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = interface.run_command(common::ControlPacket::Twist(1.0, twist));
|
||||||
|
interface.sensor_update_blocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Stats<T> {
|
||||||
|
table: VecDeque<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy> Stats<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { table: VecDeque::new() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_ELEMENTS: usize = 3;
|
||||||
|
|
||||||
|
pub fn update(&mut self, elem: T) {
|
||||||
|
self.table.push_front(elem);
|
||||||
|
if self.table.len() > Self::MAX_ELEMENTS {
|
||||||
|
self.table.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// panics if no values have been written
|
||||||
|
pub fn latest(&self) -> T {
|
||||||
|
self.table.front().unwrap().to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Ord + Sub<Output = T> + Copy + From<u8>> Stats<T> {
|
||||||
|
pub fn delta(&self) -> T {
|
||||||
|
*self.table.get(0).unwrap_or(&T::from(0)) - *self.table.get(1).unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max(&self) -> T {
|
||||||
|
*self.table.iter().max().unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min(&self) -> T {
|
||||||
|
*self.table.iter().max().unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,10 @@
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::{path::Path, time::{Duration, SystemTime, UNIX_EPOCH}};
|
||||||
|
|
||||||
use anyhow::Ok;
|
use anyhow::Ok;
|
||||||
use common::{ControlPacket, TelemetryPacket};
|
use common::{ControlPacket, TelemetryPacket};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{fs::File, io::AsyncWriteExt, sync::mpsc::Receiver, time::Instant};
|
use tokio::{fs::File, io::AsyncWriteExt, sync::mpsc::Receiver, time::Instant};
|
||||||
|
|
||||||
use crate::storage_dir::storage;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub enum CombatData {
|
pub enum CombatData {
|
||||||
|
@ -16,8 +14,8 @@ pub enum CombatData {
|
||||||
|
|
||||||
type CombatLogRow = (CombatData, u128);
|
type CombatLogRow = (CombatData, u128);
|
||||||
|
|
||||||
pub async fn combat_logger(mut data: Receiver<CombatData>) -> anyhow::Result<()> {
|
pub async fn combat_logger(mut data: Receiver<CombatData>, path: &Path) -> anyhow::Result<()> {
|
||||||
let mut path = storage();
|
let mut path = path.to_path_buf();
|
||||||
let time = chrono::offset::Utc::now();
|
let time = chrono::offset::Utc::now();
|
||||||
let formatted = time.to_rfc3339_opts(chrono::SecondsFormat::Secs, false);
|
let formatted = time.to_rfc3339_opts(chrono::SecondsFormat::Secs, false);
|
||||||
path.push(format!("{formatted}.combatlog"));
|
path.push(format!("{formatted}.combatlog"));
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use std::{cell::OnceCell, collections::HashMap, path::PathBuf, sync::{atomic::Ordering, Arc}, time::Duration};
|
use std::{cell::OnceCell, collections::HashMap, path::PathBuf, sync::{atomic::{AtomicBool, Ordering}, Arc}, time::Duration};
|
||||||
|
|
||||||
use common::{ControlPacket, TelemetryPacket};
|
use common::{ControlPacket, TelemetryPacket};
|
||||||
use eframe::{egui::{self, containers, Align2, Checkbox, Context, IconData, Id, ImageSource, Label, Ui}, Storage};
|
use eframe::{egui::{self, containers, Align2, Checkbox, Context, IconData, Id, ImageSource, Label, Ui}, Storage};
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use tokio::{runtime::Runtime, sync::{mpsc, watch::Receiver}};
|
use tokio::{runtime::Runtime, sync::{mpsc, watch::{self, Receiver}}};
|
||||||
use egui_toast::{Toast, Toasts};
|
use egui_toast::{Toast, Toasts};
|
||||||
|
|
||||||
use crate::{auto::Configurable, storage_dir::storage_dir, POWER_THRESHOLD};
|
use crate::{auto::Configurable, auto_impl::CONFIGS, storage::StorageManager, POWER_THRESHOLD};
|
||||||
|
|
||||||
pub const GUI: OnceCell<Context> = OnceCell::new();
|
pub const GUI: OnceCell<Context> = OnceCell::new();
|
||||||
|
|
||||||
pub fn gui(data: Receiver<GUIData>, toasts: mpsc::Receiver<Toast>, executor: Runtime) -> eframe::Result {
|
pub fn gui(data: Receiver<GUIData>, toasts: mpsc::Receiver<Toast>, executor: Runtime, autoconf: watch::Receiver<&'static [Configurable]>, storage: StorageManager, auto_allowed: Arc<AtomicBool>, auto_enabled: Arc<AtomicBool>) -> eframe::Result {
|
||||||
let icon = egui::include_image!("../assets/lizard.png");
|
let icon = egui::include_image!("../assets/lizard.png");
|
||||||
|
|
||||||
let icon = image::load_from_memory_with_format(include_bytes!("../assets/lizard.png"), ImageFormat::Png).unwrap();
|
let icon = image::load_from_memory_with_format(include_bytes!("../assets/lizard.png"), ImageFormat::Png).unwrap();
|
||||||
|
@ -35,7 +35,7 @@ pub fn gui(data: Receiver<GUIData>, toasts: mpsc::Receiver<Toast>, executor: Run
|
||||||
// This gives us image support:
|
// This gives us image support:
|
||||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||||
|
|
||||||
Ok(Box::new(GUI::with_receivers(data, toasts, executor, cc.storage.unwrap())))
|
Ok(Box::new(GUI::with_receivers(data, toasts, executor, storage, autoconf, auto_allowed, auto_enabled)))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,13 @@ pub struct GUIData {
|
||||||
pub last_command: Option<ControlPacket>,
|
pub last_command: Option<ControlPacket>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub const DEFAULT_VOLUME_THRESHOLD: f32 = 5.0;
|
pub const DEFAULT_VOLUME_THRESHOLD: f32 = 5.0;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub const DEFAULT_VOLUME_THRESHOLD: f32 = 1.0;
|
pub const DEFAULT_VOLUME_THRESHOLD: f32 = 1.0;
|
||||||
|
const VOLUME_THRESHOLD: Configurable = Configurable::new("Volume").range(0.0..10.).default(DEFAULT_VOLUME_THRESHOLD)
|
||||||
|
.description("higher accepts less noise (better)");
|
||||||
const DEFAULT_TURN_GAIN: f32 = 0.3;
|
const DEFAULT_TURN_GAIN: f32 = 0.3;
|
||||||
const DEFAULT_FIRE_DISTANCE: f32 = 55.0;
|
const DEFAULT_FIRE_DISTANCE: f32 = 55.0;
|
||||||
|
|
||||||
|
@ -57,72 +60,45 @@ struct GUI {
|
||||||
data: Receiver<GUIData>,
|
data: Receiver<GUIData>,
|
||||||
toasts: mpsc::Receiver<Toast>,
|
toasts: mpsc::Receiver<Toast>,
|
||||||
executor: Option<Runtime>,
|
executor: Option<Runtime>,
|
||||||
volume_threshold: f32,
|
|
||||||
auto_turn_gain: f32,
|
|
||||||
/// mm
|
|
||||||
auto_fire_distance: f32,
|
|
||||||
selected_auto: usize,
|
selected_auto: usize,
|
||||||
|
autoconf: watch::Receiver<&'static [Configurable]>,
|
||||||
|
storage: StorageManager,
|
||||||
|
auto_allowed: Arc<AtomicBool>,
|
||||||
|
auto_enabled: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GUI {
|
impl GUI {
|
||||||
fn with_receivers(data: Receiver<GUIData>, toasts: mpsc::Receiver<Toast>, executor: Runtime, storage: &dyn Storage) -> Self {
|
fn with_receivers(data: Receiver<GUIData>, toasts: mpsc::Receiver<Toast>, executor: Runtime, storage: StorageManager, autoconf: watch::Receiver<&'static [Configurable]>, auto_allowed: Arc<AtomicBool>, auto_enabled: Arc<AtomicBool>) -> Self {
|
||||||
let volume_threshold: f32 = storage.get_string("volume_threshold").map(|s| s.parse().ok()).flatten().unwrap_or(DEFAULT_VOLUME_THRESHOLD);
|
|
||||||
|
|
||||||
let auto_turn_gain: f32 = storage.get_string("auto_turn_gain").map(|s| s.parse().ok()).flatten().unwrap_or(DEFAULT_TURN_GAIN);
|
|
||||||
|
|
||||||
let auto_fire_distance: f32 = storage.get_string("auto_fire_distance").map(|s| s.parse().ok()).flatten().unwrap_or(DEFAULT_FIRE_DISTANCE);
|
|
||||||
|
|
||||||
let selected_auto: usize = storage.get_string("selected_auto").map(|s| s.parse().ok()).flatten().unwrap_or(0);
|
|
||||||
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
toasts,
|
toasts,
|
||||||
executor: Some(executor),
|
executor: Some(executor),
|
||||||
volume_threshold,
|
selected_auto: 0,
|
||||||
auto_turn_gain,
|
autoconf,
|
||||||
auto_fire_distance,
|
storage,
|
||||||
selected_auto,
|
auto_allowed,
|
||||||
|
auto_enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dupe from auto crate for testing
|
|
||||||
const AUTO_GAP: Configurable = Configurable::new("auto minimum gap").range(0. .. 300.).default(140.)
|
|
||||||
.description("distance (mm) distance measurements must instantaneously drop to indicate a detection. This should line up with the size of the smallest robot you compete against");
|
|
||||||
const AUTO_SELF_OCCLUSION: Configurable = Configurable::new("auto self occlusion").range(0. .. 200.).default(143.)
|
|
||||||
.description("distance (mm) below which measurements are considered noise in the scan phase");
|
|
||||||
|
|
||||||
pub static CONFIGS: &[Configurable] = &[
|
|
||||||
AUTO_GAP,
|
|
||||||
AUTO_SELF_OCCLUSION,
|
|
||||||
];
|
|
||||||
|
|
||||||
impl eframe::App for GUI {
|
impl eframe::App for GUI {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
let _ = GUI.set(ctx.clone());
|
let _ = GUI.set(ctx.clone());
|
||||||
egui::SidePanel::right(Id::new("config")).resizable(false).show(ctx, |ui| {
|
egui::SidePanel::right(Id::new("config")).resizable(false).show(ctx, |ui| {
|
||||||
ui.heading("configuration");
|
ui.heading("configuration");
|
||||||
ui.add(egui::Slider::new(&mut self.volume_threshold, 0.0..=10.0).text("volume threshold"));
|
|
||||||
ui.label("higher accepts less noise (better)");
|
configurator(ui, &VOLUME_THRESHOLD, &self.storage);
|
||||||
ui.add(egui::Slider::new(&mut self.auto_turn_gain, 0.0..=1.0).text("auto turn kP"));
|
|
||||||
ui.add(egui::Slider::new(&mut self.auto_fire_distance, 30.0..=100.0).text("auto fire distance (mm)"));
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
egui::ComboBox::new("auto selector", "select auto")
|
egui::ComboBox::new("auto selector", "select auto")
|
||||||
.show_index(ui, &mut self.selected_auto, 3, |n| ["a","b","c"][n]);
|
.show_index(ui, &mut self.selected_auto, 3, |n| ["a","b","c"][n]);
|
||||||
ui.button("refresh").clicked();
|
ui.button("refresh").clicked();
|
||||||
});
|
});
|
||||||
|
|
||||||
let storage = _frame.storage_mut().unwrap();
|
POWER_THRESHOLD.store(self.storage.load(&VOLUME_THRESHOLD), Ordering::Relaxed);
|
||||||
storage.set_string("volume_threshold", format!("{}",self.volume_threshold));
|
|
||||||
storage.set_string("auto_turn_gain", format!("{}",self.auto_turn_gain));
|
|
||||||
storage.set_string("auto_fire_distance", format!("{}",self.auto_fire_distance));
|
|
||||||
storage.set_string("selected_auto", format!("{}",self.selected_auto));
|
|
||||||
|
|
||||||
POWER_THRESHOLD.store(self.volume_threshold, Ordering::Relaxed);
|
|
||||||
|
|
||||||
for conf in CONFIGS {
|
for conf in CONFIGS {
|
||||||
configurator(ui, conf, storage);
|
configurator(ui, conf, &self.storage);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,6 +108,9 @@ impl eframe::App for GUI {
|
||||||
if let Some(ref command) = self.data.borrow().last_command {
|
if let Some(ref command) = self.data.borrow().last_command {
|
||||||
ui.label(format!("sending {command:?}"));
|
ui.label(format!("sending {command:?}"));
|
||||||
}
|
}
|
||||||
|
ui.label(format!("auto authorized: {}", if self.auto_allowed.load(Ordering::Acquire) {"✅"} else {"❌"}));
|
||||||
|
ui.label(format!("auto running: {}", if self.auto_enabled.load(Ordering::Acquire) {"✅ zoom vroom"} else {"❌"}));
|
||||||
|
|
||||||
if let Some(ref telem) = self.data.borrow().telemetry {
|
if let Some(ref telem) = self.data.borrow().telemetry {
|
||||||
ui.label(format!("Left tof: {}", if let Some(tof) = telem.sensors.tof_l {format!("✅ {tof}mm")} else {"❌".into()}));
|
ui.label(format!("Left tof: {}", if let Some(tof) = telem.sensors.tof_l {format!("✅ {tof}mm")} else {"❌".into()}));
|
||||||
ui.label(format!("Right tof: {}", if let Some(tof) = telem.sensors.tof_r {format!("✅ {tof}mm")} else {"❌".into()}));
|
ui.label(format!("Right tof: {}", if let Some(tof) = telem.sensors.tof_r {format!("✅ {tof}mm")} else {"❌".into()}));
|
||||||
|
@ -159,17 +138,8 @@ impl eframe::App for GUI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configurator(ui: &mut Ui, config: &Configurable, map: &mut dyn Storage) {
|
fn configurator(ui: &mut Ui, config: &'static Configurable, map: &StorageManager) {
|
||||||
ui.add(egui::Slider::from_get_set(config.min as f64 ..= config.max as f64, |value| {
|
ui.add(egui::Slider::from_get_set(config.min as f64 ..= config.max as f64, map.get_set(config)).text(config.name));
|
||||||
match value {
|
|
||||||
Some(value) => {
|
|
||||||
map.set_string(&config.name,format!("{value}"));
|
|
||||||
value
|
|
||||||
},
|
|
||||||
None => map.get_string(&config.name).map(|s| s.parse().ok()).flatten().unwrap_or(config.default as f64),
|
|
||||||
}
|
|
||||||
|
|
||||||
}).text(config.name));
|
|
||||||
if let Some(description) = config.description {
|
if let Some(description) = config.description {
|
||||||
ui.label(description);
|
ui.label(description);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,10 @@ use atomic_float::AtomicF32;
|
||||||
use gui::DEFAULT_VOLUME_THRESHOLD;
|
use gui::DEFAULT_VOLUME_THRESHOLD;
|
||||||
|
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod storage_dir;
|
|
||||||
pub mod combatlog;
|
pub mod combatlog;
|
||||||
pub mod auto;
|
pub mod auto;
|
||||||
|
pub mod auto_impl;
|
||||||
|
pub mod storage;
|
||||||
|
|
||||||
pub const POWER_THRESHOLD: AtomicF32 = AtomicF32::new(DEFAULT_VOLUME_THRESHOLD);
|
pub const POWER_THRESHOLD: AtomicF32 = AtomicF32::new(DEFAULT_VOLUME_THRESHOLD);
|
||||||
|
|
||||||
|
|
0
interface/src/loader.rs
Normal file
0
interface/src/loader.rs
Normal file
|
@ -1,8 +1,9 @@
|
||||||
use std::{fmt::format, ops::ControlFlow, result, sync::{atomic::Ordering, Arc}, thread::{self, sleep}, time::Duration};
|
use std::{fmt::format, ops::ControlFlow, path::Path, result, sync::{atomic::{AtomicBool, Ordering}, Arc}, thread::{self, sleep}, time::Duration};
|
||||||
|
|
||||||
use anyhow::{Context, Ok, Result};
|
use anyhow::{Context, Ok, Result};
|
||||||
use atomic_float::AtomicF32;
|
use atomic_float::AtomicF32;
|
||||||
use interface::{auto::get_confs, combatlog::{combat_logger, CombatData}, POWER_THRESHOLD};
|
use directories::ProjectDirs;
|
||||||
|
use interface::{auto::{get_confs, Auto, AutoInterface}, auto_impl, combatlog::{combat_logger, CombatData}, gui::CONFIGS, storage::StorageManager, POWER_THRESHOLD};
|
||||||
use common::{ControlPacket, TelemetryPacket};
|
use common::{ControlPacket, TelemetryPacket};
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use egui_toast::{Toast, ToastKind};
|
use egui_toast::{Toast, ToastKind};
|
||||||
|
@ -13,8 +14,22 @@ use tokio::{io::{AsyncReadExt, AsyncWriteExt, BufWriter, WriteHalf}, net::{tcp::
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
get_confs().unwrap();
|
let directories = ProjectDirs::from("dev", "ank", "Cruise Control").context("no home")?;
|
||||||
panic!("got too far");
|
let auto = Auto::new("../auto/target/release/libauto.so")?;
|
||||||
|
|
||||||
|
let storage = StorageManager::new(directories.config_dir().to_path_buf().join(Path::new("conf.dat")))?;
|
||||||
|
|
||||||
|
let auto_allowed = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
|
let (auto_telem_sender, auto_telem) = watch::channel(TelemetryPacket::default());
|
||||||
|
let (interface, auto_command, auto_enabled) = AutoInterface::new(auto_telem.clone(), storage.clone(), auto_allowed.clone());
|
||||||
|
|
||||||
|
println!("name: {}", auto.name());
|
||||||
|
|
||||||
|
for config in auto.configs().iter() {
|
||||||
|
println!("co {}", config.name);
|
||||||
|
println!("co {:?}", config.description);
|
||||||
|
}
|
||||||
|
|
||||||
let (logging_sender, combatlog) = mpsc::channel(64);
|
let (logging_sender, combatlog) = mpsc::channel(64);
|
||||||
|
|
||||||
|
@ -84,17 +99,20 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
|
|
||||||
let spawner = executor.handle().clone();
|
let spawner = executor.handle().clone();
|
||||||
|
let auto_allowed_ = auto_allowed.clone();
|
||||||
|
let interface_ = interface.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
spawner.block_on(async {
|
spawner.block_on(async {
|
||||||
|
|
||||||
let log_toasts = toast_sender.clone();
|
let log_toasts = toast_sender.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = combat_logger(combatlog).await {
|
if let Err(e) = combat_logger(combatlog, directories.data_dir()).await {
|
||||||
let _ = log_toasts.clone().send(Toast::new().text(format!("logger crashed: {e:?}")).kind(ToastKind::Error)).await;
|
let _ = log_toasts.clone().send(Toast::new().text(format!("logger crashed: {e:?}")).kind(ToastKind::Error)).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Err(e) = connect(toast_sender.clone(), notes.resubscribe(), data_sender.clone(), logging_sender.clone()).await {
|
if let Err(e) = connect(toast_sender.clone(), notes.resubscribe(), data_sender.clone(), logging_sender.clone(), auto_telem_sender.clone(), auto_allowed_.clone(), interface_.clone()).await {
|
||||||
if let Err(_) = toast_sender.send(Toast::new().text(format!("{e:?}")).kind(ToastKind::Error)).await {
|
if let Err(_) = toast_sender.send(Toast::new().text(format!("{e:?}")).kind(ToastKind::Error)).await {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -104,18 +122,30 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let interface_ = interface.clone();
|
||||||
|
let spawner = executor.handle().clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
spawner.block_on(async {
|
||||||
|
let _stoppie = auto_impl::auto(interface_).await;
|
||||||
|
println!("auto ended");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
println!("launching gui");
|
println!("launching gui");
|
||||||
gui(gui_data, toasts, executor).unwrap();
|
let (_conf_sender, conf) = watch::channel(CONFIGS);
|
||||||
|
gui(gui_data, toasts, executor, conf, storage.clone(), auto_allowed, auto_enabled).unwrap();
|
||||||
|
|
||||||
drop(stream);
|
drop(stream);
|
||||||
|
|
||||||
|
storage.save();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// frequency, volume
|
/// frequency, volume
|
||||||
type Detection = (Option<f32>, f32);
|
type Detection = (Option<f32>, f32);
|
||||||
|
|
||||||
async fn connect(toast_sender: mpsc::Sender<Toast>, notes: broadcast::Receiver<Detection>, data_sender: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>) -> Result<()>{
|
async fn connect(toast_sender: mpsc::Sender<Toast>, notes: broadcast::Receiver<Detection>, data_sender: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>, auto_sender: watch::Sender<TelemetryPacket>, auto_allowed: Arc<AtomicBool>, interface: AutoInterface) -> Result<()>{
|
||||||
toast_sender.send(Toast::new().text("connecting to bot").kind(ToastKind::Info)).await?;
|
toast_sender.send(Toast::new().text("connecting to bot").kind(ToastKind::Info)).await?;
|
||||||
let cruisecontrol = TcpStream::connect("192.168.1.2:1234").await?;
|
let cruisecontrol = TcpStream::connect("192.168.1.2:1234").await?;
|
||||||
println!("connected");
|
println!("connected");
|
||||||
|
@ -123,13 +153,13 @@ async fn connect(toast_sender: mpsc::Sender<Toast>, notes: broadcast::Receiver<D
|
||||||
cruisecontrol.set_nodelay(true)?;
|
cruisecontrol.set_nodelay(true)?;
|
||||||
let (telem, control) = cruisecontrol.into_split();
|
let (telem, control) = cruisecontrol.into_split();
|
||||||
|
|
||||||
tokio::spawn(telemetry_handler(telem, data_sender.clone(), logging_sender.clone()));
|
tokio::spawn(telemetry_handler(telem, data_sender.clone(), logging_sender.clone(), auto_sender.clone()));
|
||||||
|
|
||||||
controller(notes, control, data_sender.clone(), logging_sender.clone()).await?;
|
controller(notes, control, data_sender.clone(), logging_sender.clone(), auto_allowed, interface).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn telemetry_handler(mut telem: OwnedReadHalf, gui: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>) -> Result<()> {
|
async fn telemetry_handler(mut telem: OwnedReadHalf, gui: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>, auto_sender: watch::Sender<TelemetryPacket>) -> Result<()> {
|
||||||
let mut buf = vec![0; 2048];
|
let mut buf = vec![0; 2048];
|
||||||
loop {
|
loop {
|
||||||
let len = telem.read_u32().await.context("bad length")? as usize;
|
let len = telem.read_u32().await.context("bad length")? as usize;
|
||||||
|
@ -139,7 +169,8 @@ async fn telemetry_handler(mut telem: OwnedReadHalf, gui: watch::Sender<GUIData>
|
||||||
|
|
||||||
//println!("telem: {telem:?}");
|
//println!("telem: {telem:?}");
|
||||||
|
|
||||||
logging_sender.send(CombatData::Telemetry(telem.clone())).await?;
|
auto_sender.send(telem.clone())?;
|
||||||
|
let _ = logging_sender.send(CombatData::Telemetry(telem.clone())).await;
|
||||||
|
|
||||||
gui.send_modify(|gui| {
|
gui.send_modify(|gui| {
|
||||||
gui.telemetry = Some(telem);
|
gui.telemetry = Some(telem);
|
||||||
|
@ -148,7 +179,7 @@ async fn telemetry_handler(mut telem: OwnedReadHalf, gui: watch::Sender<GUIData>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn controller(mut notes: broadcast::Receiver<Detection>, controller: OwnedWriteHalf, gui: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>) -> Result<()> {
|
async fn controller(mut notes: broadcast::Receiver<Detection>, controller: OwnedWriteHalf, gui: watch::Sender<GUIData>, logging_sender: mpsc::Sender<CombatData>, enable: Arc<AtomicBool>, interface: AutoInterface) -> Result<()> {
|
||||||
let mut controller = BufWriter::new(controller);
|
let mut controller = BufWriter::new(controller);
|
||||||
//send_packet(&mut controller, ControlPacket::Arm(true)).await?;
|
//send_packet(&mut controller, ControlPacket::Arm(true)).await?;
|
||||||
//println!("armed flipper");
|
//println!("armed flipper");
|
||||||
|
@ -158,6 +189,8 @@ async fn controller(mut notes: broadcast::Receiver<Detection>, controller: Owned
|
||||||
|
|
||||||
//auto = Some(spawn(seek))
|
//auto = Some(spawn(seek))
|
||||||
|
|
||||||
|
let mut auto_data = interface.subscribe();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut control = ControlPacket::Stop;
|
let mut control = ControlPacket::Stop;
|
||||||
|
|
||||||
|
@ -170,14 +203,18 @@ async fn controller(mut notes: broadcast::Receiver<Detection>, controller: Owned
|
||||||
let (note,vol) = note.context("channel closed")?;
|
let (note,vol) = note.context("channel closed")?;
|
||||||
if let Some(note) = note {
|
if let Some(note) = note {
|
||||||
dbg!(note);
|
dbg!(note);
|
||||||
if let ControlFlow::Break(_) = sax_control(&mut control, vol, note) {
|
if let ControlFlow::Break(_) = sax_control(&mut control, vol, note, enable.clone()) {
|
||||||
if let ControlFlow::Break(_) = recorder_control(&mut control, vol, note) {
|
if let ControlFlow::Break(_) = recorder_control(&mut control, vol, note, enable.clone()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if enable.load(Ordering::Acquire) && interface.enabled() {
|
||||||
|
control = auto_data.borrow_and_update().clone();
|
||||||
|
}
|
||||||
|
|
||||||
send_packet(&mut controller, control.clone()).await?;
|
send_packet(&mut controller, control.clone()).await?;
|
||||||
logging_sender.send(CombatData::Control(control.clone())).await?;
|
let _ = logging_sender.send(CombatData::Control(control.clone())).await;
|
||||||
gui.send_modify(|gui| gui.last_command = Some(control));
|
gui.send_modify(|gui| gui.last_command = Some(control));
|
||||||
} else {
|
} else {
|
||||||
send_packet(&mut controller, ControlPacket::Twist(0.0, 0.0)).await?;
|
send_packet(&mut controller, ControlPacket::Twist(0.0, 0.0)).await?;
|
||||||
|
@ -190,7 +227,7 @@ async fn controller(mut notes: broadcast::Receiver<Detection>, controller: Owned
|
||||||
/// Weapon enabled
|
/// Weapon enabled
|
||||||
const ARMED: bool = true;
|
const ARMED: bool = true;
|
||||||
|
|
||||||
fn sax_control(control: &mut ControlPacket, vol: f32, frequency: f32) -> ControlFlow<()> {
|
fn sax_control(control: &mut ControlPacket, vol: f32, frequency: f32, enable: Arc<AtomicBool>) -> ControlFlow<()> {
|
||||||
if frequency < 150. {
|
if frequency < 150. {
|
||||||
println!("too low");
|
println!("too low");
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
|
@ -243,7 +280,7 @@ fn sax_control(control: &mut ControlPacket, vol: f32, frequency: f32) -> Control
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn recorder_control(control: &mut ControlPacket, vol: f32, frequency: f32) -> ControlFlow<()> {
|
fn recorder_control(control: &mut ControlPacket, vol: f32, frequency: f32, enable: Arc<AtomicBool>) -> ControlFlow<()> {
|
||||||
if frequency < 300. {
|
if frequency < 300. {
|
||||||
println!("too low");
|
println!("too low");
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
|
@ -283,15 +320,12 @@ fn recorder_control(control: &mut ControlPacket, vol: f32, frequency: f32) -> Co
|
||||||
*control = ControlPacket::Stop;
|
*control = ControlPacket::Stop;
|
||||||
}
|
}
|
||||||
Pitch { letter: NoteLetter::F, accidental: 0} => {
|
Pitch { letter: NoteLetter::F, accidental: 0} => {
|
||||||
println!("stop");
|
println!("auto en");
|
||||||
*control = ControlPacket::Stop;
|
enable.store(true, Ordering::Release);
|
||||||
}
|
}
|
||||||
Pitch { letter: NoteLetter::E, accidental: 0} => {
|
Pitch { letter: NoteLetter::E, accidental: 0} => {
|
||||||
println!("stop");
|
println!("auto disable");
|
||||||
*control = ControlPacket::Stop;
|
enable.store(false, Ordering::Release);
|
||||||
//if let result::Result::Ok(command) = auto_rx.try_recv() {
|
|
||||||
// control = command;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
pitch => {
|
pitch => {
|
||||||
if vol > 3000. {
|
if vol > 3000. {
|
||||||
|
|
57
interface/src/storage.rs
Normal file
57
interface/src/storage.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use std::{cell::RefCell, collections::HashMap, fs::File, io::{Read, Write}, path::PathBuf, sync::Arc};
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
|
||||||
|
use crate::auto::Configurable;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct StorageManager {
|
||||||
|
map: Arc<DashMap<String, f32>>,
|
||||||
|
storage: Arc<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageManager {
|
||||||
|
pub fn new(path: PathBuf) -> Result<Self> {
|
||||||
|
let map = if let Ok(mut file) = File::open(path.clone()) {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
file.read_to_end(&mut vec)?;
|
||||||
|
postcard::from_bytes_cobs(&mut vec)?
|
||||||
|
} else {
|
||||||
|
DashMap::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let map = Arc::new(map);
|
||||||
|
|
||||||
|
Ok(Self { map, storage: Arc::new(path) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(&self) {
|
||||||
|
let map = postcard::to_stdvec_cobs(&self.map).unwrap();
|
||||||
|
|
||||||
|
// TODO: mkdir
|
||||||
|
let mut backing_file = File::options().write(true).truncate(true).create(true)
|
||||||
|
.open(self.storage.as_path()).unwrap();
|
||||||
|
backing_file.write_all(&map).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&self, setting: &'static Configurable) -> f32 {
|
||||||
|
self.map.get(setting.name).map(|v| *v).unwrap_or(setting.default)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store(&self, setting: &'static Configurable, value: f32) {
|
||||||
|
self.map.insert(setting.name.to_owned(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_set(&self, setting: &'static Configurable) -> impl 'static + FnMut(Option<f64>) -> f64 {
|
||||||
|
let self_ = self.clone();
|
||||||
|
let setting_ = setting;
|
||||||
|
move |new| {
|
||||||
|
if let Some(new) = new {
|
||||||
|
self_.store(setting_, new as f32);
|
||||||
|
}
|
||||||
|
self_.load(setting_) as f64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,157 +0,0 @@
|
||||||
// copied from eframe (private item)
|
|
||||||
// https://docs.rs/eframe/latest/src/eframe/native/file_storage.rs.html#17
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use eframe::egui;
|
|
||||||
|
|
||||||
pub fn storage() -> PathBuf {
|
|
||||||
storage_dir("cruisecontrol").unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn storage_dir(app_id: &str) -> Option<PathBuf> {
|
|
||||||
|
|
||||||
use egui::os::OperatingSystem as OS;
|
|
||||||
|
|
||||||
use std::env::var_os;
|
|
||||||
|
|
||||||
match OS::from_target_os() {
|
|
||||||
|
|
||||||
OS::Nix => var_os("XDG_DATA_HOME")
|
|
||||||
|
|
||||||
.map(PathBuf::from)
|
|
||||||
|
|
||||||
.filter(|p| p.is_absolute())
|
|
||||||
|
|
||||||
.or_else(|| home::home_dir().map(|p| p.join(".local").join("share")))
|
|
||||||
|
|
||||||
.map(|p| {
|
|
||||||
|
|
||||||
p.join(
|
|
||||||
|
|
||||||
app_id
|
|
||||||
|
|
||||||
.to_lowercase()
|
|
||||||
|
|
||||||
.replace(|c: char| c.is_ascii_whitespace(), ""),
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
}),
|
|
||||||
|
|
||||||
OS::Mac => home::home_dir().map(|p| {
|
|
||||||
|
|
||||||
p.join("Library")
|
|
||||||
|
|
||||||
.join("Application Support")
|
|
||||||
|
|
||||||
.join(app_id.replace(|c: char| c.is_ascii_whitespace(), "-"))
|
|
||||||
|
|
||||||
}),
|
|
||||||
|
|
||||||
OS::Windows => roaming_appdata().map(|p| p.join(app_id).join("data")),
|
|
||||||
|
|
||||||
OS::Unknown | OS::Android | OS::IOS => None,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapted from
|
|
||||||
|
|
||||||
// https://github.com/rust-lang/cargo/blob/6e11c77384989726bb4f412a0e23b59c27222c34/crates/home/src/windows.rs#L19-L37
|
|
||||||
|
|
||||||
#[cfg(all(windows, not(target_vendor = "uwp")))]
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
|
|
||||||
fn roaming_appdata() -> Option<PathBuf> {
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
use std::os::windows::ffi::OsStringExt;
|
|
||||||
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
|
|
||||||
use windows_sys::Win32::Foundation::S_OK;
|
|
||||||
|
|
||||||
use windows_sys::Win32::System::Com::CoTaskMemFree;
|
|
||||||
|
|
||||||
use windows_sys::Win32::UI::Shell::{
|
|
||||||
|
|
||||||
FOLDERID_RoamingAppData, SHGetKnownFolderPath, KF_FLAG_DONT_VERIFY,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
fn wcslen(buf: *const u16) -> usize;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut path_raw = ptr::null_mut();
|
|
||||||
|
|
||||||
|
|
||||||
// SAFETY: SHGetKnownFolderPath allocates for us, we don't pass any pointers to it.
|
|
||||||
|
|
||||||
// See https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
|
|
||||||
|
|
||||||
let result = unsafe {
|
|
||||||
|
|
||||||
SHGetKnownFolderPath(
|
|
||||||
|
|
||||||
&FOLDERID_RoamingAppData,
|
|
||||||
|
|
||||||
KF_FLAG_DONT_VERIFY as u32,
|
|
||||||
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
|
|
||||||
&mut path_raw,
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let path = if result == S_OK {
|
|
||||||
|
|
||||||
// SAFETY: SHGetKnownFolderPath indicated success and is supposed to allocate a nullterminated string for us.
|
|
||||||
|
|
||||||
let path_slice = unsafe { slice::from_raw_parts(path_raw, wcslen(path_raw)) };
|
|
||||||
|
|
||||||
Some(PathBuf::from(OsString::from_wide(path_slice)))
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
None
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// SAFETY:
|
|
||||||
|
|
||||||
// This memory got allocated by SHGetKnownFolderPath, we didn't touch anything in the process.
|
|
||||||
|
|
||||||
// A null ptr is a no-op for `CoTaskMemFree`, so in case this failed we're still good.
|
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cotaskmemfree
|
|
||||||
|
|
||||||
unsafe { CoTaskMemFree(path_raw.cast()) };
|
|
||||||
|
|
||||||
|
|
||||||
path
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(any(not(windows), target_vendor = "uwp"))]
|
|
||||||
|
|
||||||
fn roaming_appdata() -> Option<PathBuf> {
|
|
||||||
|
|
||||||
None
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue