Live can
This commit is contained in:
Generated
+144
-50
@@ -356,7 +356,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -488,7 +488,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -523,7 +523,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -588,7 +588,7 @@ dependencies = [
|
|||||||
"derive_utils",
|
"derive_utils",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -673,7 +673,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc-hash 2.1.2",
|
"rustc-hash 2.1.2",
|
||||||
"shlex",
|
"shlex",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -839,7 +839,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1092,7 +1092,7 @@ checksum = "9b5dc851b7ea80cc4f69aa28632385ffd3e0f88014d53db3f2e5a781896ca783"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1314,7 +1314,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1326,7 +1326,7 @@ checksum = "362f47930db19fe7735f527e6595e4900316b893ebf6d48ad3d31be928d57dd6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1365,7 +1365,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1610,6 +1610,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-can"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438"
|
||||||
|
dependencies = [
|
||||||
|
"nb",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.35"
|
version = "0.8.35"
|
||||||
@@ -1643,7 +1652,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1654,7 +1663,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1703,7 +1712,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1946,7 +1955,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2039,7 +2048,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2415,7 +2424,7 @@ dependencies = [
|
|||||||
"i-slint-renderer-software",
|
"i-slint-renderer-software",
|
||||||
"input",
|
"input",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"nix",
|
"nix 0.30.1",
|
||||||
"xkbcommon",
|
"xkbcommon",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2584,7 +2593,7 @@ checksum = "7931356d5238281e6be994ec15241fb2d9e66359776d53b4bd6b2fdd9c257c6e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2945,7 +2954,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3010,7 +3019,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"simd_cesu8",
|
"simd_cesu8",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3038,7 +3047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3281,7 +3290,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3519,6 +3528,12 @@ version = "1.0.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -3549,12 +3564,50 @@ dependencies = [
|
|||||||
"jni-sys 0.3.1",
|
"jni-sys 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "neli"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93062a0dce6da2517ea35f301dfc88184ce18d3601ec786a727a87bf535deca9"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"neli-proc-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "neli-proc-macros"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c8034b7fbb6f9455b2a96c19e6edf8dc9fc34c70449938d8ee3b4df363f61fe"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "new_debug_unreachable"
|
name = "new_debug_unreachable"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"cfg-if",
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.30.1"
|
version = "0.30.1"
|
||||||
@@ -3625,7 +3678,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3677,7 +3730,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4246,7 +4299,7 @@ dependencies = [
|
|||||||
"pest_meta",
|
"pest_meta",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4290,7 +4343,7 @@ dependencies = [
|
|||||||
"phf_shared",
|
"phf_shared",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4325,7 +4378,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4486,7 +4539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4523,7 +4576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
|
checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5050,7 +5103,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5074,7 +5127,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5367,7 +5420,36 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socketcan"
|
||||||
|
version = "3.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5e63effc7e77256358f700e5fb0160238501022fec00b75d5da03e9e385d932"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"embedded-can",
|
||||||
|
"hex",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"nb",
|
||||||
|
"neli",
|
||||||
|
"nix 0.29.0",
|
||||||
|
"socket2",
|
||||||
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5467,7 +5549,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5512,6 +5594,7 @@ dependencies = [
|
|||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"libsvld",
|
"libsvld",
|
||||||
"rfd",
|
"rfd",
|
||||||
|
"socketcan",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5525,6 +5608,17 @@ dependencies = [
|
|||||||
"zeno",
|
"zeno",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.117"
|
version = "2.0.117"
|
||||||
@@ -5544,7 +5638,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5642,7 +5736,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5653,7 +5747,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5850,7 +5944,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6138,7 +6232,7 @@ checksum = "482a37f9777480673d3a99c80ac2edc69f92382230440946855fa27ebc47cba6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6211,7 +6305,7 @@ dependencies = [
|
|||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6893,7 +6987,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6904,7 +6998,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7327,7 +7421,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-component",
|
"wit-component",
|
||||||
@@ -7343,7 +7437,7 @@ dependencies = [
|
|||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-bindgen-rust",
|
"wit-bindgen-rust",
|
||||||
]
|
]
|
||||||
@@ -7555,7 +7649,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7612,7 +7706,7 @@ checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"zbus-lockstep",
|
"zbus-lockstep",
|
||||||
"zbus_xml",
|
"zbus_xml",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
@@ -7627,7 +7721,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"zbus_names",
|
"zbus_names",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
@@ -7679,7 +7773,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7699,7 +7793,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7735,7 +7829,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7791,7 +7885,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7804,6 +7898,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"syn 2.0.117",
|
||||||
"winnow 1.0.3",
|
"winnow 1.0.3",
|
||||||
]
|
]
|
||||||
|
|||||||
+106
-57
@@ -30,16 +30,11 @@ struct FrameOutput {
|
|||||||
error_frames: Vec<ErrorFrame>,
|
error_frames: Vec<ErrorFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_worker(
|
/// Build the LD metadata for a single CAN id from the DBC, applying the
|
||||||
mmap: &[u8],
|
/// project's `ld_*`/`Frequency` attribute defaults. Returns `None` when the
|
||||||
dbc: &Dbc,
|
/// id is not described by the DBC (an "unknown" id). Shared by the ASC decode
|
||||||
) -> FrameOutput {
|
/// path and the live-CAN path so both produce identical metadata.
|
||||||
let mut channel_data = HashMap::<CanId, Vec<CanFrame>>::new();
|
pub fn build_message_metadata(dbc: &Dbc, id: CanId) -> Option<MessageMetadata> {
|
||||||
let mut metadatas = HashMap::<CanId, MessageMetadata>::new();
|
|
||||||
|
|
||||||
let mut unknown_ids = HashSet::<CanId>::new();
|
|
||||||
let mut error_frames = Vec::<ErrorFrame>::new();
|
|
||||||
|
|
||||||
let get_default = |name: &str| match dbc
|
let get_default = |name: &str| match dbc
|
||||||
.attribute_defaults
|
.attribute_defaults
|
||||||
.iter()
|
.iter()
|
||||||
@@ -56,57 +51,66 @@ fn frame_worker(
|
|||||||
let default_scale = get_default("ld_scale");
|
let default_scale = get_default("ld_scale");
|
||||||
let default_decimal_places = get_default("ld_decimal_places");
|
let default_decimal_places = get_default("ld_decimal_places");
|
||||||
|
|
||||||
let mut add_metadata = |id| {
|
let msg = dbc.messages.iter().find(|x| x.id.raw() == id)?;
|
||||||
let msg = match dbc.messages.iter().find(|x| x.id.raw() == id) {
|
let signals = &msg.signals;
|
||||||
Some(msg) => msg,
|
let mut signals_meta = Vec::<SignalMetadata>::new();
|
||||||
None => {
|
for signal in signals {
|
||||||
unknown_ids.insert(id);
|
let decimal_places = dbc
|
||||||
return;
|
.attribute_values_signal
|
||||||
}
|
|
||||||
};
|
|
||||||
let signals = &msg.signals;
|
|
||||||
let mut signals_meta = Vec::<SignalMetadata>::new();
|
|
||||||
for signal in signals {
|
|
||||||
let decimal_places = dbc
|
|
||||||
.attribute_values_signal
|
|
||||||
.iter()
|
|
||||||
.find(|x| {
|
|
||||||
x.message_id.raw() == id
|
|
||||||
&& x.signal_name == signal.name
|
|
||||||
&& x.name == "ld_decimal_places"
|
|
||||||
})
|
|
||||||
.map_or(default_decimal_places, |x| match x.value {
|
|
||||||
can_dbc::AttributeValue::Uint(val) => val,
|
|
||||||
_ => panic!("Bad ld_decimal_places value type, expected Uint."),
|
|
||||||
});
|
|
||||||
|
|
||||||
signals_meta.push(SignalMetadata {
|
|
||||||
shift: default_shift as u16,
|
|
||||||
scale: default_scale as u16,
|
|
||||||
decimal_places: decimal_places as u16,
|
|
||||||
name: signal.name.clone(),
|
|
||||||
unit: signal.unit.clone(),
|
|
||||||
signal: signal.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let frequency = dbc
|
|
||||||
.attribute_values_message
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|x| x.message_id.raw() == id && x.name == "Frequency")
|
.find(|x| {
|
||||||
.map_or(default_freqency, |x| match x.value {
|
x.message_id.raw() == id
|
||||||
|
&& x.signal_name == signal.name
|
||||||
|
&& x.name == "ld_decimal_places"
|
||||||
|
})
|
||||||
|
.map_or(default_decimal_places, |x| match x.value {
|
||||||
can_dbc::AttributeValue::Uint(val) => val,
|
can_dbc::AttributeValue::Uint(val) => val,
|
||||||
_ => panic!("Bad Frequency value type, expected Uint."),
|
_ => panic!("Bad ld_decimal_places value type, expected Uint."),
|
||||||
});
|
});
|
||||||
|
|
||||||
metadatas.insert(
|
signals_meta.push(SignalMetadata {
|
||||||
id,
|
shift: default_shift as u16,
|
||||||
MessageMetadata {
|
scale: default_scale as u16,
|
||||||
id,
|
decimal_places: decimal_places as u16,
|
||||||
frequency: frequency as u16,
|
name: signal.name.clone(),
|
||||||
signals: signals_meta,
|
unit: signal.unit.clone(),
|
||||||
},
|
signal: signal.clone(),
|
||||||
);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let frequency = dbc
|
||||||
|
.attribute_values_message
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.message_id.raw() == id && x.name == "Frequency")
|
||||||
|
.map_or(default_freqency, |x| match x.value {
|
||||||
|
can_dbc::AttributeValue::Uint(val) => val,
|
||||||
|
_ => panic!("Bad Frequency value type, expected Uint."),
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(MessageMetadata {
|
||||||
|
id,
|
||||||
|
frequency: frequency as u16,
|
||||||
|
signals: signals_meta,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame_worker(
|
||||||
|
mmap: &[u8],
|
||||||
|
dbc: &Dbc,
|
||||||
|
) -> FrameOutput {
|
||||||
|
let mut channel_data = HashMap::<CanId, Vec<CanFrame>>::new();
|
||||||
|
let mut metadatas = HashMap::<CanId, MessageMetadata>::new();
|
||||||
|
|
||||||
|
let mut unknown_ids = HashSet::<CanId>::new();
|
||||||
|
let mut error_frames = Vec::<ErrorFrame>::new();
|
||||||
|
|
||||||
|
let mut add_metadata = |id| match build_message_metadata(dbc, id) {
|
||||||
|
Some(meta) => {
|
||||||
|
metadatas.insert(id, meta);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unknown_ids.insert(id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Caller has aligned the chunk to line boundaries, so we always start at
|
// Caller has aligned the chunk to line boundaries, so we always start at
|
||||||
@@ -171,6 +175,51 @@ pub struct DecodeResult {
|
|||||||
pub info: DecodeProcessInfo,
|
pub info: DecodeProcessInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DecodeResult {
|
||||||
|
/// An empty result suitable for incrementally accumulating live CAN
|
||||||
|
/// frames via [`DecodeResult::push_live`]. The `info` fields that only
|
||||||
|
/// make sense for the file-based decode are zeroed.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
DecodeResult {
|
||||||
|
data: HashMap::new(),
|
||||||
|
metadata: HashMap::new(),
|
||||||
|
info: DecodeProcessInfo {
|
||||||
|
unknown_ids: HashSet::new(),
|
||||||
|
error_frames: Vec::new(),
|
||||||
|
date: chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc(),
|
||||||
|
thread_count: 0,
|
||||||
|
page_size: 0,
|
||||||
|
pages_per_chunk: 0,
|
||||||
|
chunk_size: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a single live frame, lazily resolving its metadata from the DBC
|
||||||
|
/// the first time an id is seen. Frames are expected to arrive in
|
||||||
|
/// non-decreasing timestamp order (as they do off a live bus), so no
|
||||||
|
/// re-sorting is performed — `compute_signal` consumes them in order.
|
||||||
|
pub fn push_live(&mut self, dbc: &Dbc, frame: CanFrame) {
|
||||||
|
match self.data.get_mut(&frame.can_id) {
|
||||||
|
Some(vec) => vec.push(frame),
|
||||||
|
None => {
|
||||||
|
let id = frame.can_id;
|
||||||
|
self.data.insert(id, vec![frame]);
|
||||||
|
if !self.metadata.contains_key(&id) {
|
||||||
|
match build_message_metadata(dbc, id) {
|
||||||
|
Some(meta) => {
|
||||||
|
self.metadata.insert(id, meta);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.info.unknown_ids.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decode(dbc: &Dbc,
|
pub fn decode(dbc: &Dbc,
|
||||||
asc_path: &Path) -> DecodeResult {
|
asc_path: &Path) -> DecodeResult {
|
||||||
let thread_count = std::thread::available_parallelism().unwrap().get();
|
let thread_count = std::thread::available_parallelism().unwrap().get();
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ egui_plot = "0.35"
|
|||||||
egui_ltreeview = "0.7"
|
egui_ltreeview = "0.7"
|
||||||
fuzzy-matcher = "0.3"
|
fuzzy-matcher = "0.3"
|
||||||
rfd = "0.17"
|
rfd = "0.17"
|
||||||
|
socketcan = "3.6.1"
|
||||||
|
|||||||
+127
-9
@@ -1,3 +1,4 @@
|
|||||||
|
mod can_live;
|
||||||
mod plot;
|
mod plot;
|
||||||
mod plot_list;
|
mod plot_list;
|
||||||
mod signal;
|
mod signal;
|
||||||
@@ -13,7 +14,7 @@ use std::{
|
|||||||
|
|
||||||
use can_dbc::Dbc;
|
use can_dbc::Dbc;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use libsvld::DecodeResult;
|
use libsvld::{can_frame::CanFrame, DecodeResult};
|
||||||
|
|
||||||
use crate::plot::show_plot_panel;
|
use crate::plot::show_plot_panel;
|
||||||
use crate::plot_list::{
|
use crate::plot_list::{
|
||||||
@@ -30,13 +31,36 @@ fn main() {
|
|||||||
native_options,
|
native_options,
|
||||||
Box::new(|cc| {
|
Box::new(|cc| {
|
||||||
let mut app = MyEguiApp::default();
|
let mut app = MyEguiApp::default();
|
||||||
// Optional CLI quick-load: `svldplotter [DBC [ASC]]`. Both args
|
// Optional CLI quick-load. Positional args are an optional DBC and
|
||||||
// are optional and intended for dev iteration.
|
// ASC, intended for dev iteration:
|
||||||
|
// svldplotter [DBC [ASC]]
|
||||||
|
// Passing `--can <iface>` (e.g. `svldplotter car.dbc --can can0`)
|
||||||
|
// switches to live mode: instead of reading an ASC file the
|
||||||
|
// plotter streams frames straight off the CAN bus and plots them
|
||||||
|
// in real time, using the DBC for signal metadata.
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
if let Some(dbc) = args.get(1) {
|
let mut positional: Vec<String> = Vec::new();
|
||||||
|
let mut can_iface: Option<String> = None;
|
||||||
|
let mut i = 1;
|
||||||
|
while i < args.len() {
|
||||||
|
match args[i].as_str() {
|
||||||
|
"--can" | "-c" => {
|
||||||
|
can_iface = args.get(i + 1).cloned();
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
positional.push(other.to_string());
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(dbc) = positional.first() {
|
||||||
app.load_dbc(PathBuf::from(dbc));
|
app.load_dbc(PathBuf::from(dbc));
|
||||||
}
|
}
|
||||||
if let Some(asc) = args.get(2) {
|
if let Some(iface) = can_iface {
|
||||||
|
// Live CAN takes precedence over any ASC argument.
|
||||||
|
app.start_can_live(&iface, &cc.egui_ctx);
|
||||||
|
} else if let Some(asc) = positional.get(1) {
|
||||||
app.asc_paths.push(PathBuf::from(asc));
|
app.asc_paths.push(PathBuf::from(asc));
|
||||||
app.set_active_asc(app.asc_paths.len() - 1, Some(&cc.egui_ctx));
|
app.set_active_asc(app.asc_paths.len() - 1, Some(&cc.egui_ctx));
|
||||||
}
|
}
|
||||||
@@ -74,6 +98,13 @@ struct MyEguiApp {
|
|||||||
next_plot_id: u64,
|
next_plot_id: u64,
|
||||||
cursor_x: Option<f64>,
|
cursor_x: Option<f64>,
|
||||||
left_tab: LeftTab,
|
left_tab: LeftTab,
|
||||||
|
/// Live CAN stream receiver, present only in `--can` mode.
|
||||||
|
live_rx: Option<Receiver<CanFrame>>,
|
||||||
|
/// Growing decode result fed by the live CAN stream.
|
||||||
|
live_data: Option<DecodeResult>,
|
||||||
|
/// Latest data x-extent from the previous frame, used to detect whether
|
||||||
|
/// the live view is pinned to the right edge for auto-scroll.
|
||||||
|
live_prev_max: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MyEguiApp {
|
impl MyEguiApp {
|
||||||
@@ -182,15 +213,95 @@ impl MyEguiApp {
|
|||||||
self.data = Some(data);
|
self.data = Some(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_dbc_toggles(&mut self, toggles: Vec<u64>) {
|
/// Enter live CAN mode: open `iface` and start streaming frames into a
|
||||||
let Some(data) = self.data.clone() else {
|
/// fresh, growing `DecodeResult`. Requires a DBC to already be loaded so
|
||||||
|
/// incoming frames can be resolved to signals.
|
||||||
|
fn start_can_live(&mut self, iface: &str, ctx: &egui::Context) {
|
||||||
|
if self.dbc.is_none() {
|
||||||
|
eprintln!("Cannot start live CAN: no DBC loaded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match can_live::spawn_reader(iface) {
|
||||||
|
Ok(rx) => {
|
||||||
|
self.live_rx = Some(rx);
|
||||||
|
self.live_data = Some(DecodeResult::empty());
|
||||||
|
// Clear any file-based state so the two sources don't mix.
|
||||||
|
self.active_asc = None;
|
||||||
|
self.data = None;
|
||||||
|
self.tree.clear();
|
||||||
|
ctx.request_repaint();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to open CAN interface '{iface}': {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drain any frames received from the live CAN stream, fold them into the
|
||||||
|
/// live `DecodeResult`, and re-resolve the tree and plotted signals so the
|
||||||
|
/// UI reflects the latest data. A repaint is always requested while live
|
||||||
|
/// so polling continues even when no frame arrived this tick.
|
||||||
|
fn poll_live(&mut self, ctx: &egui::Context) {
|
||||||
|
if self.live_rx.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Keep the UI ticking so we keep polling the stream.
|
||||||
|
ctx.request_repaint();
|
||||||
|
|
||||||
|
let Some(dbc) = self.dbc.clone() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Collect first so the receiver borrow is released before we mutate
|
||||||
|
// `self.live_data` below.
|
||||||
|
let frames: Vec<CanFrame> = self
|
||||||
|
.live_rx
|
||||||
|
.as_ref()
|
||||||
|
.map(|rx| rx.try_iter().collect())
|
||||||
|
.unwrap_or_default();
|
||||||
|
if frames.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(live) = self.live_data.as_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
for frame in frames {
|
||||||
|
live.push_live(&dbc, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-resolve tree and plots against the updated live data. These touch
|
||||||
|
// disjoint fields of `self`, so the borrows don't conflict.
|
||||||
|
let data = self.live_data.as_ref().unwrap();
|
||||||
|
self.tree = build_tree(&dbc, data);
|
||||||
|
for plot in &mut self.plots {
|
||||||
|
for sig in &mut plot.signals {
|
||||||
|
if let Some((msg_id, sig_idx)) = decode_signal_node_id(sig.id) {
|
||||||
|
if let Some(new_sig) = compute_signal(data, msg_id, sig_idx, sig.id) {
|
||||||
|
*sig = new_sig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_dbc_toggles(&mut self, toggles: Vec<u64>) {
|
||||||
for id in toggles {
|
for id in toggles {
|
||||||
if contains_signal(&self.plots, id) {
|
if contains_signal(&self.plots, id) {
|
||||||
remove_signal(&mut self.plots, id);
|
remove_signal(&mut self.plots, id);
|
||||||
} else if let Some((msg_id, sig_idx)) = decode_signal_node_id(id) {
|
} else if let Some((msg_id, sig_idx)) = decode_signal_node_id(id) {
|
||||||
if let Some(sig) = compute_signal(&data, msg_id, sig_idx, id) {
|
// Pull from the live stream when in `--can` mode, otherwise the
|
||||||
|
// decoded ASC. Accessed as disjoint fields so the immutable
|
||||||
|
// data borrow doesn't clash with the `self.plots` mutation.
|
||||||
|
let data = if self.live_data.is_some() {
|
||||||
|
self.live_data.as_ref()
|
||||||
|
} else {
|
||||||
|
self.data.as_deref()
|
||||||
|
};
|
||||||
|
let Some(data) = data else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let Some(sig) = compute_signal(data, msg_id, sig_idx, id) {
|
||||||
add_signal_auto(&mut self.plots, &mut self.next_plot_id, sig);
|
add_signal_auto(&mut self.plots, &mut self.next_plot_id, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,6 +378,7 @@ impl eframe::App for MyEguiApp {
|
|||||||
self.poll_pending();
|
self.poll_pending();
|
||||||
|
|
||||||
let ctx = ui.ctx().clone();
|
let ctx = ui.ctx().clone();
|
||||||
|
self.poll_live(&ctx);
|
||||||
egui::Panel::left(egui::Id::new("LeftPanel"))
|
egui::Panel::left(egui::Id::new("LeftPanel"))
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
@@ -317,7 +429,13 @@ impl eframe::App for MyEguiApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
show_plot_panel(ui, &self.plots, &mut self.cursor_x);
|
show_plot_panel(
|
||||||
|
ui,
|
||||||
|
&self.plots,
|
||||||
|
&mut self.cursor_x,
|
||||||
|
self.live_rx.is_some(),
|
||||||
|
&mut self.live_prev_max,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(job) = self.pending.as_ref() {
|
if let Some(job) = self.pending.as_ref() {
|
||||||
let name = job
|
let name = job
|
||||||
|
|||||||
+36
-2
@@ -65,7 +65,20 @@ fn line_label(sig: &PlottedSignal, cursor_x: Option<f64>) -> String {
|
|||||||
/// Clamp the visible x-range to [0, x_max]. Preserves the current zoom
|
/// Clamp the visible x-range to [0, x_max]. Preserves the current zoom
|
||||||
/// width when possible; if the zoomed-out width exceeds the data range,
|
/// width when possible; if the zoomed-out width exceeds the data range,
|
||||||
/// just snaps to the full range.
|
/// just snaps to the full range.
|
||||||
fn clamp_x_bounds(plot_ui: &mut egui_plot::PlotUi, x_max: f64) {
|
///
|
||||||
|
/// In live mode, if the view's right edge was pinned to the latest sample
|
||||||
|
/// (`prev_max`, the data extent from the previous frame), the window is
|
||||||
|
/// scrolled right to keep the right edge at the new `x_max` so the plot
|
||||||
|
/// auto-follows incoming data. Panning away from the edge disengages this.
|
||||||
|
fn clamp_x_bounds(
|
||||||
|
plot_ui: &mut egui_plot::PlotUi,
|
||||||
|
x_max: f64,
|
||||||
|
live: bool,
|
||||||
|
prev_max: Option<f64>,
|
||||||
|
) {
|
||||||
|
if !x_max.is_finite() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let bounds = plot_ui.plot_bounds();
|
let bounds = plot_ui.plot_bounds();
|
||||||
let lo = bounds.min();
|
let lo = bounds.min();
|
||||||
let hi = bounds.max();
|
let hi = bounds.max();
|
||||||
@@ -73,6 +86,19 @@ fn clamp_x_bounds(plot_ui: &mut egui_plot::PlotUi, x_max: f64) {
|
|||||||
let mut new_hi_x = hi[0];
|
let mut new_hi_x = hi[0];
|
||||||
let width = new_hi_x - new_lo_x;
|
let width = new_hi_x - new_lo_x;
|
||||||
|
|
||||||
|
if live && width < x_max {
|
||||||
|
// Pinned when the right edge sits at (or past) the previous extent.
|
||||||
|
// A tiny epsilon absorbs float error from last frame's snap.
|
||||||
|
let pinned = match prev_max {
|
||||||
|
Some(p) => new_hi_x >= p - width * 1e-3,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
if pinned {
|
||||||
|
new_hi_x = x_max;
|
||||||
|
new_lo_x = x_max - width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if width >= x_max {
|
if width >= x_max {
|
||||||
new_lo_x = 0.0;
|
new_lo_x = 0.0;
|
||||||
new_hi_x = x_max;
|
new_hi_x = x_max;
|
||||||
@@ -99,6 +125,8 @@ pub fn show_plot_panel(
|
|||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
plots: &[PlotGroup],
|
plots: &[PlotGroup],
|
||||||
cursor_x: &mut Option<f64>,
|
cursor_x: &mut Option<f64>,
|
||||||
|
live: bool,
|
||||||
|
prev_max: &mut Option<f64>,
|
||||||
) {
|
) {
|
||||||
egui::CentralPanel::default().show_inside(ui, |ui| {
|
egui::CentralPanel::default().show_inside(ui, |ui| {
|
||||||
if plots.is_empty() {
|
if plots.is_empty() {
|
||||||
@@ -109,6 +137,12 @@ pub fn show_plot_panel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (full_min, full_max) = full_x_range(plots);
|
let (full_min, full_max) = full_x_range(plots);
|
||||||
|
// Snapshot the previous frame's extent for the auto-follow decision,
|
||||||
|
// then record this frame's for the next one.
|
||||||
|
let follow_prev_max = *prev_max;
|
||||||
|
if full_max.is_finite() {
|
||||||
|
*prev_max = Some(full_max);
|
||||||
|
}
|
||||||
let link_group = ui.id().with("plot-link");
|
let link_group = ui.id().with("plot-link");
|
||||||
let plot_count = plots.len();
|
let plot_count = plots.len();
|
||||||
let plot_height =
|
let plot_height =
|
||||||
@@ -145,7 +179,7 @@ pub fn show_plot_panel(
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let response = plot.show(ui, |plot_ui| {
|
let response = plot.show(ui, |plot_ui| {
|
||||||
clamp_x_bounds(plot_ui, full_max);
|
clamp_x_bounds(plot_ui, full_max, live, follow_prev_max);
|
||||||
if plot_group.signals.is_empty() {
|
if plot_group.signals.is_empty() {
|
||||||
plot_ui.line(
|
plot_ui.line(
|
||||||
Line::new(
|
Line::new(
|
||||||
|
|||||||
Reference in New Issue
Block a user